当前位置: 首页 > web >正文

CMap应用场景和例子

CMap 详解

CMap 是 MFC (Microsoft Foundation Classes) 库中的一个模板类,用于实现键值对的映射关系(类似哈希表或字典)。它提供了高效的数据存储和检索功能,适用于需要通过键快速查找值的场景。

基本模板参数

cpp

运行

template<class KEY,              // 键的类型class ARG_KEY,          // 传递键的参数类型(通常是引用)class VALUE,            // 值的类型class ARG_VALUE         // 传递值的参数类型(通常是引用)
>
class CMap : public CObject
常用方法
  • 添加元素SetAt(ARG_KEY key, ARG_VALUE newValue)
  • 查找元素Lookup(ARG_KEY key, VALUE& rValue)
  • 删除元素RemoveKey(ARG_KEY key)
  • 删除所有元素RemoveAll()
  • 获取元素数量GetCount()
  • 检查是否为空IsEmpty()
实际应用场景
  1. 缓存机制:存储计算结果,避免重复计算
  2. 数据映射:将 ID 映射到对应的对象或数据
  3. 配置管理:存储键值对形式的配置信息
  4. 事件处理:将事件 ID 映射到处理函数

使用举例

下面是一个完整的示例,展示如何使用 CMap 实现一个简单的联系人管理器:

#pragma once
#include <afxtempl.h>// 联系人信息结构体
struct ContactInfo
{CString name;CString phone;CString email;ContactInfo() {}ContactInfo(const CString& n, const CString& p, const CString& e): name(n), phone(p), email(e) {}
};// 联系人管理器类
class CContactManager
{
private:// 使用CMap存储联系人信息,键为ID,值为ContactInfo结构体CMap<int, int, ContactInfo, ContactInfo&> m_contactMap;int m_nextId;  // 下一个可用IDpublic:CContactManager() : m_nextId(1) {}~CContactManager() { m_contactMap.RemoveAll(); }// 添加联系人int AddContact(const CString& name, const CString& phone, const CString& email);// 根据ID查找联系人bool FindContact(int id, ContactInfo& info) const;// 更新联系人信息bool UpdateContact(int id, const CString& name, const CString& phone, const CString& email);// 删除联系人bool DeleteContact(int id);// 获取联系人数量int GetContactCount() const;// 显示所有联系人void DisplayAllContacts() const;
};
#include "stdafx.h"
#include "ContactManager.h"
#include <iostream>// 添加联系人
int CContactManager::AddContact(const CString& name, const CString& phone, const CString& email)
{int id = m_nextId++;ContactInfo info(name, phone, email);m_contactMap.SetAt(id, info);return id;
}// 根据ID查找联系人
bool CContactManager::FindContact(int id, ContactInfo& info) const
{return m_contactMap.Lookup(id, info);
}// 更新联系人信息
bool CContactManager::UpdateContact(int id, const CString& name, const CString& phone, const CString& email)
{ContactInfo info;if (m_contactMap.Lookup(id, info)){info.name = name;info.phone = phone;info.email = email;m_contactMap.SetAt(id, info);return true;}return false;
}// 删除联系人
bool CContactManager::DeleteContact(int id)
{return m_contactMap.RemoveKey(id) != 0;
}// 获取联系人数量
int CContactManager::GetContactCount() const
{return m_contactMap.GetCount();
}// 显示所有联系人
void CContactManager::DisplayAllContacts() const
{if (m_contactMap.IsEmpty()){std::cout << "没有联系人记录" << std::endl;return;}POSITION pos = m_contactMap.GetStartPosition();while (pos != NULL){int id;ContactInfo info;m_contactMap.GetNextAssoc(pos, id, info);// 转换CString为char*以便输出CStringA name(info.name);CStringA phone(info.phone);CStringA email(info.email);std::cout << "ID: " << id << std::endl;std::cout << "  姓名: " << name << std::endl;std::cout << "  电话: " << phone << std::endl;std::cout << "  邮箱: " << email << std::endl;std::cout << "------------------------" << std::endl;}
}
#include "stdafx.h"
#include "ContactManager.h"int main()
{CContactManager manager;// 添加联系人int id1 = manager.AddContact(_T("张三"), _T("13800138001"), _T("zhangsan@example.com"));int id2 = manager.AddContact(_T("李四"), _T("13900139001"), _T("lisi@example.com"));int id3 = manager.AddContact(_T("王五"), _T("13700137001"), _T("wangwu@example.com"));std::cout << "添加了 " << manager.GetContactCount() << " 个联系人" << std::endl;// 显示所有联系人std::cout << "\n所有联系人列表:" << std::endl;manager.DisplayAllContacts();// 查找联系人ContactInfo info;if (manager.FindContact(id2, info)){CStringA name(info.name);std::cout << "\n找到ID为 " << id2 << " 的联系人: " << name << std::endl;}// 更新联系人manager.UpdateContact(id2, _T("李四(更新)"), _T("13900139002"), _T("lisi_updated@example.com"));// 删除联系人manager.DeleteContact(id3);// 显示更新后的联系人列表std::cout << "\n更新后的联系人列表:" << std::endl;manager.DisplayAllContacts();return 0;
}

代码说明

上面的示例展示了如何使用 CMap 实现一个简单的联系人管理器:

  1. 数据结构设计

    • 定义了 ContactInfo 结构体存储联系人信息
    • 使用 CMap<int, int, ContactInfo, ContactInfo&> 存储联系人数据
  2. 核心功能

    • 添加联系人:使用 SetAt() 方法将新联系人添加到映射表
    • 查找联系人:使用 Lookup() 方法根据 ID 查找联系人
    • 更新联系人:先查找,然后修改信息并重新设置
    • 删除联系人:使用 RemoveKey() 方法删除指定 ID 的联系人
    • 遍历所有联系人:使用 GetStartPosition() 和 GetNextAssoc() 方法
  3. 内存管理

    • CMap 自动管理存储的对象,不需要手动释放
    • 析构函数中调用 RemoveAll() 确保所有资源被释放

使用 CMap 的注意事项

  1. 键类型要求

    • 键类型必须支持 == 运算符(用于比较)
    • 如果使用自定义类作为键,需要重载 == 运算符
  2. 内存管理

    • 对于值类型为指针的情况,需要手动管理指针指向的对象
    • 建议在删除元素前先释放指针指向的内存
  3. 遍历操作

    • 遍历过程中不要修改映射表结构(添加或删除元素)
    • 如果需要修改,应使用 GetNextAssoc() 返回的 POSITION 进行操作
  4. 性能考虑

    • CMap 提供 O (1) 的平均查找时间
    • 但在最坏情况下可能退化为 O (n)

#if !defined(AFX_LINECOLORLISTCTRL_H__92EB1CD4_CD33_4E02_A098_367A8FEFF38E__INCLUDED_)
#define AFX_LINECOLORLISTCTRL_H__92EB1CD4_CD33_4E02_A098_367A8FEFF38E__INCLUDED_#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// LineColorListCtrl.h : header file
//#include <afxtempl.h>typedef struct
{COLORREF colText; //前景色COLORREF colTextBk;//背景色
} TEXT_BK;/
// CLineColorListCtrl windowclass CLineColorListCtrl : public CListCtrl
{
public:void SetItemColor(DWORD iItem, COLORREF TextColor, COLORREF TextBkColor);	//设置某一行的前景色和背景色void SetAllItemColor(DWORD iItem, COLORREF TextColor, COLORREF TextBkColor);//指设置所有从第一行到iItem行的颜色。void ClearColor(); //清除颜色映射表  int m_iPopMenu;afx_msg void OnPaint();afx_msg BOOL OnEraseBkgnd(CDC* pDC);
// Construction
public:CLineColorListCtrl();// Attributes
public:CMap<DWORD, DWORD&, TEXT_BK, TEXT_BK&> MapItemColor;// Operations
public:// Overrides// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CLineColorListCtrl)//}}AFX_VIRTUAL// Implementation
public:virtual ~CLineColorListCtrl();// Generated message map functions
protected://{{AFX_MSG(CLineColorListCtrl)// NOTE - the ClassWizard will add and remove member functions here.//}}AFX_MSGvoid CLineColorListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);DECLARE_MESSAGE_MAP()
};///{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif // !defined(AFX_LINECOLORLISTCTRL_H__92EB1CD4_CD33_4E02_A098_367A8FEFF38E__INCLUDED_)
// LineColorListCtrl.cpp : implementation file
//#include "stdafx.h"
#include "LineColorListCtrl.h"#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif/
// CLineColorListCtrlCLineColorListCtrl::CLineColorListCtrl()
{m_iPopMenu = 0;
}CLineColorListCtrl::~CLineColorListCtrl()
{
}BEGIN_MESSAGE_MAP(CLineColorListCtrl, CListCtrl)//{{AFX_MSG_MAP(CLineColorListCtrl)// NOTE - the ClassWizard will add and remove mapping macros here.//}}AFX_MSG_MAPON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw)ON_WM_PAINT()ON_WM_ERASEBKGND()
END_MESSAGE_MAP()/
// CLineColorListCtrl message handlers
BOOL CLineColorListCtrl::OnEraseBkgnd(CDC* pDC)
{return false;return CListCtrl::OnEraseBkgnd(pDC);
}
//避免背景闪烁
void CLineColorListCtrl::OnPaint()
{//响应WM_PAINT消息CPaintDC dc(this); // device context for paintingCRect rect;CRect headerRect;CDC MenDC;//内存ID表CBitmap MemMap;GetClientRect(&rect);GetDlgItem(0)->GetWindowRect(&headerRect);MenDC.CreateCompatibleDC(&dc);MemMap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());MenDC.SelectObject(&MemMap);MenDC.FillSolidRect(&rect, RGB(228, 236, 243));//这一句是调用默认的OnPaint(),把图形画在内存DC表上DefWindowProc(WM_PAINT, (WPARAM)MenDC.m_hDC, (LPARAM)0);//输出dc.BitBlt(0, headerRect.Height(), rect.Width(), rect.Height(), &MenDC, 0, headerRect.Height(), SRCCOPY);MenDC.DeleteDC();MemMap.DeleteObject();}//自定义绘画颜色处理
void CLineColorListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{*pResult = CDRF_DODEFAULT;NMLVCUSTOMDRAW * lplvdr = (NMLVCUSTOMDRAW*)pNMHDR;NMCUSTOMDRAW &nmcd = lplvdr->nmcd;switch(lplvdr->nmcd.dwDrawStage)//判断状态{case CDDS_PREPAINT:{*pResult = CDRF_NOTIFYITEMDRAW;break;}case CDDS_ITEMPREPAINT://如果为画ITEM之前就要进行颜色的改变{// 根据在 SetItemColor(DWORD iItem, COLORREF color) 设置的// ITEM号和COLORREF 在摸板中查找,然后进行颜色赋值。TEXT_BK tb;if(MapItemColor.Lookup(nmcd.dwItemSpec, tb)){lplvdr->clrText = tb.colText;lplvdr->clrTextBk = tb.colTextBk;*pResult = CDRF_DODEFAULT;}}break;}
}void CLineColorListCtrl::ClearColor()
{MapItemColor.RemoveAll();
}void CLineColorListCtrl::SetItemColor(DWORD iItem, COLORREF TextColor, COLORREF TextBkColor)
{TEXT_BK tb;tb.colText = TextColor;tb.colTextBk = TextBkColor;MapItemColor.SetAt(iItem, tb);//设置某行的颜色。this->RedrawItems(iItem, iItem);//重新染色this->SetFocus();    //设置焦点UpdateWindow();
}void CLineColorListCtrl::SetAllItemColor(DWORD iItem, COLORREF TextColor, COLORREF TextBkColor)
{TEXT_BK tb;tb.colText = TextColor;tb.colTextBk = TextBkColor;if(iItem > 0){for(DWORD numItem = 0; numItem < iItem ; numItem ++){MapItemColor.SetAt(numItem, tb);this->RedrawItems(numItem, numItem);}}
}

TEXT_BK 结构体和 MapItemColor 映射表

这部分代码定义了一个结构体和一个映射表,用于存储和管理列表项的颜色信息:

TEXT_BK 结构体

cpp

运行

typedef struct
{COLORREF colText;     // 前景色(文本颜色)COLORREF colTextBk;   // 背景色
} TEXT_BK;

这个结构体用于存储每个列表项的颜色属性:

  • colText:文本颜色,使用 Windows API 的COLORREF类型(通常是一个 32 位整数,表示 RGB 颜色值)
  • colTextBk:背景颜色

通过typedef定义了这个结构体的别名TEXT_BK,这样在代码中可以直接使用TEXT_BK而不需要每次都写struct TEXT_BK

MapItemColor 映射表

cpp

运行

CMap<DWORD, DWORD&, TEXT_BK, TEXT_BK&> MapItemColor;

这行代码声明了一个 MFC 的CMap模板类实例,用于存储列表项索引和颜色信息的映射关系:

  • 第一个模板参数DWORD:键的类型,表示列表项的索引
  • 第二个模板参数DWORD&:键的引用类型,用于高效传递参数
  • 第三个模板参数TEXT_BK:值的类型,表示颜色信息
  • 第四个模板参数TEXT_BK&:值的引用类型,用于高效传递参数
用途

这个映射表在CLineColorListCtrl类中用于:

  1. SetItemColorSetAllItemColor方法中设置特定列表项的颜色
  2. OnNMCustomdraw方法中查找并应用颜色设置
  3. ClearColor方法中清除所有颜色设置
http://www.xdnf.cn/news/11943.html

相关文章:

  • ABP-Book Store Application中文讲解 - Part 10: Book to Author Relation
  • 【Pandas】pandas DataFrame reset_index
  • HTTP常见的请求方法、响应状态码、接口规范介绍
  • c#开发AI模型对话
  • 回归任务和分类任务损失函数详解
  • 性能剖析:在 ABP 框架中集成 MiniProfiler 实现性能可视化诊断
  • 学习笔记(24): 机器学习之数据预处理Pandas和转换成张量格式[2]
  • 以人类演示视频为提示,学习可泛化的机器人策略
  • 鸿蒙仓颉语言开发实战教程:商城登录页
  • [网页五子棋][匹配模块]实现胜负判定,处理玩家掉线
  • 【C++】std::wstring` 和 C# 的 `String`(全称 `System.String`)
  • HRI-2025 | 大模型驱动的个性化可解释机器人人机交互研究
  • .Net Framework 4/C# 面向对象编程进阶
  • 机器学习基础(四) 决策树
  • Spitfire:Codigger 生态中的高性能、安全、分布式浏览器
  • Java 线程池原理详解
  • Rust 学习笔记:Box<T>
  • 更新 Docker 容器中的某一个文件
  • 根目录0xa0属性对应的Ntfs!_SCB中的FileObject是什么时候被建立的----NTFS源代码分析--重要
  • ffmpeg(三):处理原始数据命令
  • 旅游微信小程序制作指南
  • Webpack常见的插件和模式
  • IOS 打包账号发布上传和IOS Xcode证书配置
  • .Net Framework 4/C# 属性和方法
  • VS代码生成工具ReSharper v2025.1——支持.NET 10和C# 14预览功能
  • 【设计模式-4.9】行为型——命令模式
  • 解决Required request part ‘file‘ is not present
  • StarRocks与Apache Iceberg:构建高效湖仓一体的实时分析平台
  • OPENCV重点结构体Mat的讲解
  • 数据结构 [一] 基本概念