Как сделать, чтобы флажок заголовка столбца listcontrol был идеально выровнен в соответствии с флажками элемента?

Я хочу создать флажок заголовка для столбца listcontrol в Windows XP. И я могу создать флажок очень успешно, но проблема здесь в том, что выравнивание флажка не соответствует флажкам в listcontrol, и еще одна проблема заключается в том, когда тема изменена, размер флажка становится больше. Вот код, который я использую в OnInitDialog().

BOOL CCheckLCDemoDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    pcHeaderCtrl->Attach (m_listCtrl.GetHeaderCtrl()->GetSafeHwnd());
    pcHeaderCtrl->SetDlgCtrlID(IDC_LISTVIEWCONTROL_HEADER);
    m_ListView_HeaderCtrlID = (*pcHeaderCtrl).GetDlgCtrlID();

    CRect rect;
    m_listCtrl.GetClientRect(rect);
    m_listCtrl.InsertColumn(0, _T(""), LVCFMT_LEFT, 80);
    m_listCtrl.InsertColumn(1, _T("Name"), LVCFMT_LEFT, 150);
    m_listCtrl.InsertColumn(2, _T("Country"), LVCFMT_LEFT, rect.Width() - 230);

    CString cs(_T(""));
    for(int i = 0; i < 5; i++)
    {
        cs.Format(_T("%d"), i+1);
        m_listCtrl.InsertItem(i, cs);
        cs.Format(_T("It's the %d item"), i+1);
        m_listCtrl.SetItemText(i, 2, cs);
    }

    m_listCtrl.SetExtendedStyle( m_listCtrl.GetExtendedStyle() | LVS_EX_CHECKBOXES);
    //Header Checkbox is being created in this method.
    Init();


    return TRUE;  // return TRUE  unless you set the focus to a control
}
BOOL CCheckLCDemoDlg::Init()
{
    if (m_blInited)
        return TRUE;

    HWND HeaderCtrl = GetDlgItem(IDC_LISTVIEWCONTROL_HEADER)->GetSafeHwnd();
    //Everything is being done in this function "CreateCheckboxImageList"
    //Function Prototype HIMAGELIST CreateCheckboxImageList(HWND hWnd,HDC hDC,int nSize,COLORREF crBackground,BOOL bUseVisualThemes)
    //nSize- refers the size of the checkbox to be created.
    HIMAGELIST hil = HDCheckboxImageList::CreateCheckboxImageList(HeaderCtrl,GetDC()->GetSafeHdc(), 16, GetSysColor(COLOR_WINDOW), TRUE);

    m_checkImgList.Attach(hil);
    pcHeaderCtrl->SetImageList(&m_checkImgList);

    HDITEM hdItem;
    hdItem.mask = HDI_IMAGE | HDI_FORMAT;
    pcHeaderCtrl->GetItem(0, &hdItem);
    hdItem.iImage = 1;
    hdItem.fmt |= HDF_IMAGE;

    pcHeaderCtrl->SetItem(0, &hdItem);

    m_blInited = TRUE;

    ::DeleteObject(hil);
    return TRUE;
}
HIMAGELIST CreateCheckboxImageList(HWND hWnd,HDC hDC,
                                   int nSize, 
                                   COLORREF crBackground,
                                   BOOL bUseVisualThemes)
{
    TRACE(_T("in CreateCheckboxImageList:  nSize=%d\n"), nSize);

    _ASSERTE(hDC);
    _ASSERTE(nSize > 0);

    HIMAGELIST hImageList = 0;


    //=========================================================================
    //
    // CHECKBOX IMAGES
    //
    // From MSDN:  "To indicate that the item has no state image, set the
    //             index to zero. This convention means that image zero in 
    //             the state image list cannot be used as a state image."
    //
    // Note that comparable 
    //                      hot image = cold image index OR 8.
    //                      disabled image = index OR 4.
    //
    //=========================================================================

    static struct CHECKBOXDRAWDATA
    {
        TCHAR * pszDesc;    // description for debugging
        int nStateId;       // for DrawThemeBackground
        UINT nState;        // for DrawFrameControl
    } 
    cbdd[] =
    {
        // cold -----------------------------------------------------------------------------------
/*0000*/_T("unused"),               0,                      0,
/*0001*/_T("unchecked normal"),     CBS_UNCHECKEDNORMAL,    DFCS_BUTTONCHECK | DFCS_FLAT,
/*0010*/_T("checked normal"),       CBS_CHECKEDNORMAL,      DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_FLAT,

#if 0
/*0011*/_T("tri-state normal"),     CBS_MIXEDNORMAL,        DFCS_BUTTON3STATE | DFCS_CHECKED | DFCS_FLAT,
/*0100*/_T("unused"),               0,                      0,
/*0101*/_T("unchecked disabled"),   CBS_UNCHECKEDDISABLED,  DFCS_BUTTONCHECK | DFCS_FLAT | DFCS_INACTIVE,
/*0110*/_T("checked disabled"),     CBS_CHECKEDDISABLED,    DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_FLAT | DFCS_INACTIVE,
/*0111*/_T("tri-state disabled"),   CBS_MIXEDDISABLED,      DFCS_BUTTON3STATE | DFCS_CHECKED | DFCS_FLAT | DFCS_INACTIVE,

        // hot ------------------------------------------------------------------------------------
/*1000*/_T("unused"),               0,                      0,
/*1001*/_T("unchecked normal"),     CBS_UNCHECKEDHOT,       DFCS_BUTTONCHECK | DFCS_FLAT,
/*1010*/_T("checked normal"),       CBS_CHECKEDHOT,         DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_FLAT,
/*1011*/_T("tri-state normal"),     CBS_MIXEDHOT,           DFCS_BUTTON3STATE | DFCS_CHECKED | DFCS_FLAT,
/*1100*/_T("unused"),               0,                      0,
/*1101*/_T("unchecked disabled"),   CBS_UNCHECKEDDISABLED,  DFCS_BUTTONCHECK | DFCS_FLAT | DFCS_INACTIVE,
/*1110*/_T("checked disabled"),     CBS_CHECKEDDISABLED,    DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_FLAT | DFCS_INACTIVE,
/*1111*/_T("tri-state disabled"),   CBS_MIXEDDISABLED,      DFCS_BUTTON3STATE | DFCS_CHECKED | DFCS_FLAT | DFCS_INACTIVE,
#endif
        NULL, 0, 0      // last entry
    };


    if (nSize > 0)
    {
        const int nBmpWidth = nSize;
        const int nBmpHeight = nSize;
        const int nImages = sizeof(cbdd)/sizeof(cbdd[0]) - 1;
        _ASSERTE(nImages == 3);

        CDC dc;
        dc.Attach(hDC);
        CBitmap bmpCheckboxes;

        // create bitmap with requested size
        if (bmpCheckboxes.CreateCompatibleBitmap(&dc, nBmpWidth * nImages, nBmpHeight))
        {
            // create imagelist for 16 images
            hImageList = ImageList_Create(nBmpWidth, nBmpHeight, ILC_COLOR32, nImages, 1);
            _ASSERTE(hImageList);

            if (hImageList)
            {
                // create dc for imagelist bitmap
                CDC dcMem;
                if (dcMem.CreateCompatibleDC(&dc))
                {
                    // create dc for one 16x16 image
                    CBitmap bmpImage;
                    bmpImage.CreateCompatibleBitmap(&dc, 16, 16);
                    //bmpImage.CreateCompatibleBitmap(&dc, 13, 13);
                    CDC dcImage;
                    dcImage.CreateCompatibleDC(&dc);
                    HBITMAP hOldImage = (HBITMAP) dcImage.SelectObject(bmpImage);
                    RECT rectImage1 = { 0,0,15,15 };


                    // open theme for checkbox
                    HTHEME hTheme = NULL;
                    hTheme = (bUseVisualThemes &&
                              IsThemeActive() && 
                              IsAppThemed()) ? 
                              OpenThemeData(NULL, L"BUTTON") : NULL;

                    // initialize imagelist bitmap
                    HBITMAP hOldBmp = (HBITMAP) dcMem.SelectObject(bmpCheckboxes);
                    dcMem.FillSolidRect(0, 0, nBmpWidth*nImages, nBmpHeight, 
                        crBackground);

                    int nImageWidth  = nBmpWidth - 2;       // allow 2 for border
                    int nImageHeight = nBmpHeight - 2;
                    int nImageLeft   = (nBmpWidth - nImageWidth) / 2;
                    int nImageTop    = (nBmpHeight - nImageHeight) / 2;

                    RECT rectImage = { nImageLeft, 
                                       nImageTop, 
                                       nImageLeft+nImageWidth, 
                                       nImageTop+nImageHeight };
                    //TRACERECT(rectImage);

                    // loop thru checkboxes
                    for (int i = 0; cbdd[i].pszDesc != NULL; i++)
                    {
                        //dcImage.FillSolidRect(0, 0, 16, 16, crBackground);
                        dcImage.FillSolidRect(0, 0, 16, 16, crBackground);

                        if (_tcscmp(cbdd[i].pszDesc, _T("unused")) == 0)
                        {
                            // unused image slot
                            // note that we skip the first image - they are 1-based
                        }
                        else
                        {
                            if (hTheme)
                            {
                                DrawThemeBackground(hTheme, dcImage, 
                                    BP_CHECKBOX, cbdd[i].nStateId, &rectImage1, 
                                    NULL);
                                DrawThemeEdge(hTheme, dcImage, 
                                    BP_CHECKBOX, cbdd[i].nStateId, &rectImage1, 0, BF_ADJUST|BF_RECT, 
                                    NULL);
                            }
                            else
                            {
                                dcImage.DrawFrameControl(&rectImage1, DFC_BUTTON, 
                                    cbdd[i].nState);
                            }

                            // size checkbox as requested
                            dcMem.StretchBlt((rectImage.left-(2)), 0, nSize, nSize, 
                                &dcImage, 0, 0, 16, 16, SRCCOPY);
                        }

                        rectImage.left  += nBmpWidth;
                        rectImage.right += nBmpWidth;
                        //TRACERECT(rectImage);
                    }

                    if (hTheme)
                    {
                        CloseThemeData(hTheme);
                        hTheme = NULL;
                    }

                    dcImage.SelectObject(hOldImage);
                    dcMem.SelectObject(hOldBmp);
                    BOOL bDelDcRet = dcMem.DeleteDC();
                    BOOL bDelImageDcRet = dcImage.DeleteDC();

                    // add imagelist bitmap (16 checkboxes) to imagelist
                    ImageList_Add(hImageList, bmpCheckboxes, 0);

                }
                else
                {
                    TRACE(_T("ERROR - failed to create DC\n"));
                }
            }
            else
            {
                TRACE(_T("ERROR - failed to create image list\n"));
            }
        }
        else
        {
            TRACE(_T("ERROR - failed to create bitmap\n"));
        }
    }
    else
    {
        TRACE(_T("ERROR - bad parameters\n"));
    }

    return hImageList;
}

}

И когда я запускаю приложение, флажок заголовка listcontrol выглядит следующим образом,

Для следа и ошибки я передал nSize как 16, Какой размер должен быть передан, который должен быть динамическим, а не статическим?

Когда тема изменилась на Windows Classic, это выглядит следующим образом.

Может кто-нибудь, пожалуйста, помогите мне, какой размер будет передаваться в качестве параметра для создания флажка, который должен точно соответствовать флажку элемента и то же самое, когда тема меняется.

1 ответ

Невозможно сделать то, что вы хотите, потому что выравнивание флажков не является стандартным размером. Вы имитируете флажок в элементе управления заголовком, рисуя непосредственно на нем, поэтому лучше всего проверить с различными темами, которые вы хотите поддерживать, а затем отрегулировать смещение в методе CreateCheckboxImageList(), чтобы оно соответствовало смещению, при котором флажки в список управления нарисован.

Другие вопросы по тегам