---- 1. Delphi でツリー コントロールを使用するためのヒント
---- 開発者が主にデータベース管理ソフトウェアの開発に Delphi を使用していることは誰もが知っています。そのため、ツリー コントロールの使用がデータベースと最もよくリンクされています。 Delphi は、複雑な階層関係を記述するために使用できるツリー コントロール TTreeView を提供します。
---- 1. ツリーノード情報の保存と読み込み
---- 一般的に使用される方法は、ツリー コントロールの LoadFromFile メソッドと SavetoFile メソッドを使用してツリー コントロールとファイル間の対話を実現するか、Assign メソッドを使用してツリー コントロールと DBMemo 間の対話を実現することです。 、データベースとの対話。この方法の利点は、プログラミングが比較的簡単であることです。欠点は、「大きなツリー」の場合、毎回ロードおよび保存されるデータの量が増加する可能性があることです。速度が低下し、システムのオーバーヘッドが増加し、データの冗長性が生じます。もう 1 つの方法は、ツリー内に「可視」ノードのみを生成することです。ツリー ノード構造全体を記録するための専用のファイルやデータベース フィールドはなく、ツリー ノード構造はデータベースの各レコードに分散されます。
---- 具体的な方法は次のとおりです。データベースを作成します。フィールドは実際の業務に応じて決定されます。ツリー コントロールのノードに情報が表示されるフィールドが 1 つ必要です。また、その情報を保存するフィールドもあります。ノードの固有の識別番号。識別番号は同じ長さの 2 つの部分で構成され、最初の部分は現在のノードの親ノード番号を表します。この識別番号は現在のノードのノード番号を表します。ツリー上のノードの構造を記録する「リンク リスト」。この方法の利点: ユーザーは、「大きなツリー」を操作する場合、通常、すべてのノードを展開するのではなく、ツリーのルートからレイヤーごとにのみ展開できます。このメソッドは「可視」ノードのみを生成するため、「大きなツリー」の保存と読み込みの速度が速く、データ量が少なく、システムのオーバーヘッドとデータの冗長性が小さくなります。欠点: プログラミングはより複雑になりますが、この方法を組み合わせて新しいツリー コントロールを形成することができ、プログラミング効率が大幅に向上します。 ID 番号は一意でなければならないため、プログラミングにおいて ID を合理的に生成する方法が特に重要であることに注意してください。
---- 2. データベース構造例
----データベースを作成する 手順を簡略化するために、次のように定義された 2 つのデータベース フィールドのみを作成します。
フィールド名の型の長さ
テキストC10
ロングIDC6
----LongID フィールドは実際には 2 つのセグメントで構成されており、各セグメントは 3 桁の LongID しか表現できません。 LongID をインデックス フィールドとして定義し、c: esttree ree.dbf として保存します。 DBF ファイルを編集し、新しいレコードを作成し、Text フィールドを TOP に設定し、LongID フィールドを "000" (3 つの "0" の前に 3 つのスペース) に設定します。
---- 3. デモプログラムの作成
---- Form1 に TreeView1、Table1、PopupMenu1、Edit1、Edit2 を配置します。 TreeView1 の PopupMenu 属性は PopupMenu1 に設定され、Table1 の DataBaseName 属性は c: esttree に設定され、TableName 属性は Tree.dbf に設定され、IndexFieldNames 属性は PopupMenu1 に追加されます。および Caption はそれぞれ Add と Del です。Edit1 は新しいノードの Text 属性値を入力するために使用され、Edit2 は新しいノードの 3 桁の ID 番号を入力するために使用されます。 c:esttree reunit.pas および c:esttree esttree.dPR として保存します。 Treeunit.pas の Type キーワードの後に行を追加します: Pstr:^string;{Pstr は文字列ポインター} Form1 の OnCreate イベントのコードを追加します。
プロシージャ TForm1.FormCreate(送信者: TObject);
var p:Pstr;Node:TTreeNode;
始める
Table1,Treeview1 で行う
始める
開ける;
初め;
new(p);{ポインタ p にメモリを割り当てる}
p^:=FieldByName('LongID').AsString;
Node:=Items.AddChildObject(nil,FieldByName
('テキスト').AsString,p);
if HasSubInDbf(Node) then Items
.AddChildObject(Node,′ ′,nil);{子ノードがある場合は、空の子ノードを追加します}
終わり;
終わり;
---- HasSubInDbf はカスタム関数、独立変数は Node、ノード Node に子ノードがあるかどうかを確認し、あれば True を返し、そうでない場合は False を返し、プロトタイプ宣言を TForm1 のクラス定義に追加します (他のカスタム関数も TForm1 のクラス定義で宣言されています (詳しい説明は省略します)。関数コードは次のとおりです。
関数 TForm1.HasSubInDbf(Node:TTreeNode):Boolean;
始める
Table1 で行う
始める
表1.FindNearest([copy(Pstr(Node.Data)^,4,3)+'000']);
result:=copy(FieldByName('LongID').
AsString,1,3)=copy(Pstr(Node.Data)^,4,3);
{たとえば、データベース内の現在のレコードの LongID フィールドの内容の最初の 3 桁の合計
ノード Node のデータの最後の 3 桁が同じである場合、そのノードには子ノードが必要です。}
終わり;
終わり;
TreeView1 コントロールの OnDeletion イベントのコードを追加します。
OnDeletion イベントは、Delete メソッドの呼び出しによってトリガーされるだけでなく、ツリー コントロール自体が解放される前にもトリガーできます。
OnDeletion イベントもトリガーされるため、ここに destroy(node.data) を追加するのが「安全」です。
プロシージャ TForm1.TreeView1Deletion
(送信者: TObject; ノード: TTreeNode);
始める
Dispose(Node.Data);{ノード データ メモリを解放}
終わり;
次のコードを Add1 メニュー項目の OnClick イベントに追加します。
プロシージャ TForm1.Add1Click(送信者: TObject);
var p:pstr;Tmpstr:string;i:integer;
始める
試す
StrToInt(Edit2.Text);
Tmpstr:=Edit2.Text;{注: 実際には、ID を生成するにはより良い方法を使用する必要があります}
を除外する;
ShowMessage('Edit2の内容を再入力');
アボート;
終わり;
TreeView1 で行うこと
始める
新しい(p);
p^:=copy(Pstr(Selected.Data)^,4,3)+TmpStr;
Items.AddChildObject(Selected,Edit1.Text,p);
終わり;
Table1 では {データベースにレコードを追加}
始める
追加;
FieldByName('Text').AsString:=Edit1.text;
FieldByName('LongID').AsString:=p^;
役職;
終わり;
TmpStr:=inttostr(strtoint(TmpStr)+1);
i:=length(TmpStr) から 2 の場合、TmpStr:='0'+TmpStr; を実行します。
Edit2.Text:=TmpStr;
終わり;
次のコードを Del1 メニュー項目の OnClick イベントに追加します。
プロシージャ TForm1.Del1Click(送信者: TObject);
var DelList:TStringList;LongID,NSubLongID:string;
始める
DelList:=TStringList.create;
DelList.Sorted:=True;
DelList.Add(Pstr(TreeView1.Selected.Data)^);
DelList.Count>0 が実行する間
始める
LongID:=DelList.Strings[0];
DelList.削除(0);
表1.SetKey;
Table1.FieldByName('LongID').AsString:=LongID;
Table1.GotoKey の場合は Table1.Delete;
HasSubInDbf(TreeView1.Selected) の場合
始める
NSubLongID:=Table1.FieldByName('LongID').AsString;
while (copy(NSubLongID,1,3)=コピー
(LongID,4,3)) と (Table1.Eof ではありません) を行います
始める
dellist.Add(NSubLongId);
表1.次へ;
NSubLongId:=Table1.FieldByName('LongID').AsString;
終わり;
終わり;
終わり;
DelList.Free;
TreeView1.Items.Delete(TreeView1.Selected);
終わり;
TreeView1 の OnExpanding イベントのコードを追加します。
プロシージャ TForm1.TreeView1Expanding
(送信者: TObject; ノード: TTreeNode;
varAllowExpansion:ブール値);
var TmpNode:TTreeNode;NSubLongID:
文字列;p:Pstr;bm:TBookMark;
始める
Table1,TreeView1 で行う
始める
Items.BeginUpdate;
セットキー;
FieldByName('LongID').AsString:=Pstr(Node.Data)^;
GotoKey でない場合は Items.Delete(Node)
それ以外
始める
TmpNode:=Node.GetFirstChild;
if (TmpNode.Text=' ')and(TmpNode.Data=nil) then
始める
TmpNode.削除;
HasSubInDbf(Node) の場合
始める
NSubLongID:=FieldByName('LongID').AsString;
while (copy(NSubLongID,1,3)=copy(Pstr
(Node.Data)^,4,3)) と (Eof ではない) を行います
始める
新しい(p);
p^:=FieldByName('LongID').AsString;
bm:=GetBookMark;
TmpNode:=Items.AddChildObject(Node,
FieldByName('Text').AsString,p);
HasSubInDbf(TmpNode) の場合は項目。
AddChildObject(TmpNode,' ',nil);
GotoBookMark(bm);
FreeBookMark(bm);
次;
NSubLongId:=FieldByName('LongID').AsString;
終わり; 終わり;
終わり;
Items.EndUpdate;
終わり;
終わり;
---- 以上はデータベースのツリー表示の基本的な方法について簡単に説明しましたが、同じデータベースを操作している場合、ツリー内のノードの Text 属性を編集すると、同時にデータベースも変更されます。複数のユーザーの同時使用、データベースとツリーの一貫性、および上位ノードのコピーとレプリケーションについては詳細には説明しませんが、読者は自分で改善できます。
---- 2. IP制御の利用
---- ネットワーク プログラムでは、ユーザーが IP アドレスの入力を要求される場面によく遭遇します。ただし、Delphi には IP 文字列の入力に使用できるコントロールが提供されていないため、Tedit コントロール (単一行のテキスト ボックス) を使用して、ユーザーが入力した IP 文字列を受け入れる必要があります。ただし、Tedit を使用して IP 文字列を入力するのは、扱いが非常に不便であるため、お勧めできません。実際、IP 文字列を入力するための Windows コントロールがすぐそばにあります。 IP コントロールは不正な IP 文字列を拒否します (各部分には 0 ~ 255 の数値のみを入力できます)。これにより、コントロール内の IP 文字列に対応する IP 値 (32 ビット整数) を簡単に取得できます。 IP 文字列と IP 値の間で変換する手間が省け、さらに、IP コントロールに入力できる IP の範囲を制限することもできます。このセクションでは、Delphi プログラムで Windows IP コントロールを使用する方法を紹介します。
---- Windows には、Windows のカスタム コントロール ライブラリ (Windows コモン コントロール) である commctrl.dll と comctl32.dll という 2 つの非常に重要なダイナミック リンク ライブラリがあります。カスタム コントロール ライブラリには、Delphi でステータスバー、クールバー、ホットキーなど、一般的に使用される Windows コントロールが多数含まれており、これらのコントロールのほとんどはビジュアル コントロールとしてパッケージ化されています。 Microsoft が Internet Explorer 3 を発表した後、Windows IP コントロール (IP アドレス編集コントロール) など、いくつかの新しいコントロールがカスタム コントロール ライブラリに追加されました。
---- 1. Windows カスタム コントロール ライブラリの初期化
---- Windows には、カスタム コントロール ライブラリを初期化するための 2 つの API 関数、InitCommonControls と InitCommonControlsEx が提供されています。名前から、これら 2 つの API 関数の関係を理解するのは難しくありません。後者は前者の機能強化です。プログラムで IP コントロールを使用する場合は、InitCommonControlsEx を使用してカスタム コントロール ライブラリとクラスの初期化を完了する必要があります。関数 InitCommonControlsEx のプロトタイプは次のとおりです (Pascal 構文)。
……
IP コントロールの作成
……
IP コントロールを使用します。 プログラムでは、IP コントロールにメッセージを送信して通信します。
IP コントロールは次の 6 つのメッセージに応答できます。これらのメッセージとその意味を以下の表に示します。
……
IP コントロールの IP 文字列に対応する IP 値を取得したい場合は、次のように送信する必要があります。
IPM_GETADDRESS メッセージ。次のように 32 ビット整数アドレスが必要です。
SendMessage の最後のパラメータ。
……
---- 2. IP制御の通知メッセージ
---- IP 文字列が変更されるか、入力フォーカスが転送されると、IP コントロールは通知メッセージ IPN_FIELDCHANGED を親ウィンドウに送信します。ほとんどの場合、この通知メッセージは無視してかまいません。以下は、通知メッセージ IPN_FIELDCHANGED を処理する例です。
プロシージャ Tform1.WndProc(var Msg: TMessage);
var p:PNMHDR;
始める
継承された。
if Msg.Msg=WM_NOTIFY
それから始めます
p:=ポインター(Msg.lParam);
p^.code=IPN_FIELDCHANGED の場合
それから始めます
{…
IP コントロールの IPN_FIELDCHANGED 通知メッセージの処理
…}
終わり;
終わり;
終わり;
---- 3. 動的に制御を生成する方法と応用
---- 1.Delphi でコントロールを生成する 2 つの方法
---- (1). フォームデザインでコントロールを生成します。
---- フォームを設計するときは、コントロール ツールボックスで必要なコントロールを直接選択し、そのプロパティを設定してイベントに応答するのが一般的です。
---- (2). プログラム内でコントロールを動的に生成します。
---- 場合によっては、プログラムの実行中にコントロールを動的に生成する必要があります。これには 2 つの大きな利点があります。1 つは、プログラムの柔軟性が向上することです。2 つ目は、生成されるコントロールの数が中間実行結果に関連する場合です。プログラムの方法 1 では当然実現できず、プログラム内で動的に生成する方法を使用する必要があります。
---- プログラム内でコントロールを動的に生成する方法は 3 つのステップに分かれています。まず、生成されるコントロールのタイプを定義し、次に Create 関数を使用してコントロールを生成し、最後にコントロールの関連プロパティに値を割り当てます。コントロール。 TButton コントロールを例として、手順は次のとおりです。
---- a. コントロールの種類を定義します。
変数
ボタン1:Tボタン;
---- b. コントロールを生成する
Button1:=TButton.Create(self);
Button1.Parent:=Self;
//通常、Parent の値が設定されていない場合は、親コントロールを Self に設定します。
コントロールは画面上に表示されなくなります
//それを表示する
---- c. 他のプロパティを設定し、Caption、Left、Top、Height、Width、Visible、Enabled、Hint、onClick イベント応答関数などの関連イベント応答関数を定義します。
---- 2. 動的に生成された制御手法の適用
---- 生産計画・管理システムの開発においては、ガントチャートに代表される生産計画表を動的に生成する必要があり、部品の加工状況(加工開始時刻)を表示するShapeコントロールが非常に便利です。および各プロセスの終了時刻)。 Chart コントロールを使用すると、処理装置の使用率が 3 次元ヒストグラムで表示され、非常に直感的です。次に、プログラム内で Shape コントロールと Chart コントロールを動的に生成する処理を説明します。
---- (1). 生産計画図(ガントチャート)を表示する形状コントロールを動的に生成します。
プロシージャ TCreateMultiCharts.ProcCreateCharts;
変数
i、j、行、列、行スペース、グラフの高さ: 整数;
ShapeChart: TShape の配列の配列;
始める
Rows:=16; //Shape コントロール配列の行数
Columns:=8; //形状制御配列の列番号
RowSpace:=20; // 行間隔を形状制御します。
ChartsHeight:=20; // 形状コントロールの高さ
SetLength(ShapeChart,Rows,Columns);
//ShapeChart 配列のサイズを設定します
for i:=0 から Rows do
for j:=0 から Columns do
始める
ShapeChart[i][j]:=TShape.Create(self);
ShapeChart[i,j]で行うこと
始める
Parent:=Self; // この行は必須です。
そうしないと、Shape コントロールが画面に表示されません。
Shape:=stRectangle; // シェイプコントロールの形状は長方形です
トップ:=45+i*(行スペース+グラフの高さ);
左:=Round(180+Q[i,j].StartTime);
//Q[i,j].StartTime は実数であるため、四捨五入する必要があります。
幅:=Round(Q[i,j].Value)
高さ:=チャートの高さ;
Brush.Color:=ランダムカラー;
//カスタム関数、説明書が添付されています
Brush.Style:=bsSolid //塗りつぶし方法を設定します。
有効:=True;
終わり;
終わり;
終わり;
---- 注: aQ はレコード型の 2 次元配列であり、次のように定義されます。
タイプ
TempData=レコード
値: 実数;
開始時間: 実数;
終わり;
Q:TempData の配列の配列
そして、Q のコンポーネントには別のプロセスで値が割り当てられています。
---- b. 異なる部分を区別するために、Shape を異なる色で表示します。このとき、RandomColor 関数が呼び出されます。機能は次のとおりです。
関数 TCreateMultiCharts.RandomColor;
変数
赤、緑、青:バイト;
始める
赤:=ランダム(255);
緑:=ランダム(255);
青:=ランダム(255);
結果:= 赤 または (緑 shl 8) または (青 shl 16);
終わり;
---- (2) Charts コントロールの ChartSeries コンポーネントを動的に生成して、デバイスの使用率を表示します。
プロシージャ TFormMultiMachinesBurthen。
ShowMachineBurthenCharts;
変数
i:整数;
負担:本物;
シリーズクラス:TChartシリーズクラス;
NewSeries:TChartSeries の配列;
始める
SetLength(NewSeries,CreateMultiCharts.Rows);
MachinesBurthenCharts.height:=200;
MachinesBurthenCharts.Width:=550;
for i:=0 から CreateMultiCharts.Rows への実行
始める
SeriesClass:=TBarSeries // 形状を 3 次元棒グラフに設定します。
NewSeries[i]:=SeriesClass.Create(Self);
NewSeries[i].ParentChart:=MachinesBurthenCharts;
NewSeries[i].クリア;
Burthen:=MachineBurthen[i];
Burthen:=Round(Burthen*100)/100; //小数点以下 2 桁のみを使用します。
NewSeries[i].add(Burthen,',NewSeries[i].SeriesColor);
終わり;
終わり;
---- 注: (a).MachineBurthen[i] は実数の配列であり、その値は、別の関数で計算された対応するデバイスの使用率です。
---- (b). MachinesBurthenCharts は、タイプのセクションで説明されている TChart コントロールです。
---- 3. プログラム実行結果表示
---- (1) 部品のスケジュール計画を表示する Shape コントロールを動的に生成します (省略)。
---- (2) Chart コントロールの ChartSeries コンポーネントを動的に生成し、デバイスの使用率を表示します(省略)。