【问题标题】:WINAPI: Colored Border for Static Dialog ItemWINAPI:静态对话框项的彩色边框
【发布时间】:2015-02-26 09:28:45
【问题描述】:

我在 win32 api 中有一个对话框。我有一个如下创建的静态元素。

lpw = lpwAlign(lpw);     // Align DLGITEMTEMPLATE on DWORD boundary
lpdit = (LPDLGITEMTEMPLATE)lpw;
lpdit->x  = 12;
lpdit->y  = 36;
lpdit->cx = 75;
lpdit->cy = 7;
lpdit->id = ID_ERROR_MSG;
lpdit->style =  WS_CHILD | SS_BITMAP | WS_VISIBLE  ;

lpw = (LPWORD)(lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0082;        // Static class

lpwsz = (LPWSTR)lpw;
nchar = MultiByteToWideChar(CP_ACP, 0, errorMsg.c_str(), -1, lpwsz, 50);
lpw += nchar;
*lpw++ = 0;             

在对话过程中,我使用 WM_PAINT 和以下代码处理它。

HWND ErrorMessage = GetDlgItem(hwndDlg, ID_ERROR_MSG);

hdc = BeginPaint(ErrorMessage, &ps_Confirm);
    hFont = CreateFont(18,0,0,0,FW_BOLD,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
            CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial"));
        SelectObject(hdc, hFont);

        wchar_t sCaption[100];
        GetWindowText(ErrorMessage,sCaption, 100);

        //Sets the coordinates for the rectangle in which the text is to be formatted.
        SetRect(&rect, 0,0,75,7);
        SetTextColor(hdc, RGB(0,0,0));
        SetBkColor(hdc, RGB(255,255,255));
        //SetBkMode(hdc, TRANSPARENT);
        DrawText(hdc, sCaption, -1,&rect, DT_NOCLIP);
        DeleteObject(hFont);
    EndPaint(ErrorMessage, &ps_Confirm);

我想在它周围画上红色边框。我尝试使用 DrawEdge() 但边缘只有黑色。此外,它有点3D效果。我想做类似的事情:

我可以做的一个技巧是用深红色绘制一个空白静态元素,然后在其上绘制另一个白色静态元素。但这不是一个很好的解决方案。

有人可以帮忙吗?

【问题讨论】:

  • 等等,你为什么要手动绘制静态控件而没有所有者绘制?你试过DrawEdge() 但不是Rectangle()
  • 嘿,我不知道Rectangle() 函数。但是,在建议的答案中,FrameRect() 对我来说很好。
  • Rectangle()FrameRect() 相似,但 FrameRect()DrawEdge() 不同。作为记录,DrawEdge() 主要用于在不使用主题时绘制 UI 控件,以及 DrawFrameControl()DrawFocusRect()DrawCaption()(我认为 DrawState() 也是,但我不是 100% 确定)。
  • 谢谢,我会记住这些。 :)

标签: c++ windows winapi


【解决方案1】:

我要解决的方法是子类化静态控件。这样做意味着您只需要专注于实现您想要的不同行为,而不是整个控件的行为/逻辑。

首先,您需要告诉 Windows 您正在执行此操作。接下来需要为窗口实现一个WndProc(实际上是一个SUBCLASSPROC)函数。最后,您需要进行绘画。

这是一个粗略的例子:

#define _WIN32_WINNT 0x0501  // min version for subclassing funcs
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "resource.h"

HINSTANCE hInst;

const int errorPanelSubclassId = 1;

LRESULT paintErrorPanel(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    hdc = BeginPaint(hWnd, &ps);

    RECT mRect;
    GetClientRect(hWnd, &mRect);

    HBRUSH redBrush = CreateSolidBrush( RGB(255,0,0) );
    FrameRect(hdc, &mRect, redBrush);
    DeleteObject(redBrush);

    EndPaint(hWnd, &ps);
    return 0;
}

LRESULT CALLBACK subclassedWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    if (uMsg == WM_PAINT)
    {
        paintErrorPanel(hWnd, wParam, lParam);
        return 0;
    }

    else
        return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}


BOOL CALLBACK DlgMain(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
        case WM_INITDIALOG:
        {
            HWND errorPanel = GetDlgItem(hwndDlg, IDC_ERROR_STATIC);
            SetWindowSubclass(errorPanel, subclassedWinProc, errorPanelSubclassId, NULL);
        }
        return TRUE;

        case WM_CLOSE:
        {
            EndDialog(hwndDlg, 0);
        }
        return TRUE;

        case WM_DESTROY:
        {
            RemoveWindowSubclass(errorPanel, subclassedWinProc, errorPanelSubclassId);
        }
        return 0;

        case WM_COMMAND:
        {
            switch(LOWORD(wParam))
            {
            }
        }
        return TRUE;
    }
    return FALSE;
}



int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    hInst=hInstance;
    InitCommonControls();
    return DialogBox(hInst, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)DlgMain);
}

【讨论】:

  • +1,但是您忘记在对话框的WM_DESTROY 处理程序中调用RemoveWindowSubclass(或者您可以在子类过程中调用,以响应WM_NCDESTROY)...最好问候(我们已经很久没有“说话”了)。
  • 干杯,有趣的是你应该提到 - 几分钟前我还在想同样的事情。我会解决这个问题。你是怎么用光标的,有什么好处吗?确实有一段时间了,希望你一切都好。 :)
  • 我遇到了很多“有趣”的问题,但我无法自己解决。最大的一个是可重新排列的列表视图。我曾想过使用 OLE 拖放来重新排列项目,但找到了一个更简单的解决方案。不过,我需要处理多选的情况。带有自定义背景的 DateTimePicker 控件也是一个无法解决的问题。如果你愿意,我可以在这里链接这些问题或在 CP 上给你发评论,让你看看... 确实有一段时间了,希望你一切都好。 :) 还在“踢” :) 生活如何对待你?
  • :) 听起来很熟悉。哦,很好,这就像攀岩——不能这样走吗?找到另一个.. 我会看看你的 Qs。我可以在您的个人资料中看到它们,无需链接。 :) 很好 - 最近是 RC 大约 3 年来第一次飞行 - 我非常需要它!
  • @enhzflep 非常感谢。这太棒了。它确实锻炼了。但是,我不需要实现 SUBCLASSPROC。在 WM_PAINT 消息中,对于 dialogproc,我使用了 FrameRect 并且它有效。是否有实施 SUBCLASSPROC 的具体需求?
猜你喜欢
  • 1970-01-01
  • 2016-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多