C++ 在我将视觉样式设置为on后,常用控件未正确使用WM_CTLCOLORSTATIC处理程序绘制 导言和有关资料:

C++ 在我将视觉样式设置为on后,常用控件未正确使用WM_CTLCOLORSTATIC处理程序绘制 导言和有关资料:,c++,winapi,C++,Winapi,我有两个通过资源编辑器创建的对话框。由于我使用的是Microsoft Visual Studio Express edition,所以必须下载才能创建它们。在我的程序中,我启用了视觉样式,如下所示: #include <commctrl.h> #pragma comment( lib, "comctl32.lib") #pragma comment( linker, "/manifestdependency:\"type='win32' \ name='Micro

我有两个通过资源编辑器创建的对话框。由于我使用的是Microsoft Visual Studio Express edition,所以必须下载才能创建它们。在我的程序中,我启用了
视觉样式
,如下所示:

#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='*'\"")
我希望这些控件有透明的文本背景和黑色的文本

问题是: 在Windows XP上,以下是第一个对话框的结果图像:

组框有蓝色文本和棕色边框,而复选框的所有内容都是黑色的。在Windows 7上,启动同一程序后,我得到以下结果:

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

到目前为止,我尝试了什么: 我浏览了SO归档文件,但没有找到任何可以用来修改我的
WM\u ctlcolorstic
处理程序的内容

我已经找到了一种解决方法,从这些控件中删除视觉样式,这样可以达到预期的效果,但我需要保持视觉样式并使文本背景透明,因此此解决方案不能满足我的要求

在浏览了视觉样式参考和一些实验之后,我找到了单选按钮和复选框(但不适用于组框)的解决方案,代码如下:

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) );
尽管如此,我还是“撞到了墙”:

在我的对话框中有一个树状视图,一旦我选择了节点并按下空格键(或任何其他键),对话框的背景位图就会显示在我的静态控件上

在我注释掉
DrawThemeParentBackground()
之后,重新编译并再次启动程序,一切正常(当我选择树的节点并按空格键时),但我“处于第一方”

问题是:
  • 如何修改我的
    WM_CTLCOLORSTATIC
    处理程序来解决问题

  • 如果无法实现上述功能,我是否可以使用
    NM\u CUSTOMDRAW
    获得所需的效果

  • 注:

    我想我必须使用
    GDI
    绘制
    分组框。如果是这样,我也会接受这个解决方案,因为我主要关心的是
    复选框
    单选按钮

    使用提交的示例项目编辑: 根据要求,我将提交一份申请。要创建项目,请执行以下步骤:

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

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

    5.)在tWinMain中启动
    通用控件

    // initialize common controls
    
    INITCOMMONCONTROLSEX iccex;
    iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_STANDARD_CLASSES ;
    InitCommonControlsEx(&iccex);
    
    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;
    
    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) );
    
    这将是创建演示问题的最小程序所需的所有步骤和信息。现在运行应用程序并观察差异:

    带有
    IDC_RADIO1
    的单选按钮和带有
    IDC_CHECK1
    的复选框将正确绘制(黑色透明文本),而其他复选框和单选按钮将不会正确绘制。此外,单击树视图并按空格键后,您将看到对话框背景的问题

    HDC hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
    hdcMemDialogBackground = CreateCompatibleDC(hdc);
    hBitmap = CreateCompatibleBitmap(hdc, dialogWidth, dialogHeight);
    hBitmapOld = SelectObject(hdcMemDialogBackground , hBitmap);
    DeleteDC(hdc);
    
    编辑结束 多谢各位


    致意。

    WM\u CTLCOLORSTATIC
    处理程序中,您只能更改静态控件的背景


    按钮、单选按钮和检查按钮是相同的控制按钮。要更改它,你需要处理
    WM\u CTLCOLORBTN
    。可以找到一个例子。

    我已经创建了您的对话框,并在xp和7中运行,一切都很顺利。您应该做以下几点:

    在内存中创建位图并在那里绘制所有图形。这应该是对话框的背景

    HDC hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
    hdcMemDialogBackground = CreateCompatibleDC(hdc);
    hBitmap = CreateCompatibleBitmap(hdc, dialogWidth, dialogHeight);
    hBitmapOld = SelectObject(hdcMemDialogBackground , hBitmap);
    DeleteDC(hdc);
    
    要创建radiobutton和复选框,请使用非静态的“button”类

    WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX
    WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON
    
    风格

    在对话框中,您应包括

    WS_CLIPCHILDREN
    
    风格。这将解决按空格键时背景与控件重叠的问题

    您不应在
    WM_ERASEBKGND
    消息中绘制对话框的背景,而应在
    WM_PAINT

    case WM_PAINT:
            RECT r, rt;
            GetUpdateRect(hDlg, &rt, false);
    
            GetClientRect( hDlg, &r );
    
            GradientTriangle( hdcMemDialogBackground, 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( hdcMemDialogBackground, r.right, r.bottom - r.top, 
            r.right, r.top,
            r.left, r.top, 
            RGB( 0xFF, 0x0, 0x0 ), RGB( 0x0, 0xFF, 0x0 ) );
    
            hdc = BeginPaint(hDlg, &ps);
    
            BitBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, hdcMemDialogBackground, rt.left, rt.top, SRCCOPY);
    
            EndPaint(hDlg, &ps);
    
            break;
    
    最后,对于透明背景,在
    WM\u NOTIFY
    中:

    case WM_NOTIFY:
        NMHDR *nmr;
        NMCUSTOMDRAW *nmcd;
    
        nmr = (NMHDR *)lParam;
        nmcd = (NMCUSTOMDRAW *)lParam;
    
        if(nmr->idFrom == IDC_RADIO1 && nmr->code == NM_CUSTOMDRAW){
            if(nmcd->dwDrawStage == CDDS_PREERASE){
                BitBlt(nmcd->hdc, 0, 0, radioButton1Width, radioButton1Height, hdcMemDialogBackground, radioButton1PosX, radioButton1PosY, SRCCOPY);
    
                return CDRF_SKIPDEFAULT;
            }
        }
    
        if(nmr->idFrom == IDC_RADIO2 && nmr->code == NM_CUSTOMDRAW){
            //the same
        }
    
        if(nmr->idFrom == IDC_CHECK1 && nmr->code == NM_CUSTOMDRAW){
            //the same
        }
    
        if(nmr->idFrom == IDC_CHECK2 && nmr->code == NM_CUSTOMDRAW){
            //the same
        }
    
        break;
    
    最后,处置您的资源:

    SelectObject(hdcMemDialogBackground, hBitmapOld);
    DeleteObject(hBitmap);
    hBitmap = NULL;
    DeleteDC(hdcMemDialogBackground);
    hdcMemDialogBackground= NULL;
    
    编辑

    EDIT2(用于调整大小)

    更改WM_油漆:

    case WM_PAINT:
        GetUpdateRect(hDlg, &rt, false);
        hdc = BeginPaint(hDlg, &ps);
    
        BitBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, hdcMemDialogBackground, rt.left, rt.top, SRCCOPY);
    
        EndPaint(hDlg, &ps);
    
        break;
    
    在WM_大小中:

    case WM_SIZE:
        r.left = 0;
        r.top = 0;
        r.right = LOWORD(lParam);;
        r.bottom = HIWORD(lParam);
    
        GradientTriangle(hdcMemDialogBackground, 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(hdcMemDialogBackground, r.right, r.bottom - r.top, 
                    r.right, r.top,
                    r.left, r.top, 
                    RGB( 0xFF, 0x0, 0x0 ), RGB( 0x0, 0xFF, 0x0 ) );
    
        InvalidateRect(hwndRadioButton1, NULL, false);
        InvalidateRect(hwndRadioButton2, NULL, false);
        InvalidateRect(hwndCheck11, NULL, false);
        InvalidateRect(hwndCheck2, NULL, false);
        InvalidateRect(hDlg, NULL, false);
    
        break;
    
    要使调整大小正常工作,您需要使用最大值创建
    hdcMemDialogBackground
    尺寸对话框将具有例如1280x1024或1680x1050或任何其他

    就这样


    瓦尔特

    你能准备一份吗?也就是说,准备一个最小的示例来演示这个问题,其中所有代码都包含在一个文件中,比如main.cpp,我可以复制并粘贴到一个新项目中,然后运行,而无需修改,它会重现问题?你如何创建你的对话框?@sashoalm:我已经用最少的代码编辑了我的帖子来重现问题。致以最良好的祝愿。@valter:我使用了
    CreateDialogParam(…)
    ,但我已经编辑了我的文章,将SSCE包括在内,并且使用了
    DialogBox(…)
    API。致以最诚挚的问候。您无法更改groupbox框架。你必须自己画。如果您不打算调整对话框的大小,您可以通过自己绘制所有内容来实现所需的功能。这并不难,因为你的对话很简单。在对话框的WM_PAINT中绘制背景、文本和框架。添加常规按钮,而不是复选按钮和单选按钮,并在各种事件(输入、向下、离开)中绘制图像。我总是这样做的。如果您感兴趣,我将为您提供code.MSDN备注:复选框或单选按钮的文本颜色适用于该框或按钮、其复选标记和文本。这些按钮的焦点矩形保持系统默认颜色(通常为黑色)。最后
    SelectObject(hdcMemDialogBackground, hBitmapOld);
    DeleteObject(hBitmap);
    hBitmap = NULL;
    DeleteDC(hdcMemDialogBackground);
    hdcMemDialogBackground= NULL;
    
    POINT pt;
    RECT rt;
    GetClientRect(hwndRadioButton1, &rt);
    pt.x = 0;
    pt.y = 0;
    ClientToScreen(hwndRadioButton1, &pt);
    ScreenToClient(hDlg, &pt);
    
    BitBlt(nmcd->hdc, 0, 0, rt.right, rt.bottom, hdcMemDialogBackground, pt.x, pt.y, SRCCOPY);
    
    case WM_PAINT:
        GetUpdateRect(hDlg, &rt, false);
        hdc = BeginPaint(hDlg, &ps);
    
        BitBlt(hdc, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, hdcMemDialogBackground, rt.left, rt.top, SRCCOPY);
    
        EndPaint(hDlg, &ps);
    
        break;
    
    case WM_SIZE:
        r.left = 0;
        r.top = 0;
        r.right = LOWORD(lParam);;
        r.bottom = HIWORD(lParam);
    
        GradientTriangle(hdcMemDialogBackground, 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(hdcMemDialogBackground, r.right, r.bottom - r.top, 
                    r.right, r.top,
                    r.left, r.top, 
                    RGB( 0xFF, 0x0, 0x0 ), RGB( 0x0, 0xFF, 0x0 ) );
    
        InvalidateRect(hwndRadioButton1, NULL, false);
        InvalidateRect(hwndRadioButton2, NULL, false);
        InvalidateRect(hwndCheck11, NULL, false);
        InvalidateRect(hwndCheck2, NULL, false);
        InvalidateRect(hDlg, NULL, false);
    
        break;