2016-12-19 36 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);

執行它,然後我創建了一個新的數據斷點&lplvcd->clrText

的數據斷點被擊中上功能

comctl32.dll!SHThemeComputeTextColors()

,作爲調用堆棧的圖像所示:

,這顯然是重寫變量的值。

當我在互聯網上搜索SHThemeComputeTextColors,什麼也沒有出現,有人可以幫我強制選定的項目文本是紅色的?

回答

1

更改突出顯示的項目的顏色和字體比看起來更復雜,因爲突出顯示所選項目是系統範圍的問題。事實上,這是我延遲了很長一段時間,直到今天我終於解決了......

有至少兩種方法來改變列表控件的外觀:所有者繪製(你必須自己做繪圖)和自定義繪製(系統會告訴您何時它將執行繪圖的一些步驟,並允許您更改顏色,字體等)。這個答案是關於自定義繪製。 This article covers the basics of using Custom Draw with CListCtrl.

如何更改CListCtrl中的高亮顏色(不是CMFCListCtrl,我們很快會達到)解釋爲in this other article。這是你必須做的步驟:

  1. 攔截列表視圖畫例行之前它是要繪製一個突出顯示的行(項目)。
  2. 關閉高亮顯示的行。
  3. 將行顏色設置爲任何你想要的。
  4. 讓列表視圖繪製行。
  5. 截取列表視圖繪製例程後,它已繪製行(後繪製項目)。
  6. 打開這一行的高亮顯示。

所以,當列表視圖將要繪製一個突出顯示的行,你必須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

爲什麼SetIemState上的0xFF?如果我總結所有'LVIS_ *'標誌遜色於'0xFF':'#定義LVIS_FOCUSED 0x0001' '#定義LVIS_SELECTED 0x0002' '#定義LVIS_CUT 0x0004' '#定義LVIS_DROPHILITED 0x0008' '#定義LVIS_GLOW 0x0010' '#define LVIS_ACTIVATING 0x0020' 我得到'0x3F'! – sergiol

+0

雖然你的方法在這裏不起作用,但我贊成,因爲你的文章似乎在'CListCtrl'自定義繪製上帶有很好的信息。 – sergiol

+0

@sergiol這是0xff,以確保所有的位都設置爲1,但不管它是0xff,0x3f還是隻是LVIS_SELECTED,因爲你告訴第三個參數要使用哪些位。 – MikMik