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源码分析之&lt;context:component-scan/&gt;vs&lt;annotation-config/&gt;

    1.<context:annotation-config/> xsd中说明: <xsd:element name="annotation-config"> ...

  2. 【二分】POJ 2109

    谁骗我这是贪心TT 大概就是求k的n次方等于p时的k(k到10^9),由于,p的数据到了10^101,n到200,所以直接算估计T ?? 反正看完想到二分,其实数据要是再大点估计我这个二分不行. 网上 ...

  3. JS中的this对象详解

    JS中this关键字很常见,但是它似乎变幻莫测,让人抓狂.这篇文章就来揭示其中的奥秘. 借助阮一峰老师的话:它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用.这句话看似平常,可是要非常注意 ...

  4. 如何写好CSS?(OOCSS\DRY\SMACSS)

    我现在面对的CSS基本上就是一个三头六臂的怪物,一点不夸张,因为真的是三头六臂,同一个样式在同一个element上作用了好几遍,而同一个样式又分散在4,5个class上,优先级有很多层.可以看得出这个 ...

  5. 编程异常——假设你报createSQLQuery is not valid without active transaction,...

    非常多时候我们使用hibernate的session时,都是让session在某一执行环境中保持其唯一. 比如在同一线程内用同一个session.在同一方法内用同一session,这样我们就能够用se ...

  6. MySQL查询优化--细节理论

    select的 high_priority还是比较有用,在实践中,平均5~6秒提高到3秒 ======================================================= ...

  7. Excel文件数据保存到SQL中

    1.获取DataTable /// <summary> /// 查询Excel文件中的数据 /// </summary> /// <param name="st ...

  8. msf

    show exploit show payload msf使用数据库加快搜索,不然每次都等半天 service postgresql startmsfdb reinitmsf > db_rebu ...

  9. Vue-admin工作整理(二):项目结构个人配置

    通过上一篇文章(Vue-admin工作整理(一):项目搭建)操作完毕后,基础项目已经搭建,下面就要对项目本身进行一下项目结构调整来符合自己的项目要求 1.首先要对package.json文件进行调整, ...

  10. SQLAchemy基础知识

    一.什么是SQLAchemy? SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据 ...