Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2005年02月26日] [更新 2012年04月11日] Delphi サンプルプログラム集
120_SC_DRAGMOVE コマンドによるコントロールのドラッグ
動作確認等 Windows XP(SP3) + Delphi XE Pro
Windows 7 U64(SP1) + Delphi XE Pro
120_ControlDrag3.zip [843 KB] 2012年04月11日版 (EXE 同梱)



  • 2012年04月11日
  • Delphi XE での動作確認とコードと記事の整備




01_SC_DRAGMOVE コマンドでコントロールをドラッグ開始


ウィンドウをドラッグすると,システムの SC_DRAGMOVE コマンドが発行されます.逆にこのコマンドをドラッグ対象のウィンドウに対して送ると,ドラッグできることになります.
このコマンドは,WM_SYSCOMMAND メッセージのパラメータとして送ります.ウィンドウに対してメッセージを送りますから,この方法は,ウィンドウハンドルを持たない,TImage 等,TGraphicControl の派生コンポーネントでは使用できません.TWinControl 専用です.


旧Delphi FAQ - VCL(2) の [マウスでコンポーネント (たとえば、TPanel) を実行時にドラッグ] に次のようなサンプルコードがあります.このコードでドラッグを開始できます.


リスト1 
procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
const
   SC_DRAGMOVE = $F012;
begin
   ReleaseCapture;
   TWinControl(Sender).Perform(WM_SYSCOMMAND, SC_DRAGMOVE, 0);
end;




02_マウスカーソルを変更


上のコードでは,MouseUp イベントを捕らえることができません.そのため,このコード内でマウスカーソルの形状を変更した場合,ローカルフック等で MouseUp を捕らえて変更する必要があります.その対策をしたのが次のコードです.TChart も移動可能でしたので,ついでに TChart の一部をコードで設定してみました.


図1
実行開始画面
  • 以下のコントロールを配置
    TBitBtn
    TButton
    TPanel
    TScrollBox
    TCheckListBox
    TChart (TBarSeries)
  • TChart の一部をコードで設定している
図2
TChart をドラッグ中
  • Windows XP では,ドロップすると,そのコントロールが最前面に来てしまう
  • 元の Z オーダにするには対策が必要
  • この仕様がいい場合もあるかも知れない

リスト2
SC_DRAGMOVE コマンドでコントロールをドラッグ開始
unit Unit1;


interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, Buttons, CheckLst, TeeProcs, TeEngine, Chart, Grids,
  AppEvnts, Series,XPMan;

type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    Button1: TButton;
    Panel1: TPanel;
    ScrollBox1: TScrollBox;
    CheckListBox1: TCheckListBox;
    Chart1: TChart;
    Series1: TBarSeries;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Panel1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

var
  HookHandle : HHOOK;
  AControl   : TWinControl;

//=============================================================================
//  WH_GETMESSAGEフックのコールバック関数
//  ここではマウスの左ボタンが離された時だけ処理
//  ローカルフックについてはHalbow資料館を参考
//=============================================================================
function GetMsgProc(Code: Integer; wParam: wParam; lParam:lParam): LRESULT; stdcall;
var
  Msg : PMsg;
begin
  if (Code < 0) then begin
    Result := CallNextHookEx(HookHandle, Code, wParam, lParam);
    exit;
  end;

  if (Code = HC_ACTION) then begin
    Msg := PMsg(lParam);
    case Msg^.message of
      WM_LBUTTONUP:
      begin
        if wParam = PM_REMOVE then begin
          if AControl <> nil then AControl.Cursor := crDefault;
        end;
      end;
    end;
  end;
  Result := CallNextHookEx(HookHandle, Code, wParam, lParam);
end;

//=============================================================================
//  FormのCreate時
//  ローカルフック開始
//  TChartもこのPerformで移動可能なのでついでに,TChartの一部分の設定をコード
//  で行ってみた
//  TChartは設計時に棒グラフを作成してある
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Series1.Clear;
  Randomize;

  //タイトル
  Chart1.Title.Text.Clear;
  Chart1.Title.Text.Add('棒グラフの例');

  //棒グラフの棒の色
  Series1.SeriesColor := $005BA466;
  //データ
  Series1.Add(Random(50), 'A');
  Series1.Add(Random(50), 'B');
  Series1.Add(Random(50), 'C');
  Series1.Add(Random(50), 'D');

  //縦軸の設定
  Chart1.LeftAxis.Automatic       := False;
  Chart1.LeftAxis.Maximum         := 50;
  Chart1.LeftAxis.Increment       := 10;
  Chart1.LeftAxis.TickLength      := 0;
  Chart1.LeftAxis.MinorTickCount  := 1;
  Chart1.LeftAxis.MinorTickLength := -5;

  //横軸の設定
  Chart1.BottomAxis.Grid.Visible       := False;
  Chart1.BottomAxis.Ticks.Visible      := False;
  Chart1.BottomAxis.MinorTicks.Visible := False;

  HookHandle := SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, 0, GetCurrentThreadID);
end;

//=============================================================================
//  ローカルフック解除
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
begin
  UnHookWindowsHookEx(HookHandle);
end;

//=============================================================================
//  コントロール上でマウスをクリックしたらドラッグ開始
//=============================================================================
procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
const
  SC_DRAGMOVE = $F012;
begin
  ReleaseCapture;

  AControl := TWinControl(Sender);
  AControl.Cursor := crSizeAll;
  AControl.Perform(WM_SYSCOMMAND, SC_DRAGMOVE, 0);
end;

end.