DirectUI界面技术和lua脚本
Duilib库地址 http://duilib.googlecode.com/files/duilib%20v1.1.zip 类图结构(删除了接口): 类图2: (1)window类可以用来host那些UI控件,CWindowWnd使用DialogBuilder放置所有的UI控件在它上面。 (2)也可以被UI控件作为部件组合,比如CEditWnd,就是被CEditUi组合。 为什么Edit控件是这样设计呢,以及acitvex控件: “Native Win32 controls are used only for the http://www.viksoe.dk/code/windowless1.htm Lua官方地址,for windows. http://luaforwindows.googlecode.com/files/LuaForWindows_v5.1.4-45.exe // LuaUiFrame.cpp : Defines the exported functions for the DLL application. // #include <windows.h> #include <objbase.h> #include <string> /*dui include*/ #include <UIlib.h> using namespace DuiLib; /*lua include*/ #ifdef __cplusplus extern "C" { #endif #include <lua.h> #include <lualib.h> #include <lauxlib.h> #ifdef __cplusplus }; #endif #define MSGBOX(title,content) MessageBoxA(GetActiveWindow(),content,title,MB_YESNOCANCEL | MB_ICONQUESTION); // 声明宿主的5个函数给脚本使用 #ifdef __cplusplus extern "C" { #endif int FindControl(lua_State * l); int SetAttr(lua_State * l); int GetAttr(lua_State * l); int SetCallback(lua_State * l); int MsgBox(lua_State * l); #ifdef __cplusplus }; #endif // 用这5个函数定义一个导出数组 const static struct luaL_reg LuaUiFrameExports [] = { {"FindControl",&FindControl},{"SetAttr",&SetAttr},{"GetAttr",&GetAttr},{"SetCallback",&SetCallback},{"MsgBox",&MsgBox},{NULL,NULL} //required! }; class CFrameWindowWnd : public CWindowWnd,public INotifyUI { public: CFrameWindowWnd(const char * xmlPath,const char * luaPath) : m_xmlPath(xmlPath),m_luaPath(luaPath),m_L(NULL){ if (!m_L) m_L = lua_open(); if (m_L) luaL_openlibs(m_L); } ~CFrameWindowWnd(){ if (m_L) lua_close(m_L); } LPCTSTR GetWindowClassName() const { return _T("LuaUIFrame"); }; UINT GetClassStyle() const { return CS_DBLCLKS; }; void OnFinalMessage(HWND /*hWnd*/) { delete this; }; void Init() { /** * 把这5个函数注册成lua的一个库,叫做frame **/ luaL_register(m_L,"frame",LuaUiFrameExports); char szPath[MAX_PATH] = ""; GetModuleFileNameA(NULL,szPath,MAX_PATH-1); strrchr(szPath,'')[1] = ' '; strcat_s(szPath,MAX_PATH,m_luaPath.c_str()); luaL_dofile(m_L,szPath); } bool OnHChanged(void* param) { TNotifyUI* pMsg = (TNotifyUI*)param; if( pMsg->sType == _T("valuechanged") ) { short H,S,L; CPaintManagerUI::GetHSL(&H,&S,&L); CPaintManagerUI::SetHSL(true,(static_cast<CSliderUI*>(pMsg->pSender))->GetValue(),L); } return true; } bool OnSChanged(void* param) { TNotifyUI* pMsg = (TNotifyUI*)param; if( pMsg->sType == _T("valuechanged") ) { short H,H,L); } return true; } bool OnLChanged(void* param) { TNotifyUI* pMsg = (TNotifyUI*)param; if( pMsg->sType == _T("valuechanged") ) { short H,(static_cast<CSliderUI*>(pMsg->pSender))->GetValue()); } return true; } bool OnAlphaChanged(void* param) { TNotifyUI* pMsg = (TNotifyUI*)param; if( pMsg->sType == _T("valuechanged") ) { m_pm.SetTransparent((static_cast<CSliderUI*>(pMsg->pSender))->GetValue()); } return true; } void Notify(TNotifyUI& msg) { if( msg.sType == _T("windowinit") ) { CSliderUI* pSilder = static_cast<CSliderUI*>(m_pm.FindControl(_T("alpha_controlor"))); if( pSilder ) pSilder->OnNotify += MakeDelegate(this,&CFrameWindowWnd::OnAlphaChanged); pSilder = static_cast<CSliderUI*>(m_pm.FindControl(_T("h_controlor"))); if( pSilder ) pSilder->OnNotify += MakeDelegate(this,&CFrameWindowWnd::OnHChanged); pSilder = static_cast<CSliderUI*>(m_pm.FindControl(_T("s_controlor"))); if( pSilder ) pSilder->OnNotify += MakeDelegate(this,&CFrameWindowWnd::OnSChanged); pSilder = static_cast<CSliderUI*>(m_pm.FindControl(_T("l_controlor"))); if( pSilder ) pSilder->OnNotify += MakeDelegate(this,&CFrameWindowWnd::OnLChanged); } else if( msg.sType == _T("click") ) { if( msg.pSender->GetName() == _T("insertimagebtn") ) { CRichEditUI* pRich = static_cast<CRichEditUI*>(m_pm.FindControl(_T("testrichedit"))); if( pRich ) { pRich->RemoveAll(); } } else if( msg.pSender->GetName() == _T("changeskinbtn") ) { if( CPaintManagerUI::GetResourcePath() == CPaintManagerUI::GetInstancePath() ) CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath() + _T("skinFlashRes")); else CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath()); CPaintManagerUI::ReloadSkin(); } } } LRESULT HandleMessage(UINT uMsg,WPARAM wParam,LPARAM lParam) { if( uMsg == WM_CREATE ) { // 设置窗口无边框样式 LONG styleValue = ::GetWindowLong(*this,GWL_STYLE); styleValue &= ~WS_CAPTION ; //& ~WS_BORDER & ~WS_THICKFRAME; ::SetWindowLong(*this,GWL_STYLE,styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); m_pm.Init(m_hWnd); CDialogBuilder builder; //CDialogBuilderCallbackEx cb; wchar_t szXmlPath [MAX_PATH] = L""; MultiByteToWideChar(CP_ACP,m_xmlPath.c_str(),-1,szXmlPath,_countof(szXmlPath)); CControlUI* pRoot = builder.Create(szXmlPath,(UINT)0,NULL,&m_pm); ASSERT(pRoot && "Failed to parse XML"); m_pm.AttachDialog(pRoot); m_pm.AddNotifier(this); // 圆角 SIZE szRoundCorner = m_pm.GetRoundCorner(); if( !::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0) ) { CRect rcWnd; ::GetWindowRect(*this,&rcWnd); rcWnd.Offset(-rcWnd.left,-rcWnd.top); rcWnd.right++; rcWnd.bottom++; HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left,rcWnd.top,rcWnd.right,rcWnd.bottom,szRoundCorner.cx,szRoundCorner.cy); ::SetWindowRgn(*this,hRgn,TRUE); ::DeleteObject(hRgn); } Init(); return 0; } else if( uMsg == WM_DESTROY ) { ::PostQuitMessage(0L); } else if( uMsg == WM_ERASEBKGND ) { return 1; } LRESULT lRes = 0; if( m_pm.MessageHandler(uMsg,wParam,lParam,lRes) ) return lRes; return CWindowWnd::HandleMessage(uMsg,lParam); } public: // 绘制管理器 CPaintManagerUI m_pm; // 布局文件 std::string m_xmlPath; // 控制脚本 std::string m_luaPath; protected: // lua脚本状态机 lua_State * m_L; }; int APIENTRY WinMain( __in HINSTANCE hInstance,__in HINSTANCE hPrevInstance,__in LPSTR lpCmdLine,__in int nCmdShow ) { CPaintManagerUI::SetInstance((HINSTANCE)hInstance); CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath()); HRESULT Hr = ::CoInitialize(NULL); if( FAILED(Hr) ) return 0; CFrameWindowWnd* pFrame = new CFrameWindowWnd("LuaUiFrame.xml","LuaUiFrame.lua"); if( pFrame == NULL ) return 0; pFrame->Create(NULL,_T("LuaUiFrameApp"),WS_VISIBLE | WS_POPUPWINDOW //,WS_VISIBLE | WS_POPUPWINDOW| WS_OVERLAPPEDWINDOW,0L,1,1); pFrame->CenterWindow(); pFrame->ShowWindow(true); CPaintManagerUI::MessageLoop(); ::CoUninitialize(); return 0; } int FindControl(lua_State * l) { return 0; } int SetAttr(lua_State * L) { return 0; } int GetAttr(lua_State * l) { return 0; } int SetCallback(lua_State * l) { const char * pCallbackName = lua_tostring(l,1); //MSGBOX(pCallbackName,pCallbackName); lua_getglobal(l,pCallbackName); //lua_pushnumber(l,0); /* push 1st argument */ //lua_pushnumber(l,0); /* push 2nd argument */ lua_pcall(l,0); return 0; } int MsgBox(lua_State * l) { int argc = lua_gettop(l); MSGBOX(lua_tostring(l,1),lua_tostring(l,2)); lua_pushnumber(l,0x00000000); // return value return 1; // count of ret val } xml布局文件 <?xml version="1.0" encoding="UTF-8"?> <Window mininfo="10,10" size="200,200"> <Font name="幼圆" size="16" default="true" /> <Font name="微软雅黑" size="18" /> <!-- Slider的外观定义 --> <Default name="Slider" value="thumbsize="10,10" bkimage="file='bg.bmp' corner='6,6,0' mask='#FFFF00FF'" fgimage="file='fg.bmp' corner='6,0' mask='#FFFF00FF'" thumbimage="file='thumb.bmp' source='30,40,10' mask='#FFDAEBF9'" thumbhotimage="file='thumb.bmp' source='10,20,10' mask='#FFDAEBF9'" " /> <!-- Button的外观定义 --> <Default name="Button" value="normalimage="file='button_nor.bmp' corner='4,2,4,2' fade='200' hsl='true'" hotimage="file='button_over.bmp' corner='4,2' fade='200' hsl='true'" pushedimage="file='button_down.bmp' corner='4,2' fade='200' hsl='true' " " /> <!-- 使用垂直布局放置以下4个ui组件 --> <VerticalLayout inset="10,10,6" bkcolor="#FFEA679F" colorhsl="true" borderround="18,18"> <!-- 如果richedit在窗口内是第一个获得焦点的,会出现一个光标刷新bug,暂无解决办法 --> <!-- 定义3个slider --> <Slider name="alpha_controlor" min="20" max="255" value="255"/> <Slider name="h_controlor" max="360" value="180"/> <Slider name="s_controlor" max="200" value="100"/> <Slider name="l_controlor" max="200" value="100"/> <!-- 定义1个按钮 --> <Button name="changeskinbtn" height="20" text="换肤" maxwidth="120" /> </VerticalLayout> </Window> lua脚本文件 function onButtonClick() // frame 这个库已经注册到lua脚本虚拟机里面了,可以直接使用 frame.MsgBox("Hello","ButtonClicked"); end frame.MsgBox("title","text"); frame.SetCallback("onButtonClick"); 一些看法: 1) 作者当尝试dui和lua的结合是仅仅是一次探索,该技术的跨平台是一个大问题。dui是关于windows的技术。 2) 以前也关注过xul,属于mozila的跨平台界面技术实现,这个比较有意思,脚本是js,moziila在html标签之外重新定义了一套标签专门用于app的开发,确实煞费苦心,为什么不直接增强html标签呢?当然也是可以xmlns引入xhtml标签,但是一个app里面使用2中ns的标签有些奇怪,另外mozilla也不建议在xulrunner里面使用xhtml标签。 3)html5和js未来应该是一个大的趋势,浏览器编程和本地编程应该可以融合。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |