Programming Windows Maniacs - プログラミング ウィンドウズ マニアックス ■ ご利用に際して ■ 更新履歴 ■ お問い合わせ ■ このホームページについて  
ホーム >> 基本 >> クライアント領域もドラッグして移動できるウィンドウを作るためには(HITTEST)

クライアント領域もドラッグして移動できるウィンドウを作るためには(HITTEST)

  クライアント領域もドラッグして移動できるようにするためには、クライアント領域をクリックした際、タイトルバーをクリックしたのと同じ動作をウィンドウにエミュレートさせる必要があります。
  ウィンドウのどこをクリックしているかやマウスが移動しているかは、WM_NCHITTESTで拾うことができます。
  このWM_NCHITTESTの返り値で、クリックしている箇所がどの分類なのか返しているのですが、たとえばクライアント領域であれば、DefWindowProc () APIは、HTCLIENTを返しています。タイトルバー(キャプションバー)であれば、HTCAPTIONを返しています。
  これをプログラムで変更してしまうことにより、クライアントでもタイトルバーの振りをさせ、ドラッグしてウィンドウを移動できるようにするのです。

  処理としては、WM_NCHITTESTのlParamの値は、マウスのスクリーン座標が入ります。
  これをクライアント座標に変換し(ScreenToClient () API)、クライアント領域にいるかどうか(PtInRect () API)判断し、かつ右クリックしていればHTCAPTIONを返すことにより、クライアントをタイトルバーの振りをさせます。
右クリックしているかどうかは、マウス状態を取得できる GetAsyncKeyState () APIにより取得します。

以下、サンプルになります。

■■■ hittest プロジェクト
main.cpp

#include <windows.h>
#include <tchar.h>

// イベントハンドラ
long CALLBACK WindowFunc ( HWND hWnd,
    UINT nMessage,
    WPARAM wParam,
    LPARAM lParam )
{
    switch ( nMessage ) {
    case WM_NCHITTEST:
        {
            // クライアント領域をマウスでドラッグしてウィンドウを移動できるように
            // キャプションバーの振りをさせる
            RECT rcClient;
            POINT poClient;
            poClient.x = LOWORD ( lParam );
            poClient.y = HIWORD ( lParam );
            GetClientRect ( hWnd, &rcClient );

            ScreenToClient ( hWnd, &poClient );
            
            if ( PtInRect ( &rcClient, poClient )
                && GetAsyncKeyState ( VK_LBUTTON ) < 0 )
            {
                return HTCAPTION;
            }

        }
        break;
    case WM_DESTROY:
        PostQuitMessage ( 0 );
        return 0;
    }
    
    return DefWindowProc ( hWnd, nMessage, wParam, lParam );
}

// エントリポイント
int WINAPI _tWinMain ( HINSTANCE hThisInstance,
    HINSTANCE,
    _TCHAR *,
    int nCmdShow )
{
    _TCHAR cszClsName[] = _TEXT ( "HitTest" );

    WNDCLASSEX wcex;
    wcex.cbClsExtra = 0;
    wcex.cbSize = sizeof ( WNDCLASSEX );
    wcex.cbWndExtra = 0;
    wcex.hbrBackground = reinterpret_cast < HBRUSH > ( COLOR_WINDOW );
    wcex.hCursor = LoadCursor ( NULL, IDC_ARROW );
    wcex.hIcon = LoadIcon ( NULL, IDI_APPLICATION );
    wcex.hIconSm = LoadIcon ( NULL, IDI_APPLICATION );
    wcex.hInstance = hThisInstance;
    wcex.lpfnWndProc = WindowFunc;
    wcex.lpszClassName = cszClsName;
    wcex.lpszMenuName = NULL;
    wcex.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
    
    ATOM atom;
    atom = RegisterClassEx ( &wcex );
    if ( 0 == atom )
    {
        return 0;
    }

    HWND hWnd;
    hWnd = CreateWindowEx ( 0,
        cszClsName,
        cszClsName,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hThisInstance,
        NULL );

    ShowWindow ( hWnd, nCmdShow );
    UpdateWindow ( hWnd );

    MSG msg;
    while ( GetMessage ( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage ( &msg );
        DispatchMessage ( &msg );
    }

    return 0;
}
  ■ ご利用に際して ■ 更新履歴 ■ お問い合わせ ■ このホームページについて Copyright © 2014 A.Morita