天天看點

給duilib增加腳本支援(二)

上篇文章介紹了腳本響應duilib控件事件,以及腳本中調用duilib的函數。現在說一下具體的實作方式。

為了避免對duilib庫太大的改動,使用插件方式載入。首先在CPaintManagerUI頭部定義一個接口。

​

class UILIB_API IScriptEngine
{
public:
	virtual bool AddScriptCode(LPCTSTR pScriptCode) = 0;	//添加腳本段
	virtual bool AddScriptFile(LPCTSTR pstrFileName) = 0;	//添加腳本檔案
	virtual bool ExecuteScript(LPCTSTR funName, CControlUI *pControl) = 0;	//執行腳本
	virtual bool ExecuteScript(LPCTSTR funName, CControlUI *pControl, TEventUI *ev) = 0; //執行腳本
};
typedef IScriptEngine* (__stdcall *CREATE_SCRIPT_ENGINE_INSTANCE)(); //插件接口,建立新的腳本引擎
typedef void (__stdcall *DELETE_SCRIPT_ENGINE_INSTANCE)(IScriptEngine *pEngine); //插件接口,删除腳本引擎

​
           

給CPaintManagerUI添加成員變量和函數,依然提供shared與否的方式。

//
// 腳本
//
public:
	static bool LoadScriptPlugin(LPCTSTR pstrModuleName);
	IScriptEngine *GetScriptEngine(bool bShared = false);
	void AddScriptCode(LPCTSTR pScriptCode, LPCTSTR pLanguageType, bool bShared = false);
	void AddScriptFile(LPCTSTR pstrFileName, LPCTSTR pLanguageType, bool bShared = false);
	bool ExecuteScript(LPCTSTR funName, CControlUI *pControl);
	bool ExecuteScript(LPCTSTR funName, CControlUI *pControl, TEventUI *ev);
private:
	IScriptEngine *m_pScriptEngine;
	static IScriptEngine *m_pSharedScriptEngine;
	static CREATE_SCRIPT_ENGINE_INSTANCE m_funCreateScriptEngine;
	static DELETE_SCRIPT_ENGINE_INSTANCE m_funDeleteScriptEngine;
           

UIManager.cpp的修改内容,别忘了在構造函數中初始化指針。

CPaintManagerUI::~CPaintManagerUI()
{
	//解除安裝腳本引擎
	if(m_funDeleteScriptEngine)
	{
		(*m_funDeleteScriptEngine)(m_pScriptEngine);
	}

    ..................
}

void CPaintManagerUI::Term()
{
	//解除安裝腳本引擎
	if(m_funDeleteScriptEngine){
		(*m_funDeleteScriptEngine)(m_pSharedScriptEngine);
	}

    .....................
 }

	CREATE_SCRIPT_ENGINE_INSTANCE CPaintManagerUI::m_funCreateScriptEngine = NULL;	//add by liqs99
	DELETE_SCRIPT_ENGINE_INSTANCE CPaintManagerUI::m_funDeleteScriptEngine = NULL;	//add by liqs99
	IScriptEngine* CPaintManagerUI::m_pSharedScriptEngine = NULL;					

	bool CPaintManagerUI::LoadScriptPlugin(LPCTSTR pstrModuleName)
	{
		ASSERT( !::IsBadStringPtr(pstrModuleName,-1) || pstrModuleName == NULL );
		if( pstrModuleName == NULL ) return false;
		HMODULE hModule = ::LoadLibrary(pstrModuleName);
		if( hModule != NULL ) 
		{
			m_funCreateScriptEngine = (CREATE_SCRIPT_ENGINE_INSTANCE)::GetProcAddress(hModule, "CreateScriptEngine");
			m_funDeleteScriptEngine = (DELETE_SCRIPT_ENGINE_INSTANCE)::GetProcAddress(hModule, "DeleteScriptEngine");
			if(m_funCreateScriptEngine != NULL || m_funDeleteScriptEngine != NULL)
			{
				return true;
			}
		}
		return false;
	}
	
	IScriptEngine *CPaintManagerUI::GetScriptEngine(bool bShared)
	{
		if(m_funCreateScriptEngine == NULL)	return NULL;

		if(bShared)
		{
			if(m_pSharedScriptEngine == NULL)
				m_pSharedScriptEngine = (*m_funCreateScriptEngine)();
			return m_pSharedScriptEngine;
		}

		if(m_pScriptEngine == NULL)
			m_pScriptEngine = (*m_funCreateScriptEngine)();
		return m_pScriptEngine;
	}

	void CPaintManagerUI::AddScriptCode(LPCTSTR pScriptCode, LPCTSTR pLanguageType, bool bShared)
	{
		IScriptEngine *pScriptEngine = GetScriptEngine(bShared);
		if(pScriptEngine == NULL) return;
		pScriptEngine->AddScriptCode(pScriptCode);
	}

	void CPaintManagerUI::AddScriptFile(LPCTSTR pstrFileName, LPCTSTR pLanguageType, bool bShared)
	{
		IScriptEngine *pScriptEngine = GetScriptEngine(bShared);
		if(pScriptEngine == NULL) return;
		pScriptEngine->AddScriptFile(pstrFileName);
	}

	bool CPaintManagerUI::ExecuteScript(LPCTSTR funName, CControlUI *pControl)
	{
		IScriptEngine *pScriptEngine = GetScriptEngine(false);
		if(pScriptEngine)
		{
			if(!pScriptEngine->ExecuteScript(funName, pControl))
			{
				pScriptEngine = GetScriptEngine(true);
				if(!pScriptEngine) return false;
				if(!pScriptEngine->ExecuteScript(funName, pControl)) return false;
			}
		}
		else return false;

		return true;
	}

	bool CPaintManagerUI::ExecuteScript(LPCTSTR funName, CControlUI *pControl, TEventUI *ev)
	{
		IScriptEngine *pScriptEngine = GetScriptEngine(false);
		if(pScriptEngine)
		{
			if(!pScriptEngine->ExecuteScript(funName, pControl, ev))
			{
				pScriptEngine = GetScriptEngine(true);
				if(!pScriptEngine) return false;
				if(!pScriptEngine->ExecuteScript(funName, pControl, ev)) return false;
			}
		}
		else return false;

		return true;
	}

           

接着,修改CControlUI::Event(TEventUI& event), 截獲事件傳遞給腳本。

//在事件中執行腳本内容
void CControlUI::Event(TEventUI& event)
{
	if( OnEvent(&event) ) DoEvent(event);

	if( event.Type == UIEVENT_SETFOCUS ) 
	{
		if(!m_asOnSetFocus.IsEmpty()) GetManager()->ExecuteScript(m_asOnSetFocus, this);
	}
	if( event.Type == UIEVENT_KILLFOCUS ) 
	{
		if(!m_asOnKillFocus.IsEmpty()) GetManager()->ExecuteScript(m_asOnKillFocus, this);
	}
}

//增加屬性定義
void CControlUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)

{
    ............
	else if( _tcscmp(pstrName, _T("OnSetFocus"))	== 0 )		m_asOnSetFocus = pstrValue;
	else if( _tcscmp(pstrName, _T("OnKillFocus"))	== 0 )		m_asOnKillFocus = pstrValue;
...............
}
           

m_asOnSetFocus和m_asOnKillFocus是兩個CDuiString,儲存腳本内容。

接下來,需要讓duilib載入腳本内容,如上一篇在xml中定義或as檔案定義的函數。language屬性無用,隻做預留。

else if( _tcsicmp(pstrClass, _T("Script")) == 0 ) 
				{
					nAttributes = node.GetAttributeCount();
					LPCTSTR pstrIncludeFile = NULL;
					LPCTSTR pstrLanguage = NULL;
					LPCTSTR pScriptCode = node.GetValue();
					bool shared = false;
					for( int i = 0; i < nAttributes; i++ ) 
					{
						pstrName = node.GetAttributeName(i);
						pstrValue = node.GetAttributeValue(i);
						if( _tcsicmp(pstrName, _T("include")) == 0 ) 
						{
							pstrIncludeFile = pstrValue;
						}
						else if( _tcsicmp(pstrName, _T("language")) == 0 ) 
						{
							pstrLanguage = pstrValue;
						}
						else if( _tcsicmp(pstrName, _T("shared")) == 0 ) 
						{
							shared = (_tcsicmp(pstrValue, _T("true")) == 0);
						}
					}

					if(pstrIncludeFile)
					{
						pManager->AddScriptFile(pstrIncludeFile, pstrLanguage, shared);
					}
					if(pScriptCode && pScriptCode[0] != '\0')
					{
						pManager->AddScriptCode(pScriptCode, pstrLanguage, shared);
					}
				}
           

現在萬事俱備,隻欠插件了。

代碼共享位址:

https://gitee.com/Liqs99/DuiLib_DuiEditor

https://github.com/xfcanyue/DuiLib_DuiEditor