【问题标题】:Properly determine checkbox state for custom draw正确确定自定义绘图的复选框状态
【发布时间】:2014-03-28 19:31:29
【问题描述】:

简介及相关资料:

我需要有主题的通用控件,但要使用不同的文本颜色和透明背景。我遇到了this question 中详细记录的问题。

我在处理NM_CUSTOMDRAW 方面取得了一些进展,并决定先完成复选框

问题:

我在确定复选框的状态时遇到了困难,所以我无法为DrawThemeBackground()传递正确的参数。

代码胜于雄辩,所以这里是 sn-p:

case WM_NOTIFY:
    {
        if( ((LPNMHDR)lParam)->code == NM_CUSTOMDRAW )
        {
            switch( ((LPNMHDR)lParam)->idFrom ) 
            {
            case IDC_CHECK1:
                {
                    switch( ((LPNMCUSTOMDRAW)lParam)->dwDrawStage  )
                    {
                    case CDDS_PREERASE:
                        {
                            HRESULT hr = DrawThemeParentBackground(
                                ((LPNMCUSTOMDRAW)lParam)->hdr.hwndFrom
                                ((LPNMCUSTOMDRAW)lParam)->hdc,
                                &((LPNMCUSTOMDRAW)lParam)->rc );

                            if( FAILED(hr) ) // if failed draw without theme
                            {
                                SetWindowLongPtr( hDlg, DWLP_MSGRESULT
                                    (LONG_PTR)CDRF_DODEFAULT );
                                return TRUE;
                            }

                            HTHEME hTheme = OpenThemeData(
                                ((LPNMCUSTOMDRAW)lParam)->hdr.hwndFrom,
                                L"BUTTON" );

                            if( ! hTheme )  // if failed draw without theme
                            {
                                CloseThemeData(hTheme);
                                SetWindowLongPtr( hDlg, DWLP_MSGRESULT
                                    (LONG_PTR)CDRF_DODEFAULT );
                                return TRUE;
                            }

                            // draw the state-->this is the problem part

                            // I thought this might be useful           
                            LRESULT state = SendMessage(
                                ((LPNMCUSTOMDRAW)lParam)->hdr.hwndFrom,
                                BM_GETSTATE, 0, 0 );

                            int stateID;  // parameter for DrawThemeBackground

                            switch( ((LPNMCUSTOMDRAW)lParam)->uItemState )
                            {
                            case CDIS_HOT:
                                {
                                    if( IsDlgButtonChecked( hDlg, ((LPNMCUSTOMDRAW)lParam)->hdr.idFrom ) )
                                        stateID = CBS_CHECKEDHOT;
                                    else
                                        stateID = CBS_UNCHECKEDHOT;
                                    break;
                                }
                            case CDIS_DEFAULT:
                                {
                                    if( IsDlgButtonChecked( hDlg, ((LPNMCUSTOMDRAW)lParam)->hdr.idFrom ) )
                                        stateID = CBS_CHECKEDNORMAL;
                                    else
                                        stateID = CBS_UNCHECKEDNORMAL;
                                    break;
                                }
                            case CDIS_FOCUS:
                                {
                                    if( IsDlgButtonChecked( hDlg, ((LPNMCUSTOMDRAW)lParam)->hdr.idFrom ) )
                                        stateID = CBS_CHECKEDNORMAL;
                                    else
                                        stateID = CBS_UNCHECKEDNORMAL;
                                    break;
                                }
                            case CDIS_SELECTED:
                                {
                                    if( IsDlgButtonChecked( hDlg, ((LPNMCUSTOMDRAW)lParam)->hdr.idFrom ) )
                                        stateID = CBS_CHECKEDPRESSED;
                                    else
                                        stateID = CBS_UNCHECKEDPRESSED;
                                    break;
                                }
                            }

                            RECT r;
                            SIZE s;

                            // get check box dimensions so we can calculate 
                            // rectangle dimensions for text
                            GetThemePartSize( hTheme, 
                                ((LPNMCUSTOMDRAW)lParam)->hdc, 
                                BP_CHECKBOX, stateID, NULL, 
                                TS_TRUE ,&s );

                            r.left = ((LPNMCUSTOMDRAW)lParam)->rc.left;
                            r.top = ((LPNMCUSTOMDRAW)lParam)->rc.top;
                            r.right = ((LPNMCUSTOMDRAW)lParam)->rc.left + s.cx;
                            r.bottom = ((LPNMCUSTOMDRAW)lParam)->rc.top + s.cy;

                            DrawThemeBackground( hTheme, ((LPNMCUSTOMDRAW)lParam)->hdc,
                                BP_CHECKBOX, stateID, &r, NULL );

                            // adjust rectangle for text drawing
                            ((LPNMCUSTOMDRAW)lParam)->rc.left +=  2 + s.cx;

                            DrawText( ((LPNMCUSTOMDRAW)lParam)->hdc,
                                L"Example text", -1, 
                                &((LPNMCUSTOMDRAW)lParam)->rc,
                                DT_SINGLELINE | DT_VCENTER );

                            CloseThemeData(hTheme);
                            SetWindowLongPtr( hDlg, DWLP_MSGRESULT
                                (LONG_PTR)CDRF_SKIPDEFAULT );
                            return TRUE;
                        }
                    }
                }
            }
        }
    }
    break;

文字颜色和文字背景在WM_CTLCOLORSTATIC处理程序中设置:

case WM_CTLCOLORSTATIC:
    {
        SetTextColor( (HDC)wParam, RGB( 255, 0, 0 ) );
        SetBkMode( (HDC)wParam, TRANSPARENT );
    }
    return (INT_PTR)( (HBRUSH)GetStockObject(NULL_BRUSH) );

我在#pragma commentInitCommonControlsEx() 中包含了常用控件6。

问题:

我现在只需要为DrawThemeBackground 传递正确的状态。有人可以帮我解决这个问题吗?

谢谢。

最好的问候。

【问题讨论】:

    标签: c++ winapi checkbox custom-draw


    【解决方案1】:

    NM_CUSTOMDRAW 为您提供有关正在绘制的控件的状态信息。 NMCUSTOMDRAW::uItemState 字段是一个 位掩码,一次可以保存 多个 值,但您没有考虑到这一点。您需要使用& 位运算符来检查是否存在特定值。

    改变这个:

    // I thought this might be useful           
    LRESULT state = SendMessage(
        ((LPNMCUSTOMDRAW)lParam)->hdr.hwndFrom,
        BM_GETSTATE, 0, 0 );
    
    int stateID;  // parameter for DrawThemeBackground
    
    switch( ((LPNMCUSTOMDRAW)lParam)->uItemState )
    {
        case CDIS_HOT:
        {
            if( IsDlgButtonChecked( hDlg, ((LPNMCUSTOMDRAW)lParam)->hdr.idFrom ) )
                stateID = CBS_CHECKEDHOT;
            else
                stateID = CBS_UNCHECKEDHOT;
            break;
        }
        case CDIS_DEFAULT:
        {
            if( IsDlgButtonChecked( hDlg, ((LPNMCUSTOMDRAW)lParam)->hdr.idFrom ) )
                stateID = CBS_CHECKEDNORMAL;
            else
                stateID = CBS_UNCHECKEDNORMAL;
            break;
        }
        case CDIS_FOCUS:
        {
            if( IsDlgButtonChecked( hDlg, ((LPNMCUSTOMDRAW)lParam)->hdr.idFrom ) )
                stateID = CBS_CHECKEDNORMAL;
            else
                stateID = CBS_UNCHECKEDNORMAL;
            break;
        }
        case CDIS_SELECTED:
        {
            if( IsDlgButtonChecked( hDlg, ((LPNMCUSTOMDRAW)lParam)->hdr.idFrom ) )
                stateID = CBS_CHECKEDPRESSED;
            else
                stateID = CBS_UNCHECKEDPRESSED;
            break;
        }
    }
    

    改为类似这样的东西:

    int stateID;  // parameter for DrawThemeBackground
    
    UINT uiItemState = ((LPNMCUSTOMDRAW)lParam)->uItemState;
    bool bChecked = (uiItemState & CDIS_CHECKED);
    
    if (uiItemState & CDIS_HOT)
        stateID = bChecked ? CBS_CHECKEDHOT : CBS_UNCHECKEDHOT;
    
    else if (uiItemState & CDIS_SELECTED)
        stateID = bChecked ? CBS_CHECKEDPRESSED : CBS_UNCHECKEDPRESSED;
    
    else
        stateID = bChecked ? CBS_CHECKEDNORMAL : CBS_UNCHECKEDNORMAL;
    

    【讨论】:

    • 它不能完全正常工作。似乎比较bool bChecked = (uiItemState & CDIS_CHECKED); 是一个问题。我会尝试自己修复它,但希望能得到帮助。我试过bChecked = ( (uiItemState & CDIS_CHECKED) == CDIS_CHECKED );,但失败了。谢谢你的回答。赞成。最好的问候。
    • 我忘了说它会抛出warning C4800,并且我已经用bool bChecked = ( BST_CHECKED == IsDlgButtonChecked( hDlg, ((LPNMCUSTOMDRAW)lParam)->hdr.idFrom ) ); 做了一个解决方法。在重新排列 if 语句后,我能够获得一致且正确的行为。剩下的唯一事情是通过绘制焦点矩形的正确颜色来处理 checkbox 具有键盘焦点的情况。不过,这可能是一个单独的问题。谢谢你。我已正式接受您的回答(不过,我的解决方法将不胜感激)。谢谢你。最好的问候。
    猜你喜欢
    • 1970-01-01
    • 2020-05-04
    • 2019-01-21
    • 2013-05-23
    • 2020-09-01
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多