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 EDIT control. This control contains so much functionalitythat it would take ages to do a decent replacement. Single-line edit controls are created on the fly (when you click on theframe) and multi-line edits are always visible. So the framework does have the ability to embed native Win32 controlsand even ActiveX controls, but at the expense of screen flickering and severe restrictions in the visual effects I'm planning.”

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] = '\0';
		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(), S, L);
		}
		return true;
	}

	bool OnSChanged(void* param) {
		TNotifyUI* pMsg = (TNotifyUI*)param;
		if( pMsg->sType == _T("valuechanged") ) {
			short H, S, L;
			CPaintManagerUI::GetHSL(&H, &S, &L);
			CPaintManagerUI::SetHSL(true, H, (static_cast<CSliderUI*>(pMsg->pSender))->GetValue(), L);
		}
		return true;
	}

	bool OnLChanged(void* param) {
		TNotifyUI* pMsg = (TNotifyUI*)param;
		if( pMsg->sType == _T("valuechanged") ) {
			short H, S, L;
			CPaintManagerUI::GetHSL(&H, &S, &L);
			CPaintManagerUI::SetHSL(true, H, S, (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("skin\\FlashRes"));
				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, 0, 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, wParam, 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, 0, 0, 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, 0, 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,0,6,0' mask='#FFFF00FF'" fgimage="file='fg.bmp' corner='6,0,6,0' mask='#FFFF00FF'" thumbimage="file='thumb.bmp' source='30,0,40,10' mask='#FFDAEBF9'" thumbhotimage="file='thumb.bmp' source='10,0,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,4,2' fade='200' hsl='true'" pushedimage="file='button_down.bmp' corner='4,2,4,2' fade='200' hsl='true' " " />
  
  <!-- 使用垂直布局放置以下4个ui组件 -->
  <VerticalLayout inset="10,6,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未来应该是一个大的趋势,浏览器编程和本地编程应该可以融合。


  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值