学习duilib

来源:互联网 发布:淘宝图片设计原则 编辑:程序博客网 时间:2024/04/29 01:26

学习duilib

最近在学习windows开发,真是两眼一抹黑,刚开始看windows的代码被全是大写和匈牙利命名法搞得生活不能自理。
主要是看书《Windows程序设计 5e》,最近发现了duilib,简单看了下用来写界面真是极好的,与Android非常相似,于是专研了几天,整理如下内容分享给大家,这样就能快速起飞……

目录

  • 一个最基本的程序
  • duilib定义的Notify方法中的事件类型
  • 对UI的操作
  • 开新线程做耗时操作以及回调
  • 参考资料

一个最基本的程序

最基本的程序只需要一个入口main函数和一个window即可。先看看window应该如何定义。比如我想写一个功能为注册的窗口,取名为RegisterWindow。
新建一个RegisterWindow.cpp。代码如下:

// 这一坨头文件是为了使用duilib#define WIN32_LEAN_AND_MEAN#define _CRT_SECURE_NO_DEPRECATE#include <windows.h>#include <objbase.h>#include "..\DuiLib\UIlib.h"using namespace DuiLib;#ifdef _DEBUG# ifdef _UNICODE# pragma comment(lib, "DuiLib_ud.lib")# else# pragma comment(lib, "DuiLib_d.lib")# endif#else# ifdef _UNICODE# pragma comment(lib, "DuiLib_u.lib")# else# pragma comment(lib, "DuiLib.lib")# endif#endif// 继承的是WindowImplBase这个类class RegisterWindow : public WindowImplBase{public:    RegisterWindow() {};    virtual LPCTSTR    GetWindowClassName() const { return _T("RegisterWindow"); }    // 这里填写xml的路径,这个路径是相对于生成的exe的位置    virtual CDuiString GetSkinFile() { return _T("res\\layout\\register.xml"); }    virtual CDuiString GetSkinFolder() { return _T(""); }    virtual void InitWindow() {        // 这个方法里可以做一些初始化操作    }    virtual void Notify(TNotifyUI& msg) {        // 这个方法里是duilib封装的一些事件的回调,它定义了一些msg type,然后根据消息的sender        // 来得知这个消息是什么控件发送出来的        if (msg.sType == MSG_TYPE::CLICK)         {            if (msg.pSender->GetName() == _T("btn_next")) {                // do your job            }        }        // 这一行是必须的,可以帮助我们去处理一些预置的消息,比如closebtn这个按钮点击就会关闭窗口        __super::Notify(msg);     }    virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) {        // 这里可以获得windows的原始的所有消息        // 这一行是必须的,否则上面的notify方法就失效了        return __super::HandleMessage(uMsg, wParam, lParam);     }};

然后xml文件,非常类似于Android中的布局文件。
具体可以参考这个教程:2013 duilib入门简明教程

Window准备好了,接下来就写一个main函数,作为程序的入口就行了。程序的入口我是放到一个单独的文件main.cpp中去写的。

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow){    CPaintManagerUI::SetInstance(hInstance);    // 注意这一坨代码,以后开启另一个新的窗口也是用这样一坨类似的代码来搞就行了    RegisterWindow* pFrame = new RegisterWindow();    pFrame->Create(NULL, _T("测试"), UI_WNDSTYLE_FRAME | WS_VSCROLL, WS_EX_WINDOWEDGE);    pFrame->CenterWindow();    pFrame->ShowModal();    delete pFrame;    return 0;}

duilib定义的Notify方法中的事件类型

Notify方法中拿到的消息,type都是字符串类型的,这一点略微蛋疼(因为要写很多if),
这些msg type的定义在duilib的UIDefine.h头文件中

#define DUI_MSGTYPE_MENU                   (_T("menu"))#define DUI_MSGTYPE_LINK                   (_T("link"))#define DUI_MSGTYPE_TIMER                  (_T("timer"))#define DUI_MSGTYPE_CLICK                  (_T("click"))#define DUI_MSGTYPE_RETURN                 (_T("return"))#define DUI_MSGTYPE_SCROLL                 (_T("scroll"))#define DUI_MSGTYPE_DROPDOWN               (_T("dropdown"))#define DUI_MSGTYPE_SETFOCUS               (_T("setfocus"))#define DUI_MSGTYPE_KILLFOCUS              (_T("killfocus"))#define DUI_MSGTYPE_ITEMCLICK              (_T("itemclick"))#define DUI_MSGTYPE_TABSELECT              (_T("tabselect"))#define DUI_MSGTYPE_ITEMSELECT             (_T("itemselect"))#define DUI_MSGTYPE_ITEMEXPAND             (_T("itemexpand"))#define DUI_MSGTYPE_WINDOWINIT             (_T("windowinit"))#define DUI_MSGTYPE_BUTTONDOWN             (_T("buttondown"))#define DUI_MSGTYPE_MOUSEENTER             (_T("mouseenter"))#define DUI_MSGTYPE_MOUSELEAVE             (_T("mouseleave"))#define DUI_MSGTYPE_TEXTCHANGED            (_T("textchanged"))#define DUI_MSGTYPE_HEADERCLICK            (_T("headerclick"))#define DUI_MSGTYPE_ITEMDBCLICK            (_T("itemdbclick"))#define DUI_MSGTYPE_SHOWACTIVEX            (_T("showactivex"))#define DUI_MSGTYPE_ITEMCOLLAPSE           (_T("itemcollapse"))#define DUI_MSGTYPE_ITEMACTIVATE           (_T("itemactivate"))#define DUI_MSGTYPE_VALUECHANGED           (_T("valuechanged"))#define DUI_MSGTYPE_SELECTCHANGED          (_T("selectchanged"))

对UI的操作

duilib中的UI跟Android中的View很类似,基类是CControlUI。如果不需要对某个UI进行操作,比如一个logo,万年静止的图片,那么在xml里写好就行了。

如果对某个UI需要进行操作,比如在点击按钮的时候要改变一些属性什么的,就需要在代码中获取到这个UI的对象。

可以使用下面这行代码来获取,有点像findViewById

// 这一行代码可以放在window定义的InitWindow方法里面CEditUI* mAddressInput = static_cast<CEditUI*>(m_PaintManager.FindControl(_T("input_email_address")));

里面写的字符串input_email_address是在xml中定义的name属性。

<Edit     name="input_email_address"     text="email address"     bordersize="2"     font="0"     height="50"     bordercolor="ffd3d5db"     borderround="6, 6"     padding="10, 0, 10, 0"/>

能获得某个UI对象的指针,就可以调用它的方法来进行操作了,这一点就是面向对象的那种套路了。不过我发现,调用某个方法后,需要调用NeedUpdate方法才会进行重绘。比如:

// 设置文本mAddressInput->SetText(HINT_EMAIL_ADDRESS_INPUT);// 调用这一行才生效mAddressInput->NeedUpdate();

更多更细节的API还不是很熟悉,再慢慢研究吧。

开新线程做耗时操作以及回调

开新线程有windows提供的CreateThread方法和C库提供的_beginthread方法(在process.h头文件里)。我比较习惯用第二个,因为参数少……

class RegisterWindow: public WindowImplBase {public:    void __stdcall doWork(void* param) {        for (int i = 0; i < 20; i++) {            TCHAR* buffer = new TCHAR[100];            wsprintf(buffer, _T("doWork: %i \n"), i);            OutputDebugString(buffer);            delete[] buffer;            Sleep(200);        }        HWND hwnd = (HWND)param;        ::PostMessage(hwnd, 9999, NULL, NULL);    };    //beginthread方法不能直接传一个成员方法进去,所以要用static方法裹一下    static void __cdecl doWorkWrap(void* param) {        static_cast<RegisterWindow*>(param)->doWork(param);    }      virtual void Notify(TNotifyUI& msg) {        if (msg.sType == _T("click"))         {            if (msg.pSender->GetName() == _T("btn_valid"))            {                //这里启动线程搞事情                HWND hwnd = GetHWND();                _beginthread(&RegisterWindow::doWorkWrap, 0, hwnd);            }        }        __super::Notify(msg);    }    virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) {        // 在这里拿到9999消息        return __super::HandleMessage(uMsg, wParam, lParam);    }}

掌握了上面着一些就可以做一些基本的异步操作了。

参考资料

  • 2013 duilib入门简明教程
  • duilib进阶教程
  • github: duilib
0 0
原创粉丝点击