2013年8月19日月曜日

Win32APIでListBoxを使ってみる

挨拶


つかさです。
Win32APIでリストボックスを使ったサンプル。勉強のために、eClipっぽいのとfenrirっぽいのの二つを作ってみたのですがそのひとつ。



今日はこのようなどっかで見た気がしないでもないGUIを作って、エディットボックスでカーソル移動できるまで…といっても試しに作ってみただけなので、次回はおそらくないです。
ちなみに同じことをPythonでやったのがwxPythonでAA管理ツールを作ろう!第二回 ListBoxの操作です。参考までに。

コード


lbox.cpp

#define ID_EDIT 101

#include <windows.h>
#include <windowsx.h>

LPCTSTR strText[] = {
    TEXT("tukasa") ,
    TEXT("kagami") ,
    TEXT("konata") ,
    TEXT("homuhomu") ,
    TEXT("madoka")
};

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK MyEditProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);

TCHAR szClassName[] = TEXT("SETZER2");  // ウィンドウクラス
HINSTANCE hInst;
HWND hMain;             // メインウィンドウのハンドル
HWND hSubsortList;
WNDPROC OrgEditProc;   // プロシージャアドレスを格納するための変数
int CursorDown(HWND hEdit, HWND hsortList);
int CursorUp(HWND hEdit, HWND hsortList);

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
                   LPSTR lpsCmdLine, int nCmdShow)
{
    MSG msg;
    BOOL bRet;

    hInst = hCurInst;
    if (!InitApp(hCurInst))
        return FALSE;
    if (!InitInstance(hCurInst, nCmdShow))
        return FALSE;
    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
        if (bRet == -1) {
            break;
        } else {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}

// ウィンドウクラスの登録
ATOM InitApp(HINSTANCE hInst)
{
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;  // プロシージャ名
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;      // インスタンス
    wc.hIcon = NULL;
    wc.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW),
                    IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;    // メニュー名
    wc.lpszClassName = szClassName;
    wc.hIconSm = NULL;

    return (RegisterClassEx(&wc));
}

// ウィンドウの生成
BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
{
    HWND hWnd;

    hWnd = CreateWindow(szClassName, TEXT("SETZER2"),
        WS_OVERLAPPEDWINDOW & ~WS_CAPTION, CW_USEDEFAULT,
        CW_USEDEFAULT, 230, 300, NULL, NULL, hInst, NULL);
    if (!hWnd)
        return FALSE;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    hMain = hWnd;
    return TRUE;
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    static HWND sortList, edit;
    int i;

    switch (msg) {
        case WM_CREATE:
            sortList = CreateWindow(TEXT("LISTBOX"), TEXT(""),
                WS_CHILD | WS_VISIBLE | LBS_STANDARD,
                0, 0, 0, 0, hWnd, (HMENU)ID_EDIT, hInst, NULL);
            hSubsortList = sortList;
            for (i = 0 ; i < 5 ; i++)
                SendMessage(sortList , LB_ADDSTRING , 0 , (LPARAM)strText[i]);
            SendMessage(sortList , LB_SETCURSEL , 0 , 0);
            edit = CreateWindow(
                TEXT("EDIT") , NULL , 
                WS_CHILD | WS_VISIBLE | WS_BORDER ,
                0 , 0 , 0 , 0 , hWnd , (HMENU)ID_EDIT, hInst, NULL);
            // エディットコントロールをサブクラス化
            OrgEditProc = (WNDPROC)SetWindowLongPtr(
                edit, GWL_WNDPROC, (LONG)MyEditProc);
            break;
        case WM_SIZE:    
            // ウィンドウサイズを調整
            MoveWindow(edit, 0, 0, LOWORD(lp), 25, TRUE);
            MoveWindow(sortList, 0, 25, LOWORD(lp), HIWORD(lp), TRUE);
            break;
        case WM_SETFOCUS:
            SetFocus(edit);
            break;
        case WM_CLOSE:
             DestroyWindow(sortList);
             DestroyWindow(hWnd);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return (DefWindowProc(hWnd, msg, wp, lp));
    }
    return 0;
}

// エディットボックスのプロシージャ
LRESULT CALLBACK MyEditProc(HWND hEdit, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg) {
        case WM_KEYDOWN:
        if( wp == VK_DOWN )
        {
            CursorDown(hEdit, hSubsortList);
            break;
        }
        else if ( wp == VK_UP )
        {
            CursorUp(hEdit, hSubsortList);
            break;
        }
        else if ( wp == VK_ESCAPE )
        {
            DestroyWindow(hEdit);
            DestroyWindow(hSubsortList);
            DestroyWindow(hMain);
        }
    }
    return CallWindowProc(OrgEditProc, hEdit, msg, wp, lp);
}

// リストボックスのカーソルを上に
int CursorUp(HWND hEdit, HWND hsortList)
{
    int i;

    i = SendMessage(hsortList , LB_GETCURSEL , 0 , 0);
    if( i == 0 )
    {
        SendMessage(hsortList , LB_SETCURSEL , SendMessage(hsortList , LB_GETCOUNT , 0 , 0) - 1 , 0);
    }
    else
    {
        SendMessage(hsortList , LB_SETCURSEL , i - 1 , 0);
    }
    return 0;
}

// リストボックスのカーソルを下に
int CursorDown(HWND hEdit, HWND hsortList)
{
    int i;

    i = SendMessage(hsortList , LB_GETCURSEL , 0 , 0);
    if( i == SendMessage(hsortList , LB_GETCOUNT , 0 , 0) - 1 )
    {
        SendMessage(hsortList , LB_SETCURSEL , 0 , 0);
    }
    else
    {
        SendMessage(hsortList , LB_SETCURSEL , i + 1 , 0);
    }
    return 0;
}

解説


前回の記事の「cppファイルにコードを書く」過程で、上のコードをコピペしたら多分動くと思う。
エディットボックスでカーソル上下したらそれに連動して、リストボックスの選択カーソルが上下するようになってます。またEscを押したらプログラムを終了します。

Win32APIは、メッセージを受け取ったらそれにあわせて何か動作をするという仕組みらしい。コードは長いが、処理の中心はWndProcとかMyEditProcとかなので、そこらへんを追っていけばだいたいわかるかなと。ウィンドウの登録とかウィンドウの生成とかはどのプログラムでも同じなので、あまり気にしなくてもいいらしい。

0 件のコメント:

コメントを投稿