ソフトウェア開発 Win32プログラミング

スプリッタで操作画面を分割する

戻る


操作画面を分割するときには、スプリッタ ウィンドウ(splitter window)と呼ばれるものを使って、分割幅を調節できるようにすることが多い。

スプリッタウィンドウを自作して操作画面を分割するコードを以下に示す。

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

HINSTANCE g_hInstance;
HWND g_hMainWnd;
HWND g_hSplitterWnd;
HWND g_hEdit1, g_hEdit2;
INT g_xSplitPos = 200;
INT g_xSplitOldPos;
 
const TCHAR g_szWndClassName[] = TEXT("SplitterTest");
const TCHAR g_szSplitterWndClassName[] = TEXT("SplitterWnd");
 
#define SPLITTER_WIDTH 4

INT Splitter_OnCreate(HWND hWnd)
{
    g_hEdit1 = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("Edit1"),
        WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
        hWnd, (HMENU)1, g_hInstance, NULL);
    if (g_hEdit1 == NULL)
        return -1;
 
    g_hEdit2 = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("Edit2"),
        WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
        hWnd, (HMENU)1, g_hInstance, NULL);
    if (g_hEdit2 == NULL)
        return -1;
 
    return 0;
}
 
VOID Splitter_OnSize(HWND hWnd)
{
    RECT rc;
    GetClientRect(hWnd, &rc);
 
    MoveWindow(g_hEdit1, 0, 0,
        g_xSplitPos, rc.bottom - rc.top, TRUE);
    MoveWindow(g_hEdit2, g_xSplitPos + SPLITTER_WIDTH, 0,
        rc.right - rc.left - (g_xSplitPos + SPLITTER_WIDTH),
        rc.bottom - rc.top, TRUE);
}
 
/* hit test code */
enum {Splitter_HT_NONE, Splitter_HT_HIT};
 
INT Splitter_HitTest(INT x, INT y)
{
    if (g_xSplitPos - SPLITTER_WIDTH / 2 - 1 <= x &&
        x <= g_xSplitPos + SPLITTER_WIDTH / 2 + 1)
        return Splitter_HT_HIT;
    return Splitter_HT_NONE;
}
 
VOID Splitter_Draw(HWND hWnd, INT x)
{
    HDC hDC;
    HBRUSH hbr;
    HGDIOBJ hbrOld;
    RECT rc, rc2;
 
    GetClientRect(hWnd, &rc);
    hDC = GetDC(hWnd);
    if (hDC != NULL)
    {
        hbr = CreateSolidBrush(RGB(0, 0, 0));
        if (hbr != NULL)
        {
            rc2.left = x;
            rc2.top = 0;
            rc2.right = x + SPLITTER_WIDTH;
            rc2.bottom = rc.bottom;
            SetROP2(hDC, R2_NOT);
            SetBkMode(hDC, TRANSPARENT);
            hbrOld = SelectObject(hDC, hbr);
            Rectangle(hDC, rc2.left, rc2.top, rc2.right, rc2.bottom);
            SelectObject(hDC, hbrOld);
            DeleteObject(hbr);
        }
        ReleaseDC(hWnd, hDC);
    }
}
 
VOID Splitter_OnMouseMove(HWND hWnd, INT x, INT y)
{
    RECT rc;
    SetCursor(LoadCursor( NULL, IDC_SIZEWE));
    if (GetCapture() == hWnd)
    {
        GetClientRect(hWnd, &rc);
        if (x < SPLITTER_WIDTH * 3)
            x = SPLITTER_WIDTH * 3;
        else if (x >= rc.right - SPLITTER_WIDTH * 3)
            x = rc.right - SPLITTER_WIDTH * 3;
        x -= SPLITTER_WIDTH / 2;
        Splitter_Draw(hWnd, g_xSplitOldPos);
        Splitter_Draw(hWnd, x);
        g_xSplitOldPos = x;
    }
}
 
VOID Splitter_OnLButtonDown(HWND hWnd, INT x, INT y)
{
    RECT rc;
    INT n = Splitter_HitTest(x, y);
    if (n == Splitter_HT_HIT)
    {
        GetClientRect(hWnd, &rc);
        SetCapture(hWnd);
        if (x < SPLITTER_WIDTH * 3)
            x = SPLITTER_WIDTH * 3;
        else if (x >= rc.right - SPLITTER_WIDTH * 3)
            x = rc.right - SPLITTER_WIDTH * 3;
        x -= SPLITTER_WIDTH / 2;
        Splitter_Draw(hWnd, x);
        g_xSplitOldPos = x;
    }
}
 
VOID Splitter_OnLButtonUp(HWND hWnd, INT x, INT y)
{
    RECT rc;
    if (GetCapture() == hWnd)
    {
        GetClientRect(hWnd, &rc);
        ReleaseCapture();
        SetCursor((HCURSOR)GetClassLongPtr(hWnd, GCLP_HCURSOR));
        if (x < SPLITTER_WIDTH * 3)
            x = SPLITTER_WIDTH * 3;
        else if (x >= rc.right - SPLITTER_WIDTH * 3)
            x = rc.right - SPLITTER_WIDTH * 3;
        x -= SPLITTER_WIDTH / 2;
        g_xSplitPos = x;
        SendMessage(hWnd, WM_SIZE, 0, 0);
    }
}
 
VOID Splitter_OnCaptureChanged(HWND hWnd)
{
    Splitter_Draw(hWnd, g_xSplitOldPos);
}
 
LRESULT CALLBACK SplitterWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_CREATE:
        return Splitter_OnCreate(hWnd);
 
    case WM_SIZE:
        Splitter_OnSize(hWnd);
        break;
 
    case WM_MOUSEMOVE:
        Splitter_OnMouseMove(hWnd, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
        break;
 
    case WM_LBUTTONDOWN:
        Splitter_OnLButtonDown(hWnd, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
        break;
 
    case WM_LBUTTONUP:
        Splitter_OnLButtonUp(hWnd, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
        break;
 
    case WM_CAPTURECHANGED:
        Splitter_OnCaptureChanged(hWnd);
        break;
        
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}
 
INT OnCreate(HWND hWnd)
{
    g_hSplitterWnd = CreateWindow(g_szSplitterWndClassName,
        g_szSplitterWndClassName, WS_CHILD | WS_VISIBLE,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, hWnd,
        (HMENU)1, g_hInstance, NULL);
    if (g_hSplitterWnd == NULL)
        return -1;
    return 0;
}
 
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_CREATE:
        return OnCreate(hWnd);
 
    case WM_SIZE:
        MoveWindow(g_hSplitterWnd, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
        break;
 
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
 
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}
 
INT WINAPI WinMain(
    HINSTANCE   hInstance,
    HINSTANCE   hPrevInstance,
    LPSTR       pszCmdLine,
    INT         nCmdShow)
{
    WNDCLASS wc;
    BOOL f;
    MSG msg;
 
    g_hInstance = hInstance;
    wc.style            = 0;
    wc.lpfnWndProc      = WindowProc;
    wc.cbClsExtra       = 0;
    wc.cbWndExtra       = 0;
    wc.hInstance        = hInstance;
    wc.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)(COLOR_3DFACE + 1);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = g_szWndClassName;
    if (!RegisterClass(&wc))
        return 1;
    wc.lpfnWndProc      = SplitterWndProc;
    wc.lpszClassName    = g_szSplitterWndClassName;
    if (!RegisterClass(&wc))
        return 1;
 
    g_hMainWnd = CreateWindow(g_szWndClassName, g_szWndClassName,
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 400, 400,
        NULL, NULL, hInstance, NULL);
    if (g_hMainWnd == NULL)
        return 2;
 
    ShowWindow(g_hMainWnd, nCmdShow);
    UpdateWindow(g_hMainWnd);
 
    while((f = GetMessage(&msg, NULL, 0, 0)) != FALSE)
    {
        if (f == -1)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (INT)msg.wParam;
}

ソース: split.zip


戻る

©片山博文MZ
katayama.hirofumi.mz@gmail.com

inserted by FC2 system