アトリエ ぺっぺ

トップページ > プログラムTips > クライアント領域でドラッグ

◆ クライアント領域でドラッグ
タイトルバーのないダイアログ等、クライアント領域でドラッグしたい場合があります。
 
実現方法は次の2通りあります。
 
@  クライアント領域のクリックをキャプションのクリックに置き換える
   (お手軽ですが、ボタン等の別のコントロール上で無い限り、
   クライアント領域のクリックイベントは一切とれなくなります)
A  ボタンダウン・ボタン移動・ボタンアップを管理し、ダイアログを動かす
 
@の場合、OnNcHitTest()メソッドをオーバーライドします。
このメソッドはClassWizardからはオーバーライドできないので、
自分の手でダイアログに追加します。
…と思ったのですが、環境によってはClassWizardから追加できるようです。
私の環境では表示されなかったので、以下の追加方法の記述は残して置きます。
ClassWizardで作成できた場合は、実装方法のみをご覧ください。
 
まず、ダイアログのヘッダに関数定義を追加します。
class CMyDlg : public CDialog
{
// 構築
public:
    CMyDlg(CWnd* pParent = NULL);    // 標準のコンストラクタ
    virtual ~CMyDlg();
    //    :
    //    省略
    //    :
    // ClassWizard は仮想関数のオーバーライドを生成します。
    //{{AFX_VIRTUAL(CTskBrDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV のサポート
    //}}AFX_VIRTUAL
    afx_msg UINT OnNcHitTest(CPoint point) ;
};
 
次に、cppファイルにあるメッセージマップにWM_NCHITTESTへのハンドラを追加します。
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
    ON_MESSAGE(WM_NCHITTEST, OnNcHitTest)
    //{{AFX_MSG_MAP(CMyDlg)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
最後に、OnNcHitTest()メソッドを次のように実装します。
// クライアント領域でドラッグ
UINT CMyDlg::OnNcHitTest(CPoint point) 
{
    UINT nHitTest = CDialog::OnNcHitTest(point);
    if( nHitTest == HTCLIENT )    // もしクライアント領域だったら、
        return HTCAPTION;         // キャプションです、と返す
    else
        return nHitTest;
}
 
Aの場合、まずドラッグ中かどうかを判断するメンバと、開始位置を保持するメンバをダイアログクラスに追加します。
class CMyDlg : public CDialog
{
// 構築
public:
    CMyDlg(CWnd* pParent = NULL);    // 標準のコンストラクタ
    virtual ~CMyDlg();
    //    :
    //    省略
    //    :
protected:
    BOOL      m_bMoving;
    CPoint    m_pointOld
};
 
コンストラクタでFALSEに初期化します。
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CMyDlg::IDD, pParent)
    , m_bMoving(FALSE)
{
    //{{AFX_DATA_INIT(CMyDlg)
        // メモ: この位置に ClassWizard によってメンバの初期化が追加されます。
    //}}AFX_DATA_INIT
    // メモ: LoadIcon は Win32 の DestroyIcon のサブシーケンスを要求しません。
}
 
次に、OnLButtonDown()メソッド、OnLButtonUp()メソッド、OnMouseMove()メソッドをそれぞれ次のようにオーバーライドします。
void CMyDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
    m_bMoving = TRUE;        // 移動開始
    SetCapture();                // マウスキャプチャを独占
    m_pointOld = point;    // 開始位置を保持
    
    CDialog::OnLButtonDown(nFlags, point);
}

void CMyDlg::OnLButtonUp(UINT nFlags, CPoint point) 
{
    if(m_bMoving){    // もしドラッグされていたなら
        m_bMoving = FALSE;        // ドラッグ終了
        ::ReleaseCapture();        // マウスキャプチャ解放
    }
    CDialog::OnLButtonUp(nFlags, point);
}

void CMyDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
    if(m_bMoving){    // もしドラッグ中だったら、移動距離を算出してダイアログを動かす
        CRect rect;
        GetWindowRect(&rect);
        rect.left += (point.x - m_pointOld.x);
        rect.right += (point.x - m_pointOld.x);
        rect.top += (point.y - m_pointOld.y);
        rect.bottom += (point.y - m_pointOld.y);
        SetWindowPos(&wndTopMost, rect.left, rect.top,
        rect.right - rect.left, rect.bottom - rect.top, SWP_SHOWWINDOW);
    }
    CDialog::OnMouseMove(nFlags, point);
}

(C) 2002 atelier-peppe
ababa@atelier-peppe.sakura.ne.jp