CListCtrl控件绘制OK*(精华)

本文介绍了一个自定义的CListCtrl控件,通过CHeaderCtrl派生实现皮肤化的头部,支持排序功能。包括代码实现、布局设置和控件样式调整,适用于Windows桌面应用的界面美化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不过多数是参照别人的,希望希望熟练继续完善,非常的满意

先晒图,并做备份
CListCtrl控件绘制OK*(精华) - きたがって - msopengls House
代码如下:
SkinHeaderCtrl.h
#pragma once

enum
{
    _nSortNone = 0,
    _nSortUp,
    _nSortDown,

    _nSortCount = 3,
};

// CSkinHeaderCtrl

class CSkinHeaderCtrl : public CHeaderCtrl
{
    DECLARE_DYNAMIC(CSkinHeaderCtrl)

public:
    CSkinHeaderCtrl();
    virtual ~CSkinHeaderCtrl();
public:
    void SetItemSortState(int iItem, UINT sortState);
    UINT GetItemSortState(int iItem);

protected:
    DECLARE_MESSAGE_MAP()
    afx_msg LRESULT OnLayout(WPARAM wParam,LPARAM lParam);
private:
    void Init();
public:
    afx_msg void OnPaint();
    virtual void DoPaint(CDC *pDC);
protected:
    virtual void PreSubclassWindow();
public:
    afx_msg void OnHdnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
};
SkinHeaderCtrl.cpp
// SkinHeaderCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "../YFileSys.h"
#include "SkinHeaderCtrl.h"
#include <atlbase.h>
#include <atlimage.h>

// CSkinHeaderCtrl

IMPLEMENT_DYNAMIC(CSkinHeaderCtrl, CHeaderCtrl)

CSkinHeaderCtrl::CSkinHeaderCtrl()
{

}

CSkinHeaderCtrl::~CSkinHeaderCtrl()
{
}


BEGIN_MESSAGE_MAP(CSkinHeaderCtrl, CHeaderCtrl)
    ON_MESSAGE(HDM_LAYOUT,OnLayout)
    ON_WM_PAINT()
    //ON_NOTIFY(HDN_ITEMCHANGEDA, 0, &CSkinHeaderCtrl::OnHdnItemchanged)
    //ON_NOTIFY(HDN_ITEMCHANGEDW, 0, &CSkinHeaderCtrl::OnHdnItemchanged)
    ON_WM_ERASEBKGND()
END_MESSAGE_MAP()



// CSkinHeaderCtrl message handlers
void CSkinHeaderCtrl::SetItemSortState(int iItem, UINT sortState)
{
    ASSERT(sortState == _nSortUp || sortState == _nSortUp || sortState == _nSortDown);
    ASSERT(m_hWnd != NULL && IsWindow(m_hWnd));

    int nItemCount = GetItemCount();
    ASSERT(iItem >= 0 && iItem < nItemCount);

    HDITEM hditem;
    hditem.mask = HDI_FORMAT;
    GetItem(iItem, &hditem);

    if (sortState == _nSortUp)
    {
        hditem.fmt &= ~HDF_SORTDOWN;
        hditem.fmt |= HDF_SORTUP;
    }
    else
    {
        hditem.fmt &= ~HDF_SORTUP;
        hditem.fmt |= HDF_SORTDOWN;
    }
    SetItem(iItem, &hditem);

    CRect rect;
    GetItemRect(iItem, &rect);
    InvalidateRect(&rect);
}

UINT CSkinHeaderCtrl::GetItemSortState(int iItem)
{
    ASSERT(m_hWnd != NULL && IsWindow(m_hWnd));
    int nItemCount = GetItemCount();
    ASSERT(iItem >= 0 && iItem < nItemCount);

    HDITEM hditem;
    hditem.mask = HDI_FORMAT;
    GetItem(iItem, &hditem);

    if (hditem.fmt & HDF_SORTUP)
    {
        return _nSortUp;
    }
    else if (hditem.fmt & HDF_SORTDOWN)
    {
        return _nSortDown;
    }
    else
    {
        return _nSortNone;
    }
}

LRESULT CSkinHeaderCtrl::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;
    pwpos->cy = 22;
    prc->top = 22;
    return lResult;
}

void CSkinHeaderCtrl::Init()
{
    ModifyStyle(0, HDS_FLAT);
}

void CSkinHeaderCtrl::OnPaint()
{
    CPaintDC dc(this); // device context for painting
    DoPaint(&dc);
}

void CSkinHeaderCtrl::DoPaint(CDC *pDC)
{
    CRect rect, rcItem;
    GetClientRect(&rect);
   
    CDC memDC;
    CBitmap bmp;
    memDC.CreateCompatibleDC(pDC);
    bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
    memDC.SelectObject(&bmp);

    memDC.SetBkMode(TRANSPARENT);
    memDC.SetTextColor(RGB(220, 0, 0));  //设置头字体颜色
    memDC.SetStretchBltMode(HALFTONE);

    LOGFONT logfont;
    memset(&logfont, 0x0, sizeof(logfont));
    logfont.lfHeight = 12;
    logfont.lfWeight = FW_NORMAL;
    logfont.lfCharSet = GB2312_CHARSET;
    _tcscpy_s(logfont.lfFaceName, LF_FACESIZE, _T("宋体"));

    CFont font;
    font.CreateFontIndirect(&logfont);
    memDC.SelectObject(&font);

    // 填充背景
    CImage image;
    image.LoadFromResource(AfxGetResourceHandle(), IDB_BITMAP_LISTHEAD);
    image.Draw(memDC, rect);
    image.Destroy();

    int nItems = GetItemCount();
    for (int i = 0; i < nItems; ++i)
    {
        TCHAR buf[256];
        HDITEM

<think>在MFC中显示全局变量数组的元素,通常可以通过以下几种方式实现: 1. 使用消息框(MessageBox)显示所有元素(适用于元素数量较少的情况) 2. 在对话框的列表控件(如CListCtrl、CListBox)中显示 3. 在文档/视图结构的视图窗口中显示(如使用CView的OnDraw函数) 4. 在控制台窗口输出(主要用于调试) 这里我将提供几种常见的方法,并给出代码示例。 假设我们有一个全局的整型数组和一个全局的字符串数组(CStringArray): 在stdafx.h或某个全局头文件中声明: extern int g_nArray[10]; extern CStringArray g_strArray; 在某个全局源文件中定义: int g_nArray[10] = {1,2,3,4,5,6,7,8,9,10}; CStringArray g_strArray; 然后,我们在程序中初始化字符串数组(例如在InitInstance中): g_strArray.Add("Apple"); g_strArray.Add("Banana"); g_strArray.Add("Orange"); 现在,我们想要显示这些全局数组的元素。 方法1:使用消息框(AfxMessageBox)显示 这种方法适用于数组元素较少的情况,因为消息框的显示区域有限。 代码示例: void ShowGlobalArrays() { CString strMessage; // 显示整型数组 strMessage = "整型数组内容:\n"; for (int i = 0; i < 10; i++) { CString strTemp; strTemp.Format(_T("%d "), g_nArray[i]); strMessage += strTemp; } // 显示字符串数组 strMessage += "\n\n字符串数组内容:\n"; for (int i = 0; i < g_strArray.GetSize(); i++) { strMessage += g_strArray[i] + _T("\n"); } AfxMessageBox(strMessage, MB_OK | MB_ICONINFORMATION); } 方法2:在对话框的列表控件中显示 步骤: a. 创建一个对话框资源,并添加一个列表控件List Control)或列表框(List Box)。 b. 为对话框创建一个类,比如CArrayDisplayDlg。 c. 在对话框初始化,将全局数组的内容添加到列表控件中。 示例(使用CListCtrl): // 在对话框类中 BOOL CArrayDisplayDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 初始化列表控件 CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST1); // IDC_LIST1是列表控件的ID if (pList) { // 设置列表控件为报告模式 pList->ModifyStyle(0, LVS_REPORT); pList->InsertColumn(0, _T("索引"), LVCFMT_LEFT, 100); pList->InsertColumn(1, _T("值"), LVCFMT_LEFT, 200); // 添加整型数组数据 for (int i = 0; i < 10; i++) { CString strIndex, strValue; strIndex.Format(_T("整型数组[%d]"), i); strValue.Format(_T("%d"), g_nArray[i]); int nItem = pList->InsertItem(i, strIndex); pList->SetItemText(nItem, 1, strValue); } // 添加字符串数组数据 int nBaseIndex = pList->GetItemCount(); for (int i = 0; i < g_strArray.GetSize(); i++) { CString strIndex, strValue; strIndex.Format(_T("字符串数组[%d]"), i); strValue = g_strArray[i]; int nItem = pList->InsertItem(nBaseIndex + i, strIndex); pList->SetItemText(nItem, 1, strValue); } } return TRUE; } 然后,在需要显示的地方弹出这个对话框: void ShowArrayDialog() { CArrayDisplayDlg dlg; dlg.DoModal(); } 方法3:在视图窗口中显示(适用于文档/视图结构) 在视图类的OnDraw函数中,我们可以使用pDC来绘制文本。 示例: void CYourView::OnDraw(CDC* pDC) { CYourDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; int y = 10; // 起始Y坐标 // 输出整型数组 for (int i = 0; i < 10; i++) { CString str; str.Format(_T("g_nArray[%d] = %d"), i, g_nArray[i]); pDC->TextOut(10, y, str); y += 20; // 换行 } // 输出字符串数组 for (int i = 0; i < g_strArray.GetSize(); i++) { CString str; str.Format(_T("g_strArray[%d] = %s"), i, g_strArray[i]); pDC->TextOut(10, y, str); y += 20; } } 方法4:在控制台输出(调试用) 在MFC应用程序中,我们可以通过创建控制台窗口来输出信息。 示例: void ConsoleOutput() { AllocConsole(); // 创建控制台窗口 freopen_s((FILE**)stdout, "CONOUT$", "w", stdout); printf("整型数组:\n"); for (int i = 0; i < 10; i++) { printf("%d ", g_nArray[i]); } printf("\n"); printf("字符串数组:\n"); for (int i = 0; i < g_strArray.GetSize(); i++) { CStringA strA(g_strArray[i]); // 转换为ANSI字符串 printf("%s\n", strA.GetString()); } // 注意:使用完毕后,可以调用FreeConsole()来释放控制台 // 但通常我们可能希望控制台一直存在直到程序结束,所以这里不立即释放 } 注意事项: - 全局变量的使用要谨慎,尤其是在多线程环境中,需要同步访问。 - 显示大量数据,使用对话框的列表控件(报告模式)并启用滚动条比较合适。 - 在视图窗口中显示,当数据变化需要调用Invalidate()刷新视图。 根据具体需求选择合适的方法。 §§相关问题§§: 1. MFC中如何安全地使用全局变量? 2. 如何在MFC的列表控件中显示大量数据? 3. 在文档/视图结构中如何更新视图显示? 4. MFC多线程编程中如何同步对全局数组的访问?</think>在 MFC 中显示全局变量数组的元素,有几种常用方法。下面我将详细介绍每种方法,并提供完整的代码实现。 ### 方法 1:使用列表框控件 (CListBox) ```cpp // 全局数组声明 CStringArray g_strArray; // 字符串数组 int g_intArray[5] = {10, 20, 30, 40, 50}; // 整数数组 // 在对话框初始化填充列表框 BOOL CMyDialog::OnInitDialog() { CDialogEx::OnInitDialog(); CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST_ARRAY); if (pListBox) { // 显示字符串数组 for (int i = 0; i < g_strArray.GetSize(); i++) { CString strItem; strItem.Format(_T("字符串[%d]: %s"), i, g_strArray[i]); pListBox->AddString(strItem); } // 显示整数数组 for (int i = 0; i < sizeof(g_intArray)/sizeof(g_intArray[0]); i++) { CString strItem; strItem.Format(_T("整数[%d]: %d"), i, g_intArray[i]); pListBox->AddString(strItem); } } return TRUE; } ``` ### 方法 2:使用列表控件 (CListCtrl) - 报告视图 ```cpp BOOL CMyDialog::OnInitDialog() { CDialogEx::OnInitDialog(); CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LISTCTRL_ARRAY); if (pListCtrl) { // 设置列表样式 pListCtrl->SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); // 添加列 pListCtrl->InsertColumn(0, _T("索引"), LVCFMT_LEFT, 80); pListCtrl->InsertColumn(1, _T("类型"), LVCFMT_LEFT, 80); pListCtrl->InsertColumn(2, _T("值"), LVCFMT_LEFT, 150); int nItem = 0; // 添加字符串数组 for (int i = 0; i < g_strArray.GetSize(); i++) { pListCtrl->InsertItem(nItem, _T("")); pListCtrl->SetItemText(nItem, 0, CString(_T("字符串 ") + CString(g_strArray[i]).MakeUpper())); pListCtrl->SetItemText(nItem, 1, _T("字符串")); pListCtrl->SetItemText(nItem, 2, g_strArray[i]); nItem++; } // 添加整数数组 for (int i = 0; i < sizeof(g_intArray)/sizeof(g_intArray[0]); i++) { pListCtrl->InsertItem(nItem, _T("")); CString index; index.Format(_T("整数 %d"), i); pListCtrl->SetItemText(nItem, 0, index); pListCtrl->SetItemText(nItem, 1, _T("整数")); CString value; value.Format(_T("%d"), g_intArray[i]); pListCtrl->SetItemText(nItem, 2, value); nItem++; } } return TRUE; } ``` ### 方法 3:在视图窗口中显示 (CView) ```cpp void CMyView::OnDraw(CDC* pDC) { CMyDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); CRect rect; GetClientRect(&rect); int y = 10; // 设置标题字体 CFont fontTitle; fontTitle.CreateFont(16, 0, 0, 0, FW_BOLD, FALSE, FALSE, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Arial")); CFont* pOldFont = pDC->SelectObject(&fontTitle); // 显示字符串数组标题 pDC->TextOut(10, y, _T("字符串数组内容:")); y += 30; // 恢复默认字体 pDC->SelectObject(pOldFont); fontTitle.DeleteObject(); // 显示字符串数组内容 for (int i = 0; i < g_strArray.GetSize(); i++) { CString strItem; strItem.Format(_T("元素 %d: %s"), i, g_strArray[i]); pDC->TextOut(20, y, strItem); y += 20; } y += 10; // 添加间距 // 设置整数数组标题 pDC->SelectObject(&fontTitle); pDC->TextOut(10, y, _T("整数数组内容:")); y += 30; pDC->SelectObject(pOldFont); // 显示整数数组内容 for (int i = 0; i < sizeof(g_intArray)/sizeof(g_intArray[0]); i++) { CString strItem; strItem.Format(_T("元素 %d: %d"), i, g_intArray[i]); pDC->TextOut(20, y, strItem); y += 20; } } ``` ### 方法 4:使用编辑框控件 (CEdit) - 多行显示 ```cpp void CMyDialog::DisplayArrayInEditBox() { CEdit* pEdit = (CEdit*)GetDlgItem(IDC_EDIT_ARRAY); if (pEdit) { CString strContent; // 添加字符串数组内容 strContent += _T("===== 字符串数组 =====\r\n"); for (int i = 0; i < g_strArray.GetSize(); i++) { strContent.AppendFormat(_T("元素 %d: %s\r\n"), i, g_strArray[i]); } // 添加整数数组内容 strContent += _T("\r\n===== 整数数组 =====\r\n"); for (int i = 0; i < sizeof(g_intArray)/sizeof(g_intArray[0]); i++) { strContent.AppendFormat(_T("元素 %d: %d\r\n"), i, g_intArray[i]); } pEdit->SetWindowText(strContent); // 设置为只读 pEdit->SetReadOnly(TRUE); } } ``` ### 方法 5:使用树形控件 (CTreeCtrl) ```cpp BOOL CMyDialog::OnInitDialog() { CDialogEx::OnInitDialog(); CTreeCtrl* pTree = (CTreeCtrl*)GetDlgItem(IDC_TREE_ARRAY); if (pTree) { // 添加字符串数组节点 HTREEITEM hStrRoot = pTree->InsertItem(_T("字符串数组")); for (int i = 0; i < g_strArray.GetSize(); i++) { CString strItem; strItem.Format(_T("元素 %d: %s"), i, g_strArray[i]); pTree->InsertItem(strItem, hStrRoot); } // 添加整数数组节点 HTREEITEM hIntRoot = pTree->InsertItem(_T("整数数组")); for (int i = 0; i < sizeof(g_intArray)/sizeof(g_intArray[0]); i++) { CString strItem; strItem.Format(_T("元素 %d: %d"), i, g_intArray[i]); pTree->InsertItem(strItem, hIntRoot); } // 展开所有节点 pTree->Expand(hStrRoot, TVE_EXPAND); pTree->Expand(hIntRoot, TVE_EXPAND); } return TRUE; } ``` ### 全局数组管理的最佳实践 1. **安全访问(多线程环境)**: ```cpp // 在头文件中声明 extern CCriticalSection g_csArray; extern CStringArray g_strArray; // 在实现文件中定义 CCriticalSection g_csArray; CStringArray g_strArray; // 线程安全的数组访问 void AddToGlobalArray(LPCTSTR str) { CSingleLock lock(&g_csArray, TRUE); g_strArray.Add(str); } void DisplayGlobalArray() { CSingleLock lock(&g_csArray, TRUE); // 显示数组内容... } ``` 2. **动态更新显示**: ```cpp void CMyDialog::UpdateArrayDisplay() { CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LISTCTRL_ARRAY); if (pList) { pList->DeleteAllItems(); // 新填充列表... // [使用前面列表控件的填充代码] } } // 当全局数组改变调用 void OnGlobalArrayChanged() { UpdateArrayDisplay(); } ``` 3. **支持大型数组**: ```cpp class CVirtualListCtrl : public CListCtrl { public: // 写虚拟列表支持 virtual void OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; if (pDispInfo->item.iItem >= 0 && pDispInfo->item.iItem < g_strArray.GetSize()) { if (pDispInfo->item.mask & LVIF_TEXT) { _tcscpy_s(pDispInfo->item.pszText, pDispInfo->item.cchTextMax, g_strArray[pDispInfo->item.iItem]); } } *pResult = 0; } DECLARE_MESSAGE_MAP() }; BEGIN_MESSAGE_MAP(CVirtualListCtrl, CListCtrl) ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetDispInfo) END_MESSAGE_MAP() ``` ### 完整示例:对话框中使用列表控件 ```cpp // MyDialog.h class CMyDialog : public CDialogEx { public: CMyDialog(CWnd* pParent = nullptr); enum { IDD = IDD_MY_DIALOG }; protected: virtual BOOL OnInitDialog(); afx_msg void OnBnClickedRefresh(); DECLARE_MESSAGE_MAP() }; // MyDialog.cpp BOOL CMyDialog::OnInitDialog() { CDialogEx::OnInitDialog(); // 初始化列表控件 CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST_ARRAY); pList->InsertColumn(0, _T("索引"), LVCFMT_LEFT, 80); pList->InsertColumn(1, _T("值"), LVCFMT_LEFT, 200); // 填充数组内容 UpdateArrayDisplay(); return TRUE; } void CMyDialog::UpdateArrayDisplay() { CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST_ARRAY); pList->DeleteAllItems(); // 添加字符串数组 for (int i = 0; i < g_strArray.GetSize(); i++) { int nIndex = pList->InsertItem(i, CString(g_strArray[i]).MakeUpper()); pList->SetItemText(nIndex, 1, g_strArray[i]); } // 添加整数数组 int baseIndex = pList->GetItemCount(); for (int i = 0; i < sizeof(g_intArray)/sizeof(g_intArray[0]); i++) { CString strValue; strValue.Format(_T("%d"), g_intArray[i]); int nIndex = pList->InsertItem(baseIndex + i, _T("")); pList->SetItemText(nIndex, 0, _T("整数")); pList->SetItemText(nIndex, 1, strValue); } } void CMyDialog::OnBnClickedRefresh() { UpdateArrayDisplay(); } ``` ### 选择合适的方法 1. **小型数组**:使用列表框( CListBox)或编辑框( CEdit) 2. **结构化数据**:使用列表控件( CListCtrl)的报告视图 3. **层次化数据**:使用树形控件( CTreeCtrl) 4. **图形界面**:在视图( CView)绘制 5. **大型数据集**:虚拟列表控件( LVS_OWNERDATA)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值