MFC-小型工具通用界面框架

0x1 场景

由于工作需要我会写代码开发工具给客户或者同事用。代码都能实现,但写个黑乎乎的命令行工具给别人用确实显得不够专业,用别人写好的成型工具又担心有后门。

所以掌握积累几个MFC的常用控件随时调用,代码量堆起来了就是不断反复利用的过程了。未来还是会把精力用在实现实际功能上,以成为界面工程师作为目标学习很容易找不到工作。

这篇文章主要分享给大家使用MFC做GUI的技巧,选用它是因为我更熟悉C++。而且VS是非常强大的调试器,除了下载就可以用之外,还能看反汇编、内存、堆栈。

环境:VS2017

效果

0x2 技术点

  • CListCtrl,界面增加列名、跟随界面调整、增加内容
  • 菜单使用,删除单条、删除多条

0x3 代码

1、CListCtrl控件

界面使用部分

1、【对话框编辑器】-【List Control】,增加一个List控件拖到指定位置

2、【属性】-【View】-【Report】,把显示方式改成报表形式

3、【类向导】-【成员变量】-【添加变量】-【m_List_xxx】,绑定一个操作的变量

代码部分

  • 添加List控件的列表头,增加列 InsertColumn();
m_List_xxx.InsertColumn(i,                    // 插入的列
g_Column_Message_Data[i].title, // 插入的标题
LVCFMT_CENTER, // 插入的样式
g_Column_Message_Data[i].nWidth); // 插入的宽度

封装函数,定义结构体部分:

定义一个结构体,成员是标题【WCHAR *title】、宽度【int nWidth】。然后初始化每一列的列名占据叫什么名字,占据多宽。

/////////////////////////////////////////// 列表控件
typedef struct
{
WCHAR *title; //列表的名称
int nWidth; //列表的宽度
}COLUMNSTRUCT; COLUMNSTRUCT g_Column_Message_Data[] =
{
{ _T("信息类型"), 80 },
{ _T("时间"), 100 },
{ _T("信息内容"), 300 }
};
//变量声明
int g_Column_Message_Count = 3; //列表的个数
int g_Column_Message_Width = 0; //列总宽度,初始化为0。在后面的函数中会赋值

新建一个函数【int GUI_InitList(void)】,在【OnInitDialog()】里调用。初始化List显示的列表名

int CAPTFilecheckDlg::GUI_InitList(void)
{
// init online list
m_CList_dirlist.SetExtendedStyle(LVS_EX_FULLROWSELECT);
for (int i = 0; i < g_Column_Online_Count; i++)
{ m_CList_dirlist.InsertColumn(i, g_Column_Online_Data[i].title, LVCFMT_CENTER, g_Column_Online_Data[i].nWidth);
g_Column_Online_Width += g_Column_Online_Data[i].nWidth; //得到总宽度 }
m_CList_MESSAGE.SetExtendedStyle(LVS_EX_FULLROWSELECT);
for (int i = 0; i < g_Column_Message_Count; i++)
{
m_CList_MESSAGE.InsertColumn(i, g_Column_Message_Data[i].title, LVCFMT_CENTER, g_Column_Message_Data[i].nWidth);
g_Column_Message_Width += g_Column_Message_Data[i].nWidth; //得到总宽度
}
return 0;;
}
  • 跟随界面调整大小

最大化的时候界面跟着变大。

【类向导】-【消息】-【WM_SIZE】-【添加处理程序】,增加一个【OnSize】的消息函数

void CMFCClistDlg::OnSize(UINT nType, int cx, int cy)
{
CDialogEx::OnSize(nType, cx, cy); // TODO: 在此处添加消息处理程序代码
// 命中目标
double dcx = cx; //对话框的总宽度
if (m_List_xxx.m_hWnd != NULL)
{
CRect rc;
rc.left = 1; //列表的左坐标
rc.top = 20; //列表的上坐标
rc.right = cx - 1; //列表的右坐标
rc.bottom = cy - 20; //列表的下坐标
m_List_xxx.MoveWindow(rc);
for (auto i = 0; i < g_Column_Message_Count; i++) { //遍历每一个列
double dd = g_Column_Message_Data[i].nWidth; //得到当前列的宽度
dd /= g_Column_Message_Width; //看一看当前宽度占总长度的几分之几
dd *= dcx; //用原来的长度乘以所占的几分之几得到当前的宽度
auto lenth = dd; //转换为int 类型
m_List_xxx.SetColumnWidth(i, (lenth)); //设置当前的宽度
} }
}
  • 增加列内容InsertItem()/SetItemText()
m_List_xxx.InsertItem(0, L"ok");               // 第一行的第一列内容
m_List_xxx.SetItemText(0, 1, L"2"); // 第一行的第二列内容
m_List_xxx.SetItemText(0, 2, L"hello world"); // 第一行的第三列内容

封装函数部分1:

void CAPTFilecheckDlg::GUI_ShowMessage(bool bIsOK, CString strMsg)
{
CString strIsOK, strTime;
CTime t = CTime::GetCurrentTime();
strTime = t.Format("%H:%M:%S");
if (bIsOK)
{
strIsOK = "执行成功";
}
else {
strIsOK = "执行失败";
}
m_CList_MESSAGE.InsertItem(0, strIsOK);
m_CList_MESSAGE.SetItemText(0, 1, strTime);
m_CList_MESSAGE.SetItemText(0, 2, strMsg);
} 调用方法: GUI_ShowMessage(true, L"mesage");
GUI_ShowMessage(true, L"mesage1");
GUI_ShowMessage(true, L"mesage2");

2、菜单控件

  • 新建菜单

    【资源视图】-【添加资源】-【Menu】

  • 控件增加右键的说明

    【删除单条】

    【删除全部】

    【增加内容】

  • 添加右键菜单

在【List Control】控件右键属性找到【NM_RCLICK】,双击绑定右键事件,根据需要再增加改动。

void CMFCClistDlg::OnNMRClickList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码 CMenu popup;
popup.LoadMenu(IDR_MENU1);
CMenu* pM = popup.GetSubMenu(0);
CPoint p;
GetCursorPos(&p);
int count = pM->GetMenuItemCount();
//如果没有选中
if (m_List_xxx.GetSelectedCount() == 0)
{
for (int i = 2; i < count; i++)
{ //菜单全部变灰
pM->EnableMenuItem(i, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
}
}
pM->TrackPopupMenu(TPM_LEFTALIGN, p.x, p.y, this);
*pResult = 0;
}
  • 绑定事件

在每个安全事件上添加事件处理程序,在消息类型【COMMAND】、类列表【xxxxDlg】,指定事件函数比如删除单条就绑定【GUI_Dir_Delete()】、删除全部就绑定【GUI_Dir_DeleteALL_Items()】。

    • 右键删除单行功能实现,GetItemCount()/DeleteItem():

删除单条要先获取选中的条目,然后遍历

void CMFCClistDlg::GUI_Dir_Delete()
{
// TODO: 在此添加命令处理程序代码 int i, iState;
// 当前选择的条目
int nItemSelected = m_List_xxx.GetSelectedCount();
// 检索在列表视图控件中的项的数目。
int nItemCount = m_List_xxx.GetItemCount();
// 如果没有选择值,就退出这个函数,不执行删除判断。
if (nItemSelected < 1)
return;
// 遍历当前所有的列,找到选中的那条删除。
for (i = nItemCount - 1; i >= 0; i--)
{
iState = m_List_xxx.GetItemState(i, LVIS_SELECTED); // 获取选择状态
if (iState != 0)
{ m_List_xxx.DeleteItem(i); // 删除
}
}
}
    • 右键删除所有行功能实现,DeleteAllItems()/SetRedraw()/RedrawWindow();
// 删除所有特征
void CMFCClistDlg::GUI_Dir_DeleteALL_Items()
{
// TODO: 在此添加命令处理程序代码
m_CList_dirlist.DeleteAllItems();
m_CList_dirlist.SetRedraw(FALSE);
//do erase and insert operation
m_CList_dirlist.SetRedraw(TRUE);
m_CList_dirlist.RedrawWindow();
}
    • 右键增加内容功能实现

结合前面增加内容的函数,可以绑定一个【增加内容】的函数,【GUI_Add_Check_Dir()】。

函数作用主要是打开文件浏览器,然后选中路径,增加到LIST控件中。

void CMFCClistDlg::GUI_Add_Check_Dir()
{
// TODO: 在此添加命令处理程序代码
CString m_strFileOut = _T("");
TCHAR servPath[MAX_PATH];//用来存放文件夹路径
BROWSEINFO bi;
LPITEMIDLIST pidl;
bi.hwndOwner = this->m_hWnd;
bi.pidlRoot = NULL;
bi.pszDisplayName = servPath;
bi.lpszTitle = _T("选择文件路径");
bi.ulFlags = BIF_RETURNONLYFSDIRS;
bi.lpfn = NULL;
bi.lParam = NULL;
bi.iImage = NULL;
if ((pidl = SHBrowseForFolder(&bi)) != NULL)
{
//得到文件夹的全路径,不要的话,只得本文件夹名
if (SHGetPathFromIDList(pidl, servPath))
{
// 增加内容
GUI_ShowMessage(true, servPath);
}
}
// 把变量内容更新到对话框
UpdateData(FALSE);
}

0x4 总结

界面功能并不会太复杂,知道怎么得到结果,怎么插入数据和扩展就足够了。

主要功能:

CListCtrl控件使用,右键菜单功能删除单行、删除全部、增加自定义内容。

扩展性:

主要考虑在右键菜单栏增加处理函数,实现主要功能,然后得到结果返回到界面上。

0x5 参考

MSDN VS2017

https://docs.microsoft.com/zh-cn/cpp/mfc/reference/clistctrl-class?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DZH-CN%26k%3Dk(AFXCMN%2FCListCtrl%3A%3AInsertItem)%3Bk(CListCtrl%3A%3AInsertItem)%3Bk(InsertItem)%3Bk(DevLang-C%2B%2B)%3Bk(TargetOS-Windows)%26rd%3Dtrue&view=vs-2017#insertcolumn

VS2010/MFC编程入门之二十九(常用控件:列表视图控件List Control 下)

http://www.jizhuomi.com/software/197.html

MFC小型工具通用界面框架CLIST控件+右键菜单功能的更多相关文章

  1. WPf 带滚动条WrapPanel 自动换行 和控件右键菜单

    原文:WPf 带滚动条WrapPanel 自动换行 和控件右键菜单 技能点包括 WPf 样式的引用 数据的验证和绑定 比较适合初学者 前台: <Window.Resources> < ...

  2. FineUI Grid控件右键菜单的实现

    FineUI官方Demo上一直没有Grid右键菜单的实现,其实从4.1.x的版本开始,允许添加自定义的事件监听(Listeners),所以要实现这个功能已经相当容易了. ExtJs右键菜单有很多种,对 ...

  3. win32 listctrl控件右键菜单的实现

    HMENU Menu_list,Menu_all; POINT point; HINSTANCE hInstance;//下面代码放到BOOL WINAPI DialogProc下 case WM_C ...

  4. VS编程,编辑WPF过程中,点击设计器中界面某一控件,在XAML中高亮突出显示相应的控件代码的设置方法。

    原文:VS编程,编辑WPF过程中,点击设计器中界面某一控件,在XAML中高亮突出显示相应的控件代码的设置方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net ...

  5. asp.net中遍历界面上所有控件进行属性设置

    * 使用方法: *  前台页面调用方法,重置:    protected void Reset_Click(object sender, EventArgs e)        {           ...

  6. 不在界面上用控件 动态创建idhttp,IdAntiFreeze来用

    不在界面上用控件 动态创建idhttp,IdAntiFreeze来用 var IdHTTP: Tidhttp; IdAntiFreeze: TidAntiFreeze; begin IdAntiFre ...

  7. FoxOne---一个快速高效的BS框架--WEB控件属性编辑器

    FoxOne---一个快速高效的BS框架--(1) FoxOne---一个快速高效的BS框架--(2) FoxOne---一个快速高效的BS框架--(3) FoxOne---一个快速高效的BS框架-- ...

  8. Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件

    前言: 忙完了结婚乐APP的开发,终于可以花一定的时间放在博客上了.好了,废话不多说,今天我们要带来的效果是苹果版本的QQ下拉刷新.首先看一下目标效果以及demo效果:      因为此效果实现的步骤 ...

  9. .NET Framework的属性类对控件的支持功能

     ToolBoxItem 此属性为类特性.属于工具箱属性,可以设置当前控件是否在工具箱中显示,以及所在工具箱项的类型名称等信息.默认生成的控件都显示在工具箱中. 更多设计时属性介绍: 4.3 属性的 ...

随机推荐

  1. A总结

    Alpha 答辩总结 评审表 组名 格式 内容 ppt 演讲 答辩 总计 天机组 15 15 14 15 14 73 PMS 16 16 15 15 16 78 日不落战队 16 16 16 15 1 ...

  2. Alpha版本事后诸葛亮

    目录 设想和目标 计划 资源 变更管理 设计/实现 测试/发布 团队的角色,管理,合作 总结: 本小组和其他组的评分 分工和贡献分 全组讨论的照片 问题 第一组提问回答:爸爸饿了队 第二组提问回答:拖 ...

  3. 2013长春网赛 1006 hdu 4764 Stone(巴什博弈)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4764 题意:Tang 和 Jiang 玩一个游戏,轮流写下一个数,Tang先手,第一次Tang只能写[ ...

  4. 索引器 C#

    概述 索引器允许类或结构的实例就像数组一样进行索引. 索引器类似于属性,不同之处在于它们的访问器采用参数. 在下面的示例中,定义了一个泛型类,并为其提供了简单的 get 和 set 访问器方法(作为分 ...

  5. AOP 如果被代理对象的方法设置了参数 而代理对象的前置方法没有设置参数 则无法拦截到

    AOP 如果被代理对象的方法设置了参数 而代理对象的前置方法没有设置参数 则无法拦截到

  6. 知识点【JavaScript模块化】

    JavaScript模块化历程 JavaScript发展变迁大概是一下几个步骤: 工具(浏览器兼容) 组件(功能模块) 框架(功能模块组织) 应用(业务模块组织) 但是经过了长长的后天努力过程Java ...

  7. Codeforces914G Sum the Fibonacci(FWT)

    FWT大杂烩.跟着模拟做很多次FWT即可. #include<iostream> #include<cstdio> #include<cmath> #include ...

  8. Antenna Placement POJ - 3020 (最小边集覆盖)

    Antenna Placement Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10699   Accepted: 526 ...

  9. 学习Spring Boot:(十二)Mybatis 中自定义枚举转换器

    前言 在 Spring Boot 中使用 Mybatis 中遇到了字段为枚举类型,数据库存储的是枚举的值,发现它不能自动装载. 解决 内置枚举转换器 MyBatis内置了两个枚举转换器分别是:org. ...

  10. dwr网上使用例子

    转: dwr实现聊天室功能 2016年01月15日 10:22:43 我爱喝可乐 阅读数:564   用dwr的comet(推)来实现简单的无刷新多人聊天室,comet是长连接的一种.通常我们要实现无 ...