2016-12-19 5 views
2

У меня есть свой собственный CMFCListCtrl производного класса, где я реализовал функциюCMFCListCtrl сила выбранного элемент, чтобы иметь красный цвета

virtual COLORREF OnGetCellTextColor(int nRow, int nColum) 
{ 
    CMyClass* pMyClass = (CMyClass*)GetItemData(nRow); 
    if (pMyClass && pMyClass->m_bDeleted) 
     return RGB(255, 0, 0); 

    return __super::OnGetCellTextColor(nRow, nColum); 
} 

для маркировки красного удаленных записей. Это работает, только если выбран элемент.

Я пошел к функции void CMFCListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) и поставил точку останова с условием iRow==selected item на линии

lplvcd->clrText = OnGetCellTextColor(iRow, iColumn);

исполнил его, а затем я создал новый Breakpoint данных для &lplvcd->clrText.

Паспорт Breakpoint получил удар по функции

comctl32.dll!SHThemeComputeTextColors()

, как CallStack изображение показывает:

, которая явно переопределяет значение переменного.

Как я ищу SHThemeComputeTextColors в Интернете, и ничего не появляется, может ли кто-нибудь помочь мне заставить текст выбранных предметов быть красным?

ответ

1

Изменение цвета и шрифтов выделенных элементов сложнее, чем кажется, потому что выделение выбранных элементов является общесистемной проблемой. Фактически, это было то, что я задержал надолго, и только сегодня я наконец занялся ...

Существует как минимум два способа изменить внешний вид элемента управления списком: рисовать владельца (вы должны сделайте все чертеж самостоятельно) и пользовательский чертеж (система сообщит вам, когда он собирается выполнить некоторые шаги чертежа и позволяет вам изменить цвет, шрифт и т. д.). Этот ответ касается пользовательской ничьей. This article covers the basics of using Custom Draw with CListCtrl.

Как изменить цвет подсветки в CListCtrl (не CMFCListCtrl, мы скоро доберемся до этого) объясняется in this other article. Эти шаги, которые вы должны сделать:

  1. перехватывать ListView сделать процедуру непосредственно перед собирается нарисовать выделенную строку (пункт).
  2. Отключите подсветку строки.
  3. Установите цвета строк на все, что хотите.
  4. Позвольте списку просмотреть строку.
  5. Перехватить процедуру рисования списка, после того как она нарисовала строку (элемент после рисования).
  6. Включите подсветку этой строки.

Итак, когда ListView собирается нарисовать выделенную строку, вы должны telll системы строка не выделена, так что она не использует системные цвета, чтобы нарисовать его, скажите, какой цвет использовать , и снова установите элемент, как выделено, так что выбор работает как обычно.

Вот код из этой статьи:

COLORREF g_MyClrFgHi; // My foreground hilite color 
COLORREF g_MyClrBgHi; // My background hilite color 
HWND  g_hListView; // Window handle of listview control 
void EnableHighlighting(HWND hWnd, int row, bool bHighlight) 
{ 
    ListView_SetItemState(hWnd, row, bHighlight? 0xff: 0, LVIS_SELECTED); 
} 
bool IsRowSelected(HWND hWnd, int row) 
{ 
    return ListView_GetItemState(hWnd, row, LVIS_SELECTED) != 0; 
} 
bool IsRowHighlighted(HWND hWnd, int row) 
{ 
    // We check if row is selected. 
    // We also check if window has focus. This was because the original listview 
    // control I created did not have style LVS_SHOWSELALWAYS. So if the listview 
    // does not have focus, then there is no highlighting. 
    return IsRowSelected(hWnd, row) && (::GetFocus(hWnd) == hWnd); 
} 
BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{ 
    static bool bIsHighlighted = false; 
    *pResult = 0; 
    NMHDR *p = (NMHDR *)lParam; 
    switch (p->code) 
    { 
    ... 
    case NM_CUSTOMDRAW: 
    NMLVCUSTOMDRAW *lvcd = (NMLVCUSTOMDRAW *)p; 
    NMCUSTOMDRAW &nmcd = lvcd->nmcd; 
    switch (nmcd.dwDrawStage) 
    { 
    case CDDS_PREPAINT: 
     // We want item prepaint notifications, so... 
     *pResult = CDRF_NOTIFYITEMDRAW; 
     break; 
    case CDDS_ITEMPREPAINT: 
    { 
     int iRow = (int)nmcd.dwItemSpec; 
     bHighlighted = IsRowHighlighted(g_hListView, iRow); 
     if (bHighlighted) 
     { 
     lvcd->clrText = g_MyClrFgHi; // Use my foreground hilite color 
     lvcd->clrTextBk = g_MyClrBgHi; // Use my background hilite color 
     // Turn off listview highlight otherwise it uses the system colors! 
     EnableHighlighting(g_hListView, iRow, false); 
     } 
     // We want item post-paint notifications, so... 
     *pResult = CDRF_DODEFAULT | CDRF_NOTIFYPOSTPAINT; 
     break; 
    } 
    case CDDS_ITEMPOSTPAINT: 
    { 
     if (bHighlighted) 
     { 
     int iRow = (int)nmcd.dwItemSpec; 
     // Turn listview control's highlighting back on now that we have 
     // drawn the row in the colors we want. 
     EnableHighlighting(g_hListView, iRow, true); 
     } 
     *pResult = CDRF_DODEFAULT; 
     break; 
    } 
    default: 
     *pResult = CDRF_DODEFAULT; 
     break; 
    } 
    break; 
    ... 
    } 
} 

Это прекрасно работает с CListCtrl, но вы спрашиваете о CMFCListCtrl. Проблема в том, что CMFCListCtrl уже запрашивает уведомление об уведомлениях NM_CUSTOMDRAW (это когда он вызывает функцию OnGetCellTextColor, как вы видели). Если вы создаете обработчик для этого в вашем собственном классе CMFCListCtrl, эти уведомления не попадут в CMFCListCtrl, и вы потеряете эту функциональность (это может быть в порядке, в зависимости от ваших потребностей).

Вот что я сделал: я создал обработчик NM_CUSTOMDRAW в моем элементе управления списком и, если я имею дело с выделенной строкой, я меняю цвета, в противном случае я вызываю CMFCListCtrl :: OnNMCustomDraw (). Как вы увидите, я просто использую обычные цвета подсветки; это потому, что я просто хотел, чтобы увидеть выбранные элементы, даже если этот элемент управления не имеет фокуса:

void CMyListCtrl::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult) 
{ 
    bool callParent = true; 
    static bool bHighlighted = false; 
    LPNMLVCUSTOMDRAW lpLVCustomDraw = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR); 
    NMCUSTOMDRAW nmcd = lpLVCustomDraw->nmcd; 

    *pResult = CDRF_DODEFAULT; 

    switch (lpLVCustomDraw->nmcd.dwDrawStage) 
    { 
    case CDDS_PREPAINT: 
     *pResult = CDRF_NOTIFYITEMDRAW; 
     break; 
    case CDDS_ITEMPREPAINT: 
    { 
     int row = nmcd.dwItemSpec; 
     bHighlighted = IsRowHighlighted(row); 
     if (bHighlighted) 
     { 
      lpLVCustomDraw->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT); 
      lpLVCustomDraw->clrTextBk = GetSysColor(COLOR_HIGHLIGHT); 

      EnableHighlighting(row, false); 
      *pResult = CDRF_DODEFAULT | CDRF_NOTIFYPOSTPAINT; 
      callParent = false; 
     } 
    } 
    break; 
    case CDDS_ITEMPOSTPAINT: 
     if (bHighlighted) 
     { 
      int row = nmcd.dwItemSpec; 
      EnableHighlighting(row, true); 
      callParent = false; 
     } 
     *pResult = CDRF_DODEFAULT; 

     break; 
    default: 
     break; 
    } 

    if (callParent) 
    { 
     __super ::OnCustomDraw(pNMHDR, pResult); 
    } 
} 

bool CMyListCtrl::IsRowHighlighted(int row) 
{ 
    bool selected = GetItemState(row, LVIS_SELECTED) != 0; 
    return selected; 
} 

void CMyListCtrl::EnableHighlighting(int row, bool enable) 
{ 
    SetItemState(row, enable ? 0xff : 0, LVIS_SELECTED); 
} 

Я не проверял его тщательно, но это, кажется, работает.

UPDATE:

Существует небольшая проблема. Когда вы вызываете EnableHigilighting(), диалоговое окно получит уведомления LVN_ITEMCHANGED, которые могут вызвать перерисовку, что вызовет уведомление LVN_ITEMCHANGED ... Поэтому, если вы слушаете уведомления LVN_ITEMCHANGED, вам может потребоваться сделать что-то вроде этого:

void CMyListCtrl::EnableHighlighting(int row, bool enable) 
{ 
    m_internalStateChange = true; 
    SetItemState(row, enable ? 0xff : 0, LVIS_SELECTED); 
    m_internalStateChange = false; 
} 


void CWhateverDialog::OnLvnItemchangedListaEjesPane(NMHDR *pNMHDR, LRESULT *pResult) 
{ 
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); 

    if (!c_List.InternalStateChange() && /* other conditions */) 
    { 
     // Respond to state changes 
    } 
} 
+0

Почему '0xFF' на' SetIemState'? Если я просуммировать все '' LVIS_ * флаги, нижестоящие по '0xFF':' #define LVIS_FOCUSED 0x0001' '#define LVIS_SELECTED 0x0002' ' #define LVIS_CUT 0x0004' '#define LVIS_DROPHILITED 0x0008' ' #define LVIS_GLOW 0x0010' '#define LVIS_ACTIVATING 0x0020' Я получаю' 0x3F'! – sergiol

+0

Несмотря на то, что ваш подход не работает здесь, я поддержал, потому что ваш пост, похоже, содержит хорошую информацию о пользовательской ничьей CListCtrl. – sergiol

+0

@sergiol Это 0xff, чтобы убедиться, что все биты установлены в единицу, но не имеет значения, является ли это 0xff, 0x3f или просто LVIS_SELECTED, потому что вы указываете, какие биты использовать с третьим параметром. – MikMik

Смежные вопросы