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. 第一个spring,第五天。

    陈志棚:界面跳转与框架 李天麟:游戏界面ui 徐侃:算法代码的设计 经过五天的时间,经过队员的汇报,我们初步已经完成了各项的任务.

  2. 《当大数据遇见网络:大数据与SDN》

    总体结构: <当大数据遇见网络:大数据与SDN> 摘要 大数据和SDN无论是对于学术界还是工业界来说都极具吸引力.传统上人们都是分别在最前沿工作中研究这两个重要的领域.然而一方面,SDN的 ...

  3. PAT 甲级 1078 Hashing

    https://pintia.cn/problem-sets/994805342720868352/problems/994805389634158592 The task of this probl ...

  4. 删除或添加最大化、最小化按钮 - 回复 "Tommy the CAT" 的问题

    本例效果图: 代码文件: unit Unit1; interface uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, ...

  5. java学习之switch 等值判断

    当匹配到相等的值时候 则进入case里面执行语句 当该语句有break时候 则退出匹配 当没有break时候 则继续往下匹配 直到遇到break才停止匹配

  6. SSM 项目搭建 (IDEA)

    好好想了想,还是准备给大家发一个简单的SSM的项目搭建教程. 我觉得通常来说,只是XML的配置文件可能让人头痛了点,其他的倒真不是问题. 不过话说回来,mybatis一直让我觉得用起来不方便.因为数据 ...

  7. Racket里的方括号

    Racket里的方括号 Racket编程指南 https://blog.csdn.net/chinazhangyong/article/category/7386082 来自于QQ群racket!(  ...

  8. Problem C Dist 解题报告

    Problem C Dist Description 有一个\(n\)个点带边权的连通无向图,边集用\(k\)个集合\(s_1,s_2,\dots,s_k\)和\(k\)个整数\(w_1,w_2,\d ...

  9. 洛谷P3928 Sequence2(dp,线段树)

    题目链接: 洛谷 题目大意在描述底下有.此处不赘述. 明显是个类似于LIS的dp. 令 $dp[i][j]$ 表示: $j=1$ 时表示已经处理了 $i$ 个数,上一个选的数来自序列 $A[0]$ 的 ...

  10. JavaScript -- 标签 , Break 和 Continue 语句

    break 语句用于跳出循环. continue 用于跳过循环中的一个迭代. 标签引用,break 语句可用于跳出任何 JavaScript 代码块. demo: <!DOCTYPE html& ...