Delphi Programming / Object Pascal
[掲載 2015年07月28日] [更新 2015年07月28日] Delphi サンプルプログラム集 |
073_TTreeView のスクロールバーの表示制御 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro |
|
073_TTreeView_ScrollBar.zip [2,282 KB] 2015年07月28日版 (EXE 同梱) |
TTreeView のスクロールバーの表示制御関係のサンプルです.
TTreeView には,TStringGrid や TRichEdit のような,ScrollBars プロパティはありません.
TTreeView では,クライアント領域にデータが表示できなくなると,必要に応じて水平スクロールバーまたは垂直スクロールバーが表示されます.
本ページのサンプルは,TTreeView の継承クラス (コンポーネント) を作成し,これらのスクロールバーを強制的に表示したり,非表示にするサンプルです.
本ページのサンプルでは,継承クラスをコンポーネントとして登録 (インストール) しないで,[派生元のコンポーネントと交換する方法] で説明しているユニットを使用しています.
|
01_TTreeView のスクロールバーの表示と非表示を切り換え |
TTreeView の継承クラス (コンポーネント) を作成して,水平スクロールバー,垂直スクロールバーを常に表示または常に非表示するようにするサンプルです.
Button1 のクリックで表示と非表示を切り換えるようにしています.
TTreeView が生成,再生成すると RecreateWnd が実行されます.RecreateWnd は WM_NCCALCSIZE メッセージを発行します.このメッセージ処理内で表示スタイルを設定しています.
本サンプルでは,TTreeView の継承クラスに HideScrollBars というプロパティを実装して,このプロパティの値を Button1 で切り換えるようにしています.
垂直スクロールバーだけ,あるいは水平スクロールバーだけの表示制御は,スタイルの設定フラグによって変更できます. |
|
図1
設計時の画面 |
|
図2
実行開始画面
|
|
図3
ノードの一部を閉じる
|
|
図4
Button1 をクリック
- 未表示のデータがあってもスクロールバーが非表示となる
|
リスト1
TTreeView のスクロールバーの表示と非表示を切り換え |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, Grids, StdCtrls, ComCtrls;
type
TplTreeView = class(TTreeView)
private
FHideScrollBars : Boolean;
procedure SetHideScrollBars(const Value: Boolean);
protected
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
public
property HideScrollBars : Boolean read FHideScrollBars write SetHideScrollBars;
end;
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
TreeView1: TTreeView;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
plTreeView1 : TplTreeView;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
plChgCompo,
CommCtrl;
{$R *.dfm}
//=============================================================================
// フォームのOnCreateイベント処理
// TTreeViewの派生クラス(コンポーネント)を生成
// すぐにテストできるようにテスト用のデータをセット
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
j : Integer;
k : Integer;
LText1 : String;
LText2 : String;
LNode1 : TTreeNode;
LNode2 : TTreeNode;
begin
//フォーム作成時にコンポーネントの入れ替え
plTreeView1 := TplTreeView(ChangeComponent(TreeView1, TplTreeView));
plTreeView1.Items.BeginUpdate;
for i := 0 to 2 do begin
LText1 := Format('%.5d',[i + 1]);
LNode1 := TreeView1.Items.Add(nil, LText1);
for j := 0 to 2 do begin
LText2 := LText1 + '-' + Format('%.5d',[j + 1]);
LNode2 := plTreeView1.Items.AddChild(LNode1, LText2);
if i = 2 then begin
for k := 0 to 2 do begin
plTreeView1.Items.AddChild(LNode2, LText2 + '-' + Format('%.10d',[k + 1]));
end;
end;
end;
end;
plTreeView1.FullExpand;
plTreeView1.Items.EndUpdate;
LNode1 := plTreeView1.Items.GetFirstNode;
LNode1.MakeVisible;
LNode1.Selected := True;
ActiveControl := plTreeView1;
end;
//=============================================================================
// TTreeViewの継承クラスに実装したHideScrollBarsプロパティをトグル操作
// HideScrollBarsがTrueだと水平,垂直スクロールバーは共に非表示(Hide)になる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
plTreeView1.HideScrollBars := not plTreeView1.HideScrollBars;
end;
{ TplTreeView }
//-----------------------------------------------------------------------------
// TTreeViewの継承クラスに実装したHideScrollBarsプロパティの設定メソッド
// 変更したらRecreateWndを実行する
// RecreateWndを実行するとWM_NCCALCSIZEメッセージが発生する
//-----------------------------------------------------------------------------
procedure TplTreeView.SetHideScrollBars(const Value: Boolean);
begin
if FHideScrollBars <> Value then begin
FHideScrollBars := Value;
RecreateWnd;
end;
end;
//=============================================================================
// WM_NCCALCSIZEメッセージ処理
// スクロールバー表示のフラグを強制的に変更
//=============================================================================
procedure TplTreeView.WMNCCalcSize(var Message: TWMNCCalcSize);
var
LStyle : Integer;
begin
LStyle := GetWindowLong(Handle, GWL_STYLE);
if FHideScrollBars then begin
LStyle := LStyle and not WS_HSCROLL and not WS_VSCROLL;
end else begin
LStyle := LStyle or WS_HSCROLL or WS_VSCROLL;
end;
SetWindowLong(Handle, GWL_STYLE, LStyle);
inherited;
end;
end.
02_TTreeView のスクロールバーの無効化表示 |
TTreeView のスクロールバーは,操作不可の状態になっても,無効化の表示とはなりません.
これを無効化の表示状態にするサンプルです.
GetScrollInfo 関数で,表示データがクライアント領域に収まらない状態でスクロールの Range を取得すると,水平スクロールの範囲としてのピクセル数が,垂直のスクロール範囲として表示可能なノード数が取得できます.表示可能なノード数には,展開していないノードは含まれていません.
データがクライアント領域に全て表示されている時は,これらの値は 0 です.
このことを利用しています.
リサイズ以外にも,ノードの追加,削除,あるいはノードを展開した時やノードを閉じた時もチェックが必要です.これらをチェックする処理も追加してみました.
|
[備考]
TTreeView のメッセージとして,MSDN の [Tree View Messages] の記事に TVM_XXXX という形式がありますが,これらのメッセージは,情報の取得や設定に使用するメッセージです.TVM_XXX 処理のメッセージを受信するには,TVM_XXX 受信用のプロシージャーを実装します.
もし,すでに VCL 内で TVM_XXX 受信用のプロシージャーが実装されている場合は,inherited 処理が必要です.
処理の結果としてのメッセージは,[Tree View Notifications]
の記事にある TVN_XXXX 等の通知メッセージが利用できます.TVN_XXXX の通知メッセージは CN_NOTIFY メッセージで受信できます.
|
|
図5
EXE の実行開始画面 |
|
図6
一部のノードを閉じる
- データが全てクライアント領域内にある状態
- スクロールバーが無効化の表示になる
|
|
図7
ノードを全て展開して縦方向にリサイズ
|
リスト2
TTreeView のスクロールバーの無効化表示 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, Grids, StdCtrls, ComCtrls, CommCtrl;
type
TplTreeView = class(TTreeView)
private
procedure Available_Disable_ScrollBars;
protected
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
procedure CNNotify(var Message: TWMNotifyTV); message CN_NOTIFY;
procedure Added(Node: TTreeNode); override;
procedure Resize; override;
end;
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
TreeView1: TTreeView;
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
plTreeView1 : TplTreeView;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
plChgCompo;
{$R *.dfm}
//=============================================================================
// フォームのOnCreateイベント処理
// TTreeViewの派生クラス(コンポーネント)を生成
// すぐにテストできるようにテスト用のデータをセット
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
j : Integer;
k : Integer;
LText1 : String;
LText2 : String;
LNode1 : TTreeNode;
LNode2 : TTreeNode;
begin
//フォーム作成時にコンポーネントの入れ替え
plTreeView1 := TplTreeView(ChangeComponent(TreeView1, TplTreeView));
plTreeView1.Items.BeginUpdate;
for i := 0 to 2 do begin
LText1 := Format('%.5d',[i + 1]);
LNode1 := plTreeView1.Items.Add(nil, LText1);
for j := 0 to 2 do begin
LText2 := LText1 + '-' + Format('%.5d',[j + 1]);
LNode2 := plTreeView1.Items.AddChild(LNode1, LText2);
if i = 2 then begin
for k := 0 to 2 do begin
plTreeView1.Items.AddChild(LNode2, LText2 + '-' + Format('%.15d',[k + 1]));
end;
end;
end;
end;
plTreeView1.FullExpand;
plTreeView1.Items.EndUpdate;
LNode1 := plTreeView1.Items.GetFirstNode;
LNode1.MakeVisible;
LNode1.Selected := True;
end;
{ TplTreeView }
//-----------------------------------------------------------------------------
// スクロールバーの有効化表示と無効化表示の制御用メソッド
//-----------------------------------------------------------------------------
procedure TplTreeView.Available_Disable_ScrollBars;
var
LScrollInfo : TScrollInfo;
begin
LScrollInfo.cbSize := SizeOf(LScrollInfo);
LScrollInfo.fMask := SIF_ALL;
//垂直スクロールバーの有効化表示,無効化表示の処理
GetScrollInfo(Handle, SB_VERT, LScrollInfo);
if LScrollInfo.nMax > 0 then begin
EnableScrollBar(Handle, SB_VERT, ESB_ENABLE_BOTH);
end else begin
EnableScrollBar(Handle, SB_VERT, ESB_DISABLE_BOTH);
end;
//水平スクロールバーの有効化表示,無効化表示の処理
GetScrollInfo(Handle, SB_HORZ, LScrollInfo);
if LScrollInfo.nMax > 0 then begin
EnableScrollBar(Handle, SB_HORZ, ESB_ENABLE_BOTH);
end else begin
EnableScrollBar(Handle, SB_HORZ, ESB_DISABLE_BOTH);
end;
end;
//=============================================================================
// Resizeメソッド
// コントロールがリサイズされると自動的に実行されるメソッド
//=============================================================================
procedure TplTreeView.Resize;
begin
inherited;
Available_Disable_ScrollBars;
end;
//=============================================================================
// Addedメソッド
// ノードが追加された時に自動的に実行されるメソッド
//=============================================================================
procedure TplTreeView.Added(Node: TTreeNode);
begin
inherited;
Available_Disable_ScrollBars;
end;
//=============================================================================
// CN_NOTIFYメッセージ処理
// TVN_XXX等はCN_NOTIFYメッセージで受信できる
// CN_NOTIFYの引数の型は,コード補完機能を使用するとTMessage型となる
// これをTWMNotifyTV型に変更して使用
//
// TVN_XXXの使用にはusesにCommCtrlが必要
//=============================================================================
procedure TplTreeView.CNNotify(var Message: TWMNotifyTV);
var
LCode : Integer;
begin
inherited;
LCode := Message.NMHdr.code;
case LCode of
TVN_ENDLABELEDIT,
TVN_DELETEITEM,
TVN_ITEMEXPANDED:
begin
Available_Disable_ScrollBars;
end;
end;
end;
//=============================================================================
// WM_NCCALCSIZEメッセージ処理
// スクロールバー表示のフラグを強制的に変更
//=============================================================================
procedure TplTreeView.WMNCCalcSize(var Message: TWMNCCalcSize);
var
LStyle : Integer;
begin
LStyle := GetWindowLong(Handle, GWL_STYLE);
SetWindowLong(Handle, GWL_STYLE, LStyle or WS_HSCROLL or WS_VSCROLL);
inherited;
end;
end.
03_TTreeView のスクロールバーのコンテキストメニュー |
TTreeView のスクロールバー上で,マウスの右ボタンをクリックすると,下図のようなコンテキストメニューが現れます.このコンテキストメニューを表示しないようにする方法です.
コンテキストメニューが表示する際,WM_CONTEXTMENU メッセージが発生します.このメッセージ処理内で何もしなければコンテキストメニューは現れません.
何もしないと,TTreeView で TPopupMenue コンポーネント等を使用していると,そのポップアップメニューも表示しなくなってしまいます.そこで,マウスクリックの位置が,TListView のクライアント領域の時は,WM_CONTEXTMENU メッセージ本来の処理を実行するようにしています.
|
|
図8
スクロールバーのコンテキストメニュー
|
リスト3
TTreeView のスクロールバーのコンテキストメニューを表示しないようにする |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, Grids, StdCtrls, ComCtrls, Menus;
type
TplTreeView = class(TTreeView)
private
protected
procedure WMContextMenu(var Message: TWMContextMenu);
message WM_CONTEXTMENU;
end;
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
TreeView1: TTreeView;
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
plTreeView1 : TplTreeView;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
plChgCompo;
{$R *.dfm}
//=============================================================================
// フォームのOnCreateイベント処理
// TTreeViewの派生クラス(コンポーネント)を生成
// すぐにテストできるようにテスト用のデータをセット
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
j : Integer;
k : Integer;
LText1 : String;
LText2 : String;
LNode1 : TTreeNode;
LNode2 : TTreeNode;
begin
//フォーム作成時にコンポーネントの入れ替え
plTreeView1 := TplTreeView(ChangeComponent(TreeView1, TplTreeView));
plTreeView1.Items.BeginUpdate;
for i := 0 to 2 do begin
LText1 := Format('%.5d',[i + 1]);
LNode1 := TreeView1.Items.Add(nil, LText1);
for j := 0 to 2 do begin
LText2 := LText1 + '-' + Format('%.5d',[j + 1]);
LNode2 := plTreeView1.Items.AddChild(LNode1, LText2);
if i = 2 then begin
for k := 0 to 2 do begin
plTreeView1.Items.AddChild(LNode2, LText2 + '-' + Format('%.10d',[k + 1]));
end;
end;
end;
end;
plTreeView1.FullExpand;
plTreeView1.Items.EndUpdate;
LNode1 := plTreeView1.Items.GetFirstNode;
LNode1.MakeVisible;
LNode1.Selected := True;
ActiveControl := plTreeView1;
end;
{ TplTreeView }
//=============================================================================
// WM_CONTEXTMENUメッセージ処理
// スクロールバーのコンテキストメニューを表示しないようにする
//=============================================================================
procedure TplTreeView.WMContextMenu(var Message: TWMContextMenu);
var
LPos : TPoint;
begin
LPos := ScreenToClient(Point(Message.XPos, Message.YPos));
if PtInRect(ClientRect, LPos) then begin
inherited;
end else begin
Message.Result := 0;
end;
end;
end.
04_TTreeView のノードのテキストのツールチップを非表示 |
TTreeView のノードにマウスカーソルを移動します.この時,ノードのテキストがクライアントの右端に表示しきれない場合,下図のようなツールチップが現れます.
このツールチップが現れないようにする方法です.
方法は,スクロールバーの表示または非表示と同じで,ウィンドウのスタイルに TVS_NOTOOLTIPS フラグをセットします.実際にこの設定による動作を確認するためのサンプルです.
もし,上の方のサンプルのような TTreeView のウィンドウの再生成の処理を行わなければ,以下のように TreeView_SetToolTips メソッドで非表示にできます.
|
procedure TForm1.Button1Click(Sender: TObject);
begin
TreeView_SetToolTips(TreeView1.Handle, 0);
end;
|
図9
ノードのテキストのツールチップ
|
リスト4
TTreeView のノードのテキストのツールチップを表示しないようにする |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, Grids, StdCtrls, ComCtrls;
type
TplTreeView = class(TTreeView)
protected
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
end;
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
TreeView1: TTreeView;
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
plTreeView1 : TplTreeView;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
plChgCompo,
CommCtrl;
{$R *.dfm}
//=============================================================================
// フォームのOnCreateイベント処理
// TTreeViewの派生クラス(コンポーネント)を生成
// すぐにテストできるようにテスト用のデータをセット
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
j : Integer;
k : Integer;
LText1 : String;
LText2 : String;
LNode1 : TTreeNode;
LNode2 : TTreeNode;
begin
//フォーム作成時にコンポーネントの入れ替え
plTreeView1 := TplTreeView(ChangeComponent(TreeView1, TplTreeView));
plTreeView1.Items.BeginUpdate;
for i := 0 to 2 do begin
LText1 := Format('%.5d',[i + 1]);
LNode1 := TreeView1.Items.Add(nil, LText1);
for j := 0 to 2 do begin
LText2 := LText1 + '-' + Format('%.5d',[j + 1]);
LNode2 := plTreeView1.Items.AddChild(LNode1, LText2);
if i = 2 then begin
for k := 0 to 2 do begin
plTreeView1.Items.AddChild(LNode2, LText2 + '-' + Format('%.10d',[k + 1]));
end;
end;
end;
end;
plTreeView1.FullExpand;
plTreeView1.Items.EndUpdate;
LNode1 := plTreeView1.Items.GetFirstNode;
LNode1.MakeVisible;
LNode1.Selected := True;
ActiveControl := plTreeView1;
end;
{ TplTreeView }
//=============================================================================
// WM_NCCALCSIZEメッセージ処理
// スクロールバー表示のフラグを強制的に変更
//
// 定数名TVS_XXXの使用にはusesにCommCtrlが必要
//=============================================================================
procedure TplTreeView.WMNCCalcSize(var Message: TWMNCCalcSize);
var
LStyle : Integer;
begin
LStyle := GetWindowLong(Handle, GWL_STYLE);
SetWindowLong(Handle, GWL_STYLE, LStyle or TVS_NOTOOLTIPS);
inherited;
end;
end.
|