博瑞博客

青春是一个充满活力的季节,即便是我们失去了天使的翅膀,只要我们还有一颗青春的心,那么我们的生活依然能够如阳光般灿烂!......
推荐阅读站长精心推荐阅读
现在位置:首页 >
  • GetWindowThreadProcessId

    GetWindowThreadProcessId

    C/C++  8-8  1070浏览  0评论  

    GetWindowThreadProcessId,找出某个窗口的创建者(线程或进程),返回创建者的标志符。

  • OpenProcess

    OpenProcess

    C/C++  8-8  981浏览  0评论  

    方法名称:OpenProcess 位置:Kernel32.dll OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄。 1.函数原型 HANDLE OpenProcess( DWORD dwDesiredAccess, //渴望得到的访问权限(标志) BOOL bInheritHandle, // 是否继承句柄 DWORD dwProcessId// 进程标示符 );

  • C++中的类模板详解及示例

    C++中的类模板详解及示例

    C/C++  4-12  840浏览  0评论  

    我们在定义函数时,可以通过定义函数模板,来简化一些功能相同而数据类型不同的函数的定义和调用过程

  • 如何正确创建DLL和使用DLL

    如何正确创建DLL和使用DLL

    C/C++  4-11  775浏览  0评论  

    本文将通过一个简单的实例来说明,如何正确的导出DLL中的类、对象、函数,并如何通过静态加载或动态加载的方式来使用DLL。   一、DLL中导出类、函数、对象   1. 创建一个空的Win32 Dynamic-Link Library项目Test   2. 在项目中添加一个Test.h头文件,该文件的内容如下:   //导出类   class __declspec(dllexport) CTest   {   ...   };   //导出函数   __declspec(dllexport) void FuncTest();   //导出对象   extern __declspec(dllexport) CTest  ObjTest;   这段代码中通过__declspec(dllexport)导出了类CTest、函数FuncTest和对象ObjTest。在.cpp文件中实现上面的声明与类的定义后,经编译就可以生成一个.dll和.lib文件了。   二、静态加载DLL   1. 新建一个Win32 项目。   2. 将上面编译生成的.lib文件复制到,该项目下。   3. 在项目中添加一个Test.h(通过该文件实现对DLL的静态加载),该.h文件的内容主要是从DLL的.h文件中复制过来。具体内容如下:   #pragma comment(lib, "test.lib")   //导入类   class __declspec(dllimport) CTest   ...{   ...   };   //导入函数   __declspec(dllimport) void FuncTest();   //导入对象   extern __declspec(dllimport) CTest  ObjTest;   这个.h文件与dll的.h的不同就是,在开头加了#pragma comment(lib, "test.lib"),以及类、函数、对象前面的__declspec(dllexport)变成了__declspec(dllimport) 。通过这些修改就可以告诉编译器,这个.h文件中定义的类、声明的函数和对象 都是从test.dll中导入的。在项目中完成对这些类、函数、对象的调用代码后,就可以将其编译成可执行文件。将生成的可执行为文件、以及上面生成的.dll文件复制到同一个文件夹中就可以正常运行这个可执行文件。   三、动态加载DLL   如果上面的DLL需要被动态调用,这需在DLL的代码中添加一个 .def文件,在该文件中指出哪些被导出的函数和对象是可以动态调用的。根据上面的例子.def文件的内容如下:   LIBRARY    TestImp   EXPORTS   ObjTest   FuncTest   在完成.def文件后,重新编译dll。重新编译dll后就可以对该Dll进行动态调用了,调用过程的代码如下:   typedef void (*HFUNC)()   HINSTANCE hDLL = LoadLibrary("Test.dll");             //加载DLL   if(hDLL)   {   HFUNC hFun = (HFUNC)GetProcAddress(hDLL, "FuncTest");       //获得Dll中FuncTest函数的指针。   if (hFun)   hFun();    //执行函数FuncTest   else   ...            //没有找到函数FuncTest   }   else   {   //加载失败   }   上面的代码实现的对DLL中函数的动态调用,在代码中通过LoadLibrary将DLL加载到内存中,然后GetProcAddress获得指定函数所在的内存地址(即该函数的函数指针),获得指向这个函数的指针后就可以对它进行调用了。   对于DLL中对象的动态调用过程基本上是一样的,先将DLL加载到内存,然后通过GetProcAddress获得对象所在的地址。   从上面可以看出,DLL的动态调用过程就是将DLL加载到内存,然后通过GetProcAddress获得DLL中指定对象或函数在该内存中的地 址,通过该地址就可以对函数或对象进行调用。由于在C++中没有类的对象,也没有类指针一说,所以是无法动态使用DLL中的类的(如果谁知道如何使用可以 告诉我)。

  • google 打不开

    google 打不开

    Windows  4-7  1098浏览  0评论  

    在c:\windows\system32\drivers\etc\hosts文件后面添加以下内容: 91.213.30.151 www.google.com 91.213.30.151 google.com 74.125.20.31 www.google.com.hk 74.125.20.31 accounts.google.com 74.125.20.31 accounts.l.google.com 74.125.20.31 google.com 74.125.20.31 www.google.com 74.125.20.31 csi.gstatic.com 74.125.20.31 ssl.gstatic.com 74.125.20.31 ssl.google-analytics.com 74.125.20.31 www.google-analytics.com7 74.125.20.31 scholar.google.com 74.125.20.31 safebrowsing.google.com 74.125.20.31 gmail.com 74.125.20.31 mail.google.com 74.125.20.31 play.google.com 74.125.20.31 news.google.com 74.125.20.31 plus.google.com 74.125.20.31 code.google.com 74.125.20.31 tools.google.com 74.125.20.31 productforums.google.com 74.125.20.31 translate.google.com 74.125.20.31 chrome.google.com 74.125.20.31 youtube.com 74.125.20.31 www.youtube.com3 74.125.20.31 talk.google.com 74.125.20.31 talkgadget.google.com 74.125.20.31 apis.google.com 74.125.20.31 clients1.google.com 74.125.20.31 clients2.google.com 74.125.20.31 clients3.google.com 74.125.20.31 clients4.google.com 74.125.20.31 clients5.google.com 74.125.20.31 clients6.google.com 74.125.20.31 clients7.google.com 74.125.20.31 googleusercontent.com 74.125.20.31 lh1.googleusercontent.com 74.125.20.31 lh2.googleusercontent.com 74.125.20.31 lh3.googleusercontent.com 74.125.20.31 lh4.googleusercontent.com 74.125.20.31 lh5.googleusercontent.com 74.125.20.31 lh6.googleusercontent.com 74.125.20.31 lh7.googleusercontent.com 74.125.20.31 local.google.com 74.125.20.31 m.google.com 74.125.20.31 map.google.com 74.125.20.31 maps.google.com 74.125.20.31 maps.google.com.hk 74.125.20.31 maps.l.google.com 74.125.20.31 maps-api-ssl.google.com 74.125.20.31 maps.gstatic.com 74.125.20.31 maps.googleapis.com 74.125.20.31 gmaps-samples-flash.googlecode.com 74.125.20.31 earth.google.com 74.125.20.31 earth-api-samples.googlecode.com 74.125.20.31 earthengine.googlelabs.com  

  • duilib DirectUI库里面的一个简单的例子RichListDemo

    duilib DirectUI库里面的一个简单的例子RichListDemo

    C/C++  4-7  965浏览  0评论  

    1、首先来看这里的CRichListWnd 已经不再是从CWindowWnd继承了 classCRichListWnd:publicWindowImplBase 从WindowImplBase中,可以看到有三个抽象函数: virtualCDuiStringGetSkinFolder()=0; virtualCDuiStringGetSkinFile()=0; virtualLPCTSTRGetWindowClassName(void)const=0; 这些都很简单,只是返回固定的string   2、看看WindowImplBase class UILIB_API WindowImplBase : public CWindowWnd , public CNotifyPump , public INotifyUI , public IMessageFilterUI , public IDialogBuilderCallback { …… } 这个类其实也是实现了CWindowWnd、INotifyUI,即一个窗体和消息,所以他含有virtualvoidNotify(TNotifyUI&msg); 但是这里又继承了CNotifyPump,所以这里的Notify可以这么实现:   void WindowImplBase::Notify(TNotifyUI& msg) { return CNotifyPump::NotifyPump(msg); } NotifyPump主要是遍历所有的虚拟窗口把消息传递出去 下面的代码列出了CRichListWnd比较重要的函数:   class CRichListWnd : public WindowImplBase { public: virtual void OnFinalMessage( HWND ); virtual void Notify( TNotifyUI &msg ); virtual LRESULT OnMouseWheel( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); virtual LRESULT OnSysCommand( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ); virtual void InitWindow(); virtual LRESULT OnMouseHover( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ); virtual LRESULT OnChar( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ); DUI_DECLARE_MESSAGE_MAP() virtual void OnClick(TNotifyUI& msg); virtual void OnSelectChanged( TNotifyUI &msg ); virtual void OnItemClick( TNotifyUI &msg ); }; 因为WindowImplBase类实现了CWindowWnd中的HandleMessage,所以我们如果需要把一些重要的消息事件给重写就行; 可以看到WindowImplBase中的OnCreate(): LRESULT WindowImplBase::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { …… InitWindow(); return 0; } 所以我们需要把InitWindow给重写了 在InitWindow给每一个控件和XML的控件属性对应起来: // 初始化的事件 void CRichListWnd::InitWindow() { m_pCloseBtn = static_cast<CButtonUI*>(m_PaintManager.FindControl(_T("closebtn"))); m_pMaxBtn = static_cast<CButtonUI*>(m_PaintManager.FindControl(_T("maxbtn"))); m_pRestoreBtn = static_cast<CButtonUI*>(m_PaintManager.FindControl(_T("restorebtn"))); m_pMinBtn = static_cast<CButtonUI*>(m_PaintManager.FindControl(_T("minbtn"))); } 这就完成了初始化,窗口也就起来了 这个Demo中,是使用到了虚拟页的,也就是CPage1,如果不使用,他的消息会回到CRichListWnd中被处理,但是如果CPage1中处理了消息,CRichListWnd就不做处理了 我们来看看CPage1所要处理的消息:   同样的CRichListWnd消息   当页面发生OnClick或者OnItemClick时候,已经挂上了虚拟页CPage1,那么CRichListWnd消息的就失效了 3、关于虚拟页CPage的 这样挂上虚拟页的: CRichListWnd::CRichListWnd(void) { m_Page1.SetPaintMagager(&m_PaintManager); AddVirtualWnd(_T("page1"),&m_Page1); } CRichListWnd::~CRichListWnd(void) { RemoveVirtualWnd(_T("page1")); } 看到这里有个宏(因为继承了CNotifyPump都可以这样用): DUI_BEGIN_MESSAGE_MAP(CPage1, CNotifyPump) DUI_ON_MSGTYPE(DUI_MSGTYPE_CLICK, OnClick) DUI_ON_MSGTYPE(DUI_MSGTYPE_SELECTCHANGED, OnSelectChanged) DUI_ON_MSGTYPE(DUI_MSGTYPE_ITEMCLICK, OnItemClick) DUI_END_MESSAGE_MAP() 这是整个消息映射的,表面我们关心这几个消息函数,同样的还可以在UIDefine.h中找到其他的消息类型的事件 在void CPage1::OnItemClick( TNotifyUI &msg )中原来是没有代码的,需要手动把CRichListWnd的那部分粘上去(或者去掉挂上虚拟页的部分)   之后我们点击进度条的时候,这个函数才会执行   同样的把鼠标停留 在操作按钮上面会执行函数CRichListWnd::OnMouseHover   同样的这个demo的其他部分也就这么回事了                                              

  • DuiLib : 使用CListUI显示海量数据

    DuiLib : 使用CListUI显示海量数据

    C/C++  3-31  2247浏览  0评论  

    最近遇到要在一个DuiLib::CListUI中显示动态数据的子任务. 在使用我改版的DuiLib中发现如下问题, 真杯具. * 如果反复添加删除CListContainerElementUI, 会引起CListUI所在的Dialog退出时挂掉的问题.  e.g. 在CListUI中增加2000条数据, 在CListUI中删掉2000条数据, 如此反复20次.  再退出该CListUI所在的Dialog, UI就挂掉了. 现象是WM_PAINT陷入了一个循环(这个正常), 但是UI显示不出来了.  这个问题我回避了, 搞不定.  采用妥协的方法, 使CListUI只固定一个行数(e.g. 20行),  根据要显示的内容计算List的UI可见部分应该写什么数据.  这样, 只在建立ListUI时, 插入了新的行. 以后都是更新行上的内容. 就不存在退出时UI挂掉的问题. * 当CListUI一次添加太多数据时(e.g. 一次添加2000行), 当滚动时, List反应特别的迟钝, 有时还会导致UI卡死.  这个问题我同样回避了, 搞不定.  采用妥协的方法, 使CListUI只固定一个行数(e.g. 20行),  根据要显示的内容计算List的UI可见部分应该写什么数据.  这样, 只在建立ListUI时, 插入了新的行. 以后都是更新行上的内容. 就不存在滚动List自带竖向滚动条时, 引起的机率性UI卡死. 这个问题让我做了5天实验, 才想到折中的解决方法. 我采用的方法是: * 隐藏CListUI实例自带的竖向滚动条控件, 每次只显示一页的数据 * 在CListUI实例右边的Container中自己摆一个 CScrollBarUI, 用户点击滚动条时, 记录点击的位置, 发送自定义消息, 去刷新CListUI中的显示. 实验过了, 准备20W条数据, 在CListUI中显示, 也是蛮快的, 和数据多少无关, 花费的操作和显示时间都是常量. 这个折中的方法, 让我感到很欣慰. 备注: 数据的容器使用std::vector, 而不能是std::deque, 防止数据释放时, 时间太长. 20W条数据时, std::deque释放的不是一般的慢, 和构造数据的速度比较, 慢了100倍. 使用std::vector时, 构造数据和释放数据的时间是基本相同的. 在20W条数据的条件下做过实验了. 运行效果图:      

  • 动态加载CListUI

    动态加载CListUI

    C/C++  3-31  1328浏览  0评论  

      CListUI* pList = new CListUI; pList->SetTextCallback(this); CListHeaderUI* pHeader = pList->GetHeader(); CListHeaderItemUI* pHeaderItem = new CListHeaderItemUI; pHeaderItem->SetText(L"kdsjlakjfsdl"); pHeaderItem->SetBkColor(0xFFFFFFFF); pHeader->Add(pHeaderItem); pHeader->SetVisible(false); pList->SetFixedHeight(300); pList->SetAttribute(_T("vscrollbar"), _T("true")); pHorzLayout = new CHorizontalLayoutUI; pHorzLayout->Add(pList); pVertLayout->Add(pHorzLayout); //pHorzLayout->SetBkImage(strImage); //pHorzLayout->SetBkColor(0x00ff00); pList->SetBkImage(strImage); CLabelUI* pLabel; for (int i = 0; i < 100; ++i) { CListTextElementUI* pListElement = new CListTextElementUI; pList->Add(pListElement); }

  • duilib各种布局的作用,相对布局与绝对布局的的意义与用法

    duilib各种布局的作用,相对布局与绝对布局的的意义与用法

    C/C++  3-23  795浏览  0评论  

    转载请说明原出处,谢谢~~ http://blog.csdn.net/zhuhongshu/article/details/38531447       我使用duilib快3个月了,总体感觉duilib的使用还是较为简单的,只是刚入门时可能有些摸不清头脑。今天写一篇关于duilib的入门日志,大致说一下duilib中的各个布局的作用,以及很关键的相对布局与绝对布局的意义与用法。希望可以帮到使用duilib的新手朋友们。duilib高手就可以直接省略这篇文章了!      我刚使用duilib的时候非常依赖duilib自带的设计器,用他可以拖拉控件,可视化的做出自己想要的界面。可是用一段时间就会发现原带的设计器有很多bug,时不时会崩溃,支持的控件数量有限,属性数量也有限,导出的代码冗余。当时问了几个高手,大家建议不要使用设计器而应该自己手写xml代码。起初手写时感觉特别麻烦,可是用几天后你会发现手写要比使用设计器好得多:你可以更加了解duilib,熟悉每个控件的各个属性,对控件的控制也更加方便。而如果想称心如意的脱离设计器去编写xml文件,有非常有必要弄明白各个布局的用法和布局技巧。我现在可以完全靠手写xml来做出一个程序的界面,相信用了一段duilib的朋友也是这样。     在这里提醒一下新手朋友,在duilib的根目录有一个属性列表.xml的文件,他包含了绝大多数控件的绝大多数属性的介绍,有不懂的属性记得时常翻看他,同时不得不说这个文件包含的属性的确是不全面的,想要知道最全面的属性信息,可以看每个控件的源代码,在SetAttribute函数中可以看到最全面的属性信息!      要想手写xml,当然必须有一个编写工具,原则上只要是可以编写文本的工具都可以,大家根据习惯自己挑选适合的工具,我目前在使用的是sublime这款工具,感觉编写xml非常方便,使用界面也不错。 6大布局的作用:      duilib的Layout目录专门放置布局相关的容器控件,这6个布局分别为:Container、VerticalLayout、HorizaontalLayout、TileLayout、TabLayout、ChildLayout。容器之间可以任意相互嵌套,我分别说明他们的用法。      首先我要说明一下,下面介绍的时候,我都默认认为每个控件的float属性为false,也就是不使用绝对定位,这个属性会打破各个布局的作用。    Container:     Container布局是其他所有布局以及含有容器特性(如CList、CListContainerElement)的控件的基类,而实际上开发过程中很少使用这个布局,只用他来做其他更高级的布局的基类。因为Container布局中的所有控件都会自动填充满整个布局,所有的控件都叠到了一起。而这个效果一般不是我们想要的。我目前想得到的他的唯一用途就是用于绝对布局,而且里面的所有元素都使用绝对布局。绝对布局的概念看下文。      VerticalLayout、HorizaontalLayout:      VerticalLayout与HorizaontalLayout布局无疑是duilib中最常使用的两个布局,巧妙的使用这两个布局可以满足大多数的布局需求。从单词的意思上不难看出 VerticalLayout是纵向布局,HorizaontalLayout是横向布局。这门两个直接继承自Container布局。      VerticalLayout布局会让他包含的元素都纵向排列开, HorizaontalLayout布局会让给他包含的元素都横向排列开:如图        我故意没让控件填满整个容器,为了说明这两个布局不会强行让子元素的总和去填满容器,纵向布局会从上到下根据每个控件的高度让他们排到一起,横向布局会从左到右根据每个控件的宽度让他们排到一起。另外可以看到,纵向布局只关心子元素的高度,而不会强行让子元素的宽度等于容器的宽度,这点从图片可以看到,横向布局同理也是只关心子元素的宽度。而这两个布局经常会嵌套使用,如下效果:       可以看到我最外层使用了一个纵向布局,他包含了横纵横三个布局(分别为红绿蓝颜色),每个横向布局里又分别包含了几个按钮。我们在编写界面时经常用到这个方法!以下是这个布局效果图对应的xml代码: TileLayout:        TileLayout布局是用来做类似360工具箱的效果:       在前面的文章里,我写的《 duilib中ListCtrl控件的实现 》 和 《 仿酷狗音乐播放器开发日志十三——左侧功能块的完善 》 正是使用了这个布局完成的,这个布局有一个columns属性来设置每行中包含的列数,他会自动把包含的元素从左到右从上到下按照 columns属性的设置排列起来,让我们做出工具箱的效果。     TabLayout:     TabLayout布局同样常用,他就像MFC的选项卡 CTabCtrl 控件,如图:      但是在duilib中TabLayout只是下面的布局界面,而不包含顶端的选项卡按钮,所以经常用Option控件配合他一起使用,使用他时他会把他包含的下一级元素作为一个页面,所以我们通常在他里面放入横纵向布局来作为一个页面,在横纵向布局里再规划每个页面的外观。      这个控件的详细使用方法大家可以看duilib自带的360demo,我就不赘述了!      ChildLayout:      ChildLayout布局比较少用,因为他的功能可以用其他布局来代替,他的作用就是从一个xml文件中加载布局来嵌入到ChildLayout布局所在的地方,使用这个布局一般只需要指定xmlfile属性来设置xml文件位置就可以了。他的意义在于可以把繁杂的大量xml代码分隔开。比如他和TabLayout布局结合,让TabLayout布局包含5个ChildLayout布局,而每个ChildLayout布局分别从5个xml文件加载自己的布局文件,这样就可以分块化的编写布局代码。 绝对布局的意义与用法:       在知道了6大布局的用法之后,知道了各种样式的界面外观的大致布局方法,而这还远不够让我们写出漂亮的布局外观,只有配合相对布局与绝对布局才可以更好的控制界面的元素。值得一提的是,我这里说的相对布局和绝对布局并不是一个容器或者控件,这只是一种技巧和使用方法,用在容器布局所包含的控件上,常用到横纵向布局中。      我先来介绍绝对布局,笼统上说绝对布局和相对布局其实只有一个差别,也就是我在前面提到的float属性,容器中包含的控件float属性为真就是绝对布局,为假就是相对布局。不要小看这一个属性,他带来的效果可以天壤之别!      给控件的float属性设为真后,就使用了绝对布局,故名意思,绝对布局就是让控件的坐标绝对化,这样这个控件就不受他的容器的束缚而可以自己随意设置自己的位置!比如在横纵向布局中给他们包含的子控件设置float属性,这个控件就不会被自动横纵向排列。而我的建议是,能不用绝对布局就别用绝对布局!原因有三个:      1)绝对布局破坏了各个容器的特性,而不受容器的束缚。      2)绝对布局让控件的坐标固定,不利于控件自动调节位置。      3)后面提到的相对布局几乎可以完成绝对布局的所有特性。     那么为什么要用绝对布局,因为他的一个功能是相对布局无法完成的,就是让控件或者布局重叠或者相交!有的时候我们必须这样做来让控件组合起来达到一些效果。我可以明确的说,我在做仿酷狗播放器的过程中,整个xml布局代码只用了2个绝对布局,一个是编写搜索栏 《 仿酷狗音乐播放器开发日志二——搜索栏的编写 》 ,一个是编写电台控件。如图:        另外一个非常经典的使用绝对布局的例子就是我前几天写的 《 用duilib制作仿QQ2013动态背景登录器 》 ,这些例子都是因为要让控件重叠起来组合出新的控件才使用了绝对布局,如果不让控件重叠或者没有特殊需求,最好别用绝对布局。        虽然不建议使用,但我也得说一下绝对布局相关的属性和使用技巧。        1)把float属性设置为真。        2)设置pos属性,这个属性在float为真时才有效,他包含四个字段,分别以为了控件的左上右下下个坐标的位置,但是建议只指定前两个字段来设置控件的左上角的坐标,控件的宽度用width和height属性来控制,这样做的好处是避免了计算右下角坐标的繁琐!以后修改的时候也很清晰!        举出一个例子:       这里设置了一个Label控件,左上角放到100,100的坐标上,控件高22,宽26        不得不提一个很有用的属性,那就是relativepos属性,属性列表没有列出这个属性,这是我自己总结的        用了这个属性,就可以让控件拥有相对布局的一部分特性,那就是根据容器的大小,自己可以调整位置和大小!这个特点我在 《 仿酷狗音乐播放器开发日志二——搜索栏的编写 》 用到了,是为了让搜索按钮可以自己移动。这个属性的前两个字段表示横纵向的位移值,后两个字段表示缩放值,具体效果大家应该自己实践一下!另外这个属性默认是有严重bug的,就是窗体最小化再恢复后有这个属性的控件会自动无规律偏移,这个bug我修复了,详见 《 仿酷狗音乐播放器开发日志二——搜索栏的编写 》 。        这样就介绍完了绝对布局,然后就是整片文章的最重要部分,相对布局! 相对布局的意义与用法:       我把相对布局的介绍放到最后,因为它很重要!       在容器内部使用控件或者容器时,float属性设置为flase(duilib默认为false)就是相对布局了。这是我非常推荐使用的,前面我也说了我在写仿酷狗的整个布局中,上百个控件中我只给两个控件使用了绝对布局,其余都是相对布局。他的优点如下:        1)布局和控件是可以根据窗体的大小改变而自动调整位置的,这点很重要        2)不需要绝对布局那样麻烦的计算各个控件的位置        3)在容器中调整前一个控件的位置,后面的控件都会自动调整坐标      其实总得来说使用相对布局意义就是使用布局控件的自动排列特性!      使用了相对布局后,就不用设置float属性和pos属性,一般只设置甚至不设置width和height属性。这点很重要,如果你的控件或者布局的大小是固定的,那么就设置width和height属性,如果想让控件或者布局根据窗体的大小而自动调整大小和位置,就不设置这两个属性。如果只设置了一个属性,比如width设置为100,而height不设置,那么他的高度是自动调整的而宽度是固定的。父容器会自动安排他包含的元素,让含有width和height属性的控件占据相应的大小,把剩下的空间都分配给没有设置wieth和height属性的容器或者控件里。看下面一个例子:        可以看到窗体的大小为300x300,而最外层的是一个名为Fahter的纵向容器,包含三个子容器。而Father没有指定width和height,所以当我改变了窗体的大小时,Father会自动调整自己的大小到和窗体大小相同,而三个子容器我都眉头指定width属性,所以三个子容器的宽度和Father是一样,也就是他们的宽度都是和窗体宽度一样,并且会自动调整。Sub1和Sub3的高度设置为50,所以他们的高度就固定了,而Sbu2的高度也没有指定,那他会自动占据了除了Sub1和Sub2的所有空间!其实这个例子的布局是非常常见的界面布局例子,比如说酷狗,sub1和sub3分别表示标题栏和状态栏,sub2为程序的主界面:       关于酷狗的更加详细的布局分析可以看我前面写的博客 《 仿酷狗音乐播放器开发日志——整体框架分析 》 ,几乎每开发酷狗的一部分,我都会把布局分析一下写出来。      把这些知识综合起来,现在就可以写出一个自动调整大小的大致布局了,但是还没法精确控制每个控件的位置。      利用上面介绍的自动占位的特性,我这里举一个标题栏编写的例子:       这个例子是我的仿酷狗播放器的换肤窗体的标题栏。他的外层是一个横向布局,高度为30,宽度随窗体调整。让标题文字居于左侧,关闭按钮在最右侧,如果让窗体调整宽度后文字和关闭按钮自动调整位置,就需要把中间的空位占满。这时我们就需要一个占位控件,不给他设置width和height属性,这样子他就会自动占据剩余的空间!就达到了相对布局的自动调整位置的效果。这个使用方法是相对布局里非常常用的!而这个占位控件在没有什么其他要求时建议像我给出的例子那样,使用Control控件,因为他是所有控件和容器的祖先基类,代码和属性相对是最少的,这样有利于提高程序的效率!       在充分理解了占位的技巧后,再配合一些微调属性,就可以完美控制各个控件了,这几个微调属性分别是 inset、padding、childpadding ,这几个属性的介绍如下:      在float为假,也就是相对布局中,这几个属性才起效。      inset属性      这是给容器控件使用的,使用后他所包含的所有使用相对布局的元素,都会被限制在设置的范围内,适合对容器内所用元素进行整体的坐标控制。比如在前面提到的做360工具箱时,我们使用TileLayout容器来存放每一个工具,我们首先设置inset属性,就可以让所有的工具项限制在一定范围内,例子如下:       通过设置inset属性,让所有元素限制在一定范围内而不用重复设置每个元素的属性。      childpadding属性:      childpadding属性设置容器内每个元素之间的间距,这个比较容易理解,上面的例子中也用到了childpadding属性。四个字段分别是代表左上右下的间距。       padding属性:      padding属性是相对布局中最常用的属性!用来设置相对于前一个控件的位置,这个属性的控件位置微调的关键。一般只用他的前两个字段,设置左边距和上边距,后两个字段是无效的,或者说存在问题(为什么会有问题?请看源码)。不过使用这两个字段就够了。这是我的仿酷狗播放器的状态的布局代码:      使用padding属性,这是底部这四个按钮的相对位置。如果我想整体让这四个控件向右位移10像素,那么我只要设置第一个按钮的padding属性为padding="10,0,0,0",就可以了,其他布局完全不需要修改! 结束语      说到这里也就把布局的知识总结得差不多了,对于duilib的新手朋友,建议多看看各个demo的布局文件,他们几乎涵盖了所有知识点。然后结合我总结的东西自己手动写几个布局代码,相信很快就可以熟练编写界面布局了。另外我的前面博客里经常会分析布局,大家也可以看看。     我使用duilib的时间也不算长,水平有限,文章中有什么错误或者描述不清,请留言给我,我会及时纠正!

  • Duilib技巧:背景图片平铺

    Duilib技巧:背景图片平铺

    C/C++  3-23  1248浏览  0评论  

    方式有两种    // 1、aaa.jpg    // 2、file='aaa.jpg' res='' restype='0' dest='0,0,0,0' source='0,0,0,0' corner='0,0,0,0'    // mask='#FF0000' fade='255' hole='false' xtiled='false' ytiled='false' 第一种是最简单的,加载图片文件并将整张图片拉伸铺满整个控件 第二种既支持从文件中加载图片,也可以从资源中加载 1、如果是从文件加载,设置file属性,如file='XXX.png',不要写res和restype属性 2、如果从资源加载,设置res和restype属性,不要设置file属性 3、dest属性的作用是指定图片绘制在控件的一部分上面(绘制目标位置) 4、source属性的作用是指定使用图片的一部分 5、corner属性是指图片安装scale9方式绘制(scale9含义往下边看) 6、mask属性是给不支持alpha通道的图片格式(如bmp)指定透明色 7、fade属性是设置图片绘制的透明度 8、hole属性是指定scale9绘制时要不要绘制中间部分(有些地方对提升性能比较有用) 9、xtiled属性设置成true就是指定图片在x轴不要拉伸而是平铺,ytiled属性设置成true就是指定图片在y轴不要拉伸而是平铺 让背景图片平铺要写:xtiled='true' ytiled='true'