zoukankan      html  css  js  c++  java
  • MFC小型工具通用界面框架CLIST控件+右键菜单功能

    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
    
  • 相关阅读:
    LNMP编译
    数据库(二)tab补全功能,使数据库支持简体中文,日志管理,备份脚本
    MySQL数据库(一)编译安装、安装后优化操作及超户忘记数据库密码的解决方法
    awk简题
    NFS
    WCF 传递数据量大时的报错处理
    Windows服务工程创建、部署
    反射创建BLL层控制器
    php yii环境简易配置
    php 搭建mvc框架
  • 原文地址:https://www.cnblogs.com/17bdw/p/10238922.html
Copyright © 2011-2022 走看看