« 2004年3月 | トップページ | 2004年5月 »

☆TreeViewを使ってみる。

[Windowsフォームアプリケーション]
<TreeNodeの追加と削除>
TreeViewへのTreeNodeの追加と削除を試してみました。なんかごちゃごちゃしていますが、 下記のプログラムで問題なく動作しているみたいです。
//選択ノードの兄弟を追加する。
procedure TWinForm.Button1_Click(sender: System.Object;
 e: System.EventArgs);
begin
 if (TreeView1.SelectedNode = nil) or
  (TreeView1.SelectedNode.Parent = nil) then
  TreeView1.Nodes.Add('Sibling')
 else
  TreeView1.SelectedNode.Parent.Nodes.Add('Sibling');
end;

//選択ノードの子を追加する。
procedure TWinForm.Button2_Click(sender: System.Object;
 e: System.EventArgs);
begin
 if (TreeView1.SelectedNode <> nil) then
  TreeView1.SelectedNode.Nodes.Add('Child');
end;

//選択ノード位置に挿入する。
procedure TWinForm.Button3_Click(sender: System.Object;
 e: System.EventArgs);
begin
 if (TreeView1.SelectedNode <> nil) then
 begin
  if (TreeView1.SelectedNode.Parent = nil) then
   TreeView1.Nodes.Insert
     (TreeView1.SelectedNode.Index, TreeNode.Create('Insert'))
  else
   TreeView1.SelectedNode.Parent.Nodes.Insert
     (TreeView1.SelectedNode.Index , TreeNode.Create('Insert'));
 end;
end;

//選択ノードを削除する。
procedure TWinForm.Button4_Click(sender: System.Object;
 e: System.EventArgs);
begin
 if (TreeView1.SelectedNode <> nil) then
  TreeView1.SelectedNode.Remove;
end;
<TreeNodeの取得>
TreeNodeの取得には下記のプロパティが用意されています。

FirstNode  ツリー ノード コレクション内の最初の子ツリー ノードを取得します。
LastNode  最後の子ツリー ノードを取得します。
NextNode  次のレベルにある兄弟ツリー ノードを取得します。
PrevNode  前のレベルにある兄弟ツリー ノードを取得します。
NextVisibleNode 次のレベルにある、表示されているツリー ノードを取得します。
PrevVisibleNode 前のレベルにある、表示されているツリー ノードを取得します。

<気になること>
私はTreeViewを使って階層構造のファイルの読み書きする時、Delphi7までは、TTreeNodeのLevelというプロパティを多用してきましたが、それが見当たりません。 その代わりになるかどうかわかりませんが、FullPathというプロパティがあります。 今後検討していきたいと思います。

|

☆コンポーネントの配置

[Windowsフォームアプリケーション]
フォーム上にコンポーネントを配置するとき、VCLフォームアプリケーションでは、Alignというプロパティが用意されていますが、Windowsフォームアプリケーションでは、Dockというプロパティを使います。

|

■1000カウント

今、このサイトを表示させたら、ちょうど1000カウントでした。ただそれだけの話なんですが、多くの皆さんに見て頂き、たいへんうれしく思っています。皆さんのお役に立つかどうかわかりませんが、これからもよろしくお願いします。

|

■REGIONって。

Windowsフォームアプリケーションを新規作成してコードをみると、デザイナ管理コードと四角形で囲われている項目があります。
これを展開すると

{$REGION 'デザイナ管理コード'}
   (略)
{$ENDREGION}

というようにREGIONというものが使われています。

これって、Helpで探しても出てこないようですが、上記のように使うと、折りたたまれた時にタイトルのみになり、コードが見やすくなるので、「結構いいかも」って感じです。

|

■IDE 日本語入力の不具合?

IDE内でコメントを日本語で入力しようとするとカーソル位置と違うところで候補が表示され、決定するとカーソル位置にきちんと入力されます。なんでかな??
[環境]
WinXP Pro, IME スタンダード2002 8.1.4004.0, Delphi8 pro

|

☆TMyListの使用例

[Windowsフォームアプリケーション]
☆ArrayListを使ったクラスで作成したTMyListの使用例です。
Button1をクリックすると、テストデータを作成して、ファイルに書き込みます。
Button2をクリックすると、ファイルからデータを読み込んでListViewに設定します。

 1.Windowsフォームアプリケーションを新規作成します。
 2.Button1, Button2, ListView1を配置します。
 3.フォームのPrivate宣言に
    MyList: TMyList;
   と記述します。
 4.下記の通りプログラムを記述します。

constructor TWinForm1.Create;
begin
 (略)
 MyList := TMyList.Create;

 //ListViewの設定
 ListView1.View := View.Details;
 ListView1.Columns.Add('No', 50, HorizontalAlignment.Center);
 ListView1.Columns.Add('Name', 200, HorizontalAlignment.Left);
end;

//SaveToFile
procedure TWinForm1.Button1_Click(sender: System.Object;
 e: System.EventArgs);
var
 I: Integer;
begin
 //ダミーデータの作成
 for I := 0 to 9 do
  MyList.Add(TMyItem.Create(I, 'Item'+Convert.ToString(I)));
 MyList.SaveToFile('c:\abc.dat');
end;

//LoadFromFile
procedure TWinForm1.Button2_Click(sender: System.Object;
 e: System.EventArgs);
var
 I: Integer;
 LI: ListViewItem;
begin
 MyList.LoadFromFile('c:\abc.dat');
 ListView1.Items.Clear;
 for I := 0 to MyList.Count -1 do
 begin
  LI := ListView1.Items.Add(Convert.ToString(MyList[I].No));
  LI.SubItems.Add(MyList[I].Item);
 end;
end;

※SaveToFileは2回目に実行したときにエラーになります。
 これに対応するためには、TMyListの procedure SaveToFile中の下記部分を変更します。
//fs := FileStream.Create(FILENAME, FileMode.CreateNew);
  fs := FileStream.Create(FILENAME, FileMode.Create);
  (FileMode.CreateNewではなく、FileMode.Createとします。)

|

☆ArrayListを使ったクラス

[Windowsフォームアプリケーション]
今までTListを多用してきましたが、Windowsフォームアプリケーションでは、基本的にそれが使えません。リストから自作する必要があるのかなとあきらめていたところ System.Collections.ArrayList というものを見つけました。早速簡単なクラスを作ってみましたが、TListと同じように使えるので、これで問題はなさそうです。

<TMyItemクラスをTMyListクラスで管理する。>
uses System.IO;

 TMyItem = class(TObject)
 private
  FNo: Integer;
  FItem: String;
 public
  constructor Create(No: Integer; Item: String);
 published
  property No: Integer read FNo write FNo;
  property Item: String read FItem write FItem;
 end;

 TMyList = class(TObject)
 private
  FList: ArrayList;
  function GetData(Index: Integer): TMyItem;
  procedure SetData(Index: Integer; MyItem: TMyItem);
  function GetCount: Integer;
 protected
  procedure Error;
 public
  constructor Create;
  procedure Clear; 
  function Add(MyItem: TMyItem): Integer;
  procedure Insert(Index: Integer; MyItem: TMyItem);
  procedure Delete(Index: Integer);
  procedure SaveToFile(const FileName: String);
  procedure LoadFromFile(const FileName: String);
  property Items[Index: Integer]: TMyItem read GetData
   write SetData; default;
 published
  property Count: Integer read GetCount;
 end;

{ TMyItem }

constructor TMyItem.Create(No: Integer; Item: String);
begin
 inherited Create;
 FNo := No;
 FItem := Item;
end;

{ TMyList }

constructor TMyList.Create;
begin
 inherited Create;
 FList := ArrayList.Create;
end;

procedure TMyList.Clear;
begin
 FList.Clear;
end;

procedure TMyList.Error;
const
 Mes = 'インデックスがリストの範囲を超えています';
begin
 raise Exception.Create(Mes);
end;

function TMyList.GetCount: Integer;
begin
 Result := FList.Count;
end;

function TMyList.GetData(Index: Integer): TMyItem;
begin
 if (Index < 0) or (Index >= FList.Count) then Error;
 Result := TMyItem(FList[Index]);
end;

procedure TMyList.SetData(Index: Integer; MyItem: TMyItem);
begin
 if (Index < 0) or (Index >= FList.Count) then Error;
 FList[Index] := MyItem;
end;

function TMyList.Add(MyItem: TMyItem): Integer;
begin
 Result := FList.Add(MyItem);
end;

procedure TMyList.Insert(Index: Integer; MyItem: TMyItem);
begin
 FList.Insert(Index, MyItem);
end;

procedure TMyList.Delete(Index: Integer);
begin
 TMyItem(FList[Index]).Free;
 FList.RemoveAt(Index);
end;

procedure TMyList.SaveToFile(const FileName: String);
var
 fs: FileStream;
 I: Integer;
 w: BinaryWriter;
begin
 fs := FileStream.Create(FILENAME, FileMode.CreateNew);
 try
  w := BinaryWriter.Create(fs);
  try
   w.Write(FList.Count);
   for I := 0 to Count -1 do
   begin
    w.Write(TMyItem(FList[I]).No);
    w.Write(TMyItem(FList[I]).Item);
   end;
  finally
   W.Close;
  end;
 finally
  fs.Close;
 end;
end;

procedure TMyList.LoadFromFile(const FileName: String);
var
 fs: FileStream;
 I, J: Integer;
 r: BinaryReader;
 No: Integer;
 Item: String;
begin
 FList.Clear;
 fs := FileStream.Create(FILENAME, FileMode.Open, FileAccess.Read);
 try
  r := BinaryReader.Create(fs);
  try
   J := r.ReadInt32;
   for I := 0 to J -1 do
   begin
    No := r.ReadInt32;
    Item := r.ReadString;
    FList.Add(TMyItem.Create(No, Item));
   end;
  finally
   r.Close;
  end;
 finally
  fs.Close;
 end;
end;

※注釈は面倒なので入れていません。
※かなり適当に書いたので、間違いがあるかもしれません。

|

■ASAドライバー用エントリ修正

readme_upd2.txtの中に次のような記述がありました。
以下引用--------------------------------------------------------------
* Delphi 8 Professional Update 2 をインストールすると,
 dbExpress ini ファイルの ASA ドライバ用のエントリが正しくマ
 ージされません。次の手順にしたがって,dbxconnections.ini フ
 ァイルと dbxdrivers.ini ファイルを手動で編集し,欠けている
 ASA エントリを追加します。
------------------------------------------------------------------------
早速、修正しましたが、きちんとReadmeファイルは読んでおかないといけないですね。

|

■ところでアップデート2って?

アップデート2を適用したDelphi8を使っていて、ふと思いました。

「適用前と何が変わったんだろう。」

そこで、readme_upd2.txtを読んでみると、
このアップデートによって解決される問題
という項目でカテゴリ毎に修正内容が挙げられていました。
しかもその項目の多いこと・・・。

まだ、Update2を適用されておられない方は、ぜひ適用して下さいね。

|

☆印刷プレビュー

[Windowsフォームアプリケーション]
前回のサンプルを利用して、印刷プレビューのサンプルを作ってみました。
印刷プレビューには、PrintPreviewDialogを使います。

 1.前回作成したフォームにButton2、PrintPreviewDialog1を配置します。
 2.Button2のClickイベントとPrintDocument1のBeginPrintイベントに
   下記のプログラムを設定します。

procedure TWinForm1.Button2_Click(sender: System.Object;
  e: System.EventArgs);
begin
 StreamToPrint := StreamReader.Create('c:\PrintMe.txt');
         ↑↑テキストファイル名は適当に設定して。
 try
  PrintFont := System.Drawing.Font.Create('Arial', 10);
  PrintPreviewDialog1.ShowDialog();
 finally
  StreamToPrint.Close;
 end;
end;

procedure TWinForm1.PrintDocument1_BeginPrint(sender: System.Object;
  e: System.Drawing.Printing.PrintEventArgs);
begin
 StreamToPrint.BaseStream.Seek ( 0 , SeekOrigin.Begin ) ;
end;

|

☆簡単な印刷サンプル

[Windowsフォームアプリケーション]
.NET Framework SDKを見ながら、簡単な印刷サンプルを作ってみました。
このサンプルは、テキストファイルを読み込んでPrintDialogで設定された内容で印刷し
ます。(実際には印刷せずにFuji Xerox Docuworksに印刷して確認しました。)
 1.Windowsフォームアプリケーションを新規作成します。
 2.Button1, PrintDocument1, PrintDialog1を配置します。
 3.usesに System.IO を追加します。
 4.フォームのPrivate宣言に
    StreamToPrint: StreamReader;
    PrintFont: System.Drawing.Font;
   と記述します。
 5.Button1のClickイベントとPrintDocument1のPrintPageイベントに
   下記のプログラムを設定します。

procedure TWinForm1.Button1_Click(sender: System.Object; 
 e: System.EventArgs);
begin
 PrintDialog1.Document := PrintDocument1;

 if PrintDialog1.ShowDialog <> 
   System.Windows.Forms.DialogResult.OK then Exit;

 PrintDocument1.PrinterSettings := PrintDialog1.PrinterSettings;

 StreamToPrint := StreamReader.Create('c:\PrintMe.txt');
         ↑↑テキストファイル名は適当に設定して。
 try
  PrintFont := System.Drawing.Font.Create('Arial', 10);
  PrintDocument1.Print;
 finally
  StreamToPrint.Close;
 end;
end;


procedure TWinForm1.PrintDocument1_PrintPage(sender: System.Object;
 e: System.Drawing.Printing.PrintPageEventArgs);
var
 lpp: Single;
 yPos: Single;
 Count: Integer;
 LeftMargin: Single;
 TopMargin: Single;
 Line: String;
begin
 Count := 0;
 LeftMargin := e.MarginBounds.Left;
 TopMargin := e.MarginBounds.Top;

 lpp := e.MarginBounds.Height / PrintFont.GetHeight(e.Graphics);
 Line := StreamToPrint.ReadLine;

 while (Count < lpp) do
 begin
  yPos := TopMargin + (Count * PrintFont.GetHeight(e.Graphics));
  e.Graphics.DrawString (Line, PrintFont, Brushes.Black, 
   LeftMargin, yPos, StringFormat.Create);
  Inc(Count);
  if (Count < lpp) then
   Line := StreamToPrint.ReadLine;
 end;

 //これではLineが偶然空白行だった場合、
 //次ページが印刷されないのだがサンプルということでお許しを(^^;
 e.HasMorePages := (Line <> ''); 
end;

|

■カウンター数が・・・。

Googleで「Delphi8」というキーワードで検索するとトップページに表示されるようになったせいだと思うのですが、3日前につけたカウンターがもう320を超えています。予想に反して多くの方々に訪問して頂き、うれしく思っています。ただそれだけ「Delphi8」の情報が少ないということなんですよね。「Delphiでありながら、DelphiでないDelphi8」を前にして、私と同じように悩んでる方がたくさんおられるということでしょうか。トラックバックもコメントもできない、おまけにメールアドレスまで公開されていないというとてもわがままなサイトですが、私が悩んだことを書くことによって、少しでもみなさんのお役に立てればいいなと思っています。これからもよろしくお願いします。

|

■Delphi 8 アップデート2適用

次の手順により、日本語版Delphi8アップデート2を適用しました。
1.Borland USAより、Update2関連のファイルをダウンロードします。
  ・d8_ja_pro_upd2.exe
  ・RaveReportsSetup_ja.exe

2.下記の順番にインストールしました。
  ・d8_ja_pro_upd2.exe
  ・RaveReportsSetup_ja.exe

d8_ja_pro_upd2.exeインストール途中、
「セットアップによって、インストールで選択したドライバーに基づき新規の ファイルが作成されました。既存の ファイルのコピーをこれで上書きしますか?」
というメッセージに対しては「はい」を選択しました。
その後、Delphi8を起動させると
「指定されたキャストは有効ではありません。」
というエラーメッセージが表示されました。それを無視してOKボタンを押すと今度は、
「オブジェクト参照がオブジェクト インスタンスに設定されていません。」
というエラーメッセージが表示されました。これも無視してOKボタンを押すと、Delphi8が起動しました。
バージョンを確認したら7.1.1523.17956(Update2)となっており、アップデートの適用を終了しました。

しかしながら上記のエラーメッセージは、Delphi8を起動させるたびに表示されました。

このエラーメッセージが表示された場合の対処方法がBorlandのホームページで紹介されています。
※私は、Borlandのホームページの情報を知らずに、試行錯誤の結果、Windowsフォームアプリケーションを新規に作成し、コードを書かずに実行させ、そのままDelphi8を閉じることにより、このエラーがでなくなりました。

<環境>WinXP pro SP1、日本語版Delphi8 pro

Delphi8 Pro版のアップデートは、readme_upd2.txtを読んで、ASAドライバー用エントリを修正する必要があります。

|

■Delphi 8 アップデート2案内

Borlandのサイトで日本語版Delphi 8 アップデート2の案内がありました。明日にでも挑戦してみます。

|

☆RichTextBoxの読み書き

[Windowsフォームアプリケーション]
RichTextBoxを使ってテキストファイルを読み書きする簡単なサンプルです。

新規フォームにRichTextBox1,Button1,Button2,OpenFileDialog1,SaveFileDialog1を適当に配置します。

uses System.IO;

//読み込み
procedure TWinForm1.Button1_Click(sender: System.Object;
   e: System.EventArgs);
var
 FS: FileStream;
 Path: String;
begin
 if (OpenFileDialog1.ShowDialog =
   System.Windows.Forms.DialogResult.OK) then
 begin
   Path := OpenFileDialog1.FileName;

  //RTF(Rich Text Format)以外の読み込みではエラーになる。
  //RichTextBox1.LoadFile(Path);

  //テキストファイルを読み込む。
  RichTextBox1.LoadFile(Path, RichTextBoxStreamType.PlainText);

  //ストリームを使って読み込む。
  //FS := FileStream.Create(Path, FileMode.Open,
  //     FileAccess.ReadWrite);
  //RichTextBox1.LoadFile(FS, RichTextBoxStreamType.PlainText);
 end;
end;

//書き込み
procedure TWinForm1.Button2_Click(sender: System.Object;
   e: System.EventArgs);
var
 FS: FileStream;
 Path: String;
begin
 if (SaveFileDialog1.ShowDialog =
   System.Windows.Forms.DialogResult.OK) then
 begin
  Path := SaveFileDialog1.FileName;

  //RTF(Rich Text Format)として保存する。
  //RichTextBox1.SaveFile(Path);

  //テキストファイルとして保存する。
  RichTextBox1.SaveFile(Path, RichTextBoxStreamType.PlainText);

  //ストリームを使って保存する。
  //FS := FileStream.Create(Path, FileMode.Create,
  //        FileAccess.ReadWrite);
  //RichTextBox1.SaveFile(FS, RichTextBoxStreamType.PlainText);
 end;
end;

|

☆MouseDownの処理で・・・。(2)

[Windowsフォームアプリケーション]
前回、MouseDownの処理で、左ボタンが押されたというチェックをしましたが、今回は、どの修飾子キー (Shift、Ctrl、および Alt) と一緒に押されているかをチェックします。

if (System.Windows.Forms.Control.ModifierKeys =
   (Keys.Shift or Keys.Control or Keys.Alt)) and
   (e.Button = System.Windows.Forms.MouseButtons.Left) then
  MessageBox.Show('Hello World!');
このコードは、SHIFTキーとCTRLキーとALTキーを押しながら、左クリックした場合にメッセージを表示します。

SHIFTキーのみをチェックするのであれば、
(System.Windows.Forms.Control.ModifierKeys = Keys.Shift)
とします。

|

■アクセスカウンター

最近Googleで表示されるようになったので、カウンターをつけてみました。このサイトのコンセプトは、「私個人の備忘録」なので、みなさんのお役に立つことがあるのかどうかが疑問ですが、アクセスが多いようであればもう少しがんばって勉強していきたいと思います。

|

■InstallShieldの表記

Delphi8付属のInstallShieldをインストールして、「プログラムの追加と削除」で確認しますと、InstallShield Express Boland Editionと表示されています。BorlandではなくBolandです。InstallShield Software Corporationが間違えたのかどうかは知りませんし、細かいことなので敢えて取り上げるものでもないかも知れませんが、こういうところのチェックすらきちんとできていないというのは悲しい気持ちになります。(レジストリでProductNameを訂正したところ、きちんと表示されましたけど)

|

☆Windows XP テーマの適用

Windowsフォームで、XPテーマを適用するには、下記のような処理が必要になります。
・各コントロールのFlatStyleプロパティをSystemに設定する。
・マニフェストファイルを作成する。

↓↓↓詳しい内容はこちら↓↓↓
http://www.gotdotnet.com/japan/team/windowsforms/Themes.aspx

|

☆四角形でないフォーム

.NET Framework SDKに「四角形以外の Windows フォームの作成」のサンプルがありました。Win32だとAPIでややこしいプログラムを書く必要がありましたが、.NETだと次の手順で簡単に実現できます。
(モニタの色深度の設定が 24 ビットより大きい場合は、フォームの特定の部分が透明にならないという問題があるみたいですが)
1.フォームの形のビットマップを作成し、BackgroundImageプロパティに設定します。
2.FormBorderStyleプロパティをNoneに設定します。
3.TransparencyKeyプロパティにビットマップの背景色を設定します。
※プロパティは、すべてフォームのプロパティです。

詳細は、.NET Framework SDKを参照して下さい。
C#のサンプル中、Delphiで躓きそうなところは次ぐらいかな?
[C#]
  mouseOffset = new Point(xOffset, yOffset);
[Delphi]
  mouseOffset := Point.Create(xOffset, yOffset);

|

☆整数を文字列にするには?

[Windowsフォームアプリケーション]
整数を文字列にするためには、Convert.ToStringメソッドを使います。

ex) MessageBox.Show(Convert.ToString(123));

整数のみならず、様々な変換が可能です。又、Convertクラスには、Convert.ToXxxxxxというメソッドがたくさん用意されています。
詳しくは、HelpでConvertクラスを調べてみて下さい。

|

☆MouseDownの処理で・・・。

[Windowsフォームアプリケーション]
MouseDownの処理で、左ボタンが押されたという判定をさせようと次のような処理を書きました。

if (e.Button = MouseButtons.Left) then
 MessageBox.Show('Left');

しかし、次のようなコンパイルエラーになってしまいました。
「レコード、オブジェクトまたはクラスのいずれかが必要です。」

いろいろ試した結果、次のようにすればいいみたいです。

if (e.Button = System.Windows.Forms.MouseButtons.Left) then
 MessageBox.Show('Left');

わかってみると簡単なことですが、こんなことにさえ躓くなんて・・・(T_T)

|

■オフィス家具

インターネットで検索していたら、こんなページを見つけました。
コクヨのオフィス家具なんですけど、ロゴも似ていてなんだか不思議な感じです。
どうしてこんな名前にしたんでしょうね?

|

« 2004年3月 | トップページ | 2004年5月 »