改变 CListCtrl、CHeaderCtrl 高度、字体、颜色和背景

改变 CListCtrl、CHeaderCtrl 高度、字体、颜色和背景

 

用CListCtrl来显示数据比较方便,有时候我们需要标注某一列或某一个单元格的背景和字体颜色,或者需要改变一下行高和字体大小,CListCtrl要改变这些并不是很方便。本文将介绍如何派生一个类来改变CListCtrl及其表头的高度、字体大小、列背景颜色、单元格背景颜色、列字体颜色、单元格字体颜色

 

实现过程:

1.表头修改
  新建一个MFC类CHeaderCtrlCl,其基类为CHeaderCtrl,响应OnPaint消息实现自绘,在头文件中定义函数LRESULT OnLayout( WPARAM wParam, LPARAM lParam ),之后手动添加消息响应ON_MESSAGE(HDM_LAYOUT, OnLayout),在消息响应中改变高度。

 

HeaderCtrlCl.h文件的代码如下:

class CHeaderCtrlCl : public CHeaderCtrl
{
    DECLARE_DYNAMIC(CHeaderCtrlCl)

public:

    CHeaderCtrlCl();
    virtual ~CHeaderCtrlCl();

    afx_msg void OnPaint();
    CStringArray m_HChar;
    CString m_Format; //表示对齐类型的整型数组,0表示左对齐,1表示中间对齐,2表示右对齐

protected:
    LRESULT OnLayout( WPARAM wParam, LPARAM lParam );
    DECLARE_MESSAGE_MAP()

public:
    int m_R;
    int m_G;
    int m_B;
    int m_Gradient;    // 画立体背景,渐变系数
    float m_Height;  //表头高度,这是倍数,
    int m_fontHeight; //字体高度
    int m_fontWith;   //字体宽度

    COLORREF m_color;
    
};
 

 

cpp 

IMPLEMENT_DYNAMIC(CHeaderCtrlCl, CHeaderCtrl)

CHeaderCtrlCl::CHeaderCtrlCl() : m_R(171)
    , m_G(199), m_B(235), m_Gradient(8)
{
    m_Format = "";
    m_Height = 1;
    m_fontHeight = 15;
    m_fontWith = 0;
    m_color = RGB(0,0,0);
}

CHeaderCtrlCl::~CHeaderCtrlCl()
{
}

BEGIN_MESSAGE_MAP(CHeaderCtrlCl, CHeaderCtrl)
    ON_WM_PAINT()
    ON_MESSAGE(HDM_LAYOUT, OnLayout)
END_MESSAGE_MAP()

// CHeaderCtrlCl 消息处理程序
void CHeaderCtrlCl::OnPaint()
{
    CPaintDC dc(this); // device context for painting
    // 不为绘图消息调用 CHeaderCtrl::OnPaint()
    int nItem; 
    nItem = GetItemCount();//得到有几个单元 
    for(int i = 0; i     { 
        CRect tRect;
        GetItemRect(i,&tRect);//得到Item的尺寸
        int R = m_R,G = m_G,B = m_B;
        CRect nRect(tRect);//拷贝尺寸到新的容器中 
        nRect.left++;//留出分割线的地方 
        //绘制立体背景 
        for(int j = tRect.top;j<=tRect.bottom;j++) 
        { 
            nRect.bottom = nRect.top+1; 
            CBrush _brush; 
            _brush.CreateSolidBrush(RGB(R, G, B));//创建画刷 
            dc.FillRect(&nRect,&_brush); //填充背景 
            _brush.DeleteObject(); //释放画刷 
            R-=m_Gradient;G-=m_Gradient;B-=m_Gradient;
            if (R<0)R = 0;
            if (G<0)G = 0;
            if (B<0)B= 0;
            nRect.top = nRect.bottom; 
        } 
        dc.SetBkMode(TRANSPARENT);
        CFont nFont ,* nOldFont; 
        //dc.SetTextColor(RGB(250,50,50)); 
        dc.SetTextColor(m_color);
        nFont.CreateFont(m_fontHeight,m_fontWith,0,0,0,FALSE,FALSE,0,0,0,0,0,0,_TEXT("宋体"));//创建字体 
        nOldFont = dc.SelectObject(&nFont);
        UINT nFormat = 1;
        if (m_Format[i]=='0')
        {
            nFormat = DT_LEFT;
            tRect.left+=3;
        }
        else if (m_Format[i]=='1')
        {
            nFormat = DT_CENTER;
        }
        else if (m_Format[i]=='2')
        {
            nFormat = DT_RIGHT;
            tRect.right-=3;
        }
        //将文字显示在一个适合的高度位置
        TEXTMETRIC metric;
        dc.GetTextMetrics(&metric);
        int ofst = 0;
        ofst = tRect.Height() - metric.tmHeight;
        tRect.OffsetRect(0,ofst/2);
        dc.DrawText(m_HChar[i],&tRect,nFormat);
        dc.SelectObject(nOldFont); 
        nFont.DeleteObject(); //释放字体 
    } 
    //画头部剩余部分(没有标题的那部分)
    CRect rtRect;
    CRect clientRect;
    GetItemRect(nItem - 1,rtRect);
    GetClientRect(clientRect); //当前(CHeaderCtrl)控件的大小
    rtRect.left = rtRect.right+1;
    rtRect.right = clientRect.right;
    int R = m_R,G = m_G,B = m_B;
    CRect nRect(rtRect);
    //绘制立体背景 
    for(int j = rtRect.top;j<=rtRect.bottom;j++) 
    { 
        nRect.bottom = nRect.top+1; 
        CBrush _brush; 
        _brush.CreateSolidBrush(RGB(R,G,B));//创建画刷 
        dc.FillRect(&nRect,&_brush); //填充背景 
        _brush.DeleteObject(); //释放画刷 
        R-=m_Gradient;G-=m_Gradient;B-=m_Gradient;
        if (R<0)R = 0;
        if (G<0)G = 0;
        if (B<0)B= 0;
        nRect.top = nRect.bottom; 
    } 
}

LRESULT CHeaderCtrlCl::OnLayout( WPARAM wParam, LPARAM lParam )
{
    LRESULT lResult = CHeaderCtrl::DefWindowProc(HDM_LAYOUT, 0, lParam); 
    HD_LAYOUT &hdl = *( HD_LAYOUT * ) lParam; 
    RECT *prc = hdl.prc; 
    WINDOWPOS *pwpos = hdl.pwpos; 
    //表头高度为原来1.5倍,如果要动态修改表头高度的话,将1.5设成一个全局变量 
    int nHeight = (int)(pwpos->cy * m_Height);
    pwpos->cy = nHeight; 
    prc->top = nHeight; 
    return lResult; 
}

2. 表的修改
  新建一个MFC类CListCtrlCl,其基类为CListCtrl,定义一个CHeaderCtrlCl的成员变量m_Header,重载PreSubclassWindow(),在函数中修改控件类型为自绘模式,然后子类化表头。

        这里在设置表头的行高时发送了一个WM_WINDOWPOSCHANGED消息。当我们给 listctrl 发送 M_WINDOWPOSCHANGED消息时,也就是告诉 listdctrl 控件大小、位置等发生变化,这时候 listctrl 控件就会触发 ON_WM_MEASUREITEM_REFLECT消息,当然这个是反射消息。通过映射这个消息,我们就可以改变 listctrl 控件的行高。 

         代码中需要手动映射 ON_WM_MEASUREITEM_REFLECT 消息,该消息的响应函数是

void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)

ListCtrlCl.h文件的代码:

class CListCtrlCl : public CListCtrl
{
    DECLARE_DYNAMIC(CListCtrlCl)

public:

    CListCtrlCl();
    virtual ~CListCtrlCl();


    // 设置表头高度
    void SetHeaderHeight(float Height);
    // Gradient - 渐变系数,立体背景用,不用渐变设为0
    void SetHeaderBKColor(int R, int G, int B, int Gradient);
    int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1);
    void SetHeaderFontHW(int nHeight,int nWith); //设置表头字体大小
    void SetHeaderTextColor(COLORREF color);
    void SetRowHeight(int nHeight); //设置行高
    bool FindColColor(int col ,COLORREF &color); //查找列颜色
    bool FindItemColor(int col,int row,COLORREF &color);
    bool FindColTextColor(int col,COLORREF &color); //查找列字体颜色
    bool FindItemTextColor(int col,int row,COLORREF &color);
    void SetColColor(int col,COLORREF color);  //设置列颜色
    void SetItemColor(int col,int row,COLORREF color); //设置Item颜色
    void SetColTextColor(int col,COLORREF color);   //设置列文本颜色
    void SetItemTextColor(int col,int row,COLORREF color);
    void SetTextColor(COLORREF cr);
    void SetFontHW(int nHeight,int nWith);  //设置字体的高和宽

protected:
    virtual void PreSubclassWindow();
    virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
    DECLARE_MESSAGE_MAP()    

protected:
    CHeaderCtrlCl m_Header; //表头
    int m_nRowHeight;// 行高
    CPtrList m_ptrListCol;  //保存列颜色
    CPtrList m_ptrListItem; //保存Item颜色表
    CPtrList m_colTextColor; //保存列字体颜色
    CPtrList m_ItemTextColor; //保存单元格字体颜色
    COLORREF m_color;
    int m_fontHeight;    // 字体高度
    int m_fontWith;     // 字体宽度
};
 

//ListCtrlCl.cpp文件的代码

 

#include "stdafx.h"
#include "RT.h"
#include "ListCtrlCL.h"


// CMyListCtrl

struct stColor
{
    int nRow;
    int nCol;
    COLORREF rgb;
};

// CListCtrlCl
IMPLEMENT_DYNAMIC(CListCtrlCl, CListCtrl)

CListCtrlCl::CListCtrlCl() : m_nRowHeight(0), m_fontHeight(12), m_fontWith(0)
{
    m_color = RGB(0,0,0);
}


CListCtrlCl::~CListCtrlCl()
{
    stColor *ptemp = NULL;

    while (m_ptrListCol.GetCount() > 0)
    {    
        ptemp = (stColor *)(m_ptrListCol.RemoveHead());
        if ( NULL != ptemp )
        {
            delete ptemp;
            ptemp = NULL;
        }
    }

    while ( m_ptrListItem.GetCount() > 0)
    {
        ptemp = (stColor *)(m_ptrListItem.RemoveHead());
        if ( NULL != ptemp )
        {
            delete ptemp;
            ptemp = NULL;
        }
    }


    while ( m_colTextColor.GetCount() > 0)
    {
        ptemp = (stColor *)(m_colTextColor.RemoveHead());
        if ( NULL != ptemp )
        {
            delete ptemp;
            ptemp = NULL;
        }
    }

    while ( m_ItemTextColor.GetCount() > 0)
    {
        ptemp = (stColor *)(m_ItemTextColor.RemoveHead());
        if ( NULL != ptemp )
        {
            delete ptemp;
            ptemp = NULL;
        }
    }
}

BEGIN_MESSAGE_MAP(CListCtrlCl, CListCtrl)
    ON_WM_MEASUREITEM_REFLECT()
END_MESSAGE_MAP()

// CListCtrlCl 消息处理程序

void CListCtrlCl::PreSubclassWindow()
{
    ModifyStyle(0,LVS_OWNERDRAWFIXED);
    CListCtrl::PreSubclassWindow();
    CHeaderCtrl *pHeader = GetHeaderCtrl();
    m_Header.SubclassWindow(pHeader->GetSafeHwnd());

}

void CListCtrlCl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    TCHAR lpBuffer[256];
    LV_ITEM lvi;
    lvi.mask = LVIF_TEXT | LVIF_PARAM;
    lvi.iItem = lpDrawItemStruct->itemID; 
    lvi.iSubItem = 0;
    lvi.pszText = lpBuffer;
    lvi.cchTextMax = sizeof(lpBuffer);
    VERIFY(GetItem(&lvi));
    LV_COLUMN lvc, lvcprev;
    ::ZeroMemory(&lvc, sizeof(lvc));
    ::ZeroMemory(&lvcprev, sizeof(lvcprev));
    lvc.mask = LVCF_WIDTH | LVCF_FMT;
    lvcprev.mask = LVCF_WIDTH | LVCF_FMT;
    CDC* pDC;
    pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    CRect rtClient;
    GetClientRect(&rtClient);
    for ( int nCol=0; GetColumn(nCol, &lvc); nCol++)
    {
        if ( nCol > 0 ) 
        {
            // Get Previous Column Width in order to move the next display item
            GetColumn(nCol-1, &lvcprev);
            lpDrawItemStruct->rcItem.left += lvcprev.cx;
            lpDrawItemStruct->rcItem.right += lpDrawItemStruct->rcItem.left; 
        }

        CRect rcItem;   
        if (!GetSubItemRect(lpDrawItemStruct->itemID,nCol,LVIR_LABEL,rcItem))   
            continue;   

        ::ZeroMemory(&lvi, sizeof(lvi));
        lvi.iItem = lpDrawItemStruct->itemID;
        lvi.mask = LVIF_TEXT | LVIF_PARAM;
        lvi.iSubItem = nCol;
        lvi.pszText = lpBuffer;
        lvi.cchTextMax = sizeof(lpBuffer);
        VERIFY(GetItem(&lvi));

        CRect rcTemp;
        rcTemp = rcItem;
        if (nCol==0)
        {
            rcTemp.left -=2;
        }

        if (lpDrawItemStruct->itemState & ODS_SELECTED)
        {
            pDC->FillSolidRect(&rcTemp, GetSysColor(COLOR_HIGHLIGHT));
            pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
        }
        else
        {
            COLORREF color;
            color = GetBkColor();
            pDC->FillSolidRect(rcTemp,color);
            if (FindColColor(nCol,color))
            {
                pDC->FillSolidRect(rcTemp,color);
            }

            if (FindItemColor(nCol,lpDrawItemStruct->itemID,color))
            {
                pDC->FillSolidRect(rcTemp,color);
            }

            //pDC->SetTextColor(m_color);
        }

        pDC->SelectObject(GetStockObject(DEFAULT_GUI_FONT));

        UINT   uFormat    = DT_CENTER;
        if (m_Header.m_Format[nCol]=='0')
        {
            uFormat = DT_LEFT;
        }
        else if (m_Header.m_Format[nCol]=='1')
        {
            uFormat = DT_CENTER;
        }
        else if (m_Header.m_Format[nCol]=='2')
        {
            uFormat = DT_RIGHT;
        }

        TEXTMETRIC metric;
        pDC->GetTextMetrics(&metric);

        int ofst = rcItem.Height() - metric.tmHeight;
        rcItem.OffsetRect(0,ofst/2);
        pDC->SetTextColor(m_color);

        COLORREF color;
        if (FindColTextColor(nCol,color))
        {
            pDC->SetTextColor(color);
        }

        if (FindItemTextColor(nCol,lpDrawItemStruct->itemID,color))
        {
            pDC->SetTextColor(color);
        }

        CFont nFont ,* nOldFont; 
        nFont.CreateFont(m_fontHeight,m_fontWith,0,0,0,FALSE,FALSE,0,0,0,0,0,0,_TEXT("宋体"));//创建字体 
        nOldFont = pDC->SelectObject(&nFont);

        DrawText(lpDrawItemStruct->hDC, lpBuffer, strlen(lpBuffer), &rcItem, uFormat);

        pDC->SelectStockObject(SYSTEM_FONT);
    }
}

void CListCtrlCl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
    if (m_nRowHeight>0)
    {
        lpMeasureItemStruct->itemHeight = m_nRowHeight;
    }
}

int CListCtrlCl::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat /* = LVCFMT_LEFT */, int nWidth /* = -1 */, int nSubItem /* = -1 */)
{
    m_Header.m_HChar.Add(lpszColumnHeading);
    if (nFormat==LVCFMT_LEFT)
    {
        m_Header.m_Format = m_Header.m_Format + "0";
    }
    else if (nFormat==LVCFMT_CENTER)
    {
        m_Header.m_Format = m_Header.m_Format + "1";
    }
    else if (nFormat==LVCFMT_RIGHT)
    {
        m_Header.m_Format = m_Header.m_Format + "2";
    }
    else
    {
        m_Header.m_Format = m_Header.m_Format + "1";
    }

    return CListCtrl::InsertColumn(nCol,lpszColumnHeading,nFormat,nWidth,nSubItem);
}

// Gradient - 渐变系数,立体背景用,不用渐变设为0
void CListCtrlCl::SetHeaderBKColor(int R, int G, int B, int Gradient) //设置表头背景色
{

    m_Header.m_R = R;
    m_Header.m_G = G;
    m_Header.m_B = B;
    m_Header.m_Gradient = Gradient;
}

// 设置表头高度
void CListCtrlCl::SetHeaderHeight(float Height) //设置表头高度
{
    m_Header.m_Height = Height;
}

bool CListCtrlCl::FindColColor(int col,COLORREF &color) //查找列颜色
{

    int flag = 0;
    for (POSITION pos = m_ptrListCol.GetHeadPosition(); pos!=NULL; )
    {
        stColor *pColor = (stColor*)m_ptrListCol.GetNext(pos);
        if (pColor->nCol==col)
        {
            flag = 1;
            color = pColor->rgb;
            break;
        }
    }

    if (1==flag)
    {
        return true;
    }

    return false;
}

bool CListCtrlCl::FindItemColor(int col,int row,COLORREF &color) //查找颜色
{

    int flag = 0;
    for (POSITION pos = m_ptrListItem.GetHeadPosition(); pos!=NULL; )
    {
        stColor *pColor = (stColor*)m_ptrListItem.GetNext(pos);
        if (pColor->nCol==col&&pColor->nRow==row)
        {
            flag = 1;
            color = pColor->rgb;
            break;
        }
    }

    if (1==flag)
    {
        return true;
    }

    return false;
}

void CListCtrlCl::SetColColor(int col,COLORREF color) //设置列颜色
{
    stColor *pColor  = new stColor;
    pColor->nCol = col;
    pColor->rgb = color;

    m_ptrListCol.AddTail(pColor);
}

void CListCtrlCl::SetItemColor(int col,int row,COLORREF color) //设置格子颜色
{
    stColor *pColor  = new stColor;
    pColor->nCol = col;
    pColor->nRow = row;
    pColor->rgb = color;
    m_ptrListItem.AddTail(pColor);
}

void CListCtrlCl::SetRowHeight(int nHeight) // 设置行高
{
    m_nRowHeight = nHeight;
    CRect rcWin;
    GetWindowRect(&rcWin);
    WINDOWPOS wp;
    wp.hwnd = m_hWnd;
    wp.cx = rcWin.Width();
    wp.cy = rcWin.Height();
    wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
    SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
}

void CListCtrlCl::SetHeaderFontHW(int nHeight,int nWith) //设置头部字体宽和高
{

    m_Header.m_fontHeight = nHeight;
    m_Header.m_fontWith = nWith;
}

void CListCtrlCl::SetHeaderTextColor(COLORREF color) //设置头部字体颜色
{
    m_Header.m_color = color;
}

void CListCtrlCl::SetTextColor(COLORREF cr)  //设置字体颜色
{
    m_color = cr;
}

void CListCtrlCl::SetFontHW(int nHeight,int nWith) //设置字体高和宽
{
    m_fontHeight = nHeight;
    m_fontWith = nWith;
}

void CListCtrlCl::SetColTextColor(int col,COLORREF color)
{

    stColor *pColor = new stColor;
    pColor->nCol = col;
    pColor->rgb = color;
    m_colTextColor.AddTail(pColor);
}

bool CListCtrlCl::FindColTextColor(int col,COLORREF &color)
{
    int flag = 0;
    for (POSITION pos = m_colTextColor.GetHeadPosition(); pos!=NULL; )
    {
        stColor *pColor = (stColor*)m_colTextColor.GetNext(pos);
        if (pColor->nCol==col)
        {
            flag = 1;
            color = pColor->rgb;
            break;
        }
    }

    if (1==flag)
    {
        return true;
    }

    return false;
}

bool CListCtrlCl::FindItemTextColor(int col,int row,COLORREF &color)
{
    int flag = 0;
    for (POSITION pos = m_ItemTextColor.GetHeadPosition(); pos!=NULL; )
    {

        stColor *pColor = (stColor*)m_ItemTextColor.GetNext(pos);
        if (pColor->nCol==col&&pColor->nRow==row)
        {
            flag = 1;
            color = pColor->rgb;
            break;
        }
    }

    if (1==flag)
    {
        return true;
    }

    return false;
}

void CListCtrlCl::SetItemTextColor(int col,int row,COLORREF color)
{

    stColor *pColor = new stColor;
    pColor->nCol = col;
    pColor->nRow = row;
    pColor->rgb = color;

    m_ItemTextColor.AddTail(pColor);
}
 

测试:在对话框的OnInitDialog()中添加初始化代码:

m_ListCtrl.SetColColor(0,RGB(10,150,20)); //设置列背景色

m_ListCtrl.SetColColor(2,RGB(30,100,90)); //设置列背景色

m_ListCtrl.SetBkColor(RGB(50,10,10));        //设置背景色

m_ListCtrl.SetItemColor(1,1,RGB(100,100,10)); //设置指定单元背景色

m_ListCtrl.SetRowHeight(25);               //设置行高度

m_ListCtrl.SetHeaderHeight(1.5);          //设置头部高度

m_ListCtrl.SetHeaderFontHW(16,0);         //设置头部字体高度,和宽度,0表示缺省,自适应 

m_ListCtrl.SetHeaderTextColor(RGB(255,200,100)); //设置头部字体颜色

m_ListCtrl.SetTextColor(RGB(0,255,255));  //设置文本颜色

m_ListCtrl.SetHeaderBKColor(100,255,100,8); //设置头部背景色

m_ListCtrl.SetFontHW(15,0);               //设置字体高度,和宽度,0表示缺省宽度

m_ListCtrl.SetColTextColor(2,RGB(255,255,100)); //设置列文本颜色

m_ListCtrl.SetItemTextColor(3,1,RGB(255,0,0));  //设置单元格字体颜色

m_ListCtrl.InsertColumn(0,_T("名字"),LVCFMT_CENTER,55);

m_ListCtrl.InsertColumn(1,_T("身高"),LVCFMT_CENTER,60);

m_ListCtrl.InsertColumn(2,_T("体重"),LVCFMT_CENTER,60);

m_ListCtrl.InsertColumn(3,_T("测量时间"),LVCFMT_CENTER,180);

m_ListCtrl.InsertItem(0,"张三");

m_ListCtrl.SetItemText(0,1,"178CM");

m_ListCtrl.SetItemText(0,2,"70KG");

m_ListCtrl.SetItemText(0,3,"2009年1月15日23时40分");

m_ListCtrl.InsertItem(1,"王五");

m_ListCtrl.SetItemText(1,1,"178cm");

m_ListCtrl.SetItemText(1,2,"70kg");

m_ListCtrl.SetItemText(1,3,"2009年1月15日23时40分");

m_ListCtrl.InsertItem(2,"阿花");

m_ListCtrl.SetItemText(2,1,"168cm");

m_ListCtrl.SetItemText(2,2,"60kg");

m_ListCtrl.SetItemText(2,3,"2009年1月15日23时40分");

SetWindowLong(m_ListCtrl.m_hWnd ,GWL_EXSTYLE,WS_EX_CLIENTEDGE);

m_ListCtrl.SetExtendedStyle(LVS_EX_GRIDLINES);                     //设置扩展风格为网格

::SendMessage(m_ListCtrl.m_hWnd, LVM_SETEXTENDEDLISTVIEWSTYLE,

LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);

你可能感兴趣的:(program)