Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2015年07月23日] [更新 2015年07月27日] Delphi サンプルプログラム集
075_TScrollBox のスクロールバーの表示制御
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro
075_TScrollBox_ScrollBar.zip [2,139 KB] 2015年07月27日版 (EXE 同梱)







TScrollBox のスクロールバーの表示制御


TScrollBox のスクロールバーの設定関係のサンプルです.

TScrollBox は,垂直スクロールバーと水平スクロールバーを独立して設定できます.
これらは TControlScrollBar 型の HorzScrollBar, VertScrollBar ですが,Visible プロパティの値を True にしても,TScrollBox のクライアント領域に全てのコントロールが表示されている状態だとスクスロールバーは表示されません.主に,これを強制的に表示するサンプルです.






01_TScrollBox のスクロールバーを常に表示


TScrollBox の継承クラス (コンポーネント) を作成して,WM_NCCALCSIZE メッセージ処理内で強制的に TScrollBox のスタイルに WS_VSCROLL を追加して,垂直スクロールバーを常に表示するようにしたサンプルです.

このサンプルでは,TScrollBox のクライアント領域にコントロール類が全て表示される状態になると,スクロールバーは操作できない状態になります.そこで,EnableScrollBar でスクロールバーを無効化します.
TScrollBox に配置しているコントロールの表示位置やサイズを変更した場合にも,スクロールバーの描画更新のために,Resize のコードと同じ処理が必要です.




図1
設計時の画面
  • 継承クラス (コンポーネント) を実行時に生成するので,フォームには TScrollBox はない
図2
実行開始画面
  • TScrollBox に配置したコントロールが全て表示されている場合
  • スクロールバーが見えているが,スクロール操作はできない
図3
フォームをリサイズ
  • スクロールバーの操作が可能になる

リスト1
TScrollBox の垂直スクロールバーを常に表示
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, GIFImg, jpeg;

type
  TplScrollBox = class(Forms.TScrollBox)
  protected
    procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
    procedure Resize; override;
  end;

  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Image1: TImage;
    procedure FormCreate(Sender: TObject);
    procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  private
    { Private 宣言 }
    plScrollBox1 : TplScrollBox;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム作成時の処理
//  TScrollBoxの派生コンポーネントを生成
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  plScrollBox1 := TplScrollBox.Create(Self);
  plScrollBox1.Parent := Self;
  plScrollBox1.Align  := alClient;

  Image1.Parent := plScrollBox1;
  Image1.Left := 10;
  Image1.Top  := 20;
end;

//=============================================================================
//  Form1のOnMouseWheelイベント
//  スクロールボックスをマウスホイールでスクロールさせる
//=============================================================================
procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
var
  SB1 : TScrollBox;
begin
  SB1 := plScrollBox1;
  if FindVCLWindow(MousePos) = SB1 then begin
    Handled := True;
    SB1.VertScrollBar.Position := SB1.VertScrollBar.Position - WheelDelta div 5;
  end;
end;

{ TplScrollBox }

//=============================================================================
//  TplScrollBoxのResizeメソッド
//  リサイズされると自動的に実行されるメソッド
//  OnResizeイベントに相当する
//=============================================================================
procedure TplScrollBox.Resize;
var
  i           : Integer;
  LBottom     : Integer;
  LScrollInfo : TScrollInfo;
begin
  inherited;

  //TScrollBox内に配置しているコントロールの表示高さを計算
  LBottom := 0;
  for i := 0 to ControlCount - 1 do begin
    if LBottom <= (Controls[i].Top + Controls[i].Height) then begin
      LBottom := Controls[i].Top + Controls[i].Height;
    end;
  end;
  //下方に少しマージンをとってみる
  LBottom := LBottom + 30;
  VertScrollBar.Range := LBottom;

  if LBottom < ClientHeight then begin
    EnableScrollBar(Handle, SB_VERT, ESB_DISABLE_BOTH);
  end else begin
    EnableScrollBar(Handle, SB_VERT, ESB_ENABLE_BOTH);
  end;
end;

//=============================================================================
//  WM_NCCALCSIZEメッセージ処理
//  縦スクロールバー(WS_VSCROLL)を強制的に表示するスタイルに変更
//=============================================================================
procedure TplScrollBox.WMNCCalcSize(var Message: TWMNCCalcSize);
var
  LStyle: Integer;
begin
  LStyle := GetWindowLong(Handle, GWL_STYLE);
  SetWindowLong(Handle, GWL_STYLE, LStyle or WS_VSCROLL);

  //スクロールバーの表示を更新
  Resize;

  inherited;
end;

end.




02_TScrollBox のスクロールバーを常に非表示


TScrollBox のスクロールバーを常に非表示するには,水平スクロールバー,あるいは,垂直スクロールバーの Visible プロパティの値を False にします.
このことを確認するためのサンプルです.各ボタンは,水平,垂直スクロールバーの表示と非表示を切り換えるトグル動作となっています.


リスト2
TScrollBox のスクロールバーを常に非表示にする
  ScrollBox1.HorzScrollBar.Visible := False;  //水平スクロールバーを常に非表示
  ScrollBox1.VertScrollBar.Visible := False;  //垂直スクロールバーを常に非表示



図4
スクロールバーが表示されている状態

図5
スクロールバーを非表示にした状態

本ページの最初のサンプルと同じ方法も使えます.
WM_NCCALCSIZE メッセージ処理内で,LStyle or WS_VSCROLL の部分を LStyle and not WS_VSCROLL とすると,垂直スクロールバーを常に表示しないようにできます.この設定をすると,VertScrollBar の Visible の値を True にしても垂直スクロールバーは表示できません.


procedure TplScrollBox.WMNCCalcSize(var Message: TWMNCCalcSize);
var
  LStyle: Integer;
begin
  LStyle := GetWindowLong(Handle, GWL_STYLE);
  SetWindowLong(Handle, GWL_STYLE, LStyle and not WS_VSCROLL);

  //スクロールバーの表示を更新
  Resize;

  inherited;
end;




03_TScrollBox のスクロールのトラッキング


スクロールのトラッキング (追従) 機能の動作確認用サンプルです.
各々のボタンクリックは,水平または垂直スクロールのトラッキングを ON, OFF するトグル動作となっています.

スクロールバーのスクロールボックス (つまみ) をドラッグすると,スクロールボックス (つまみ) を放すまで,実際のスクロールはしません.これが TScrollBox のデフォルトの設定です.
VertScrollBar, HorzScrollBar (共に TControlScrollBar 型) の Tracking プロパティを True にすると,スクロールバーのドラッグに追従して TScrollBox に配置したコントロールがスクロールするようになります.

このスクロールのトラッキング (追従) を「滑らかなスクロール」と言うことがあるようです.




図6
VertScrollBar.Tracking = False の場合
  • スクロールボックス (つまみ) を放すまではスクロールしない

図7
VertScrollBar.Tracking = True の場合
  • スクロールボックス (つまみ) のドラッグと同時にスクロールする

リスト3
TScrollBox のスクロールのトラッキングの動作確認用サンプル
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, GIFImg, jpeg;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Button2: TButton;
    ScrollBox1: TScrollBox;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  水平方向のスクロールのトラッキングのON,OFF切り換え
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  ScrollBox1.HorzScrollBar.Tracking := not ScrollBox1.HorzScrollBar.Tracking;
end;

//=============================================================================
//  垂直方向のスクロールのトラッキングのON,OFF切り換え
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
begin
  ScrollBox1.VertScrollBar.Tracking := not ScrollBox1.VertScrollBar.Tracking;
end;

end.




04_TScrollBox のスクロールバーのコンテキストメニュー


TScrollBox のスクロールバー上で,マウスの右ボタンをクリックすると,下図のようなコンテキストメニューが現れます.このコンテキストメニューを表示しないようにする方法です.

コンテキストメニューが表示する際,WM_CONTEXTMENU メッセージが発生します.このメッセージ処理内で何もしなければコンテキストメニューは現れません.何もしないと,TScrollBox で TPopupMenue コンポーネント等を使用していると,そのポップアップメニューも表示しなくなってしまいます.
そこで,マウスクリックの位置が,TScrollBox のクライアント領域の時は,WM_CONTEXTMENU メッセージ本来の処理を実行するようにしています.




図8
スクロールバーのコンテキストメニュー
  • このコンテキストメニューを表示しないようにする

リスト4
TScrollBox のスクロールバーのコンテキストメニューを表示しないようにする
TScrollBox の継承クラス (コンポーネント) を使用する場合
procedure TplScrollBox.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;