欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)激活碼778899分享:c++ SOUI總結(jié)之常用功能

柚子快報(bào)激活碼778899分享:c++ SOUI總結(jié)之常用功能

http://yzkb.51969.com/

常用功能

XML特殊字符顯示

空格 ( )

Tab ( )

回車 ( )

換行 ( )

& (&)

< (<)

> (>)

‘ (')

“ (")

帶滾動(dòng)條的自動(dòng)滾動(dòng)

SRichEdit* pWnd = FindChildByName2(L"richedit");

if (pWnd)

{

?? pWnd->ReplaceSel(strtext);

?? pWnd->SetScrollPos(TRUE,0x7fffffff,FALSE);

?? static int i = 0;

?? if (i > 0x7fffffff)

?? {

????? pWnd->SetWindowText(NULL);

????? i = 0;

?? }

?? i++;

}

控件的顯示與隱藏

?

?

?

???

?

模態(tài)對(duì)話框

uires.idx

??

xml

???

???????

???

???

??? ??

?? ??? ??

?? ??????????? pointer_hour="img.clock:pointer_hour"

?? ??????????? pointer_minute="img.clock:pointer_minute"

?? ??????????? pointer_second="img.clock:pointer_second"

?? ??????? />

?? ??????

?

頭文件

#pragma once

namespace SOUI

{

??? class CFormatMsgDlg : public SHostDialog

??? {

??? public:

??????? CFormatMsgDlg(void);

??????? ~CFormatMsgDlg(void);

BOOL OnInitDialog(HWND wnd, LPARAM lInitParam);

??????? void OnOK();

??????? SStringT m_strMsg;? //消息XML

??????? int????? m_nRepeat; //重復(fù)次數(shù)

??????? EVENT_MAP_BEGIN()

??????????? EVENT_ID_COMMAND(IDOK,OnOK)

??????? EVENT_MAP_END()

BEGIN_MSG_MAP_EX(CFormatMsgDlg )

?? MSG_WM_INITDIALOG(OnInitDialog)

?? CHAIN_MSG_MAP(SHostDialog)

?? REFLECT_NOTIFICATIONS_EX()

END_MSG_MAP()

??? };

}

源文件

#include "stdafx.h"

#include "FormatMsgDlg.h"

namespace SOUI

{

??? CFormatMsgDlg::CFormatMsgDlg(void):SHostDialog(_T("layout:dlg_formatmsg"))

??? {

??????? m_nRepeat=1;

??? }

??? CFormatMsgDlg::~CFormatMsgDlg(void)

??? {

}

BOOL CFormatMsgDlg::OnInitDialog(HWND wnd, LPARAM lInitParam)

{

}

??? void CFormatMsgDlg::OnOK()

??? {

??????? SRichEdit *pEdit = FindChildByName2(L"re_xmlinput");

??????? m_strMsg = pEdit->GetWindowText();

??????? SEdit *pRepeat = FindChildByName2(L"edit_repeat");

??????? SStringT strRepeat = pRepeat->GetWindowText();

??????? m_nRepeat = _tstoi(strRepeat);

??????? SHostDialog::OnOK();

??? }

}

調(diào)用

CFormatMsgDlg formatMsgDlg;

if(formatMsgDlg.DoModal()==IDOK)

{

}

非模態(tài)對(duì)話框

Xml文件

?

??

????

????

??????

?????? 設(shè)置皮膚

??????

??????

????

????

??????

??????

????

??

?

頭文件

#pragma once

class CSetSkinWnd:public SHostWnd

{

SOUI_CLASS_NAME(CSetSkinWnd, L"dlgserialset")

public:

?? CSetSkinWnd();

?? ~CSetSkinWnd();

?? void OnClose();

?? BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam);

public:

?? EVENT_MAP_BEGIN()

????? EVENT_NAME_COMMAND(L"btn_close",OnClose)

?? EVENT_MAP_END()

?? BEGIN_MSG_MAP_EX(CSetSkinWnd)

????? MSG_WM_INITDIALOG(OnInitDialog)

????? CHAIN_MSG_MAP(SHostWnd)? //注意這個(gè)消息放在最后

????? REFLECT_NOTIFICATIONS_EX()

?? END_MSG_MAP()

};

源文件

#include "stdafx.h"

#include "CSetSkinWnd.h"

CSetSkinWnd::CSetSkinWnd():SHostWnd(_T("LAYOUT:set_skin_wnd"))

{

}

CSetSkinWnd::~CSetSkinWnd()

{

}

BOOL CSetSkinWnd::OnInitDialog(HWND wndFocus, LPARAM lInitParam)

{

?? return TRUE;

}

void CSetSkinWnd::OnClose()

{

?? CSimpleWnd::DestroyWindow();

}

調(diào)用

m_dlgSetSkin = new CSetSkinWnd;

if (m_dlgSetSkin->m_hWnd)

{

?? SetForegroundWindow(m_dlgSetSkin->m_hWnd);

?? FlashWindow(m_dlgSetSkin->m_hWnd, TRUE);

}

else

{

?? m_dlgSetSkin->Create(NULL);

m_dlgSetSkin->SendMessage(WM_INITDIALOG);

?? m_dlgSetSkin->CenterWindow(GetDesktopWindow());

?? m_dlgSetSkin->ShowWindow(SW_SHOWNORMAL);

}

m_dlgSetSkin->Create(NULL);這條語(yǔ)句是創(chuàng)建的時(shí)候制定一個(gè)父窗口,如果不指定,那么在點(diǎn)擊主窗口的時(shí)候這個(gè)新建的窗口會(huì)被遮住,如果指定為m_hwnd主窗口,那么同樣會(huì)顯示在前面。

m_dlgSetSkin->CenterWindow(GetDesktopWindow());這條語(yǔ)句是讓新建的窗口顯示在屏幕的中間,如果想讓窗口顯示在主界面的中間,改為m_dlgSetSkin->CenterWindow(m_hwnd)即可。

在m_dlgSetSkin->SendMessage(WM_INITDIALOG);發(fā)送消息時(shí)可以帶上一些附加參數(shù),如

m_DlgSerialSet->SendMessage(WM_INITDIALOG, (WPARAM)this, (WPARAM)this);

然后在OnInitDialog中將它轉(zhuǎn)換過(guò)來(lái)

其實(shí)第一個(gè)參數(shù)wnd對(duì)應(yīng)WPARAM,第二個(gè)參數(shù)對(duì)應(yīng)lInitParam。

控件重繪篇

class SListBoxEx :public SListBox

{

public:

?? SOUI_CLASS_NAME(SListBoxEx, L"listboxex")

?? SListBoxEx(){}

?? virtual ~SListBoxEx(){}

protected:

?? void OnLButtonUp(UINT nFlags,CPoint pt);

?? SOUI_ATTRS_BEGIN()

?? SOUI_ATTRS_END()

?? SOUI_MSG_MAP_BEGIN()

?? MSG_WM_LBUTTONUP(OnLButtonUp)

?? SOUI_MSG_MAP_END()

};

注意:1.想要在繼承類中獲取鼠標(biāo)左鍵彈起事件,就需要添加SOUI_MSG_MAP_BEGIN()、MSG_WM_LBUTTONUP(OnLButtonUp)、SOUI_MSG_MAP_END()三條語(yǔ)句。

每寫(xiě)一個(gè)新的控件都要進(jìn)行注冊(cè)才能用,如:

SApplication *theApp=new SApplication(pRenderFactory,hInstance);

theApp->RegisterWindowClass();

主窗口分流篇

Main.h文件

class CMainDlg : public SHostWnd

{

public:

?? CMainDlg(LPCTSTR xmlName);

?? ~CMainDlg();

??

protected:

?? int OnCreate(LPCREATESTRUCT lpCreateStruct);

?? BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam);

?? void OnClose();//關(guān)閉響應(yīng)函數(shù)

?? void OnMaximize();//最大化響應(yīng)函數(shù)

?? void OnRestore();//恢復(fù)響應(yīng)函數(shù)

??? void OnMinimize();//最小化響應(yīng)函數(shù)

protected:

?? //soui消息

?? EVENT_MAP_BEGIN()

????? CHAIN_EVENT_MAP_MEMBER(m_uiFlashDlg)

????? 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()

?? //HostWnd真實(shí)窗口消息處理

?? BEGIN_MSG_MAP_EX(CMainDlg)

????? CHAIN_MSG_MAP_MEMBER(m_uiFlashDlg)

????? MSG_WM_CREATE(OnCreate)

????? MSG_WM_CLOSE(OnClose)

????? MSG_WM_INITDIALOG(OnInitDialog)

????? CHAIN_MSG_MAP(SHostWnd)

????? REFLECT_NOTIFICATIONS_EX()

?? END_MSG_MAP()

private:

?? BOOL???????? m_bLayoutInited;

?? CUIFlashDlg????? m_uiFlashDlg;

}

Main.cpp文件

CMainDlg::CMainDlg(LPCTSTR xmlName) : SHostWnd(xmlName)

{

?? m_bLayoutInited = FALSE;

}

CMainDlg::~CMainDlg()

{

}

int CMainDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

?? SetMsgHandled(FALSE);

?? return 0;

}

BOOL CMainDlg::OnInitDialog(HWND hWnd, LPARAM lParam)

{

?? theApp.m_pMainDlg = this;

?? m_uiFlashDlg.OnInit(this,m_hWnd);

?? ::SetTimer(m_hWnd,1,200,NULL);//創(chuàng)建定時(shí)器,同時(shí)會(huì)向其他類發(fā)送消息

?? return 0;

}

void CMainDlg::OnClose()

{

?? if(!m_uiFlashDlg.OnClose())

????? return;

??? theApp.m_singleInst.Release();

??? ::DestroyWindow(m_hWnd);

}

void CMainDlg::OnMaximize()

{

?? SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE);

}

void CMainDlg::OnRestore()

{

?? SendMessage(WM_SYSCOMMAND, SC_RESTORE);

}

void CMainDlg::OnMinimize()

{

?? SendMessage(WM_SYSCOMMAND, SC_MINIMIZE);

}

子窗口為父窗口承擔(dān)任務(wù)

CUIFlashDlg.h頭文件

class CUIFlashDlg

{

public:

?? CUIFlashDlg();

?? ~CUIFlashDlg();

?? void OnInit(SHostWnd* pRoot,HWND hWnd);

?? void OnDestory();

?? BOOL OnClose();

protected:

?? EVENT_MAP_BEGIN()

????? EVENT_CHECK_SENDER_ROOT(m_pHostWnd)

?? EVENT_MAP_BREAK()

?? BEGIN_MSG_MAP_EX(CUIFlashDlg)

????? MSG_WM_DESTROY(OnDestory)

?? END_MSG_MAP()

private:

?? HWND m_hWnd;

?? SHostWnd *m_pHostWnd;

};

CUIFlashDlg.cpp源文件

CUIFlashDlg::CUIFlashDlg()

{

?? m_pHostWnd = NULL;

?? m_hWnd = NULL;

}

CUIFlashDlg::~CUIFlashDlg()

{

}

void CUIFlashDlg::OnInit(SHostWnd* pRoot,HWND hWnd)

{

?? m_pHostWnd = pRoot;

?? m_hWnd = hWnd;

}

BOOL CUIFlashDlg::OnClose()

{

?? m_pHostWnd = NULL;

?? return TRUE;

}

void CUIFlashDlg::OnDestory()

{

?? SetMsgHandled(FALSE);

}

在 SOUI 中實(shí)現(xiàn) PreTranslateMessage

在 MFC 中,通??梢酝ㄟ^(guò)重載 CWnd::PreTranslateMessage 這樣一個(gè)虛函數(shù)來(lái)實(shí)現(xiàn)對(duì)一些窗口消息的預(yù)處理。多用于 tooltip 的顯示控制。

在 SOUI 中也實(shí)現(xiàn)了類似的機(jī)制。

要在 SOUI 中實(shí)現(xiàn) PreTranslateMessage,我們首先需要實(shí)現(xiàn)一個(gè)接口:

struct IMessageFilter

{

virtual BOOL PreTranslateMessage(MSG* pMsg) = 0;

};

可以看出,實(shí)現(xiàn)這個(gè)接口和在 MFC 中重載 PreTranslateMessage 是相同的道理。和 MFC 中只需要重載這個(gè)接口不同,在 SOUI 中,除了需要實(shí)現(xiàn) IMessageFilter 外,還需要向當(dāng)前的 MessageLoop 注冊(cè)該 IMessageFilter。

class SOUI_EXP SMessageLoop

{

public:

SArray m_aMsgFilter;

// Message filter operations

BOOL AddMessageFilter(IMessageFilter* pMessageFilter);

BOOL RemoveMessageFilter(IMessageFilter* pMessageFilter);

//...

};

上面是 SMessageLoop 兩個(gè)和 IMessageFilter 相關(guān)的方法。

SMessageLoop::AddMessageFilter 向當(dāng)前的 message loop 注冊(cè)一個(gè)

IMessageFilter;

SMessageLoop::RemoveMessageFilter 則向當(dāng)前的 message loop 注銷一個(gè)

IMessageFilter

剩下的問(wèn)題就是如何獲得當(dāng)前的 MessageLoop 了。

在 SHostWnd 或者 SHostDialog 中可以調(diào)用 SHostWnd::GetMsgLoop()方法獲得。

在 SWindow 中,則可以調(diào)用 SWindow::GetContainer()->GetMsgLoop()獲得。

使用示例可以參考 SDropDownWnd 的實(shí)現(xiàn)。

class SOUI_EXP SDropDownWnd : public SHostWnd, public IMessageFilter

{

//...

};

動(dòng)態(tài)的創(chuàng)建控件

1. 動(dòng)態(tài)創(chuàng)建按鈕第一種方式

XML文件

?

?

源代碼

void CMainDlg::OnBtn()

{

?? SWindow* pWnd = FindChildByName(L"wnd");

?? if (pWnd)

?? {

????? SWindow* pChild = pWnd->GetWindow(GSW_FIRSTCHILD);

????? while (pChild)

????? {

???????? SWindow* p = pChild->GetWindow(GSW_NEXTSIBLING);

???????? pChild->DestroyWindow();

???????? pChild = p;

????? }

????? for (int i = 0; i < 5; ++i)

????? {

???????? SStringW strXml;

???????? strXml.Format(L"", 1000 + i, i);

???????? SWindow* pRet = pWnd->CreateChildren(strXml);

???????? //訂閱事件

???????? pRet->GetEventSet()->subscribeEvent(EVT_LBUTTONDOWN, Subscriber(&CMainDlg::OnClick, this));

????? }

?? }

}

bool CMainDlg::OnClick(EventArgs* pArg)

{

?? SButton* pBtn = FindChildByID2(pArg->idFrom);

?? if (pBtn)

?? {

????? SStringW str;

????? str.Format(L"%d", pArg->idFrom);

????? SMessageBox(m_hWnd, str, L"ID", MB_OK);

?? }

?? return TRUE;

}

效果如下圖

2. 動(dòng)態(tài)創(chuàng)建按鈕第二種方式

SScrollView* pWnd = FindChildByName2(L"scrvIO");

if (pWnd)

{

??? //首先移除所有子窗口

?? SWindow* pChild = pWnd->GetWindow(GSW_FIRSTCHILD);

?? while (pChild)

?? {

????? SWindow* pNext = pChild->GetWindow(GSW_NEXTSIBLING);

????? pChild->DestroyWindow();

????? pChild = pNext;

?? }

?? SStringT strXml;

?? pugi::xml_document xmlDoc;

?? for (int i = 0;i < 100;i++)

?? {

????? strXml.Format(L"",i + 1000000);

????? xmlDoc.reset();

????? if (!xmlDoc.load_buffer((LPCWSTR)strXml,wcslen(strXml) * sizeof(wchar_t),pugi::parse_default, pugi::encoding_utf16))

????? {

???????? return FALSE;

????? }

????? pChild = new SButton();

????? if (pChild)

????? {

???????? pWnd->InsertChild(pChild);

???????? pChild->InitFromXml(xmlDoc.first_child());

????? }

?? }

//訂閱事件

SButton* pBtn = pChild->FindChildByName2(L"deleteBtn");

pBtn->GetEventSet()->subscribeEvent(EVT_LBUTTONDOWN,Subscriber(&CCombineCmdDlg::OnDelete,this));

}

按鈕點(diǎn)擊的響應(yīng)事件

bool CCombineCmdDlg::OnDelete(EventArgs* pArgs)

{

?? SButton* pBtn = (SButton*)pArgs->sender;

?? SWindow* pChild = pBtn->GetParent()->GetParent();

?? SScrollView* pWnd = FindChildByName2(L"scrollview");

?? if (pWnd)

?? {

????? pWnd->DestroyChild(pChild);

?? }

?? pWnd->RequestRelayout(); //刪除按鈕之后需要重新布局

?? return true;

}

void OnCommandRange(UINT nID);

EVENT_ID_COMMAND_RANGE(1000000,2000000,OnCommandRange)

void CMainDlg::OnCommandRange(UINT nID)

{

?? SStringT str;

?? str.Format(L"ID:%d",nID);

?? SMessageBox(m_hWnd,str,L"提示",MB_OK);

}

按鈕右鍵響應(yīng)事件

pChild->GetEventSet()->subscribeEvent(EVT_CTXMENU,Subscriber(&CMainDlg::OnBtnRClick, this));? //訂閱右鍵點(diǎn)擊事件

bool CMainDlg::OnBtnRClick(EventArgs *pEvt)

{

?? EventCtxMenu *pET = sobj_cast(pEvt);

?? if (pET)

?? {

????? int id = pET->idFrom;

????? SMenu menu;

????? menu.LoadMenu(_T("menu"),_T("SMENU"));

?? ?? CPoint pt;

????? GetCursorPos(&pt);

????? int iR = menu.TrackPopupMenu(0, pt.x, pt.y, m_hWnd);

????? if (iR != 1)

????? {

???????? SLOGFMTE("TrackPopupMenu returns a failure: CEventHandlerEffect::OnBtnRClick(EventArgs *pEvt)");

???????? return FALSE;

????? }

?? }

?? return TRUE;

}

編輯框接受文件拖拽

#pragma once

#include

#include

class CTestDropTarget :public IDropTarget

{

public:

?? CTestDropTarget()

?? {

????? nRef = 0;

?? }

?? virtual ~CTestDropTarget() {}

?? //

?? // IUnknown

?? virtual HRESULT STDMETHODCALLTYPE QueryInterface(

????? /* [in] */ REFIID riid,

????? /* [iid_is][out] */ __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)

?? {

????? HRESULT hr = S_FALSE;

????? if (riid == __uuidof(IUnknown))

???????? *ppvObject = (IUnknown*)this, hr = S_OK;

????? else if (riid == __uuidof(IDropTarget))

???????? *ppvObject = (IDropTarget*)this, hr = S_OK;

????? if (SUCCEEDED(hr)) AddRef();

????? return hr;

?? }

?? virtual ULONG STDMETHODCALLTYPE AddRef(void)

?? {

????? return ++nRef;

?? }

?? virtual ULONG STDMETHODCALLTYPE Release(void)

?? {

????? ULONG uRet = --nRef;

????? if (uRet == 0) delete this;

????? return uRet;

?? }

?? //

?? // IDropTarget

?? virtual HRESULT STDMETHODCALLTYPE DragEnter(

????? /* [unique][in] */ __RPC__in_opt IDataObject *pDataObj,

????? /* [in] */ DWORD grfKeyState,

????? /* [in] */ POINTL pt,

????? /* [out][in] */ __RPC__inout DWORD *pdwEffect)

?? {

????? *pdwEffect = DROPEFFECT_LINK;

????? return S_OK;

?? }

?? virtual HRESULT STDMETHODCALLTYPE DragOver(

????? /* [in] */ DWORD grfKeyState,

????? /* [in] */ POINTL pt,

????? /* [out][in] */ __RPC__inout DWORD *pdwEffect)

?? {

????? *pdwEffect = DROPEFFECT_LINK;

????? return S_OK;

?? }

?? virtual HRESULT STDMETHODCALLTYPE DragLeave(void)

?? {

????? return S_OK;

?? }

protected:

?? int nRef;

};

class CTestDropTarget1 : public CTestDropTarget

{

protected:

?? SWindow *m_pEdit;

public:

?? CTestDropTarget1(SWindow *pEdit) :m_pEdit(pEdit)

?? {

????? if (m_pEdit) m_pEdit->AddRef();

?? }

?? ~CTestDropTarget1()

?? {

????? if (m_pEdit) m_pEdit->Release();

?? }

public:

?? virtual HRESULT STDMETHODCALLTYPE Drop(

????? /* [unique][in] */ __RPC__in_opt IDataObject *pDataObj,

????? /* [in] */ DWORD grfKeyState,

????? /* [in] */ POINTL pt,

????? /* [out][in] */ __RPC__inout DWORD *pdwEffect)

?? {

????? FORMATETC format =

????? {

???????? CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL

????? };

????? STGMEDIUM medium;

????? if (FAILED(pDataObj->GetData(&format, &medium)))

????? {

???????? return S_FALSE;

????? }

????? HDROP hdrop = static_cast(GlobalLock(medium.hGlobal));

????? if (!hdrop)

????? {

???????? return S_FALSE;

????? }

????? bool success = false;

????? TCHAR filename[MAX_PATH];

????? success = !!DragQueryFile(hdrop, 0, filename, MAX_PATH);

????? DragFinish(hdrop);

????? GlobalUnlock(medium.hGlobal);

????? if (success && m_pEdit)

????? {

???????? m_pEdit->SetWindowText(filename);

????? }

????? *pdwEffect = DROPEFFECT_LINK;

????? return S_OK;

?? }

};

使用如下:

BOOL CMainDlg::OnInitDialog(HWND hWnd, LPARAM lParam)

{

?? m_bLayoutInited = TRUE;

?? ::RegisterDragDrop(m_hWnd, GetDropTarget());

?? SWindow* pWnd = FindChildByName(L"edit");

?? if (pWnd)

?? {

????? RegisterDragDrop(pWnd->GetSwnd(),new CTestDropTarget1(pWnd));

?? }

??

?? return 0;

}

效果如下:

從文件中創(chuàng)建窗口

1.文件資源準(zhǔn)備

?

2.test.xml

?

???

???

?

?

??? 本窗口是從文件直接創(chuàng)建的。

???

???

?

3.點(diǎn)擊按鈕創(chuàng)建

void CMainDlg::OnBtn()

{

?? wchar_t szBuf[MAX_PATH] = {};

?? GetModuleFileName(NULL, szBuf, MAX_PATH);

?? wchar_t* pFind = wcsrchr(szBuf, L'\\');

?? if (pFind)

?? {

????? *(pFind + 1) = '\0';

????? wcscat(szBuf, L"filewnd");

?? }

?? SetCurrentDirectory(szBuf);

?? if (GetFileAttributes(L"test.xml") == INVALID_FILE_ATTRIBUTES)

?? {

????? return;

?? }

?? SHostDialog dlg(L"file:test.xml");

?? dlg.DoModal(m_hWnd);

}

效果如下:

控件事件的響應(yīng)

SOUI 中提供了大部分常用的 win32 標(biāo)準(zhǔn)控件的實(shí)現(xiàn),如 pushbutton, checkbox,

radiobox, edit, richedit, listbox, combobox, treectrl, listctrl (report), hotkeyctrl 等。

大部分控件在接收用戶輸入后,會(huì)發(fā)生狀態(tài)的改變,并以事件的形式傳遞給 UI 的所有者。

在 SOUI 中提供了兩種處理事件的方式:

4.8.1 在 SHostWnd 的派生類中重載

virtual BOOL SHostWnd::_HandleEvent(SOUI::EventArgs *pEvt){return FALSE;}

為了更方便的處理事件,SOUI 提供了一組宏來(lái)構(gòu)造這個(gè)事件處理函數(shù),從而提供一種類

似消息映射的事件處理形式。

如 demo 的 CMainDlg 中的實(shí)現(xiàn):

//UI 控件的事件及響應(yīng)函數(shù)映射表

EVENT_MAP_BEGIN()

EVENT_ID_COMMAND(1, OnClose)

EVENT_ID_COMMAND(2, OnMaximize)

EVENT_ID_COMMAND(3, OnRestore)

EVENT_ID_COMMAND(5, OnMinimize)

EVENT_NAME_CONTEXTMENU(L"edit_1140",OnEditMenu)

EVENT_NAME_COMMAND(L"btn_msgbox",OnBtnMsgBox)

EVENT_NAME_COMMAND(L"btnSelectGif",OnBtnSelectGIF)

EVENT_NAME_COMMAND(L"btn_menu",OnBtnMenu)

EVENT_NAME_COMMAND(L"btn_webkit_go",OnBtnWebkitGo)

EVENT_NAME_COMMAND(L"btn_webkit_back",OnBtnWebkitBackward)

EVENT_NAME_COMMAND(L"btn_webkit_fore",OnBtnWebkitForeward)

EVENT_NAME_COMMAND(L"btn_webkit_refresh",OnBtnWebkitRefresh)

EVENT_NAME_COMMAND(L"btn_hidetst",OnBtnHideTest)

EVENT_NAME_COMMAND(L"btn_insert_gif",OnBtnInsertGif2RE)

EVENT_MAP_END()

上面的 EVENT_MAP_BEGIN()和 EVENT_MAP_END()結(jié)合構(gòu)造出一個(gè)_HandleEvent 函數(shù)

的實(shí)現(xiàn),具體可以自己展開(kāi)這兩個(gè)宏查看代碼。

同時(shí) SOUI 也提供了一組解析 SOUI::EventArgs *pEvt 的宏,如上例中的

EVENT_NAME_COMMAND, EVENT_ID_COMMAND 等。

幫助用戶直接從控件的 name 或者 ID 屬性映射到消息響應(yīng)函數(shù)。

這種事件響應(yīng)方式最大的好處是能夠集中處理事件的分發(fā),方便閱讀代碼,同時(shí)也和傳統(tǒng)

的 MFC,WTL 的編程風(fēng)格類似,降低用戶的學(xué)習(xí)成本。

采用事件訂閱的方式響應(yīng)控件事件

雖然事件映射表提供了一種簡(jiǎn)單有效的事件響應(yīng)機(jī)制,由于事件映射表是一種編譯期形成

的靜態(tài)的映射表,對(duì)于在運(yùn)行期動(dòng)態(tài)創(chuàng)建的控件的事件響應(yīng)就無(wú)能為力了。

在 MFC 中,程序員通過(guò)要重載窗口類的 DefWindowProc 來(lái)處理運(yùn)行期間動(dòng)態(tài)創(chuàng)建的控

件發(fā)來(lái)的消息。

這種方式靈活性夠了,但是不夠優(yōu)雅,要在一個(gè)函數(shù)里做大量的 swich 分枝,導(dǎo)致這個(gè)處

理函數(shù)很難維護(hù)。

設(shè)計(jì)模式里的觀察者模式可以比較好的解決這個(gè)問(wèn)題。

為些在 SOUI 中我提供了一種事件訂閱的事件處理模式。

我們先看一下 demo 中怎樣處理列表控件的表頭點(diǎn)擊來(lái)執(zhí)行排序操作:

void CMainDlg::InitListCtrl()

{

64

//找到列表控件

SListCtrl *pList=FindChildByName2(L"lc_test");

if(pList)

{

//列表控件的唯一子控件即為表頭控件

SWindow *pHeader=pList->GetWindow(GSW_FIRSTCHILD);

//向表頭控件訂閱表明點(diǎn)擊事件,并把它和 OnListHeaderClick 函數(shù)相連。

pHeader->GetEventSet()->subscribeEvent(EVT_HEADER_CLICK,Subscriber(&CMainDlg

::OnListHeaderClick,this));

//省略列表初始化代碼

}

}

//表頭點(diǎn)擊事件處理函數(shù)

bool CMainDlg::OnListHeaderClick(EventArgs *pEvtBase)

{

//事件對(duì)象強(qiáng)制轉(zhuǎn)換

EventHeaderClick *pEvt =(EventHeaderClick*)pEvtBase;

SHeaderCtrl *pHeader=(SHeaderCtrl*)pEvt->sender;

//從表頭控件獲得列表控件對(duì)象

SListCtrl *pList= (SListCtrl*)pHeader->GetParent();

//列表數(shù)據(jù)排序

SHDITEM hditem;

hditem.mask=SHDI_ORDER;

pHeader->GetItem(pEvt->iItem,&hditem);

pList->SortItems(funCmpare,&hditem.iOrder);

return true;

}

通過(guò)事件訂閱可以在運(yùn)行時(shí)方便的將一個(gè)控件的事件關(guān)聯(lián)到一個(gè)處理函數(shù)上,當(dāng)然也可以

隨時(shí)取消訂閱。

同時(shí)事件訂閱也是在腳本中響應(yīng)控件事件的唯一方式(關(guān)于在 SOUI 中使用 LUA 腳本將在

后續(xù)講解)。

多語(yǔ)言翻譯機(jī)制

為 UI 在不同地區(qū)顯示不同的語(yǔ)言是產(chǎn)品國(guó)際化的一個(gè)重要要求。

在 SOUI 中實(shí)現(xiàn)了一套類似 QT 的多語(yǔ)言翻譯機(jī)制:布局 XML 不需要調(diào)整,程序代碼也不

需要調(diào)整,只需要為不同地區(qū)的用戶提供不同的語(yǔ)言翻譯文件即可。

65

在 SOUI 中,我們實(shí)現(xiàn)了一個(gè)使用明文 XML 的語(yǔ)言翻譯模塊:translator.dll

為了使用多語(yǔ)言翻譯,首先需要準(zhǔn)備一個(gè)語(yǔ)言翻譯的 XML 文件。demo 中使用的翻譯文

件如下:

copy

復(fù)制

cut

剪切

paste

粘貼

ok

確定

cancel

取消

retry

重試

close

關(guān)閉窗口

66

可以看到該 XML 中有一個(gè) language 的根節(jié)點(diǎn),該節(jié)點(diǎn)有兩個(gè)屬性:name 和 guid,這

兩個(gè)屬性都是用來(lái)標(biāo)識(shí)該翻譯文件的。

在 language 節(jié)點(diǎn)下,有多個(gè) context 節(jié)點(diǎn),每個(gè) context 節(jié)點(diǎn)有一個(gè) name 屬性(可以

為空),對(duì)應(yīng)一個(gè)翻譯上下文。

每一個(gè) context 下有不同數(shù)量的 message 結(jié)點(diǎn),每個(gè) message 又有兩個(gè)子節(jié)點(diǎn):

source 和 translation。

source 對(duì)應(yīng)需要翻譯的文字,而 translation 則對(duì)應(yīng)翻譯后的文字。

要使用這個(gè)語(yǔ)言翻譯文件,首先需要從 translator.dll 中創(chuàng)建一個(gè) SOUI::ITranslatorMgr

對(duì)象,并將該對(duì)象交給 SOUI::SApplication 管理。

再?gòu)?ItranslatorMgr 對(duì)象創(chuàng)建 SOUI::ITranslator 對(duì)象,并將 Itranslator 對(duì)象添加到

ItranslatorMgr 管理的翻譯列表中。

最后還要為 ITranslator 對(duì)象加載翻譯數(shù)據(jù)源(也就是前面提供的 XML 文件)。

下面是 demo 中使用和語(yǔ)言翻譯相關(guān)的代碼(見(jiàn)_tWinMain 函數(shù))

SApplication *theApp=new SApplication(pRenderFactory,hInstance);//SOUI

APP

CAutoRefPtr transMgr; //多語(yǔ)言翻譯模塊,由 translator.dll

提供

transLoader.CreateInstance("translator.dll",(IObjRef**)&transMgr);//

if(trans)

{//加載語(yǔ)言翻譯包

theApp->SetTranslator(transMgr);

pugi::xml_document xmlLang;

if(theApp->LoadXmlDocment(xmlLang,_T("lang_cn"),

_T("translator")))

{

CAutoRefPtr langCN;

transMgr->CreateTranslator(&langCN);

langCN->Load(&xmlLang.child(L"language"),1);

//1=LD_XML

transMgr->InstallTranslator(langCN);

}

}

我們先看一下 editmemu 的 XML:

iconMargin="4" textMargin="8" >

cut

copy

paste

67

delete

select all

在這個(gè) XML 中,根節(jié)點(diǎn)有一個(gè)屬性 trCtx,代表翻譯上下文,對(duì)應(yīng)語(yǔ)言翻譯文件中的

context 中的 name 屬性。

在這個(gè) menu 定義中,所有的菜單項(xiàng)的文字全是英文。其中前面 3 項(xiàng):cut, copy and

paste 在語(yǔ)言翻譯文件中有對(duì)應(yīng)的翻譯項(xiàng)。

下圖為程序運(yùn)行時(shí) edit 的右鍵菜單顯示結(jié)果:

上面演示的是菜單資源的語(yǔ)言翻譯,布局 XML 中的文字的翻譯基本一樣,只需要為布局

的根結(jié)點(diǎn)定義一個(gè)翻譯上下文(trCtx)(沒(méi)有定義時(shí)則從沒(méi)有指定 name 屬性的 context 里

查找翻譯結(jié)果)。

可以參見(jiàn) demo 的"close”按照的 tooltip 的翻譯。

不管是菜單 XML 還是布局 XML,它們都是靜態(tài)的,經(jīng)過(guò)設(shè)計(jì)需要使用代碼往 UI 添加新

的文字,同樣也需要翻譯,這個(gè)時(shí)候如何處理?

其實(shí)看一下靜態(tài)資源翻譯的代碼就知道,要實(shí)現(xiàn)語(yǔ)言翻譯,需要為每一句待翻譯的文字調(diào)

用一個(gè)函數(shù):

SApplication::getSingleton().GetTranslator()->tr(const SStringW &

strSrc,const SStringW & strCtx)

第一個(gè)參數(shù)是等翻譯字符串,第二個(gè)參數(shù)是翻譯上下文。

考慮到語(yǔ)句太長(zhǎng),系統(tǒng)提供了一個(gè)宏:

#define TR(p1,p2)

SApplication::getSingleton().GetTranslator()->tr(p1,p2)

這樣用 TR 就可以實(shí)現(xiàn)文字翻譯了。

使用分層窗口

從 Windows 2K 開(kāi)始,MS 為 UI 開(kāi)發(fā)引入了分層窗口這一窗口風(fēng)格。使用分層窗口,應(yīng)

用程序的主窗口可以是半透明,也可以是逐點(diǎn)半透明(即每一個(gè)像素點(diǎn)的透明度可以不

同)。

可以說(shuō),正是因?yàn)橛辛朔謱哟翱?,?Windows 上開(kāi)發(fā)的應(yīng)用程序的 UI 才真正炫起來(lái)。

在 UI 的主窗口上加一個(gè)分層窗口的風(fēng)格對(duì)于一個(gè)稍有點(diǎn) UI 開(kāi)發(fā)經(jīng)驗(yàn)的程序員來(lái)說(shuō)是非常

簡(jiǎn)單的,本篇要說(shuō)的是在 SOUI 的窗口系統(tǒng)中實(shí)現(xiàn) SOUI 的分層窗口。

正如使用系統(tǒng)的窗口已經(jīng)可以實(shí)現(xiàn)很漂亮的 UI,我們還是會(huì)需要 DirectUI 這樣的 UI 開(kāi)發(fā)

技術(shù);有了系統(tǒng)的分層窗口,我們還是會(huì)需要在 DirectUI Window 之間的分層窗口技

術(shù)。

一個(gè) DirectUI 系統(tǒng)的分層窗口有什么用呢?

分層窗口和一般窗口的關(guān)鍵區(qū)別在在于:一個(gè)分層窗口是一個(gè)相對(duì)獨(dú)立的渲染層,它能將

它的子窗口渲染到這個(gè)窗口上,當(dāng)所有分層窗口都渲染完成后,再按照分層窗口的 zorder

89

順序通過(guò)不同的 alpha 混合技術(shù)進(jìn)行混合;而一般的 DirectUI 系統(tǒng)只有一個(gè)渲染層,所有

窗口按照 zorder 順序依次渲染到這個(gè)渲染層上,缺少了不同渲染層的概念。

一個(gè)簡(jiǎn)單的例子:業(yè)務(wù)可能希望一個(gè)功能面板能夠整體半透明,該功能面版可能包含很多

子窗口。

如果沒(méi)有分層窗口特性,在 DirectUI 中實(shí)現(xiàn)類似的需求很很復(fù)雜(如分別指定每一個(gè)子窗

口的半透明)而且可能導(dǎo)致性能下降、內(nèi)存消耗的提高等問(wèn)題。

如果有了分層窗口,實(shí)現(xiàn)類似的需求就非常簡(jiǎn)單了:只需要為該功能面板指定一個(gè)透明度

就行了。在渲染的時(shí)候,功能面板的子窗口會(huì)以正常的渲染方式渲染到分層窗口的緩存

上,全部渲染完成后,再整體和上一個(gè)渲染層混合,從而得到期望的效果。

在 SOUI 里如何使用分層窗口:

SOUI 采用 XML 定義 UI,要定義分層窗口只需要一個(gè) layeredWindow="1"的屬性即可。

XML 定義:

layeredWindow="1">

name="switch" cursor="hand" tip="click me to show the animator that show or

hide the pane">

iconSkin="skin_tree_icon" checkBox="1" font="underline:1">

90

click the left grip to

\nshow or hide the \npane

顯示效果:

做事件分發(fā)處理

不同的 SOUI 控件可以產(chǎn)生不同的事件。SOUI 系統(tǒng)中提供了兩種事件處理方式:事件訂

閱 + 事件處理映射表(參見(jiàn)第八篇:SOUI 中控件事件的響應(yīng))

事件訂閱由于直接將事件及事件處理函數(shù)連接,不存在事件分發(fā)的問(wèn)題,這里主要介紹使

用事件映射表時(shí)的事件分發(fā)。

在回答這個(gè)問(wèn)題前,首先了解一下什么是事件分發(fā)。

在大型項(xiàng)目中,程序邏輯可能非常復(fù)雜,如果將所有 UI 中控件的事件處理集中在一個(gè)消息

/事件映射表里,代碼的可維護(hù)性會(huì)變得非常差。解決這個(gè)問(wèn)題常見(jiàn)的方法就是將事件進(jìn)行

分類(如根據(jù)來(lái)源分類),不同類別的事件采用一個(gè)獨(dú)立的事件處理對(duì)象來(lái)處理,這就是

事件分發(fā)的核心。

目前流行的 UI 通常采用 Tab 控件來(lái)組織 UI,不同的功能放到不同的 Tab 頁(yè)中,不同的

Tab 頁(yè)可能互不相干的功能模塊,對(duì)于類似這樣的情形很自然的會(huì)想到采用事件分發(fā)機(jī)制

來(lái)實(shí)現(xiàn)模塊之間邏輯的解耦(如下圖中 SoTool 采用的 UI)。

在上面的 UI 中,雖然整個(gè) UI 被 TAB 分成了 6 個(gè)頁(yè)面,但是 6 個(gè)頁(yè)面都存在于同一個(gè)宿

主窗口中。

一般情況下,如果 UI 相對(duì)比較簡(jiǎn)單,我們推薦直接在宿主窗口的事件處理映射表中統(tǒng)一處

理控件事件。

但是當(dāng)出現(xiàn)如上圖這樣復(fù)雜的界面時(shí),最好是將不同功能頁(yè)的事件處理在不同的對(duì)象中分

別處理。

在 MFC 中,一個(gè)類要處理消息,這個(gè)類通常派生自 CCmdTarget(可能記錯(cuò)了,太久不

用 MFC 了),主窗口收到的消息會(huì)自動(dòng)路由到這個(gè)消息處理對(duì)象中。

在 WTL 中,WTL 提供了一組消息映射宏:CHAIN_MSG_MAP,

CHAIN_MSG_MAP_MEMBER 等以便將消息分發(fā)到同樣實(shí)現(xiàn)了消息映射表的任意 C++對(duì)

象。

SOUI 的事件分發(fā)采用了 WTL 消息分發(fā)類似的機(jī)制,同樣采用事件映射宏的方式來(lái)構(gòu)造事

件映射表,下面是 SOUI 中幾個(gè)主要的和事件分發(fā)相關(guān)的宏:

#define EVENT_MAP_BEGIN() \

protected: \

virtual BOOL _HandleEvent(SOUI::EventArgs *pEvt)\

{ \

UINT uCode = pEvt->GetID(); \

#define EVENT_MAP_DECLEAR() \

protected: \

virtual BOOL _HandleEvent(SOUI::EventArgs *pEvt);\

#define EVENT_MAP_BEGIN2(classname) \

BOOL classname::_HandleEvent(SOUI::EventArgs *pEvt)\

{ \

UINT uCode = pEvt->GetID(); \

#define EVENT_MAP_END() \

return __super::_HandleEvent(pEvt); \

} \

#define EVENT_MAP_BREAK() \

return FALSE; \

} \

#define CHAIN_EVENT_MAP(ChainClass) \

if(ChainClass::_HandleEvent(pEvt)) \

return TRUE; \

119

#define CHAIN_EVENT_MAP_MEMBER(theChainMember) \

{ \

if(theChainMember._HandleEvent(pEvt)) \

return TRUE; \

}

#define EVENT_CHECK_SENDER_ROOT(pRoot) \

{ \

SWindow *pWnd = sobj_cast(pEvt->sender);\

if(!pWnd->IsDescendant(pRoot)) \

return FALSE; \

}

// void OnEvent(EventArgs *pEvt)

#define EVENT_HANDLER(cd, func) \

if(cd == uCode) \

{ \

func(pEvt); return TRUE; \

}

下面是 SoTool 中的 MainDlg 中的事件處理:

//soui 消息

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)

CHAIN_EVENT_MAP_MEMBER(m_imgMergerHandler)

CHAIN_EVENT_MAP_MEMBER(m_codeLineCounter)

CHAIN_EVENT_MAP_MEMBER(m_2UnicodeHandler)

CHAIN_EVENT_MAP_MEMBER(m_folderScanHandler)

CHAIN_EVENT_MAP_MEMBER(m_calcMd5Handler)

EVENT_MAP_END()

上面代碼中,EVENT_MAP_BEGIN()和 EVENT_MAP_END()這兩個(gè)宏構(gòu)造出一個(gè)空的事件

處理函數(shù),該函數(shù)自動(dòng)將未處理的事件交給基類的事件處理函數(shù)處理。

如果基類中沒(méi)有事件處理函數(shù),顯然這個(gè)事件映射表編譯不能通過(guò),此時(shí) SOUI 提供了另

一個(gè) EVENT_MAP_BREAK()來(lái)代替。

上面的事件分發(fā)表中,我使用 CHAIN_EVENT_MAP_MEMBER 宏將來(lái)自不同頁(yè)面的控件

事件傳遞到不同的事件處理對(duì)象中。

下面代碼是 m_imgMergerHandler 對(duì)象頭文件。

class CImageMergerHandler : public IFileDropHandler

{

120

friend class CMainDlg;

public:

CImageMergerHandler(void);

~CImageMergerHandler(void);

void OnInit(SWindow *pRoot);

void AddFile(LPCWSTR pszFileName);

protected:

virtual void OnFileDropdown(HDROP hDrop);

void OnSave();

void OnClear();

void OnModeHorz();

void OnModeVert();

EVENT_MAP_BEGIN()

EVENT_CHECK_SENDER_ROOT(m_pPageRoot)

EVENT_NAME_COMMAND(L"btn_save", OnSave)

EVENT_NAME_COMMAND(L"btn_clear", OnClear)

EVENT_NAME_COMMAND(L"radio_horz", OnModeHorz)

EVENT_NAME_COMMAND(L"radio_vert", OnModeVert)

EVENT_MAP_BREAK()

SWindow *m_pPageRoot;

SImgCanvas *m_pImgCanvas;

};

可以看到這里的事件映射表使用了 EVENT_MAP_BREAK 來(lái)結(jié)束。

在 SOUI 中推薦使用控件的 name 屬性來(lái)標(biāo)識(shí)一個(gè)控件(name 屬性是一個(gè) wchar*的字

符串,使用 name 雖然在事件分發(fā)時(shí)采用字符串比較,較基于整數(shù) id 屬性的比較效率低

一點(diǎn),好處在于代碼的可讀性好),不同的頁(yè)面中的控件如果出現(xiàn)相同的 name 該如何識(shí)

別呢?

在 SOUI 中使用了一點(diǎn)小技巧:在事件處理對(duì)象中實(shí)現(xiàn)一個(gè) oninit 函數(shù),該函數(shù)在

maindlg 中處理 WM_INITDIALOG 時(shí)被調(diào)用,在 oninit 中保存了一個(gè)頁(yè)面根節(jié)點(diǎn)的指

針:SWindow *m_pPageRoot;

在事件映射表的開(kāi)始,我們采用 EVENT_CHECK_SENDER_ROOT(m_pPageRoot)這個(gè)宏

來(lái)識(shí)別那些來(lái)自本頁(yè)面的事件。如果事件是來(lái)自其它頁(yè)面則不處理。

使用異步通知

異步通知是客戶端開(kāi)發(fā)中常見(jiàn)的需求,比如在一個(gè)網(wǎng)絡(luò)處理線程中要通知 UI 線程更新等

等。

通常在 Windows 編程中,為了方便,我們一般會(huì)向 UI 線程的窗口句柄 Post/Send 一個(gè)

窗口消息從而達(dá)到將非 UI 線程的事件切換到 UI 線程處理的目的。

在 SOUI 引入通知中心以前要在 SOUI 中處理非 UI 線程事件我也推薦用上面的方法。

使用窗口消息至少有以下兩個(gè)不足:

1、需要在線程中持有一個(gè)窗口句柄。

2、發(fā)出的消息只能在該窗口句柄的消息處理函數(shù)里處理。

SNotifyCenter

最新的 SOUI 引入了一個(gè)新的單例對(duì)象:SNotifyCenter,專門用來(lái)處理這類問(wèn)題。

新的 SNotifyCenter 解決了窗口消息存在的上面的兩個(gè)問(wèn)題:

1、通過(guò)使用全局單例,SNotifyCenter 可以在代碼任意位置獲取它的指針(前提當(dāng)然是要

在它的生命周期內(nèi));

2、使用 SNotifyCenter 產(chǎn)生的通知采用 SOUI 的事件系統(tǒng)來(lái)派發(fā),通過(guò)結(jié)合 SOUI 的事

件訂閱系統(tǒng),用戶可以在任意位置處理發(fā)出的事件。

在介紹如何使用 SNotifyCenter 前,先看一下 NotifyCenter.h 的代碼:

#pragma once

#include

namespace SOUI

{

template

class TAutoEventMapReg

{

typedef TAutoEventMapReg _thisClass;

public:

TAutoEventMapReg()

{

SNotifyCenter::getSingleton().RegisterEventMap(Subscriber(&_thisClass::OnEve

nt,this));

}

~TAutoEventMapReg()

{

SNotifyCenter::getSingleton().UnregisterEventMap(Subscriber(&_thisClass::OnE

vent,this));

}

protected:

bool OnEvent(EventArgs *e){

T * pThis = static_cast(this);

return !!pThis->_HandleEvent(e);

}

};

class SOUI_EXP SNotifyCenter : public SSingleton

, public SEventSet

{

public:

SNotifyCenter(void);

~SNotifyCenter(void);

/**

* FireEventSync

* @brief 觸發(fā)一個(gè)同步通知事件

* @param EventArgs *e -- 事件對(duì)象

* @return

*

* Describe 只能在 UI 線程中調(diào)用

*/

void FireEventSync(EventArgs *e);

/**

* FireEventAsync

* @brief 觸發(fā)一個(gè)異步通知事件

* @param EventArgs *e -- 事件對(duì)象

* @return

*

* Describe 可以在非 UI 線程中調(diào)用,EventArgs *e 必須是從堆上分配的內(nèi)存,調(diào)用后

使用 Release 釋放引用計(jì)數(shù)

*/

void FireEventAsync(EventArgs *e);

/**

* RegisterEventMap

* @brief 注冊(cè)一個(gè)處理通知的對(duì)象

* @param const ISlotFunctor &slot -- 事件處理對(duì)象

* @return

*

* Describe

*/

bool RegisterEventMap(const ISlotFunctor &slot);

/**

* RegisterEventMap

* @brief 注銷一個(gè)處理通知的對(duì)象

* @param const ISlotFunctor &slot -- 事件處理對(duì)象

* @return

*

* Describe

*/

bool UnregisterEventMap(const ISlotFunctor & slot);

protected:

void OnFireEvent(EventArgs *e);

void ExecutePendingEvents();

static VOID CALLBACK OnTimer( HWND hwnd,

UINT uMsg,

UINT_PTR idEvent,

DWORD dwTime

);

SCriticalSection m_cs; //線程同步對(duì)象

SList *m_evtPending;//掛起的等待執(zhí)行的事件

DWORD m_dwMainTrdID;//主線程 ID

UINT_PTR m_timerID; //定時(shí)器 ID,用來(lái)執(zhí)行異步事件

SList m_evtHandlerMap;

};

}

在這個(gè)文件中提供了兩個(gè)類,一個(gè)就是 SNotifyCenter,另一個(gè)是

TAutoEventMapReg。

可以看到 SNotifyCenter 中除構(gòu)造外只有 4 個(gè) public 方法:

FireEventSync, FireEventAsync 用來(lái)觸發(fā)事件。

RegisterEventMap,UnregisterEventMap 則用來(lái)提供事件處理訂閱。

如何使用 SNotifyCenter?

1、在 main 中實(shí)例化 SNotifyCenter。(不明白可以參考 demo)

2、定義需要通過(guò)通知中心分發(fā)的事件類型,首先定義事件,然后向通知中心注冊(cè),參見(jiàn)

下面代碼:

void CMainDlg::OnBtnStartNotifyThread()

{

if(IsRunning()) return;

SNotifyCenter::getSingleton().addEvent(EVENTID(EventThreadStart));

SNotifyCenter::getSingleton().addEvent(EVENTID(EventThreadStop));

SNotifyCenter::getSingleton().addEvent(EVENTID(EventThread));

EventThreadStart evt(this);

SNotifyCenter::getSingleton().FireEventSync(&evt);

BeginThread();

}

void CMainDlg::OnBtnStopNotifyThread()

{

if(!IsRunning()) return;

EndThread();

EventThreadStop evt(this);

SNotifyCenter::getSingleton().FireEventSync(&evt);

SNotifyCenter::getSingleton().removeEvent(EventThreadStart::EventID);

SNotifyCenter::getSingleton().removeEvent(EventThreadStop::EventID);

SNotifyCenter::getSingleton().removeEvent(EventThread::EventID);

}

3、使需要處理通知中心分發(fā)的事件的對(duì)象從 TAutoEventMapReg 繼承,實(shí)現(xiàn)事件的自

動(dòng)訂閱(方便在事件映射表中統(tǒng)一處理事件),這一步是可選的,你也可以直接使用 SOUI

提供的事件訂閱機(jī)制向通知中心訂閱特定事件。

4、在事件映射表里處理事件(沒(méi)有第 3 步時(shí),則同樣沒(méi)有這一步)。

演示使用SNotifyCenter的異步事件

class EventThread : public TplEventArgs

{

?? SOUI_CLASS_NAME(EventThread,L"on_event_thread")

public:

?? EventThread(SObject *pSender):TplEventArgs(pSender){}

?? enum{EventID=EVT_EXTERNAL_BEGIN+30000};

??

?? int nData;

};

在cpp文件中使用

EventThread *pEvt = new EventThread(this);

pEvt->nData = nSleep;

SNotifyCenter::getSingleton().FireEventAsync(pEvt);

pEvt->Release();

一般在構(gòu)造函數(shù)中添加進(jìn)去,一般可以添加任意條事件,即不限于一條

SNotifyCenter::getSingleton().addEvent(EVENTID(EventThread));

SNotifyCenter::getSingleton().subscribeEvent(EventSwndSize::EventID, Subscriber(&SHostWnd::onRootResize, this));

和回調(diào)函數(shù)差不多

ACTIVATE事件用法

消息映射表中

MSG_WM_ACTIVATE(OnActivate)

聲明及實(shí)現(xiàn)

void OnActivate(UINT nState, BOOL bMinimized, HWND wndOther);

void CSetSkinWnd::OnActivate(UINT nState, BOOL bMinimized, HWND wndOther)

{

?? if (nState == WA_INACTIVE)

{

????? DestroyWindow();

}

?? Else

{

????? SHostWnd::OnActivate(nState, bMinimized, wndOther);

??? }

}

換膚

SSkinLoader類

頭文件

#pragma once

#include "pugixml\pugixml.hpp"

#include "res.mgr\SSkinPool.h"

#include "helper\SplitString.h"

#include "resprovider-zip\zipresprovider-param.h"

#include "resprovider-zip\SResProviderZip.h"

namespace SOUI

{

#define RT_SKIN _T("SkinXml")

?? class SSkinLoader :public SSingleton

?? {

?? public:

????? SSkinLoader(SApplication*);

????? ~SSkinLoader();

????? void LoadSkinFormZip(SStringT respath, const TCHAR *strXmlSkin=_T("LoadSkinXml"));

????? void LoadSkin(SStringT respath,const TCHAR *strXmlSkin = _T("LoadSkinXml"));

?? private:

????? CAutoRefPtr m_pResProvider;

????? CAutoRefPtr? m_privateSkinPool;

????? SApplication *m_theApp;

????? BOOL CreateResProvider_ZIP(IObjRef **ppObj);

?? };

}//END SOUI

源文件

#include "stdafx.h"

#include "SSkinLoader.h"

#include "res.mgr\SResProvider.h"

template<>

SSkinLoader * SSingleton::ms_Singleton = NULL;

SSkinLoader::SSkinLoader(SApplication* theApp):m_pResProvider(NULL),m_theApp(theApp)

{

?? m_privateSkinPool = new SSkinPool();

?? GETSKINPOOLMGR->PushSkinPool(m_privateSkinPool);

}

SSkinLoader::~SSkinLoader()

{?

}

BOOL SSkinLoader::CreateResProvider_ZIP(IObjRef **ppObj)

{

?? return RESPROVIDER_ZIP::SCreateInstance(ppObj);

}

void SSkinLoader::LoadSkinFormZip(SStringT respath, const TCHAR *strXmlSkin)

{

?? if (m_pResProvider == NULL)

?? {

????? if(CreateResProvider_ZIP((IObjRef**)&m_pResProvider))

????? {

???????? m_theApp->AddResProvider(m_pResProvider,NULL);

????? }

?? }

?? SASSERT(m_pResProvider);

?? ZIPRES_PARAM param;

?? param.ZipFile(m_theApp->GetRenderFactory(), respath, "www.bukengnikengshui.com");

?? if (!m_pResProvider->Init((WPARAM)¶m, 0))

?? {

????? SASSERT(0);

?? }

?? pugi::xml_document xmlDoc;

?? SStringTList strLst;

?? BOOL bLoad = FALSE;

?? if (2 == ParseResID(strXmlSkin, strLst))

?? {

????? bLoad = LOADXML(xmlDoc, strLst[1], strLst[0]);

?? }

?? else

?? {

????? bLoad = LOADXML(xmlDoc, strLst[0], RT_SKIN);

?? }

?? if (bLoad)

?? {

????? if (m_privateSkinPool->GetCount() > 0)

????? {

???????? pugi::xml_node xmlSkin = xmlDoc.child(L"skin").first_child();

???????? SStringW strSkinName, strTypeName;

???????? while (xmlSkin)

???????? {

??????????? strTypeName = xmlSkin.name();

??????????? strSkinName = xmlSkin.attribute(L"name").value();

??????????? if (strSkinName.IsEmpty() || strTypeName.IsEmpty())

??????????? {

??????????????? xmlSkin = xmlSkin.next_sibling();

??????????????? continue;

??????????? }

??????????? xmlSkin.attribute(L"name").set_userdata(1);

??????????? ISkinObj *pSkin = m_privateSkinPool->GetSkin(strSkinName,100);

??????????? if (pSkin)

??????????? {

??????????????? pSkin->InitFromXml(xmlSkin);

??????????? }

??????????? else

??????????? {

??????????????? SASSERT_FMTW(FALSE, L"load skin error,type=%s,name=%s", strTypeName, strSkinName);

??????????? }

??????????? xmlSkin.attribute(L"name").set_userdata(0);

??????????? xmlSkin = xmlSkin.next_sibling();

???????? }

????? }

????? else

????? {

???????? m_privateSkinPool->LoadSkins(xmlDoc.child(L"skin"));

????? }

?? }

}

void SSkinLoader::LoadSkin(SStringT respath,const TCHAR *strXmlSkin)

{??????????????

?? if (m_pResProvider == NULL)

?? {

????? if(CreateResProvider(RES_FILE, (IObjRef**)&m_pResProvider))

????? {

???????? m_theApp->AddResProvider(m_pResProvider, NULL);

????? }

?? }

?? SASSERT(m_pResProvider);

?? if (!m_pResProvider->Init((WPARAM)respath.GetBuffer(0), NULL))

?? {

????? SASSERT(0);

?? }

?? pugi::xml_document xmlDoc;

?? SStringTList strLst;

?? BOOL bLoad=FALSE;

?? if (2 == ParseResID(strXmlSkin, strLst))

?? {

????? bLoad=LOADXML(xmlDoc, strLst[1], strLst[0]);

?? }

?? else

?? {

????? bLoad=LOADXML(xmlDoc, strLst[0], RT_SKIN);

?? }

?? if (bLoad)

?? {

????? if (m_privateSkinPool->GetCount() > 0)

????? {

???????? pugi::xml_node xmlSkin = xmlDoc.child(L"skin").first_child();

???????? SStringW strSkinName, strTypeName;

???????? while (xmlSkin)

???????? {

??????????? strTypeName = xmlSkin.name();

??????????? strSkinName = xmlSkin.attribute(L"name").value();

??????????? if (strSkinName.IsEmpty() || strTypeName.IsEmpty())

??????????? {

??????????????? xmlSkin = xmlSkin.next_sibling();

??????????????? continue;

??????????? }

??????????? xmlSkin.attribute(L"name").set_userdata(1);

??????????? ISkinObj *pSkin = m_privateSkinPool->GetSkin(strSkinName,100);

??????????? if (pSkin)

??????????? {

??????????????? pSkin->InitFromXml(xmlSkin);

??????????? }

??????????? else

??????????? {

??????????????? SASSERT_FMTW(FALSE, L"load skin error,type=%s,name=%s", strTypeName, strSkinName);

??????????? }

??????????? xmlSkin.attribute(L"name").set_userdata(0);

??????????? xmlSkin = xmlSkin.next_sibling();

???????? }

????? }

????? else

????? {

???????? m_privateSkinPool->LoadSkins(xmlDoc.child(L"skin"));

????? }

?? }

}

SDemoSkin類

頭文件

#pragma once

namespace SOUI

{

?? enum SkinType

?? {

????? color,

????? sys,

????? builtin,

?? };

?? struct SkinInfo

?? {

????? COLORREF color;

????? SStringW filepath;

????? RECT margin;

?? };

?? interface ISetOrLoadSkinHandler

?? {

????? virtual bool SaveSkin(SkinType, SkinInfo&) = NULL;???

?? };

?? class? SDemoSkin : public SSkinImgFrame

?? {

????? SOUI_CLASS_NAME(SDemoSkin, L"demoskin")

?? public:

????? SDemoSkin();

????? SDemoSkin(ISetOrLoadSkinHandler *iSkinHander);

?? public:

????? virtual bool SetImage(IBitmap *pImg);

?????

????? bool SetImage(SStringW imgfile);

????? bool SetColor(COLORREF bkColor);

????? void ClearSkin();

????? COLORREF GetThemeColor() const;

????? void SetHander(ISetOrLoadSkinHandler*skinhander);

????? virtual SIZE GetSkinSize();

????? virtual BOOL IgnoreState();

????? bool SaveSkin();

????? bool LoadSkin(SkinType, SkinInfo& saveInf);

????? virtual int GetStates();

????? //不支持自動(dòng)色調(diào)

????? virtual void OnColorize(COLORREF cr){}

?? protected:

????? virtual void _Draw(IRenderTarget *pRT, LPCRECT rcDraw, DWORD dwState, BYTE byAlpha);

?????

????? ISetOrLoadSkinHandler *m_ISetOrLoadSkinHandler;???

????? CSize m_csSize;???

????? bool m_bIsColor;

????? COLORREF m_bkColor;

????? bool m_bAdaptiveImg;????

????? SStringW m_FilePath;?

?? };

}

源文件

#include "stdafx.h"

#include "sdemoskin.h"

#include "helper/SDIBHelper.h"

namespace SOUI

{?

?? SDemoSkin::SDemoSkin():m_csSize(0, 0),m_bkColor(RGB(255, 255, 255)), m_bIsColor(false), m_ISetOrLoadSkinHandler(NULL)

?? {

?? }

?? SDemoSkin::SDemoSkin(ISetOrLoadSkinHandler *handle) : m_csSize(0, 0), m_bkColor(RGB(255, 255, 255)), m_bIsColor(false), m_ISetOrLoadSkinHandler(handle)

?? {

?? }

?? bool SDemoSkin::SetImage(IBitmap *pImg)

?? {

????? if (m_pImg)

???????? m_pImg->Release();

????? m_pImg = pImg;

????? if (m_pImg)

????? ?m_pImg->AddRef();

????? return true;

?? }

?? bool SDemoSkin::SetImage(SStringW imgfile)

?? {

????? m_bIsColor = false;

????? m_FilePath = imgfile;

????? IBitmap *image = LOADIMAGE2(L"file:" + imgfile);

????? if (image)

????? {

???????? SetImage(image);

???????? image->Release();

???????? return true;

????? }

????? return false;

?? }

?? bool SDemoSkin::SetColor(COLORREF bkColor)

?? {

????? m_FilePath.Empty();

????? m_bIsColor = true;???

????? m_bkColor = bkColor;????

????? return true;

?? }

?? void SDemoSkin::ClearSkin()

?? {

????? m_FilePath.Empty();

????? m_bIsColor = false;

????? m_pImg = NULL;

?? }

?? SIZE SDemoSkin::GetSkinSize()

?? {????

????? SIZE ret = { 0, 0 };

????? if (m_pImg)

???????? ret = m_pImg->Size();

????? return ret;

?? }

?? BOOL SDemoSkin::IgnoreState()

?? {

????? return TRUE;

?? }

?? bool SDemoSkin::SaveSkin()

?? {

????? if (m_ISetOrLoadSkinHandler == NULL)

???????? return false;

????? SkinInfo saveInf;

????? if (m_bIsColor)

????? {

???????? saveInf.color = m_bkColor;

???????? return m_ISetOrLoadSkinHandler->SaveSkin(color, saveInf);

????? }

????? else if(!m_FilePath.IsEmpty())

????? {

???????? saveInf.margin = m_rcMargin;

???????? saveInf.filepath = m_FilePath;

???????? return m_ISetOrLoadSkinHandler->SaveSkin(sys, saveInf);

????? }

????? else

????? {

???????? return m_ISetOrLoadSkinHandler->SaveSkin(builtin, saveInf);

????? }

????? return false;

?? }

?? bool SDemoSkin::LoadSkin(SkinType skinType, SkinInfo &skinLoadInf)

?? {

????? switch (skinType)

????? {

????? case color:

???????? return SetColor(skinLoadInf.color);

????? case sys:

???????? m_rcMargin = skinLoadInf.margin;

???????? return SetImage(skinLoadInf.filepath);

????? default:

???????? break;

????? }

????? return false;

?? }

??

?? int SDemoSkin::GetStates()

?? {

????? return 1;

?? }

?? void SDemoSkin::SetHander(ISetOrLoadSkinHandler* skinhander)

?? {

????? m_ISetOrLoadSkinHandler = skinhander;

?? }

?? void SDemoSkin::_Draw(IRenderTarget * pRT, LPCRECT rcDraw, DWORD dwState, BYTE byAlpha)

?? {

????? if (m_bIsColor)

????? {???????

???????? COLORREF bkColor = m_bkColor | (byAlpha << 24);

???????? pRT->FillSolidRect(rcDraw, bkColor);

????? }

????? else if (m_pImg)

????? {

???????? SIZE sz = GetSkinSize();

???????? CPoint pt(0, 0);

???????? CRect rcSour(pt, sz);

???????? pRT->DrawBitmap9Patch(rcDraw, m_pImg, &rcSour, &m_rcMargin, GetExpandMode(), byAlpha);

????? }????

?? }?

?? COLORREF SDemoSkin::GetThemeColor() const

?? {

????? if (m_bIsColor)

???????? return m_bkColor;

????? else if (m_pImg)

???????? return SDIBHelper::CalcAvarageColor(m_pImg);

????? else

???????? return CR_INVALID;

?? }

}

SetSkinWnd類

頭文件

#pragma once

#define MagicNumber 9527

extern UINT g_dwSkinChangeMessage;

struct SKIN_CONFIG_INF

{

?? int id;

?? CRect margin;

};

class CSetSkinWnd : public SHostWnd

{

public:

?? CSetSkinWnd();

?? ~CSetSkinWnd();

?? void OnSetSkin(EventArgs *e);

?? void OnBuiltinSkin();

?? EVENT_MAP_BEGIN()

????? EVENT_NAME_COMMAND(L"btn_close", OnClose)

????? EVENT_ID_RANGE_HANDLER(10, 27, EVT_CMD, OnSetSkin)

????? EVENT_ID_RANGE_HANDLER(30, 48, EVT_CMD, OnColor)?????

????? EVENT_ID_COMMAND(51, OnBuiltinSkin)

?? EVENT_MAP_END()

?? BEGIN_MSG_MAP_EX(CSetSkinWnd)

????? MSG_WM_INITDIALOG(OnInitDialog)

????? MESSAGE_HANDLER(g_dwSkinChangeMessage, OnSkinChangeMessage)

????? CHAIN_MSG_MAP(SHostWnd)

????? REFLECT_NOTIFICATIONS_EX()

?? END_MSG_MAP()

private:

?? SList m_skinConfigInf;

?? void OnClose();

?? HRESULT OnSkinChangeMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL bHandled);

?? void OnColor(EventArgs * e);

?? BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam);

protected:

?? long NotifUpdataWindow();

?? void LoadSkinConfigFormXml();

?? CRect GetMargin(int id);

};

源文件

#include "stdafx.h"

#include "SetSkinWnd.h"

#include "SDemoSkin.h"

#include

#include "SSkinLoader.h"

#include

#define SKIN_CHANGE_MSG _T("{D17D208B-25FD-412C-8071-68816D4B1F9B}")

//注冊(cè)皮膚改變消息

UINT g_dwSkinChangeMessage = RegisterWindowMessage(SKIN_CHANGE_MSG);

CSetSkinWnd::CSetSkinWnd() :SHostWnd(_T("LAYOUT:dlg_set_skin"))

{?

?? LoadSkinConfigFormXml();

}

CSetSkinWnd::~CSetSkinWnd()

{

}

HRESULT CSetSkinWnd::OnSkinChangeMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL bHandled)

{

?? FindChildByID(MagicNumber)->Invalidate();

?? return S_OK;

}

long CSetSkinWnd::NotifUpdataWindow()

{

?? WPARAM?? wParam = MagicNumber;

?? LPARAM?? lParam = MagicNumber;

?? DWORD?? dwRecipients = BSM_APPLICATIONS;

?? return ::BroadcastSystemMessage(BSF_POSTMESSAGE, &dwRecipients, g_dwSkinChangeMessage, wParam, lParam);

}

void CSetSkinWnd::LoadSkinConfigFormXml()

{

?? SStringT strSkinConfigPath = SApplication::getSingleton().GetAppDir() + _T("\\themes\\themes_config.xml");

?? pugi::xml_document docLoad;

?? pugi::xml_parse_result result = docLoad.load_file(strSkinConfigPath);

?? if (result)

?? {

????? pugi::xml_node skinInf = docLoad.child(L"DEMO_SKIN_CONFIG").child(L"skinInf");

????? while (skinInf)

????? {

???????? SKIN_CONFIG_INF inf;

???????? inf.id = (SkinType)skinInf.attribute(L"id").as_int();

???????? int v1 = 0, v2 = 0, v3 = 0, v4 = 0;

???????? swscanf(skinInf.attribute(L"skin_margin").as_string(), L"%d,%d,%d,%d", &v1, &v2, &v3, &v4);

???????? inf.margin.left = v1;

???????? inf.margin.top = v2;

???????? inf.margin.right = v3;

???????? inf.margin.bottom = v4;

???????? m_skinConfigInf.AddTail(inf);

???????? skinInf=skinInf.next_sibling();

????? }

?? }????

}

BOOL CSetSkinWnd::OnInitDialog(HWND hWnd, LPARAM lParam)

{

?? return 0;

}

CRect CSetSkinWnd::GetMargin(int id)

{

?? SPOSITION headPos= m_skinConfigInf.GetHeadPosition();

?? while (headPos)

?? {

????? SKIN_CONFIG_INF inf= m_skinConfigInf.GetNext(headPos);

????? if (inf.id == id)

????? {

???????? return inf.margin;

????? }

?? }

?? return CRect();

}

void CSetSkinWnd::OnSetSkin(EventArgs * e)

{

?? if (!e)

?? {

????? return;

?? }

?? SWindow *sender = (SWindow*) e->sender;

?? if (!sender)

?? {

????? return;

?? }

?? int nIndex = sender->GetID();

?? SDemoSkin *skin = (SDemoSkin *) GETSKIN(L"demoskinbk",GetScale());

?? SStringT strSkinFile;

?? SStringT strSkinPath = SApplication::getSingleton().GetAppDir() + _T("\\themes\\");

?? strSkinFile.Format(_T("%s%d.png"), strSkinPath, nIndex - 9);

?? SStringT strLoadSkin;

?? strLoadSkin.Format(_T("%s\\themes\\skin%d"), SApplication::getSingleton().GetAppDir(), ((nIndex - 9)%3)+1);

?? SSkinLoader::getSingleton().LoadSkin(strLoadSkin);

?? if (_taccess(strSkinFile, 0) != 0)

?? {

????? SMessageBox(NULL, _T("無(wú)法設(shè)置當(dāng)前主題,找不到系統(tǒng)主題文件。"), _T("警告"), MB_OK);

????? return;

?? }

?? if (skin)

?? {

????? skin->SetImage(S_CT2W(strSkinFile));

????? skin->SetMargin(GetMargin(nIndex-9));

????? NotifUpdataWindow();

?? }

}

void CSetSkinWnd::OnColor(EventArgs * e)

{

?? SWindow *sender = (SWindow*)e->sender;

?? SDemoSkin *skin = (SDemoSkin *)GETSKIN(L"demoskinbk", GetScale());

?? if (skin)

?? {

????? skin->SetColor(sender->GetStyle().m_crBg);

????? NotifUpdataWindow();

?? }

}

void CSetSkinWnd::OnBuiltinSkin()

{

?? SDemoSkin *skin = (SDemoSkin *)GETSKIN(L"demoskinbk", GetScale());

?? if (skin)

?? {

????? skin->ClearSkin();

????? NotifUpdataWindow();

?? }

}

void CSetSkinWnd::OnClose()

{

?? CSimpleWnd::DestroyWindow();

}

項(xiàng)目文件中

在主文件中需要注冊(cè)

theApp->RegisterSkinClass();

并且加載一個(gè)皮膚

SSkinLoader *SkinLoader = new SSkinLoader(theApp);

SkinLoader->LoadSkin(SApplication::getSingleton().GetAppDir() + _T("\\themes\\skin1"));

MainDlg類

// MainDlg.h : interface of the CMainDlg class

//

/

#pragma once

#include "skin\SetSkinWnd.h"

#include "skin\SDemoSkin.h"

class CMainDlg : public SHostWnd, public ISetOrLoadSkinHandler

{

public:

?? CMainDlg();

?? ~CMainDlg();

?? void OnClose();

?? void OnMaximize();

?? void OnRestore();

?? void OnMinimize();

?? void OnSize(UINT nType, CSize size);

?? int OnCreate(LPCREATESTRUCT lpCreateStruct);

?? BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam);

?? void OnSkin();

?? void OnMenu();

?? bool LoadSkin();

?? bool SaveSkin(SkinType skinType, SkinInfo &skinSaveInf);

?? HRESULT OnSkinChangeMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL bHandled);

?? void OnCommand(UINT uNotifyCode, int nID, HWND wndCtl);

protected:

?? //soui消息

?? 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_NAME_COMMAND(L"btn_skin", OnSkin)

????? EVENT_NAME_COMMAND(L"btn_menu", OnMenu)

?? EVENT_MAP_END()

?????

?? //HostWnd真實(shí)窗口消息處理

?? BEGIN_MSG_MAP_EX(CMainDlg)

????? MSG_WM_CREATE(OnCreate)

????? MSG_WM_INITDIALOG(OnInitDialog)

????? MSG_WM_CLOSE(OnClose)

????? MSG_WM_SIZE(OnSize)

????? MSG_WM_COMMAND(OnCommand)

????? MESSAGE_HANDLER(g_dwSkinChangeMessage, OnSkinChangeMessage)

????? CHAIN_MSG_MAP(SHostWnd)

????? REFLECT_NOTIFICATIONS_EX()

?? END_MSG_MAP()

private:

?? BOOL???????? m_bLayoutInited;??

?? CSetSkinWnd m_SetSkinWnd;

};

源文件

// MainDlg.cpp : implementation of the CMainDlg class

//

/

#include "stdafx.h"

#include "MainDlg.h"?

#include "skin\SDemoSkin.h"

#include "skin\SSkinLoader.h"

??

CMainDlg::CMainDlg() : SHostWnd(_T("LAYOUT:XML_MAINWND"))

{

?? m_bLayoutInited = FALSE;

}

CMainDlg::~CMainDlg()

{

}

int CMainDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

?? SetMsgHandled(FALSE);

?? return 0;

}

BOOL CMainDlg::OnInitDialog(HWND hWnd, LPARAM lParam)

{

?? LoadSkin();

?? m_bLayoutInited = TRUE;

?? return 0;

}

//TODO:消息映射

void CMainDlg::OnClose()

{

?? SDemoSkin *skin = (SDemoSkin *)GETSKIN(L"demoskinbk",GetScale());

?? if (skin)

?? {

????? skin->SaveSkin();

?? }

?? CSimpleWnd::DestroyWindow();

}

void CMainDlg::OnMaximize()

{

?? SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE);

}

void CMainDlg::OnRestore()

{

?? SendMessage(WM_SYSCOMMAND, SC_RESTORE);

}

void CMainDlg::OnMinimize()

{

?? SendMessage(WM_SYSCOMMAND, SC_MINIMIZE);

}

void CMainDlg::OnSkin()

{

?? if (m_SetSkinWnd.m_hWnd)

?? {

????? SetForegroundWindow(m_hWnd);

????? FlashWindow(m_hWnd, TRUE);

????? m_SetSkinWnd.ShowWindow(SW_SHOWNORMAL);

?? }

?? else

?? {

????? m_SetSkinWnd.Create(m_hWnd);

????? m_SetSkinWnd.SendMessage(WM_INITDIALOG);

????? m_SetSkinWnd.CenterWindow(GetDesktopWindow());

????? m_SetSkinWnd.ShowWindow(SW_SHOWNORMAL);

?? }

}

void CMainDlg::OnSize(UINT nType, CSize size)

{

?? SetMsgHandled(FALSE);

?? if (!m_bLayoutInited) return;

??

?? SWindow *pBtnMax = FindChildByName(L"btn_max");

?? SWindow *pBtnRestore = FindChildByName(L"btn_restore");

?? if(!pBtnMax || !pBtnRestore) return;

??

?? if (nType == SIZE_MAXIMIZED)

?? {

????? pBtnRestore->SetVisible(TRUE);

????? pBtnMax->SetVisible(FALSE);

?? }

?? else if (nType == SIZE_RESTORED)

?? {

????? pBtnRestore->SetVisible(FALSE);

????? pBtnMax->SetVisible(TRUE);

?? }

}

HRESULT CMainDlg::OnSkinChangeMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL bHandled)

{

?? FindChildByID(9527)->Invalidate();

?? SDemoSkin *skin = (SDemoSkin *) GETSKIN(L"demoskinbk",GetScale());

?? DWORD tm1=GetTickCount();

?? COLORREF crTheme = skin->GetThemeColor();

?? if (crTheme != CR_INVALID)

????? DoColorize(crTheme | 0xff000000);

?? else

????? DoColorize(0);

?? SLOG_INFO("DoColorize spend "<

?? return S_OK;

}

void LoadSkinFormXml(SDemoSkin *skin, SkinType *skinType, SkinInfo *skininf)

{

?? SStringT strSkinConfigPath = SApplication::getSingleton().GetAppDir() + _T("\\themes\\skin_config.xml");

?? pugi::xml_document docLoad;

?? pugi::xml_parse_result result = docLoad.load_file(strSkinConfigPath);

?? if (result)

?? {

????? pugi::xml_node skinInf = docLoad.child(L"DEMO_SKIN_CONFIG").child(L"skinInf");

????? *skinType = (SkinType)skinInf.attribute(L"type").as_int();

????? switch (*skinType)

????? {

???????? //純色只有SkinInfo的color有效

????? case color:

???????? skininf->color = skinInf.attribute(L"color").as_int();

???????? break;??????

???????? //此處為系統(tǒng)皮膚,只需要給文件路徑和margin

????? case sys:

???????? skininf->filepath = skinInf.attribute(L"skin_path").as_string();

???????? int v1 = 0, v2 = 0, v3 = 0, v4 = 0;

???????? swscanf(skinInf.attribute(L"skin_margin").as_string(), L"%d,%d,%d,%d", &v1, &v2, &v3, &v4);

???????? skininf->margin.left = v1;

???????? skininf->margin.top = v2;

???????? skininf->margin.right = v3;

???????? skininf->margin.bottom = v4;

???????? break;

????? }

?? }

}

bool CMainDlg::LoadSkin()

{

?? SDemoSkin *skin = (SDemoSkin *)GETSKIN(L"demoskinbk",GetScale());

?? if (skin)

?? {

????? SkinInfo loadInf;

????? SkinType type;

????? LoadSkinFormXml(skin, &type, &loadInf);

????? skin->SetHander(this);

????? return skin->LoadSkin(type, loadInf);

?? }

?? return false;

}

void SaveSkinInf2File(SkinType skinType, SkinInfo &skinSaveInf)

{

?? pugi::xml_document docSave;

?? pugi::xml_node rootNode = docSave.append_child(L"DEMO_SKIN_CONFIG");

?? pugi::xml_node childSkinType = rootNode.append_child(L"skinInf");

?? childSkinType.append_attribute(L"type") = skinType;

?? SStringT strSkinConfigPath = SApplication::getSingleton().GetAppDir() + _T("\\themes\\skin_config.xml");

?? switch (skinType)

?? {

?? case color://純色只有SkinInfo的color有效

????? childSkinType.append_attribute(L"color") = (int)skinSaveInf.color;

????? break;?????????

?? case sys://此處為系統(tǒng)皮膚,只需要給文件路徑和margin

????? {

???????? childSkinType.append_attribute(L"skin_path") = skinSaveInf.filepath;

???????? SStringW margin;

???????? margin.Format(L"%d,%d,%d,%d", skinSaveInf.margin.left, skinSaveInf.margin.top, skinSaveInf.margin.right, skinSaveInf.margin.bottom);

???????? childSkinType.append_attribute(L"skin_margin") = margin;

????? }

????? break;

?? case builtin:

?? default:

????? break;

?? }

?? docSave.save_file(strSkinConfigPath);

}

bool CMainDlg::SaveSkin(SkinType skinType, SkinInfo &skinSaveInf)

{

?? HRESULT hr = S_OK;

?? SaveSkinInf2File(skinType, skinSaveInf);

?? return hr == S_OK;

}

void CMainDlg::OnCommand( UINT uNotifyCode, int nID, HWND wndCtl )

{

?? if(uNotifyCode==0)

?? {

????? if (nID == 51)

????? {

???????? //skin1

????? ?? SSkinLoader::getSingleton().LoadSkin(SApplication::getSingleton().GetAppDir() + _T("\\themes\\skin1"));

???????? SWindow::Invalidate();

????? }

????? else if (nID == 52)

????? {

???????? //skin2

????? ?? SSkinLoader::getSingleton().LoadSkin(SApplication::getSingleton().GetAppDir() + _T("\\themes\\skin2"));

???????? SWindow::Invalidate();

????? }

????? else if (nID == 53)

????? {

???????? //skin3

????? ?? SSkinLoader::getSingleton().LoadSkin(SApplication::getSingleton().GetAppDir() + _T("\\themes\\skin3"));

???????? SWindow::Invalidate();

????? }

?? }

}

void CMainDlg::OnMenu()

{

?? CPoint pt;

?? GetCursorPos(&pt);

?? //使用自繪菜單

?? SMenu menu;

?? menu.LoadMenu(_T("menu_test"),_T("SMENU"));

?? menu.TrackPopupMenu(0,pt.x,pt.y,m_hWnd);

}

資源配置

dlg_main.xml

?

???

???

?????

????? @string/title

?????

?????

?????

?????

?????

?????

?????

???

???

???

?????

???????

???????

???????

???????

???????

???????

???????

???????

???????

???????

???????

???????

???????

???????

???????

???????

???????

???????

?????

???

?????

???

?

Dlg_skinset.xml

?

???

?????

?????

???????

??????? 換膚

???????

???????

?????

?????

?????

???????

?????????

???????????

???????????

???????????

???????????

???????????

???????????

?????????

?????????

???????????

???????????

???????????

???????????

???????????

???????????

?????????

?????????

???????????

???????????

???????????

???????????

???????????

???????????

?????????

?????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

???????????

?????????

?????????

???????????


???????????

???

?

menu.xml

?

uires.idx

?

???

?

?

???

?

?

?

?

?

?

?

?

?

???

?

?

???

?

MainDlg.h

#pragma once

#include

class CMainDlg : public SHostWnd

{

public:

?? CMainDlg();

?? ~CMainDlg();

?? void OnClose();

?? void OnMaximize();

?? void OnRestore();

?? void OnMinimize();

?? void OnSize(UINT nType, CSize size);

?? int OnCreate(LPCREATESTRUCT lpCreateStruct);

?? BOOL OnInitDialog(HWND wndFocus, LPARAM lInitParam);

?? ?

?? void OnBtnAdd();

?? bool OnClick(EventArgs* pArgs);

?? bool OnRClick(EventArgs* pArgs);

?? void OnCommand(UINT uNotifyCode, int nID, HWND wndCtl);

protected:

?? //soui消息

?? 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_NAME_COMMAND(L"btnAdd", OnBtnAdd)

?? EVENT_MAP_END()

?????

?? //HostWnd真實(shí)窗口消息處理

?? BEGIN_MSG_MAP_EX(CMainDlg)

????? MSG_WM_CREATE(OnCreate)

????? MSG_WM_INITDIALOG(OnInitDialog)

????? MSG_WM_CLOSE(OnClose)

????? MSG_WM_SIZE(OnSize)

????? MSG_WM_COMMAND(OnCommand)

????? CHAIN_MSG_MAP(SHostWnd)

????? REFLECT_NOTIFICATIONS_EX()

?? END_MSG_MAP()

private:

?? BOOL???????? m_bLayoutInited;??

?? void ClearWnd(SWindow* pWnd);

?? void CreateWnd(SWindow* pWnd);

?? void CreateAdd(SWindow* pWnd);

?? std::vector m_vec;

?? int m_nRClickID;

};

MainDlg.cpp

#include "stdafx.h"

#include "MainDlg.h"?

??

CMainDlg::CMainDlg() : SHostWnd(_T("LAYOUT:XML_MAINWND"))

{

?? m_bLayoutInited = FALSE;

}

CMainDlg::~CMainDlg()

{

}

int CMainDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

?? SetMsgHandled(FALSE);

?? return 0;

}

BOOL CMainDlg::OnInitDialog(HWND hWnd, LPARAM lParam)

{

?? m_bLayoutInited = TRUE;

?? return 0;

}

//TODO:消息映射

void CMainDlg::OnClose()

{

?? CSimpleWnd::DestroyWindow();

}

void CMainDlg::OnMaximize()

{

?? SendMessage(WM_SYSCOMMAND, SC_MAXIMIZE);

}

void CMainDlg::OnRestore()

{

?? SendMessage(WM_SYSCOMMAND, SC_RESTORE);

}

void CMainDlg::OnMinimize()

{

?? SendMessage(WM_SYSCOMMAND, SC_MINIMIZE);

}

void CMainDlg::OnSize(UINT nType, CSize size)

{

?? SetMsgHandled(FALSE);

?? if (!m_bLayoutInited) return;

??

?? SWindow *pBtnMax = FindChildByName(L"btn_max");

?? SWindow *pBtnRestore = FindChildByName(L"btn_restore");

?? if(!pBtnMax || !pBtnRestore) return;

??

?? if (nType == SIZE_MAXIMIZED)

?? {

????? pBtnRestore->SetVisible(TRUE);

????? pBtnMax->SetVisible(FALSE);

?? }

?? else if (nType == SIZE_RESTORED)

?? {

????? pBtnRestore->SetVisible(FALSE);

????? pBtnMax->SetVisible(TRUE);

?? }

}

void CMainDlg::ClearWnd(SWindow* pWnd)

{

?? SWindow* pChild = pWnd->GetWindow(GSW_FIRSTCHILD);

?? while (pChild)

?? {

????? SWindow* pNext = pChild->GetWindow(GSW_NEXTSIBLING);

????? pChild->DestroyWindow();

????? pChild = pNext;

?? }

}

void CMainDlg::CreateWnd(SWindow* pWnd)

{

?? int nID = 9000;

?? pugi::xml_document doc;

?? int nIndex = 0;

?? for (auto it = m_vec.begin(); it != m_vec.end(); it++, nIndex++)

?? {

????? SStringW strXml;

????? strXml.Format(L"", nID + nIndex, *it);

????? if (!doc.load_buffer(strXml, strXml.GetLength() * sizeof(wchar_t), pugi::parse_default, pugi::encoding_utf16))

????? {

???????? return;

????? }

????? SWindow* pBtn = new SButton;

????? if (pBtn)

????? {

???????? pWnd->InsertChild(pBtn);

???????? pBtn->InitFromXml(doc.first_child());

????? }

?? pBtn->GetEventSet()->subscribeEvent(EVT_CMD,Subscriber(&CMainDlg::OnClick,this));

?? pBtn->GetEventSet()->subscribeEvent(EVT_CTXMENU,Subscriber(&CMainDlg::OnRClick,this));

?? }

?? CreateAdd(pWnd);

?? int nWndNum = m_vec.size() + 1;

?? int nRow = nWndNum + 4 - 1 / 4;

?? SStringW strRowCount;

?? strRowCount.Format(L"%d", nRow);

?? pWnd->SetAttribute(L"rowCount", strRowCount);

}

void CMainDlg::CreateAdd(SWindow* pWnd)

{

?? pugi::xml_document doc;

?? SStringW strXml = L"";

?? if (!doc.load_buffer(strXml, strXml.GetLength() * sizeof(wchar_t), pugi::parse_default, pugi::encoding_utf16))

?? {

????? return;

?? }

?? SWindow* pBtn = new SButton;

?? if (pBtn)

?? {

????? pWnd->InsertChild(pBtn);

????? pBtn->InitFromXml(doc.first_child());

?? }

}

void CMainDlg::OnBtnAdd()

{

?? SWindow* pWnd = FindChildByName(L"wnd");

?? if (pWnd)

?? {

????? ClearWnd(pWnd);

????? static int nIndex = 0;

????? m_vec.push_back(nIndex);

????? CreateWnd(pWnd);

????? nIndex++;

?? }

}

bool CMainDlg::OnClick(EventArgs* pArgs)

{

?? int nID = pArgs->idFrom;

?? SStringW strID;

?? strID.Format(L"L %d", nID);

?? SMessageBox(m_hWnd, strID, L"提示", MB_OK);

?? return true;

}

bool CMainDlg::OnRClick(EventArgs* pArgs)

{

?? int nID = pArgs->idFrom;

?? SStringW strID;

?? strID.Format(L"R %d", nID);

?? m_nRClickID = nID;

?? SMenuEx menu;

?? if (!menu.LoadMenu(L"SMENU:menu"))

?? {

????? return false;

?? }

??

?? CPoint pt;

?? GetCursorPos(&pt);

?? menu.TrackPopupMenu(0, pt.x, pt.y, m_hWnd);

?? return true;

}

void CMainDlg::OnCommand(UINT uNotifyCode, int nID, HWND wndCtl)

{

?? if (uNotifyCode == 0)

?? {

????? if (nID == 1000)

????? {

???????? int nIndex = m_nRClickID - 9000;

???????? m_vec.erase(m_vec.begin() + nIndex);

???????? SWindow* pWnd = FindChildByName(L"wnd");

???????? if (pWnd)

???????? {

??????????? ClearWnd(pWnd);

??????????? CreateWnd(pWnd);

???????? }

????? }????

?? }

}

界面

設(shè)置自定義messagebox

將soui源碼的msgbox的xml文件復(fù)制到自己的項(xiàng)目xml文件夾中,并改名為自己的命名。

?

在uires.idx文件中添加進(jìn)來(lái)

在winmain函數(shù)中添加代碼

//設(shè)置自定義messsagebox

pugi::xml_document xmldoc;

theApp->LoadXmlDocment(xmldoc, L"XML_MSGBOX", L"LAYOUT");

if (xmldoc)

{

?? SetMsgTemplate(xmldoc.child(L"SOUI"));

}

效果如圖

設(shè)置編輯框自定義右鍵菜單

從源碼中的系統(tǒng)資源里面復(fù)制編輯框菜單出來(lái)到自己的項(xiàng)目xml文件夾中,并改名。

在uires.idx中添加進(jìn)來(lái)

在winmain函數(shù)中添加代碼

//設(shè)置編輯框自定義右鍵菜單

theApp->LoadXmlDocment(xmldoc, L"XML_EDITMENU", L"SMENU");

if (xmldoc)

{

?? SRicheditMenuDef::getSingleton().SetMenuXml(xmldoc.child(L"editmenu"));

}

效果如圖

多語(yǔ)言翻譯模塊

//加載多語(yǔ)言翻譯模塊。

CAutoRefPtr trans;

bLoaded=m_pComMgr->CreateTranslator((IObjRef**)&trans);

SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("translator"));

if(trans)

{//加載語(yǔ)言翻譯包

?? m_pTheApp->SetTranslator(trans);

?? pugi::xml_document xmlLang;

?? if (m_pTheApp->LoadXmlDocment(xmlLang, _T("lang_cn"), _T("translator")))

?? {

????? CAutoRefPtr langCN;

????? trans->CreateTranslator(&langCN);

????? langCN->Load(&xmlLang.child(L"language"),1);//1=LD_XML

????? trans->InstallTranslator(langCN);

?? }

}

獲取XML中定義的顏色

繼承類

class CMainDlg : public SHostWnd, public SresProviderMgr

使用函數(shù)

COLORREF color = GetColor(L"@color/backgnd");

就可以取出

?

?

?

?

?

?

?

中的任意顏色。

柚子快報(bào)激活碼778899分享:c++ SOUI總結(jié)之常用功能

http://yzkb.51969.com/

參考鏈接

評(píng)論可見(jiàn),查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19505606.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問(wèn)

文章目錄