MF C - строки CListCtrl с дополнительными флажками - PullRequest
0 голосов
/ 04 апреля 2020

Во время выполнения я пытаюсь создать для одного столбца пользовательский CListCtrl (или CMFCListCtrl, но не CheckListBox - я хочу иметь возможность добавлять несколько столбцов в будущем), используя MF C , Использование стиля LVS_EX_CHECKBOXES заставляет все элементы иметь флажок. Нужный элемент управления должен выглядеть следующим образом (у item1 и item3 есть флажки, у item2 нет):

enter image description here

С точки зрения пользователя, желаемый элемент управления списком должен быть создан следующим образом:

int main() {
    MyCListCtrl list_control;
    list_control.AddItem("item1", true) // true indicates checkbox presence
    list_control.AddItem("item2", false) // false - item without checkbox
    list_control.AddItem("item3", true) // true indicates checkbox presence
}

До сих пор мне удавалось создать такой элемент управления, но добавление LVS_OWNERDRAWFIXED вызывает неудачное утверждение при вызове метода базового класса CListCtrl::DrawItem:

enter image description here

    // MyCListCtrl.h
    class MyCListCtrl : public CListCtrl {
    public:
        virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) override {
            // if the item should be without a checkbox, here I want to move it a few pixels
            // to the left so that the checkbox is hidden
            ...
            CListCtrl::DrawItem(lpDrawItemStruct); // call base's DrawItem - without this
                                  // there's no exception but the listbox appears empty
        }
    };

    BOOL MyCDialogEx::OnInitDialog() {
        CDialogEx::OnInitDialog();
        ...
        // list being defined somewhere in the header file
        list->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT | LVS_NOCOLUMNHEADER |
                                            LVS_OWNERDRAWFIXED, // for DrawItem invocation
                                            rect, this, SOME_ID);
        list->SetExtendedStyle(list->GetExtendedStyle() | LVS_EX_CHECKBOXES);

        // add 1 mandatory column because of LVS_REPORT style
        LVCOLUMN lvColumn;
        lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
        lvColumn.fmt = LVCFMT_LEFT;
        lvColumn.cx = rect.Width() - 20; // also, how to make this column fit the width exactly?
        lvColumn.pszText = nullptr;
        list->InsertColumn(0, &lvColumn);

        // for now only add 1 testing item and make his checkbox disappear by moving the
        // whole item to the left in DrawItem method (called by the system), so that the text
        // is aligned to the left list border
        list->InsertItem(0, "item1");
        ...
    }

Так выглядит мое (не работающее) решение, если вы знаете, как решить эту проблему, может быть, даже более простым способом, пожалуйста дай мне знать. Спасибо.

РЕДАКТИРОВАТЬ

С помощью @Landstalker, я теперь могу стереть флажок с пользовательским рисунком, но мне все еще нужно переместить текст слева (поэтому он заменяет несуществующий флажок, как на картинке выше). Текущее решение приводит к этому результату:

enter image description here

Это достигается путем обработки сообщения NM_CUSTOMDRAW, например:

    void MyCListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
    {
        *pResult = CDRF_DODEFAULT; // default windows painting
        LPNMLVCUSTOMDRAW lpn = (LPNMLVCUSTOMDRAW)pNMHDR;

        if (CDDS_PREPAINT == lpn->nmcd.dwDrawStage)
        {
            *pResult = CDRF_NOTIFYITEMDRAW; // notify on every item
        }
        else if (CDDS_ITEMPREPAINT == lpn->nmcd.dwDrawStage)
        {
            int row = lpn->nmcd.dwItemSpec;
            if (row == 1) {
                lpn->nmcd.rc.left -= 16; // not working
                lpn->rcText.left -= 16; // not working

                SetItemState(row, INDEXTOSTATEIMAGEMASK(0), 
                                  LVIS_STATEIMAGEMASK); // erase checkbox
            }
        }
    }

1 Ответ

2 голосов
/ 04 апреля 2020

После долгих исследований ... Я нашел для вас решение: используйте SetItemState () волхвы c Функция:

enter image description here

Замечание : наличие нескольких столбцов не является проблемой

MyCListCtrl.h

class MyCListCtrl : public CListCtrl 
{
    DECLARE_DYNAMIC(MyCListCtrl)

public:
    afx_msg void DrawItem(NMHDR* pNMHDR, LRESULT* pResult);
    DECLARE_MESSAGE_MAP()
};  

MyCListCtrl. cpp

IMPLEMENT_DYNAMIC(MyCListCtrl, CListCtrl)

BEGIN_MESSAGE_MAP(MyCListCtrl, CListCtrl)
    ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, DrawItem)
END_MESSAGE_MAP()

void MyCListCtrl::DrawItem(NMHDR* pNMHDR, LRESULT* pResult)
{
    *pResult = 0;
    LPNMLVCUSTOMDRAW  pLPN = (LPNMLVCUSTOMDRAW)pNMHDR;
    int iRow = pLPN->nmcd.dwItemSpec;

    // Get item flag : true or false (true we show checkbox, false we hide it)
    // Here i simulate, i disable rows 1 and 3
    SetItemState(1, INDEXTOSTATEIMAGEMASK(0), LVIS_STATEIMAGEMASK);
    SetItemState(3, INDEXTOSTATEIMAGEMASK(0), LVIS_STATEIMAGEMASK);

    switch(pLPN->nmcd.dwDrawStage)
    {
    case CDDS_PREPAINT | CDDS_ITEM | CDDS_SUBITEM :
        {
            *pResult = CDRF_DODEFAULT | CDRF_DOERASE; return;
        }
    case CDDS_PREPAINT :
        {
            *pResult = CDRF_NOTIFYITEMDRAW; return;
        }
    case CDDS_ITEMPREPAINT:
        {
            pLPN->clrText = RGB(0,0,0);
            *pResult = CDRF_NOTIFYSUBITEMDRAW;  return;
        }
    }
}  

MainDlg. cpp

CRect rect (30, 30, 180, 180);
list_control.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_NOCOLUMNHEADER |LBS_OWNERDRAWVARIABLE , rect, this, IDC_LIST2);
list_control.SetExtendedStyle(list_control.GetExtendedStyle() | LVS_EX_FLATSB | LVS_EX_CHECKBOXES | LVS_EX_GRIDLINES);

LVCOLUMN lvColumn;
lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
lvColumn.fmt = LVCFMT_LEFT;
lvColumn.cx = 70; 
lvColumn.pszText = "Column 1";
list_control.InsertColumn(0, &lvColumn);  

lvColumn.pszText = "Column 2";
list_control.InsertColumn(1, &lvColumn);

//// add 1 test item
LVITEM lvItem;
lvItem.mask = LVIF_TEXT;
lvItem.iItem = 0;
lvItem.iSubItem = 0;
lvItem.pszText = "Test";
list_control.InsertItem(&lvItem);

lvItem.pszText = "Stack";
list_control.InsertItem(&lvItem);

lvItem.pszText = "Over";
list_control.InsertItem(&lvItem);

lvItem.pszText = "Flow";
list_control.InsertItem(&lvItem);
...