SOUI-DEMO界面预览
在回答SOUI能做什么之前,先看看SVN中demo工程的界面截图:
使用SOUI实现上面的界面主要的工作全在配置几个XML文件,基本不需要写C++代码。(如何配置XML布局将在后续文章中讲解)
从零开始生成一个使用SOUI的应用程序
以SOUI的demo为例,我们看在SOUI中如何一步一步实现一个应用程序。
首先使用Win32应用程序向导生成一个空项目。
新建一个如demo.cpp文件,定义一个_tWinMain函数。
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpstrCmdLine*/, int /*nCmdShow*/) { return 0; }
在项目的包含目录中包含$(SOUIPATH)\soui\include;$(SOUIPATH)\utilities\include;这两个目录。同时在库依赖中增加soui.lib utilities.lib。
$(SOUIPATH)是从SVN签出的trunk的根目录,如果安装了soui下的应用程序向导会自动为系统增加这个环境变量。
做好上述准备工作后在工程目录下建立一个如uires的目录,用来存放程序中用到的资源文件,包括布局使用的图片及XML布局文件。
在该目录下应该至少有一个uires.idx文件。uires.idx是一个XML文件,它定义程序中用到的所有其它资源的类型及名称。
demo中使用的uires.xml如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <resource> 3 <UIDEF> 4 <file name="xml_init" path="xml\init.xml" /> 5 </UIDEF> 6 <ICON> 7 <file name="LOGO" path="image\img_logo.ico" /> 8 </ICON> 9 <CURSOR> 10 <file name="ANI_ARROW" path="image\021.ani" /> 11 <file name="CUR_TST" path="image\camera_capture.cur"/> 12 </CURSOR> 13 <LAYOUT> 14 <file name="maindlg" path="xml\dlg_main.xml" /> 15 <file name="menu_test" path="xml\menu_test.xml" /> 16 <file name="page_layout" path="xml\page_layout.xml" /> 17 <file name="page_treebox" path="xml\page_treebox.xml" /> 18 <file name="page_treectrl" path="xml\page_treectrl.xml" /> 19 <file name="page_misc" path="xml\page_misc.xml" /> 20 <file name="page_webkit" path="xml\page_webkit.xml" /> 21 <file name="page_about" path="xml\page_about.xml" /> 22 </LAYOUT> 23 <IMGX> 24 <file name="png_page_icons" path="image\page_icons.png" /> 25 <file name="png_small_icons" path="image\small_icons.png" /> 26 27 <file name="webbtn_back" path="image\webbtn_back.png" /> 28 <file name="webbtn_forward" path="image\webbtn_forward.png" /> 29 <file name="webbtn_refresh" path="image\webbtn_refresh.png" /> 30 31 <file name="png_treeicon" path="image\TreeIcon.png"/> 32 <file name="png_menu_border" path="image\menuborder.png" /> 33 34 <file name="png_vscroll" path="image\vscrollbar.png" /> 35 36 <file name="png_tab_left" path="image\tab_left.png" /> 37 <file name="png_tab_left_splitter" path="image\tab_left_splitter.png" /> 38 <file name="png_tab_main" path="image\tab_main.png" /> 39 <file name="btn_menu" path="image\btn_menu.png" /> 40 </IMGX> 41 <GIF> 42 <file name="gif_horse" path="image\horse.gif"/> 43 <file name="gif_penguin" path="image\penguin.gif"/> 44 </GIF> 45 <rtf> 46 <file name="rtf_test" path="rtf\RTF测试.rtf"/> 47 </rtf> 48 <script> 49 <file name="lua_test" path="lua\test.lua"/> 50 </script> 51 <translator> 52 <file name="lang_cn" path="translation files\lang_cn.xml"/> 53 </translator> 54 </resource>
如上所示,该XML有一个resource的根节点,下面可以是任意定义的类型(ICON, BITMAP,CURSOR除外,它们是预定义的类型,不能修改类型名)。
每个类型下面定义有file元素,元素中有两个属性:name 及 path。
name即资源的名称,path即资源的路径。所有资源建议采用相对路径,即相对于uires.idx文件的路径。
在程序中通过type及name来引用资源。
下面开始填空:
1 int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpstrCmdLine*/, int /*nCmdShow*/) 2 { 3 //必须要调用OleInitialize来初始化运行环境 4 HRESULT hRes = OleInitialize(NULL); 5 SASSERT(SUCCEEDED(hRes)); 6 7 int nRet = 0; 8 9 //定义一组组件加载辅助对象 10 //SComLoader实现从DLL的指定函数创建符号SOUI要求的类COM组件。 11 SComLoader imgDecLoader; 12 SComLoader renderLoader; 13 SComLoader transLoader; 14 SComLoader scriptLoader; 15 SComLoader zipResLoader; 16 17 //将程序的运行路径修改到demo所在的目录 18 TCHAR szCurrentDir[MAX_PATH]={0}; 19 GetModuleFileName( NULL, szCurrentDir, sizeof(szCurrentDir) ); 20 LPTSTR lpInsertPos = _tcsrchr( szCurrentDir, _T(‘\\‘) ); 21 _tcscpy(lpInsertPos,_T("\\..\\demo")); 22 SetCurrentDirectory(szCurrentDir); 23 24 { 25 //定义一组类SOUI系统中使用的类COM组件 26 //CAutoRefPtr是一个SOUI系统中使用的智能指针类 27 CAutoRefPtr<IImgDecoderFactory> pImgDecoderFactory; //图片解码器,由imagedecoder-wid.dll模块提供 28 CAutoRefPtr<IRenderFactory> pRenderFactory; //UI渲染模块,由render-gdi.dll或者render-skia.dll提供 29 CAutoRefPtr<ITranslatorMgr> trans; //多语言翻译模块,由translator.dll提供 30 CAutoRefPtr<IScriptModule> pScriptLua; //lua脚本模块,由scriptmodule-lua.dll提供 31 32 BOOL bLoaded=FALSE; 33 int nType=MessageBox(GetActiveWindow(),_T("选择渲染类型:\n[yes]: Skia\n[no]:GDI\n[cancel]:Quit"),_T("select a render"),MB_ICONQUESTION|MB_YESNOCANCEL); 34 if(nType == IDCANCEL) return -1; 35 //从各组件中显示创建上述组件对象 36 bLoaded=renderLoader.CreateInstance(nType==IDYES?COM_RENDER_SKIA:COM_RENDER_GDI,(IObjRef**)&pRenderFactory); 37 SASSERT_FMT(bLoaded,_T("load module [%s] failed!"),nType==IDYES?COM_RENDER_SKIA:COM_RENDER_GDI); 38 bLoaded=imgDecLoader.CreateInstance(COM_IMGDECODER,(IObjRef**)&pImgDecoderFactory); 39 SASSERT_FMT(bLoaded,_T("load module [%s] failed!"),COM_IMGDECODER); 40 bLoaded=transLoader.CreateInstance(COM_TRANSLATOR,(IObjRef**)&trans); 41 SASSERT_FMT(bLoaded,_T("load module [%s] failed!"),COM_TRANSLATOR); 42 //为渲染模块设置它需要引用的图片解码模块 43 pRenderFactory->SetImgDecoderFactory(pImgDecoderFactory); 44 //定义一个唯一的SApplication对象,SApplication管理整个应用程序的资源 45 SApplication *theApp=new SApplication(pRenderFactory,hInstance); 46 47 //定义一人个资源提供对象,SOUI系统中实现了3种资源加载方式,分别是从文件加载,从EXE的资源加载及从ZIP压缩包加载 48 CAutoRefPtr<IResProvider> pResProvider; 49 #if (RES_TYPE == 0)//从文件加载 50 CreateResProvider(RES_FILE,(IObjRef**)&pResProvider); 51 if(!pResProvider->Init((LPARAM)_T("uires"),0)) 52 { 53 SASSERT(0); 54 return 1; 55 } 56 #elif (RES_TYPE==1)//从EXE资源加载 57 CreateResProvider(RES_PE,(IObjRef**)&pResProvider); 58 pResProvider->Init((WPARAM)hInstance,0); 59 #elif (RES_TYPE==2)//从ZIP包加载 60 bLoaded=zipResLoader.CreateInstance(COM_ZIPRESPROVIDER,(IObjRef**)&pResProvider); 61 SASSERT(bLoaded); 62 ZIPRES_PARAM param; 63 param.ZipFile(pRenderFactory, _T("uires.zip")); 64 bLoaded = pResProvider->Init((WPARAM)¶m,0); 65 SASSERT(bLoaded); 66 #endif 67 //将创建的IResProvider交给SApplication对象 68 theApp->AddResProvider(pResProvider); 69 70 if(trans) 71 {//加载语言翻译包 72 theApp->SetTranslator(trans); 73 pugi::xml_document xmlLang; 74 if(theApp->LoadXmlDocment(xmlLang,_T("lang_cn"),_T("translator"))) 75 { 76 CAutoRefPtr<ITranslator> langCN; 77 trans->CreateTranslator(&langCN); 78 langCN->Load(&xmlLang.child(L"language"),1);//1=LD_XML 79 trans->InstallTranslator(langCN); 80 } 81 } 82 #ifdef DLL_SOUI 83 //加载LUA脚本模块,注意,脚本模块只有在SOUI内核是以DLL方式编译时才能使用。 84 bLoaded=scriptLoader.CreateInstance(COM_SCRIPT_LUA,(IObjRef**)&pScriptLua); 85 SASSERT_FMT(bLoaded,_T("load module [%s] failed!"),COM_SCRIPT_LUA); 86 if(pScriptLua) 87 { 88 theApp->SetScriptModule(pScriptLua); 89 size_t sz=pResProvider->GetRawBufferSize(_T("script"),_T("lua_test")); 90 if(sz) 91 { 92 CMyBuffer<char> lua; 93 lua.Allocate(sz); 94 pResProvider->GetRawBuffer(_T("script"),_T("lua_test"),lua,sz); 95 pScriptLua->executeScriptBuffer(lua,sz); 96 } 97 } 98 #endif//DLL_SOUI 99 100 //向SApplication系统中注册由外部扩展的控件及SkinObj类 101 SWkeLoader wkeLoader; 102 if(wkeLoader.Init(_T("wke.dll"))) 103 { 104 theApp->RegisterWndFactory(TplSWindowFactory<SWkeWebkit>());//注册WKE浏览器 105 } 106 theApp->RegisterWndFactory(TplSWindowFactory<SGifPlayer>());//注册GIFPlayer 107 theApp->RegisterSkinFactory(TplSkinFactory<SSkinGif>());//注册SkinGif 108 SSkinGif::Gdiplus_Startup(); 109 110 //加载系统资源 111 HMODULE hSysResource=LoadLibrary(SYS_NAMED_RESOURCE); 112 if(hSysResource) 113 { 114 CAutoRefPtr<IResProvider> sysSesProvider; 115 CreateResProvider(RES_PE,(IObjRef**)&sysSesProvider); 116 sysSesProvider->Init((WPARAM)hSysResource,0); 117 theApp->LoadSystemNamedResource(sysSesProvider); 118 } 119 120 //加载全局资源描述XML 121 theApp->Init(_T("xml_init")); 122 123 { 124 //创建并显示使用SOUI布局应用程序窗口,为了保存窗口对象的析构先于其它对象,把它们缩进一层。 125 CMainDlg dlgMain; 126 dlgMain.Create(GetActiveWindow(),0,0,800,600); 127 dlgMain.GetNative()->SendMessage(WM_INITDIALOG); 128 dlgMain.CenterWindow(); 129 dlgMain.ShowWindow(SW_SHOWNORMAL); 130 nRet=theApp->Run(dlgMain.m_hWnd); 131 } 132 133 //应用程序退出 134 delete theApp; 135 SSkinGif::Gdiplus_Shutdown(); 136 137 } 138 139 OleUninitialize(); 140 return nRet; 141 }
大家可能发现使用SOUI的这个main函数相对于其它程序可能要更加复杂,这是为了达到程序配置的灵活性需要付出的代价。
好在SOUI提供了应用程序向导,它会帮助你点两个按钮就生成一整套框架。
SOUI与其它应用程序开发框架
SOUI是一个使用纯Win32 SDK开发的UI库,内核部分使用了pugixml这个第三方库作为XML解析的模块,除此之外,不再依赖其它第三方库,同时所有使用的模块都可以通过源代码编译。
SOUI提供了一整套完整的UI开发框架,不需要依赖其它的如MFC,WTL等开发框架。同时由于SOUI是纯win32的SDK开发的,它理论上也可以和任意的其它开发框架共存。(实际处理中由于SOUI中使用的一些类的命名可能和其它框架冲突,因此可能需要注意命名空间的使用。)