如何更改 CTabCtrl 选项卡颜色?

Posted

技术标签:

【中文标题】如何更改 CTabCtrl 选项卡颜色?【英文标题】:How to change CTabCtrl tab colors? 【发布时间】:2018-01-02 15:42:57 【问题描述】:

你好,新年快乐,(可以说到星期四)

我正在尝试更改 CTabCtrl 类中选项卡的颜色。我正在尝试创建自己的 ReskinCTablCtrl,以便我可以在单独的类中调用它并在整个程序中轻松使用它。

目前我可以更改 CTabCtrl 的背景颜色,但我无法修改选项卡本身。

我使用ON_WM_ERASEBKGND() 绘制背景,它没有问题:

BOOL ReskinCTabCtrl::OnEraseBkgnd(CDC* pDC)

    CRect rect;
    GetClientRect(&rect);
    CBrush myBrush(RGB(51, 51, 51));    // dialog background color
    BOOL bRes = pDC->PatBlt(0, 0, rect.Width(), rect.Height(), PATCOPY);
    pDC->SetBkColor(RGB(51, 51, 51));
    pDC->FillRect(&rect, &myBrush);
    return bRes;

但是,我在更改标签颜色方面没有成功。它们仍然是默认的 MFC 颜色。我试图实现ON_WM_PAINT()ON_WM_DRAWITEM() 没有任何成功。我想我可以使用 OnDraw 和 DrawItem 来访问特定的选项卡矩形,类似于我在这个问题末尾发布的第二个链接示例。

void ReskinCTabCtrl::OnPaint() 

    ...

    // paint the tabs first and then the borders
    int nTab = GetItemCount();
    int nSel = GetCurSel();

    if (!nTab) // no pages added
        return;

    while (nTab--)
    
        if (nTab != nSel)
        
            dis.itemID = nTab;
            dis.itemState = 0;

            VERIFY(GetItemRect(nTab, &dis.rcItem));

            dis.rcItem.bottom -= 2;
            DrawItem(&dis);
            DrawItemBorder(&dis);
        
    

    ...


我真的很感激至少有一些解决这个问题的方向,也许还有更多的例子或者我应该专注于使用哪些方法。我不需要标签是不同的颜色,也许有一种简单的方法可以做到这一点?

我一直在尝试遵循以下链接之类的示例,但我仍然无法找到正确的方法。

https://support.microsoft.com/en-us/help/179909/how-to-change-the-background-color-of-a-tab-control

https://www.codeproject.com/Articles/1786/Ownerdraw-Tab-Controls-Borders-and-All

【问题讨论】:

你为什么不用CMFCTabCtrl 来代替呢? CTabCtrl 已经过时了,使用CMFCTabCtrl 在切换选项卡时您不需要处理隐藏/显示和启用/禁用控制逻辑。顺便说一句,我在 CMFCTabCtrl 上尝试了 m_tabControl.SetTabBkColor(0, RGB(255, 0, 0)); 并得到了结果 i.imgur.com/2VT3yTA.png ,这意味着它只在周围绘制框架。在我看来,你最好的选择是处理内部形式的ON_WM_CTLCOLOR()***.com/a/31348831/383779。 我会尝试切换到那个,谢谢,只是尽量保持一切简单,因为这是一个大项目的开始。 切换前可以尝试处理ON_WM_CTLCOLOR。可能您必须将消息从容器窗口重新路由到内部表单。 【参考方案1】:

在资源编辑器中为选项卡控件启用 OwnerDraw,或在 OnInitDialog 中设置 TCS_OWNERDRAWFIXED

CTabCtrlWM_DRAWITEM 的消息反射,因此我们不想从父类覆盖WM_DRAWITEM/OnDrawItem。而是覆盖CTabCtrl::DrawItem(LPDRAWITEMSTRUCT)

不幸的是,结果相当丑陋。这有点像在按钮中覆盖DrawItem

如果视觉样式可用且已启用,则您可以覆盖CTabCtrl::OnPaint 并手动绘制所有内容。示例:

void CMyTabCtrl::OnPaint()

    CPaintDC dc(this);

    dc.SelectObject(GetFont());

    CPen pen, pen_active;
    COLORREF color_off = RGB(240, 240, 240);
    COLORREF color_active = RGB(200, 240, 240);
    CBrush brush_off, brush_active;
    brush_off.CreateSolidBrush(color_off);
    brush_active.CreateSolidBrush(color_active);
    pen.CreatePen(PS_SOLID, 1, RGB(200, 200, 200));
    pen_active.CreatePen(PS_SOLID, 1, color_active);

    CRect rcitem;
    GetItemRect(0, &rcitem);

    CRect rc;
    GetClientRect(&rc);
    rc.bottom = rcitem.bottom;
    dc.FillSolidRect(&rc, GetSysColor(COLOR_3DFACE));

    GetClientRect(&rc);
    rc.top = rcitem.bottom - 1;
    dc.SelectObject(&pen);
    dc.SelectObject(&brush_active);
    dc.Rectangle(&rc);

    for(int i = 0; i < GetItemCount(); i++)
    
        dc.SelectObject(&pen);
        if(i == GetCurSel())
        
            dc.SelectObject(&brush_active);
            dc.SetBkColor(color_active);
        
        else
        
            dc.SelectObject(&brush_off);
            dc.SetBkColor(color_off);
        

        GetItemRect(i, &rcitem);
        rcitem.right++;
        dc.Rectangle(&rcitem);

        if(i == GetCurSel())
        
            dc.SelectObject(pen_active);
            dc.MoveTo(rcitem.left+1, rcitem.bottom - 1);
            dc.LineTo(rcitem.right, rcitem.bottom - 1);
        

        TCITEM item =  0 ;
        wchar_t buf[32];
        item.pszText = buf;
        item.cchTextMax = 32;
        item.mask = TCIF_TEXT;
        GetItem(i, &item);
        dc.DrawText(buf, &rcitem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    


BOOL CMyTabCtrl::OnEraseBkgnd(CDC*)

    return TRUE;

【讨论】:

我能达到你在图片中显示的结果,我会努力进一步改进它。我试图让所有标签始终保持相同的颜色!但是,它将背景颜色更改为默认颜色,所以我也会尝试自己修复它。 可以进行的一项改进是检查标志(TCS_BOTTOM == (GetStyle() &amp; TCS_BOTTOM)),然后需要将选项卡倒置而不是正面朝上。

以上是关于如何更改 CTabCtrl 选项卡颜色?的主要内容,如果未能解决你的问题,请参考以下文章

在 CTabCtrl 中,我可以在运行时更改选项卡的图标吗

使 MFC CTabCtrl 不使用绘图选项卡的完整控件宽度

MFC CTabCtrl如何为选项卡添加关闭按钮

我正在扩展 CTabCtrl 但无法插入任何选项卡

C++ MFC 为 CTabCtrl 中的每个选项卡附加不同的对话框

在 MFC 中将选项卡添加到 CTabCtrl