在我设置视觉样式后,常规控件未使用WM_CTLCOLORSTATIC处理程序正确绘制

Alw*_*uff 9 c++ winapi

介绍及相关资料:

我有2个通过资源编辑器创建的对话框.由于我使用的是Microsoft Visual Studio Express版本,因此我必须下载免费的资源编辑器来创建它们.在我的程序中,我启用了这样的:Visual Styles

#include <commctrl.h>

#pragma comment( lib, "comctl32.lib")

#pragma comment( linker, "/manifestdependency:\"type='win32' \
        name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
        processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
        language='*'\"")
Run Code Online (Sandbox Code Playgroud)

据我所知,复选框,单选按钮组框获取WM_CTLCOLORSTATIC消息,用于绘制文本.

这是我为第一个和第二个对话框编写的代码:

case WM_CTLCOLORSTATIC:
    {
        SetBkMode( (HDC)wParam, TRANSPARENT );
        SetTextColor( (HDC)wParam, RGB( 0, 0, 0 ) );
        return (INT_PTR)( (HBRUSH)GetStockObject(NULL_BRUSH) );
    }
Run Code Online (Sandbox Code Playgroud)

我希望这些控件具有透明文本背景和文本的黑色.

问题:

Windows XP上,这是第一个对话框的结果图像:

在此输入图像描述

组框有蓝色文字和棕色边框,而复选框有一切黑色.在Windows 7上,启动相同的程序后,我得到了这个:

在此输入图像描述

这里,组框复选框具有正确的文本颜色,但复选框的背景和组框的边框是错误的.在我的对话框中,我有静态控件,它们Windows 7Windows XP都被正确绘制.

我到底做了什么:

我浏览了SO存档,但没有找到任何我可以用来修改我的WM_CTLCOLORSTATIC处理程序的东西.

我找到了一个从这些控件中删除 视觉样式的解决方法,因此它可以实现所需的结果,但我需要保持视觉样式并使文本的背景透明,因此这个解决方案不能满足我.

通过浏览Visual Styles参考和一些小实验后,我找到了单选按钮复选框(但不适用于组框)的解决方法,其中包含以下代码:

case WM_CTLCOLORSTATIC:
    if( (HWND)lParam == GetDlgItem( hwnd, IDC_RADIO1 ) ) 
    {
        RECT r;
        GetClientRect( hwnd, &r );
        DrawThemeParentBackground( (HWND)lParam, (HDC)wParam, &r );
    }
    else
    {
        SetTextColor( (HDC)wParam, RGB( 0, 0, 0 ) );
        SetBkMode( (HDC)wParam, TRANSPARENT );
    }
    return (INT_PTR)( (HBRUSH)GetStockObject(NULL_BRUSH) );
Run Code Online (Sandbox Code Playgroud)

尽管如此,我还是"碰到了墙":

在我的对话框中有一个树视图,一旦我选择节点并按下spacebar(或任何其他键),对话框的背景位图就会出现在我的静态控件之上.

在我注释掉之后DrawThemeParentBackground(),重新编译并重新启动程序一切正常(当我选择树节点并按下时spacebar)但是我"在方形一".

问题:

  1. 如何修改我的WM_CTLCOLORSTATIC处理程序来修复我的问题?

  2. 如果上述情况不可能,我可以获得所需的效果NM_CUSTOMDRAW吗?

注意:

我想我将不得不group box使用GDI.如果是这样的话,我会接受这个解决方案也一样,我主要关注的是checkboxradio button.

使用提交的示例项目进行编辑:

根据要求,我正在提交SSCCE.要创建项目,请按照下列步骤操作:

1.)在Visual Studio中创建默认的Win32项目.

2.)在stdafx.h复制/粘贴以下指令中,如下#include <windows.h>:

#include <commctrl.h>
#include <Uxtheme.h>

#pragma comment( linker, "/manifestdependency:\"type='win32' \ 
                    name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
                    processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
                    language='*'\"")

#pragma comment( lib, "comctl32.lib")
#pragma comment( lib,"Msimg32.lib")    // needed for GradientFill(...) API
#pragma comment( lib, "UxTheme.lib")
Run Code Online (Sandbox Code Playgroud)

3.)在资源编辑器中,通过添加2个单选按钮,2个复选框和一个包围它们的组框来更改关于对话框(参见上面的图片也看到我的意思)并添加树视图控件(此控件将"触发"问题 ).

4.)在主cpp文件中,添加用于绘制自定义背景的辅助函数:

void GradientTriangle( HDC MemDC, 
    LONG x1, LONG y1, 
    LONG x2, LONG y2, 
    LONG x3, LONG y3, 
    COLORREF top, COLORREF bottom )
{
    TRIVERTEX vertex[3];

    vertex[0].x     = x1;
    vertex[0].y     = y1;
    vertex[0].Red   = GetRValue(bottom) << 8;
    vertex[0].Green = GetGValue(bottom) << 8;
    vertex[0].Blue  = GetBValue(bottom) << 8;
    vertex[0].Alpha = 0x0000;

    vertex[1].x     = x3;
    vertex[1].y     = y3; 
    vertex[1].Red   = GetRValue(bottom) << 8;
    vertex[1].Green = GetGValue(bottom) << 8;
    vertex[1].Blue  = GetBValue(bottom) << 8;
    vertex[1].Alpha = 0x0000;

    vertex[2].x     = x2;
    vertex[2].y     = y2;
    vertex[2].Red   = GetRValue(top) << 8;
    vertex[2].Green = GetGValue(top) << 8;
    vertex[2].Blue  = GetBValue(top) << 8;
    vertex[2].Alpha = 0x0000;

    // Create a GRADIENT_TRIANGLE structure that
    // references the TRIVERTEX vertices.

    GRADIENT_TRIANGLE gTriangle;

    gTriangle.Vertex1 = 0;
    gTriangle.Vertex2 = 1;
    gTriangle.Vertex3 = 2;

    // Draw a shaded triangle.

    GradientFill( MemDC, vertex, 3, &gTriangle, 1, GRADIENT_FILL_TRIANGLE);
}
Run Code Online (Sandbox Code Playgroud)

5.)发起common controls_tWinMain:

// initialize common controls

INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_STANDARD_CLASSES ;
InitCommonControlsEx(&iccex);
Run Code Online (Sandbox Code Playgroud)

6.)在树视图中插入一些项目WM_INITDIALOG:

case WM_INITDIALOG:
    {
        HWND TreeView = GetDlgItem( hDlg, IDC_TREE1 );

        // add root item

        TVINSERTSTRUCT tvis = {0};

        tvis.item.mask = TVIF_TEXT;
        tvis.item.pszText = L"This is root item";
        tvis.hInsertAfter = TVI_LAST;
        tvis.hParent = TVI_ROOT;

        HTREEITEM hRootItem = reinterpret_cast<HTREEITEM>( SendMessage( TreeView , 
            TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );

        // add firts subitem for the hTreeItem

        memset( &tvis, 0, sizeof(TVINSERTSTRUCT) );

        tvis.item.mask = TVIF_TEXT;
        tvis.item.pszText = L"This is first subitem";
        tvis.hInsertAfter = TVI_LAST;
        tvis.hParent = hRootItem;

        HTREEITEM hTreeSubItem1 = reinterpret_cast<HTREEITEM>( SendMessage( TreeView , 
            TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );

        // now we insert second subitem for hRootItem

        memset( &tvis, 0, sizeof(TVINSERTSTRUCT) );

        tvis.item.mask = TVIF_TEXT | TVIF_STATE; // added extra flag
        tvis.item.pszText = L"This is second subitem";
        tvis.hInsertAfter = TVI_LAST;
        tvis.hParent = hRootItem;

        HTREEITEM hTreeSubItem2 = reinterpret_cast<HTREEITEM>( SendMessage( TreeView , 
            TVM_INSERTITEM, 0, reinterpret_cast<LPARAM>( &tvis ) ) );
    }
    return (INT_PTR)TRUE;
Run Code Online (Sandbox Code Playgroud)

7.)绘制对话框的自定义背景:

case WM_ERASEBKGND:
    {
        RECT r;
        GetClientRect( hDlg, &r );

        GradientTriangle( (HDC)wParam, r.right, r.bottom - r.top, 
            r.left, r.bottom - r.top,
            r.left, r.top,
            RGB( 0x0, 0x0, 0xFF ), RGB( 0xFF, 0xFF, 0x0 ) );

        GradientTriangle( (HDC)wParam, r.right, r.bottom - r.top, 
            r.right, r.top,
            r.left, r.top, 
            RGB( 0xFF, 0x0, 0x0 ), RGB( 0x0, 0xFF, 0x0 ) );
    }
    return TRUE;
Run Code Online (Sandbox Code Playgroud)

8.)添加处理程序WM_CTLCOLORSTATIC:

case WM_CTLCOLORSTATIC:
    if( ( (HWND)lParam == GetDlgItem( hDlg, IDC_RADIO1 ) )       
        || ( (HWND)lParam == GetDlgItem( hDlg, IDC_CHECK1 ) ) ) 
    {
        RECT r;
        GetClientRect( hDlg, &r );
        DrawThemeParentBackground( (HWND)lParam, (HDC)wParam, &r );
    }
    else
    {
        SetTextColor( (HDC)wParam, RGB( 0, 0, 0 ) );
        SetBkMode( (HDC)wParam, TRANSPARENT );
    }
    return (INT_PTR)( (HBRUSH)GetStockObject(NULL_BRUSH) );
Run Code Online (Sandbox Code Playgroud)

这将是创建演示问题的最小程序所需的所有步骤和信息.现在运行应用程序并观察差异:

单选按钮IDC_RADIO1复选框IDC_CHECK1将正确涂(用黑色透明文本),而其他的复选框单选按钮不会.此外,单击树视图并按下后,spacebar您将看到对话框背景的问题.

编辑结束

谢谢.

最好的祝福.

Dmi*_*lov 2

WM_CTLCOLORSTATIC处理程序中,您只能更改静态控件的 BG。

按钮、单选按钮和复选按钮是相同的控制按钮。要改变它 BG 你需要处理WM_CTLCOLORBTN. 可以在这里找到一个例子。