C++ Win32,可以编辑控件由所有者绘制吗?

Posted

技术标签:

【中文标题】C++ Win32,可以编辑控件由所有者绘制吗?【英文标题】:C++ Win32, Can Edit Controls be Owner Drawn? 【发布时间】:2013-07-31 04:47:04 【问题描述】:

我正在尝试让我的对话框匹配。我一直在通过谷歌,随机测试等,甚至阅读了一些无法完成的地方。

我能够做的是使用其中一条消息来设置字体和颜色,但对绘图本身却无能为力。

我认为它必须能够做到......

有人有什么想法吗?或者对此有什么了解?

http://imageshack.com/a/img832/5955/91m.png

【问题讨论】:

您的控件是否应用了WS_EX_CLIENTEDGE 样式?另外,您是使用 Visual Studio 资源编辑器还是手动创建? 我在手工制作资源文件,并在按钮上使用了 BS_OWNERDRAW,甚至绘制了向上/向下状态。我正在使用 wxDev-CPP。 EDITTEXT IDC_TIMEINPUT, 5, 135, 160, 12, ES_CENTER//| EMS_OWNERDRAW CONTROL "Status", IDC_STATUSBAR, STATUSCLASSNAME, 0, 0, 0, 0, SBT_OWNERDRAW 是资源文件中的行。我也尝试自定义绘制状态栏,但它与“凸起边缘”的问题相同。此外,我没有在任何地方指定 WS_EX_CLIENTEDGE。感谢您的回复。 看起来资源脚本中的编辑控件默认设置了一些样式。如果我在 Visual Studio 中创建一个对话框并关闭边框,则代码为EDITTEXT IDC_EDIT1,17,51,136,14,ES_AUTOHSCROLL | NOT WS_BORDER,而不是在边框设置为打开时包含WS_BORDER 此链接确认:msdn.microsoft.com/en-us/library/windows/desktop/… 独立于资源文件的工作方式,如果您只需要简单的文本显示,您可以尝试使用静态文本控件而不是编辑控件和状态栏。他们绝对支持平面外观和颜色定制。自己动手也不是那么难。如果您需要全文编辑功能,那就更难了,但并不是那么难。 【参考方案1】:

看起来编辑控件不支持所有者绘制,但您仍然可以解决您的直接问题。根据the MSDN page for EDITTEXT,默认情况下,资源文件中的编辑控件具有WS_BORDER 样式集。看起来你可以用这样的东西摆脱它:

EDITTEXT IDC_EDIT1,17,51,136,14,ES_AUTOHSCROLL | NOT WS_BORDER

对于状态栏,您可以尝试使用带有自定义颜色的静态控件,而不是真正的状态栏。或者您可以自己滚动,在资源文件中指定窗口类名称,并确保在显示对话框之前注册该类。

更新:哇,状态栏的文档太糟糕了。不过,您可以拥有一个。请按以下步骤操作:

// where hStatus is the HWND of a status bar...

// You must set simple mode to false, because simple mode doesn't
// support owner draw.

SendMessage(hStatus, SB_SIMPLE, FALSE, 0);

// I'm assuming 1 status bar part for demonstration. Setting the right edge
// for the 1 part to -1 make it take up the whole status bar.

int partWidths[] =  -1 ;

SendMessage(hStatus, SB_PARTS, 1, reinterpret_cast<LPARAM>(partWidths));

// There is background stuff that stays behind even with owner draw,
// so you have to set the background color to black, too, to get rid of
// any appearance of borders.

SendMessage(hStatus, SB_SETBKCOLOR, 0, RGB(0, 0, 0));

// There is still a slim border that stays behind, so you need to set
// SBT_NOBORDERS in addition to SBT_OWNERDRAW. The 0 is the index of the
// status bar part. It could be anything between 0 and 255.

SendMessage(
    hStatus,
    SB_SETTEXT,
    SBT_NOBORDERS | SBT_OWNERDRAW | 0,
    reinterpret_cast<LPARAM>(_T("Status")));

从那里,您还必须处理状态栏的WM_DRAWITEM。现在,至于为什么我说状态栏的文档很糟糕......

SB_SETTEXT 的文档说WPARAM 的低位字的高字节可以是以下值之一。这样做有两个问题:

    您可以将它们组合起来,而且您必须这样做才能正常工作。 MFC 也这样做。我查过了。

    您可能想写MAKEWPARAM(MAKEWORD(0, SBT_OWNERDRAW), 0)。这不会工作。从外观上看,SBT_ 样式的定义是,如果您将它们与索引值进行 OR 运算,它们将自动出现在低位字的高字节中。

我必须查看 MFC 源代码才能弄清楚如何正确使用 SB_SETTEXT

【讨论】:

谢谢!这在状态栏上取得了一些进展,看起来我想要它。仍在使用它。回到编辑,我发现它几乎可以垂直对齐文本。我用谷歌搜索了所有内容,我能找到的最接近的是 TextAlign(),它将对齐更改为固定位置,并且没有垂直居中。我在这上面花了几个小时,一切都是通过 WM_CTLCOLOREDIT 完成的,没有任何进展。对此有何想法? 您可能可以使用EM_SETRECTEM_SETLIMITTEXT 的某种组合,但因为EM_SETRECT 显然只适用于对我来说似乎很hacky 的多行编辑控件(尽管它是一部分API)。我还没有真正尝试过,所以我不能保证它会起作用。【参考方案2】:

Edit 控件没有所有者绘制模式,但是您可以继承 Edit 控件并处理 WM_ERASEBKGNDWM_NCPAINTWM_PAINT 等消息,以及发送到编辑的父窗口。

【讨论】:

这也不起作用,Edit 控件部分重绘而不使用 WM_PAINT。非常非常顽皮,但是当它必须在 386SUX 机器上运行时,这是一个必要的破解。【参考方案3】:

第 2 部分的答案,编辑中的垂直对齐文本:

        RECT rect;
        GetClientRect(GetDlgItem(hwnd, IDC_TIMEINPUT),&rect);          
        Rectangle(hdcEdit, rect.left, rect.top, rect.right, rect.bottom);            
        rect.left+=5; rect.top+=5; rect.right+=5; //rect.bottom+=5;
        SendMessage(GetDlgItem(hwnd, IDC_TIMEINPUT), EM_SETRECTNP, 0, (LPARAM)&rect);

必须是多行的,并且您确实必须使用不同的数字来保持单行,并保持垂直对齐。 EMS_SETRECTNP 允许您指定文本的位置,从而允许编辑具有更大的高度。

【讨论】:

以上是关于C++ Win32,可以编辑控件由所有者绘制吗?的主要内容,如果未能解决你的问题,请参考以下文章

编辑控件不会获得焦点! win32 c++

本机Win32主题感知所有者绘制控件没有MFC

为啥我的编辑控件在没有使用 MFC 的 win32 c++ 应用程序中看起来很奇怪?

带有子控件的 Win32 自定义控件

在 Win32 中子类化 MonthCal 控件

位图未在 Win32 C++ 中绘制