duilib教程之duilib入门简明教程15.自绘控件
在【2013 duilib入门简明教程 -- 复杂控件介绍 (13)】中虽然介绍了界面设计器上的所有控件,但是还有一些控件并没有被放到界面设计器上,还有一些常用控件duilib并没有提供(比如菜单控件)。虽然duilib没有提供这些控件,但是自己绘制起来也是非常方便的,不过duilib的自绘可比MFC方便得不止一点点了,其实duilib的自绘大都不用自己绘制,就是一些控件和图片的组合而已,相当简单方便~~~
一、菜单控件
其实菜单控件的外观和ListBox非常像,所以我们可以用教程13的ListBox控件模拟,也可以自行用其他的组合,由于duilib自带的Demo里有两个Menu,而且样式还很不错,所以Alberl就拿来用了,不过那几个Demo同样是复杂得要命,还记得教程13中的ListCtrl使用起来多么简单吗?如果不觉得它简单,那么再对比一下duilib自带的ListDemo,就能感觉到它的简单啦~O(∩_∩)O~
相信看过duilib自带的MenuDemo以及ListDemo里面的菜单,都不会觉得菜单很简单吧,那么来看看下面这个菜单的实现吧~O(∩_∩)O~
1、新建一个menu.xml,如下:
- <?xml version="1.0" encoding="utf-8"?>
- <Window size="120,82">
- <VerticalLayout bkimage="file='Menu/menu_bk.png' corner='40,8,8,8'" hole="false">
- <List header="hidden" inset="8,8,8,8" itemhotimage="file='Menu/menu_hot_bk.png' corner='2,2,2,2'">
- <ListContainerElement name="menu_Open" height="22" inset="40,0,0,0">
- <Label text="打开" mouse="false"/>
- </ListContainerElement>
- <ListContainerElement name="menu_Mark" height="22" inset="40,0,0,0">
- <Label text="标注" mouse="false"/>
- </ListContainerElement>
- <ListContainerElement name="menu_Delete" height="22" inset="40,0,0,0">
- <Label text="删除" mouse="false"/>
- </ListContainerElement>
- </List>
- </VerticalLayout>
- </Window>
复制代码
可以看到Menu其实就是一个List和图片组合的,当然,亲们也可以用教程13中的ListBox来替换上述内容,只不过需要自己调整一下。这里非常感谢提供MenuDemo的大神,菜单样式非常漂亮~O(∩_∩)O~
2、新建一个DuiMenu.h,如下(为了方便演示,将cpp的代码都放到了.h里,并且减少了空行,在最后的教程里,会有一个完整的工程下载):
- #pragma once
- // 此处需要包含duilib的头文件#include <UIlib.h>那一段,详细代码请见前面教程
- class CDuiMenu : public WindowImplBase
- {
- protected:
- virtual ~CDuiMenu(){}; // 私有化析构函数,这样此对象只能通过new来生成,而不能直接定义变量。就保证了delete this不会出错
- CDuiString m_strXMLPath;
- public:
- explicit CDuiMenu(LPCTSTR pszXMLPath): m_strXMLPath(pszXMLPath){}
- virtual LPCTSTR GetWindowClassName()const{ return _T("CDuiMenu "); }
- virtual CDuiString GetSkinFolder() { return _T(""); }
- virtual CDuiString GetSkinFile() { return m_strXMLPath; }
- virtual void OnFinalMessage(HWND hWnd){ delete this; }
- virtual LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- Close();
- bHandled = FALSE;
- return 0;
- }
- void Init(HWND hWndParent, POINT ptPos)
- {
- Create(hWndParent, _T("MenuWnd"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);
- ::ClientToScreen(hWndParent, &ptPos);
- ::SetWindowPos(*this, NULL, ptPos.x, ptPos.y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
- }
- virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- LRESULT lRes = 0;
- BOOL bHandled = TRUE;
- switch( uMsg )
- {
- case WM_KILLFOCUS:
- lRes = OnKillFocus(uMsg, wParam, lParam, bHandled);
- break;
- default:
- bHandled = FALSE;
- }
- if(bHandled || m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes))
- {
- return lRes;
- }
- return __super::HandleMessage(uMsg, wParam, lParam);
- }
- };
复制代码
3、此时一个菜单控件的所有代码就完成啦,下面接下来要显示菜单控件,我们模仿MFC的方式,即点击一个菜单按钮后,弹出菜单项~
显然第一步需要添加一个菜单按钮,XML如下:
- <Button name="btnMenu" text="选项" float="true" pos="475,28,0,0" width="37" height="19" align="center" normalimage="" hotimage="Menu/btn_menu_hot.png" pushedimage="Menu/btn_menu_hot.png" focusedimage="Menu/btn_menu_hot.png" textcolor="#FF000000" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" focusedtextcolor="#FFFFFFFF" bkcolor="#FFECE9D8" />
复制代码
第二步就是响应菜单按钮的点击,在主窗口的Notify函数里添加以下代码:
- if( msg.sType == _T("click") )
- {
- if( msg.pSender->GetName() == _T("btnMenu") )
- {
- POINT pt = {msg.ptMouse.x, msg.ptMouse.y};
- CDuiMenu *pMenu = new CDuiMenu(_T("Menu/menu.xml"));
- pMenu->Init(*this, pt);
- pMenu->ShowWindow(TRUE);
- }
- }
复制代码
还有最重要的一步就是把图片资源解压到exe目录啦,下载资源猛戳这里~
2013 duilib入门简明教程 整个工程(含资源、代码).7z (216.45 KB, 下载次数: 97) (注意:此处已给出所有的资源和代码,后面的教程将不再重复提供资源下载)
好啦,菜单按钮是不是和MFC的很像呢,还有阴影哦~O(∩_∩)O~
(更丰富的菜单样式请参阅duilib自带的MenuDemo)
![]()
【菜单类小知识】
如果不用指针的方式,而直接用变量的方式显示菜单 CDuiMenu menu(_T("Menu/menu.xml")),则不能用ShowWindow,否则会崩溃,因为出了作用域后窗口被销毁了,所以此时可以将CDuiMenu 定义为成员变量、全局变量、或者静态变量,但是做为一个局部使用的类,这些方法显然不怎么好;
这时可以用ShowModal代替ShowWindow,于是就能看到窗口啦,但是却产生了一个问题,那就是菜单窗口不会失去焦点,或者说点击主窗口的其他区域,菜单不会消失,当然,小伙伴们可以自己捕获鼠标,来判断是否点击了主窗口的其他区域,但显然这种方法也不太好;
这个时候delete this就派上用场啦(用智能指针也会崩溃,因为出了作用域同样会销毁内存,所以只能用delete this啦~ 用delete this就是将作用域交给duilib了),据说COM里面就是用delete this来销毁内存的。Alberl在duilib的Demo里面见到了大量的delete this,觉得这种自杀的方法很不靠谱,这不,前面教程就提到了ActiveX的一个bug,也是和delete this脱不了干系的~ 不过既然COM里面都用了delete this,那就说明如果用好这把双刃剑,还是可以带来很多好处的。
因为duilib提供了一个机制,就是窗口的最后一个函数一定是OnFinalMessage,之后不再调用窗口类的其他函数,这就为自杀提供了两个必要条件;delete this而还有一个必要条件就是这个类必须是通过new来申请内存的(而非 "new[]",亦非placement的"new" ,一定要是最原始的 "new",当然malloc也行(需要用free,而不是delete)),所以就将析构函数设置成私有函数,就保证了只有通过new申请内存的方式才能编译通过。 而duilib的Demo中大量使用delete this却没有保证这些必要条件,只要直接用变量的方式来声明类,则关闭窗口时就会崩溃,作为Demo,如此不严谨,有待好好规范。 当然,没有XX党,就没有新中国,没有那些大神的Demo,也就轮不到Alberl唧唧歪歪啦,这里Alberl只是觉得Demo应该严谨和权威,毕竟是官方的,并没有其他意思,请多多谅解~O(∩_∩)O~
二、组合框控件
由于duilib也没有自带GroupBox,所以我们一般采用的是Label + Control的组合,迅雷、百度、金山快盘、华为网盘这些都是这种组合,如图:
这个就不用代码了吧,左边的Label 设置文字颜色,右边的Control设置背景色,高度设置为1就好了。
三、复选框、单选框
duilib的TestApp1中有几个CheckBox,不过也是需要图片资源的,因为图中的方框就是图片模拟的,代码也很简单,后面的教程会有详细的代码~
![]()
四、时间选择控件
这个也很简单,代码如下:
- <DateTime name="DateTimeDemo1" float="true" pos="30,118,0,0" width="120" height="30" bkcolor="#FFE2E5EA" padding="0,5,0,0" />
复制代码
![]()
五、RichList、树形控件
经过前面教程详细的介绍,相信现在已经基本入门了,由于Alberl暂时也没看这些控件,所以请自行参阅duilib自带的Demo。
RichList请参阅duilib自带的RichListDemo,效果如图:![]()
Tree控件请参阅 (QQDemo、GameDemo,TestApp1),效果如图:
duilib的控件就基本介绍完啦,其他控件也请自行参阅~O(∩_∩)O~
duilib教程之duilib入门简明教程15.自绘控件的更多相关文章
- duilib教程之duilib入门简明教程17.事件处理和消息响应
界面的显示方面就都讲完啦,下面来介绍下控件的响应. 前面的教程只讲了按钮和Tab的响应,即在Notify函数里处理.其实duilib还提供了另外一种响应的方法,即消息映射DUI_BEGIN_ME ...
- duilib教程之duilib入门简明教程14.部分bug 2
上一个教程中提到了ActiveX的Bug,即如果主窗口直接用变量生成,则关闭窗口时会产生崩溃 如果用new的方式生成,则不会崩溃,所以给出一个临时的快速解决方案,即主窗口都用new生成,_t ...
- duilib教程之duilib入门简明教程13.复杂控件介绍
首先将本节要介绍的控件全部拖到界面上,并调整好位置,如图: 然后将Name属性改成其他名字, 不能是[控件名+UI+数字]这种,因为这是DuiDesigner默认的名字,它不会实际写 ...
- duilib教程之duilib入门简明教程11.部分bug
一.WindowImplBase的bug 在第8个教程[2013 duilib入门简明教程 -- 完整的自绘标题栏(8)]中,可以发现窗口最大化之后有两个问题, 1.最大化按钮的样式还是没 ...
- duilib教程之duilib入门简明教程3.第一个程序 Hello World
小伙伴们有点迫不及待了么,来看一看Hello World吧:新建一个空的win32项目,新建一个main.cpp文件,将以下代码复制进去: #include <windows.h> #in ...
- duilib教程之duilib入门简明教程9.界面布局
上一个教程实现的标题栏代码中,并没有看到处理自适应窗口大小的代码,但是窗口大小变化后,按钮的位置会跟着变化,这是因为我们将按钮放到了HorizontalLayout.VerticalLayout,这样 ...
- duilib教程之duilib入门简明教程2.VS环境配置
既然是入门教程,那当然得基础点,因为搜索duilib相关资料时,发现有些小伙伴到处都是编译错误,以及路径配置错误等等,还有人不知道SVN,然后一个个文件手动下载的. 其实吧,duilib的定位好 ...
- duilib教程之duilib入门简明教程1.前言
关于duilib的介绍就不多讲了,一来不熟,二来小伙伴们想必已经对比了多个界面库,也无需赘述.下面进入正题: 不看广告看疗效! 已有众多知名公司采用duilib做为界面库,如华为网盘.PPS(P ...
- duilib教程之duilib入门简明教程16.结合win32和MFC
虽然duilib自带在MFC中使用duilib的Demo,但只是MFC窗口和duilib窗口不重叠的情况.如果要在MFC窗口中嵌入duilib控件,或者在duilib控件中嵌入MFC的控件的话,就没有 ...
随机推荐
- cross compile vlc 播放器
上一篇文章介绍了如何交叉编译 FFmpeg ,继续介绍 VLC播放器 交叉编译 . 首先下载 vlc 源码 我用的是 2.2.6 地址 : http://mirrors.neusoft.edu ...
- Window10 64bit Tomcat9 安装
最近正在做一个小项目,需要用到Tomcat部署java web. 准备: 1.window 10 64bit 2.jdk1.8.0_181(请自行安装,记得配置好JAVA_HOME) 3.tomcat ...
- DEV插件下的控件Grid和Gridlookupedit控件的结合使用
创建GridlookupEtid控件 设置其对应属性: 设置属性 this.gridLookUpEdit1.Properties.TextEditStyle = DevExpress.XtraEdit ...
- selenium+plantomJS
#!/usr/bin/env python # -*- coding:utf-8 -*- """ 流程框架: 1.搜索关键词,利用selenium驱动浏览器搜索关键词,查 ...
- 改变this 指向的3种方法
1.在函数内部声明一个that,然后将this赋值给that, var that=this; 最后用that 代替this使用 <!DOCTYPE html> <html lang= ...
- vue 学习三 v-model 表单绑定输入 以及修饰符的用处
v-model 指定使用过vue的同学都应该是很熟悉的了,这里就不多介绍,本章主要就是记录一些v-model非常实用的修饰符和对于v-model在html文本框,多行文本框,选择框,单选框,复选框上对 ...
- Java判断链表是否为回文链表
请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 思路:1.通过快慢指针,来遍历链表 ...
- quartz的使用(三)
1.在数据源数据库中执行下载的quartz的sql语句(创建11张表),其中表头qrtz_可以在在配置文件中更改,对应表创建时更改org.quartz.jobStore.tablePrefix=qrt ...
- 通过base64实现图片下载功能(基于vue)
1. 使用场景 当我们处理图片下载功能的时候,如果本地的图片,那么是可以通过canvas获得图片的base64的,方法如下.但是如果图片的url存在跨域问题的话,下面的方法将行不通,这时候我们可以另辟 ...
- bzoj1009题解
[解题思路] 先KMP出fail数组,再用fail数组求出M[i][j],表示上一次匹配到第i位,这次可以遇到多少种不同的字符,使之转而匹配到第j位. 设集合S=[1,m]∩N 又设f[i][j]表示 ...