环境:win7_64旗舰版,VS2013
发现了一个比较好用的DirectUI库——SOUI,但是写一个窗口程序不是很方便,程序初始化的地方稍显繁琐,这里稍微封装一下。
大概包含6个文件:
SouiConfig.h:负责SOUI的配置,包括导入动态库,定义SOUI系统资源名称等。
#ifndef _SOUI_CONFIG_ #define _SOUI_CONFIG_ #ifdef _DEBUG #define SYS_NAMED_RESOURCE _T("soui-sys-resourced.dll") #pragma comment(lib, "souid.lib") #pragma comment(lib, "utilitiesd.lib") #else #define SYS_NAMED_RESOURCE _T("soui-sys-resource.dll") #pragma comment(lib, "soui.lib") #pragma comment(lib, "utilities.lib") #endif // _DEBUG #define DLL_SOUI #endif
SouiInclude.h:负责包含SOUI的头文件。
#ifndef _SOUI_INCLUDE_H_ #define _SOUI_INCLUDE_H_ #include "SouiConfig.h" #include "souistd.h" #include "core/SHostDialog.h" #include "control/SMessageBox.h" #include "control/souictrls.h" #include "com-cfg.h" using namespace SOUI; #endif
SouiApp类:负责SOUI应用程序初始化,包括设置资源路径,初始化渲染引擎,初始化OLE和消息循环。
SouiApp.h
#ifndef _SOUI_APP_H_ #define _SOUI_APP_H_ #include <string> #include "SouiInclude.h" class SouiApp { public: SouiApp() : m_initOle(false), m_app(NULL) { } ~SouiApp(); public: // 初始化OLE void initOle(); // 初始化应用程序 void initApp(HINSTANCE hInstance); // 消息循环 void run(SHostWnd& mainWnd) { m_app->Run(mainWnd.m_hWnd); } public: // 属性设置 // 获取当前应用程序路径 std::wstring getAppPath() const; // 设置资源路径 void setResPath(const std::wstring& path); private: // 初始化渲染工厂 CAutoRefPtr<SOUI::IRenderFactory> initRenderFactory(); // 初始化语言翻译管理器 CAutoRefPtr<SOUI::ITranslatorMgr> initTranslator(const std::wstring& path); // 初始化自定义资源 CAutoRefPtr<IResProvider> initResProvider(HINSTANCE hInstance, const std::wstring& path); // 初始化系统资源 CAutoRefPtr<IResProvider> initSysResource(); private: bool m_initOle; // 初始化OLE std::wstring m_resPath; // 资源路径 SComMgr m_comMgr; // SOUI组件配置 SApplication* m_app; // SOUI应用程序类 }; #endif
SouiApp.cpp
#include <windows.h> #include "SouiApp.h" SouiApp::~SouiApp() { delete m_app; m_app = NULL; if (m_initOle) { ::OleUninitialize(); } } void SouiApp::initOle() { SASSERT(!m_initOle); HRESULT hRes = ::OleInitialize(NULL); SASSERT(SUCCEEDED(hRes)); m_initOle = true; } void SouiApp::initApp(HINSTANCE hInstance) { try { SASSERT(!m_app); // 初始化渲染工厂 CAutoRefPtr<SOUI::IRenderFactory> renderFactory = initRenderFactory(); if (!renderFactory) { throw std::runtime_error("init render factory faild!"); } m_app = new SApplication(renderFactory, hInstance); // 初始化语言翻译管理器 CAutoRefPtr<SOUI::ITranslatorMgr> trans = initTranslator(m_resPath + L"\translator\lang_cn.xml"); if (!trans) { throw std::runtime_error("init translator faild!"); } m_app->SetTranslator(trans); // 初始化自定义资源 CAutoRefPtr<IResProvider> resProvider = initResProvider(hInstance, m_resPath); if (!resProvider) { throw std::runtime_error("init resource faild!"); } m_app->AddResProvider(resProvider); // 初始化系统资源 CAutoRefPtr<IResProvider> sysResProvider = initSysResource(); if (!sysResProvider) { throw std::runtime_error("init system resource faild!"); } m_app->LoadSystemNamedResource(sysResProvider); m_app->Init(L"XML_INIT"); } catch (std::runtime_error&) { } } std::wstring SouiApp::getAppPath() const { std::wstring path(MAX_PATH, L''); DWORD dw = ::GetModuleFileName(NULL, &path[0], path.length()); path.resize(dw); path = path.substr(0, path.rfind(L"\")); return path; } void SouiApp::setResPath(const std::wstring& path) { m_resPath = path; ::SetCurrentDirectory(m_resPath.c_str()); } CAutoRefPtr<SOUI::IRenderFactory> SouiApp::initRenderFactory() { CAutoRefPtr<SOUI::IRenderFactory> renderFactory; CAutoRefPtr<SOUI::IImgDecoderFactory> imgDecoderFactory; if (m_comMgr.CreateRender_GDI((IObjRef**)&renderFactory) && m_comMgr.CreateImgDecoder((IObjRef**)&imgDecoderFactory)) { renderFactory->SetImgDecoderFactory(imgDecoderFactory); } return renderFactory; } CAutoRefPtr<SOUI::ITranslatorMgr> SouiApp::initTranslator(const std::wstring& path) { CAutoRefPtr<SOUI::ITranslatorMgr> trans; if (m_comMgr.CreateTranslator((IObjRef**)&trans)) { pugi::xml_document xmlLang; if (xmlLang.load_file(path.c_str())) { CAutoRefPtr<ITranslator> langCN; trans->CreateTranslator(&langCN); langCN->Load(&xmlLang.child(L"language"), 1); trans->InstallTranslator(langCN); } } return trans; } CAutoRefPtr<IResProvider> SouiApp::initResProvider(HINSTANCE hInstance, const std::wstring& path) { const BUILTIN_RESTYPE res = RES_FILE; CAutoRefPtr<IResProvider> resProvider; CreateResProvider(res, (IObjRef**)&resProvider); if (res == RES_FILE) { if (!resProvider->Init((LPARAM)path.c_str(), 0)) { SASSERT(false); } } else if (res == RES_PE) { if (!resProvider->Init((WPARAM)hInstance, 0)) { SASSERT(false); } } return resProvider; } CAutoRefPtr<IResProvider> SouiApp::initSysResource() { CAutoRefPtr<IResProvider> sysResProvider; HMODULE hSysResource = LoadLibrary(SYS_NAMED_RESOURCE); if (hSysResource) { CreateResProvider(RES_PE, (IObjRef**)&sysResProvider); sysResProvider->Init((WPARAM)hSysResource, 0); } return sysResProvider; }
SouiWindow类:负责SOUI窗口。
SouiWindow.h
#ifndef _SOUI_WINDOW_H_ #define _SOUI_WINDOW_H_ #include "SouiInclude.h" class SouiWindow : public SHostWnd { public: SouiWindow(LPCTSTR pszResName) : SHostWnd(pszResName), m_bLayoutInited(false) {} virtual ~SouiWindow() {} // 创建 void create(SouiWindow* window = NULL); // 居中显示 void centerShow(); // 显示 void show(); protected: void OnClose() { DestroyWindow(); } void OnMaximize() { SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE); } void OnRestore() { SendMessage(WM_SYSCOMMAND, SC_RESTORE); } void OnMinimize() { SendMessage(WM_SYSCOMMAND, SC_MINIMIZE); } int OnCreate(LPCREATESTRUCT lpCreateStruct); void OnSize(UINT nType, CSize size); BOOL OnInitDialog(HWND hWnd, LPARAM lParam); protected: EVENT_MAP_BEGIN() EVENT_NAME_COMMAND(L"btn_close", OnClose) EVENT_NAME_COMMAND(L"btn_min", OnMinimize) EVENT_NAME_COMMAND(L"btn_max", OnMaximize) EVENT_NAME_COMMAND(L"btn_restore", OnRestore) EVENT_MAP_END() BEGIN_MSG_MAP_EX(SouiWindow) MSG_WM_CREATE(OnCreate) MSG_WM_INITDIALOG(OnInitDialog) MSG_WM_CLOSE(OnClose) MSG_WM_SIZE(OnSize) CHAIN_MSG_MAP(SHostWnd) REFLECT_NOTIFICATIONS_EX() END_MSG_MAP() private: bool m_bLayoutInited; }; #endif
SouiWindow.cpp
#include "SouiWindow.h" void SouiWindow::create(SouiWindow* window /*= NULL*/) { HWND parent = window ? window->m_hWnd : NULL; SHostWnd::Create(parent, 0, 0); SHostWnd::SendMessage(WM_INITDIALOG); } void SouiWindow::centerShow() { SHostWnd::CenterWindow(m_hWnd); show(); } void SouiWindow::show() { SHostWnd::ShowWindow(SW_SHOW); } int SouiWindow::OnCreate(LPCREATESTRUCT lpCreateStruct) { SetMsgHandled(FALSE); return 0; } void SouiWindow::OnSize(UINT nType, CSize size) { SetMsgHandled(FALSE); if (!m_bLayoutInited) return; if (nType == SIZE_MAXIMIZED) { FindChildByName(L"btn_restore")->SetVisible(TRUE); FindChildByName(L"btn_max")->SetVisible(FALSE); } else if (nType == SIZE_RESTORED) { FindChildByName(L"btn_restore")->SetVisible(FALSE); FindChildByName(L"btn_max")->SetVisible(TRUE); } } BOOL SouiWindow::OnInitDialog(HWND hWnd, LPARAM lParam) { m_bLayoutInited = true; return 0; }
接下来就是如何使用了,首先编写窗口XML布局文件,这里是MainWnd.xml,具体的内容这里不再详述。
SouiApp app; // 资源路径一般为当前程序运行目录下面的res文件下 app.setResPath(app.getAppPath() + L"\res"); app.initApp(hInstance); // 必须在uires.idx文件中,必须编写窗口资源名称和窗口XML布局文件路径,例如'<file name="XML_MAINWND" path="MainWnd.xml" />' SouiWindow mainWnd(L"LAYOUT:XML_MAINWND"); mainWnd.create(); mainWnd.centerShow(); // 消息循环 app.run(mainWnd);
最后的界面显示为:
这里有一个小技巧,如何让窗体四周没有圆角矩形呢?
我们可以在root节点中使用属性skin="skin.border",它是一个半透明的png图片,定义为<imgframe name="skin.border" src="PNG:ID_SHADOW" left="5" top="3" right="5" bottom="7"/>,只显示窗口边框的阴影部分;
然后在window节点中使用一张背景图片,就可以到的上图的效果,具体可参考SOUI中的"360"deom。