作者:朱金灿
来源:http://blog.csdn.net/clever101/

现在我发现使用Visual Studio的资源编辑器进行编辑资源有着诸多的不便:首先是任何资源的变动一般变动代码,不利于系统维护,其次Visual Studio的资源编辑器的本身的功能有限,也不利于界面美化,三是不利于人员分工,开发人员既要忙实现功能,又要忙准备好的界面素材。对界面实现文件配置化正是解决上面问题的好方法。这次我实现了使用XML文件配置工具栏。这里所谓配置就是工具栏的界面信息如工具栏标题、按钮图片、是否为分隔符都在XML文件保存,程序通过解析XML文件来获取工具栏信息来创建工具栏。这样一旦发现界面不合适可以随时修改配置文件,同时利于人员分工。

具体的做法如下:

1. 在工程的输出目录下有一个SysConfig.xml,作为系统配置文件。其中关于工具栏的配置部分如下:

<AppToolbar valid="1" caption="基础工具"> <ToolButton file="Add.bmp" /> <ToolButton separator="true" /> <ToolButton file="Benchmark.bmp" /> <ToolButton file="Comment.bmp" /> <ToolButton file="Convert.bmp" /> <ToolButton file="Delete.bmp" /> <ToolButton file="Exit.bmp" /> </AppToolbar>

简单解释一下上面的节点意义:valid表示工具栏是否有效,caption表示工具栏标题,file节点为工具栏按钮所贴图片,separator表示按钮是分隔符。

2. 通过解析XML文件获取工具栏信息来创建工具栏。首先在CMainFrame类添加两个数据成员:

/** * /brief 工具栏对应的图像列表。 */ CImageList m_imgToobar; /** * /brief 系统配置文件解析器,具体看我上传的代码。 */ CXmlParse m_SysSetting;

然后实现如下函数:

/*! * /brief 获取exe所在的文件夹。 * * /param [in][out]strBinPath exe程序所在的文件夹。 * /return 无。 */ void CMainFrame::GetOutputPath(string &strBinPath) { TCHAR szModulePath[_MAX_PATH]; ::GetModuleFileName(NULL,szModulePath,_MAX_PATH); strBinPath = szModulePath; strBinPath = strBinPath.substr(0,strBinPath.rfind('//')+1); } /*! * /brief 解析系统配置文件,获取工具栏信息。 * * /param [in][out]MyToolbar 工具栏信息。 * /return 无。 */ void CMainFrame::ParseXml(ToolBar &MyToolbar) { string strBinPath; GetOutputPath(strBinPath); string strXmlPath = strBinPath + string(_T("SysConfig.xml")); m_SysSetting.OpenXml(strXmlPath); m_SysSetting.GetToolbarInfo(MyToolbar); } /*! * /brief 根据工具栏图片信息加载工具栏图像列表。 * * /param [in]MyToolbar 工具栏信息。 * /return 是否成功。true为成功,false表示失败。 */ BOOL CMainFrame::LoadImageList(ToolBar &MyToolbar) { // 获取按钮图片的个数 int nBmpNum = MyToolbar.m_MenuItemVec.size(); HBITMAP hBitmap = NULL; // 打开所有位图,将其加进图像列表 for(int i=0; i<nBmpNum; ++i) { if (MyToolbar.m_MenuItemVec[i].m_bIsSeparator) { continue; } string strBinPath; GetOutputPath(strBinPath); string strBmpPath = strBinPath + string(_T("Toolbar//")); strBmpPath = strBmpPath + MyToolbar.m_MenuItemVec[i].m_strBmpName; hBitmap = (HBITMAP)LoadImage(AfxGetResourceHandle(),strBmpPath.c_str(), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR|LR_LOADFROMFILE); if (NULL==hBitmap) { return FALSE; } CBitmap bmp; bmp.Attach(hBitmap); m_imgToobar.Add(&bmp, RGB(0, 0, 0)); bmp.DeleteObject(); } return TRUE; } /*! * /brief 设置工具栏按钮风格。 * * /param [in]MyToolbar 工具栏信息。 * /return 无。 */ BOOL CMainFrame::SetStyleToolbar(ToolBar &MyToolbar) { CToolBarCtrl& tbc = m_wndToolBar.GetToolBarCtrl(); // 删除之前的按钮 while(tbc.DeleteButton(0)); // 设置当前图像列表 tbc.SetImageList(&m_imgToobar); int i = 0; int nBtnNum = MyToolbar.m_MenuItemVec.size(); UINT nBtnID = SYS_COMMAND_BEGIN; int nImgIndex = 0; // 根据按钮属性逐个添加按钮 for(i=0; i<nBtnNum; ++i) { if (MyToolbar.m_MenuItemVec[i].m_bIsSeparator) { TBBUTTON tb = {-1,0,TBSTATE_ENABLED,TBSTYLE_SEP,0,0}; tbc.AddButtons(1, &tb); } else { TBBUTTON tb = {nImgIndex,nBtnID,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0}; tbc.AddButtons(1, &tb); nImgIndex++; nBtnID++; } } return TRUE; } int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; /* if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))*/ // 解析系统配置文件,获取位图信息 ToolBar AppToolbar; ParseXml(AppToolbar); if(!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD|WS_VISIBLE|CBRS_TOP |CBRS_GRIPPER|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC)) { TRACE0("未能创建工具栏/n"); return -1; // 未能创建 } m_wndToolBar.SetWindowText(AppToolbar.m_strCaption.c_str()); // 创建图像列表 m_imgToobar.Create(32, 32, ILC_COLOR32|ILC_MASK, 0, 0); if(LoadImageList(AppToolbar)) { // 添加工具栏按钮 SetStyleToolbar(AppToolbar); } // 设置工具栏按钮大小 m_wndToolBar.SetSizes(CSize(32+7, 32+6), CSize(32, 32)); if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("未能创建状态栏/n"); return -1; // 未能创建 } // TODO: 如果不需要工具栏可停靠,则删除这三行 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); return 0; }

为使工具栏处于有效状态,还得添加一个简单的消息处理函数,简单如下:

/*! * /brief 工具栏按钮响应事件。 * * /param [in]nID 工具栏按钮ID。 * /return 无。 */ void CMainFrame::OnButton(UINT nID) { switch (nID) { // SYS_COMMAND_BEGIN为工具栏按钮的起始ID值 case SYS_COMMAND_BEGIN: AfxMessageBox(_T("你单击的是第一个按钮")); break; case SYS_COMMAND_BEGIN+1: AfxMessageBox(_T("你单击的是第二个按钮")); break; case SYS_COMMAND_BEGIN+2: AfxMessageBox(_T("你单击的是第三个按钮")); break; case SYS_COMMAND_BEGIN+3: AfxMessageBox(_T("你单击的是第四个按钮")); break; case SYS_COMMAND_BEGIN+4: AfxMessageBox(_T("你单击的是第五个按钮")); break; case SYS_COMMAND_BEGIN+5: AfxMessageBox(_T("你单击的是第六个按钮")); break; default: break; } }

开发环境为Visual C++ 2005 + sp1,Win XP + sp3。程序效果图如下:

工程源码已上传到联合程序开发网,链接为:

源码下载 。

参考文献:

1. MFC实现 多风格真彩色大图标工具栏按钮 (感谢万连文大侠提供)

在MFC程序中使用XML文件配置工具栏相关推荐

  1. eclipse mysql Xml配置_mysql8.0在eclipse中通过xml文件配置数据库连接池

    mysql8.0在eclipse中通过xml文件配置数据库连接池 1.关于Mysql8.0 2.数据库连接池(DBCP) 3.准备工作 4.配置context.xml 5.配置web.xml 6.调用 ...

  2. Web应用中wen.xml文件配置

    构建Web应用 手动建立一个web应用 1.任意目录建立demo文件夹,用于建立一个web应用 2.文件夹中建立一个WEB-INF文件夹(区分大小写) 3.在WEB-INF中建立web.xml文件,并 ...

  3. AndroidManifest.xml文件配置教程及相关指令详解

    AndroidManifest.xml 是每个android程序中必须的文件,它位于整个项目的根目录.我们每天都在使用这个文件,往里面配置程序运行所必要的组件,权限,以及一些相关信息.但是对于这个文件 ...

  4. rf中resourceid_解决VC++ MFC程序resource.h头文件中ID重复问题

    解决VC++ MFC程序resource.h头文件中ID重复问题 2018-12-07 一般MFC开发的时候,如果有些资源是从其他工程中移植到本工程的, 而在资源移植的时候都要将对应的资源ID复制到本 ...

  5. Java 中JAF、CORBA、JTA、JAXB、JAX-WS使用Maven的pom.xml文件配置

    本文主要介绍Java EE中已经弃用的模块,需要单独引用JAF(java.activation).CORBA(java.corba).JTA(java.transaction).JAXB(java.x ...

  6. 在MFC程序中增加控制台窗口

    MFC程序中,如果想要输出调试信息,我们一般都是TRACE或者使用LOG文件,都不是很方便,第一个需要我们在调试状态下,第二个也要配置麻烦而且不直观.而使用Console来显示调试信息应该是更好的选择 ...

  7. java spring bean配置文件_Spring基于xml文件配置Bean过程详解

    这篇文章主要介绍了spring基于xml文件配置Bean过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 通过全类名来配置: class:be ...

  8. Logback.xml 文件    配置

    2019独角兽企业重金招聘Python工程师标准>>> Logback.xml 文件    配置 <?xml version="1.0" encoding= ...

  9. 修改Android中strings.xml文件, 动态改变数据

    有些朋友可能会动态的修改Android中strings.xml文件中的值,在这里给大家推荐一种简单的方法. strings.xml中节点是支持占位符的,如下所示: <string name=&q ...

  10. mfc 内嵌 本地html,MFC程序中内嵌网页,附示例工程

    最近在课程设计,因为小悠太懒了,是在不想用C++完成一些简单的文件上传下载操作,于是就想着将网页内嵌到程序中,上传下载神马的就直接使用网页Web来完成就好了,本示例中将演示在MFC程序中内嵌一个htm ...

最新文章

  1. .net webapi 接收参数_FastReport.Net报表设计器如何连接到SQLCe
  2. [android网络有效性检测] NetworkMonitor代码造成内存泄漏
  3. abap 添加alv上的工具栏的按钮_Excel里的置顶功能——快速访问工具栏
  4. 文字创作类App分享-简书
  5. AINLP-Archive:AINLP文章存档计划
  6. Nature长文:打破AI黑盒的“持久战”
  7. 用reposync 同步YUM源到本地,搭建本地YUM源服务器
  8. 一行 Python 代码能实现这么多丧心病狂的功能?
  9. 微软sql服务器可以卸载,完美卸载SQL Server 2008的方法
  10. java获取大写字母_获取中文大写首字母java实现
  11. 介绍5款非常棒的移动自动化测试工具
  12. ES6JS笔记以及部分运行问题记录
  13. U8固定资产最重要的数据表
  14. 【成像】【4】产生连续波Terahertz辐射
  15. 重磅 | 揭秘IARPA项目:解码大脑算法或将彻底改变机器学习
  16. 桂电计算机系入学怎么分班,桂电研究生-()学期课程总表
  17. 业务开发平台与SOA的统一论
  18. 回调函数基本介绍和基本使用场景
  19. 100个相见恨晚的Python库
  20. iphone12android在线,【苹果iPhone12评测】安卓机吃尽高刷红利,为何iPhone 12还是缺席?(全文)_苹果 iPhone 12_手机评测-中关村在线...

热门文章

  1. MessagingTimeout: Timed out waiting for a reply to message ID
  2. Aho-Corasic多模匹配算法的学习、理解和应用(Python环境下)
  3. Ubuntu 20.04安装字体
  4. undefined和null区别
  5. oracle报1653解决办法,oracle 建立查询账号ORA 1653和ORA 01502错误处理方法
  6. 洛谷:P1653 猴子(图存储、逆向思维 删边 -->加边)
  7. android 解析rss,在Android中解析RSS源
  8. 新一代三维GIS技术资料集锦
  9. 戴尔服务器bios设置u盘启动不了系统,戴尔电脑主板bios设置u盘启动不了怎么办...
  10. 气不足则胖,血不足则瘦