0

我的一个朋友即将发布一个应用程序,并要求我为其创建一个启动器。我发现这是一个很好的借口,最终研究了 WinAPI,并认为即使在相对较小的时间窗口内,一个简单的启动器也很容易实现。

我错了。

我正在尝试创建一个带有 5 个按钮的启动器窗口,这些按钮可以启动不同的东西。目标是拥有透明按钮(尚未完成),其中包含较小的图像。仅当用户将鼠标悬停在较大的按钮区域上时才应显示图像。

图像为 .png 格式。我正在使用 GDI+ 并使用http://www.codeproject.com/Articles/3537/Loading-JPG-PNG-resources-using-GDI从资源中加载 PNG 文件。

我正在使用 MouseTrackEvents 来跟踪鼠标,并且我还对按钮进行了子类化。问题是我不知道应该如何处理 WM_MOUSELEAVE 消息。我不知道如何擦除我绘制的图像。如果我必须将 ht_img 保存为变量并稍后引用它,我不知道如何。

这是我到目前为止所拥有的。此示例从资源 IDB_Website2 加载 .png。显示图像有效(尽管目前它一直在一遍又一遍地渲染):

WndProc:

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
GDI gdi;

switch (Msg)
{
    case WM_CREATE:
    {
        HWND hwndButton = CreateWindow(TEXT("button"), NULL,
                          WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
                          80, 10, 100, 50,
                          hWnd, (HMENU) HT_BUTTON1, NULL, NULL);
        HTButton = (WNDPROC) SetWindowLong(hwndButton, GWL_WNDPROC, (LONG) ButtonProc);
    }
...

    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        gdi.InitList(hInst, hdc);
        EndPaint(hWnd, &ps);
        break;

Buttonproc(子类按钮):

LRESULT CALLBACK ButtonProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
MouseTrackEvents MouseTrack;
GDI gdi;

HDC odc = GetDC(GetParent(hWnd));

switch(Msg)
{
    case WM_MOUSEMOVE:
        MouseTrack.OnMouseMove(hWnd);
        break;

    case WM_MOUSEHOVER:
        gdi.Create(IDB_Website2, _T("PNG"), hInst, odc, 62, 347, 200, 40, true);
        MouseTrack.Reset(hWnd);
        break;

    case WM_MOUSELEAVE:
        MouseTrack.Reset(hWnd);
        break;
}

return CallWindowProc (HTButton, hWnd, Msg, wParam, lParam);
}

类 GDI 的创建图形方法:

void Create(UINT menuid, LPCTSTR pType, HMODULE hInst, HDC hdc, int x, int y, int w, int h)
{
    Graphics grpx(hdc);

    ht_img = new CGdiPlusBitmapResource();
    ht_img -> Load(menuid, pType, hInst);
    grpx.DrawImage(*ht_img, x, y, w, h);
    delete ht_img;
}

到目前为止,这是一个相当大的挑战!这很有趣,尽管有时会让人有些发狂。:-) 对于我应该如何进行的任何建议,我将不胜感激。


编辑:回答阿德里安

我尝试更改我的 Buttonproc,但图像似乎没有被渲染。这是我所做的:

LRESULT CALLBACK ButtonProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    MouseTrackEvents MouseTrack;
    GDI gdi;
    HDC odc = GetDC(GetParent(hWnd));
    PAINTSTRUCT ps;

    int result;

    switch(Msg)
    {
    case WM_MOUSEMOVE:
        MouseTrack.OnMouseMove(hWnd);
        break;

    case WM_MOUSEHOVER:
        hovering = true;
        break;

    case WM_MOUSELEAVE:
        hovering = false;
        MouseTrack.Reset(hWnd);
        break;

    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        result = CallWindowProc(HTButton, hWnd, Msg, wParam, lParam);
        if (hovering == true) {
            gdi.Create(IDB_Play2, _T("PNG"), hInst, hdc, 62, 100, 200, 40);
        }
        EndPaint(hWnd, &ps);
        return result;
    }
    return CallWindowProc (HTButton, hWnd, Msg, wParam, lParam);
}
4

1 回答 1

1

您可能不想在处理鼠标事件时直接进行绘画。您可能希望通过调用底层实现然后根据悬停状态对其进行扩充来处理按钮 proc 中的 WM_PAINT。然后您的鼠标处理对应于翻转状态变量并使按钮无效(这将导致它重新绘制)。

case WM_PAINT:
    // start with the standard rendering
    int result = CallWindowProc (HTButton, hWnd, Msg, wParam, lParam);
    // then overdraw our embellishments
    if (my_state_variable == hovering) {
         DrawOverlayImage();
    }
    return result;  // don't just break here, or you'll call CallWindowProc again
于 2012-08-31T16:35:50.820 回答