上篇文章介紹了腳本響應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