认识soui4js(第4篇):定义一个窗口类,响应控件的事件
soui4js基于soui4设计实现。
首先我们看一下soui4中如何定义一个窗口类。
soui4最基本的窗口类是SHostWnd和SHostDialog,它需要一个布局xml。
假定布局xml在资源包中的位置为:layout:maindlg。
那么soui4中定义一个窗口可以是下面的代码(为了演示方便,这里使用SHostDialog):
SHostDialog dlg("layout:maindlg"); dlg.DoModal(NULL);
在soui4js中,这两个对象被导出为soui4.JsHostWnd, soui4.JsHostDialog。
如果不需要处理窗口消息或者事件,可以使用下面的方法来直接创建窗口:
let dlg = new soui4.JsHostDialog("layout:maindlg"); dlg.DoModal(0);
可以看出来,js的代码和C++代码基本上是一样的。
如果需要处理UI中的事件要如何处理呢?
在C++中,最简单的方法是从SHostDialog继承一个新的对象,然后使用消息或者事件映射表来响应窗口消息及控件的事件。
伪代码如下:
class CDemoDialog : public SHostDialog{
public:
CDemoDialog():SHostDialog("layout:maindlg"){} //.... protected: void OnBtnTest(){ SSLOGI()<<"test button click"; } EVENT_MAP_BEGIN() EVENT_NAME_COMMAND(L"btn_test", OnBtnTest) EVENT_MAP_END() };
EVENT_MAP_BEGIN, EVENT_MAP_END一起构成SHostDialog的事件响应虚函数,从而实现接管事件处理流程。
在js中,用法基本类似:
class OptionDlg extends soui4.JsHostDialog{ constructor(settings){ super("layout:maindlg"); this.onEvt = this.onEvent;//这一行实现事件处理的接管 } onBtnTest(){ console.log("test button click"); } onEvent(e){ //事件处理函数,e是事件对象,可以使用GetID(),Sender()等来获取id及发送者 let evt_id = e.GetID(); switch(evt_id){ case soui4.EVT_CMD:
if(e.NameFrom()=="btn_test") this.onBtnTest(); break; } } }
这样就完成了窗口中事件的处理。
窗口消息处理也类似,只需要设定JsHostDialog.onMsg就可以接管消息处理。
SOUI中另一种常见的事件响应方法是事件订阅:
例如下面的代码实现订阅表头的子控件checkbox的点击事件:
1 void CMainDlg::InitListCtrl() 2 { 3 //找到列表控件 4 SListCtrl *pList=FindChildByName2<SListCtrl>(L"lc_test"); 5 if(pList) 6 { 7 //列表控件的唯一子控件即为表头控件 8 SWindow *pHeader=pList->GetWindow(GSW_FIRSTCHILD); 9 //向表头控件订阅表明点击事件,并把它和OnListHeaderClick函数相连。 10 pHeader->GetEventSet()->subscribeEvent(EVT_HEADER_CLICK,Subscriber(&CMainDlg::OnListHeaderClick,this)); 11 } 12 } 13 14 //表头点击事件处理函数 15 BOOL CMainDlg::OnListHeaderClick(IEvtArgs *pEvtBase) 16 { 17 //事件对象强制转换 18 EventHeaderClick *pEvt =(EventHeaderClick*)pEvtBase; 19 SHeaderCtrl *pHeader=(SHeaderCtrl*)pEvt->Sender(); 20 //从表头控件获得列表控件对象 21 SListCtrl *pList= (SListCtrl*)pHeader->GetParent(); 22 //列表数据排序 23 SHDITEM hditem; 24 hditem.mask=SHDI_ORDER; 25 pHeader->GetItem(pEvt->iItem,&hditem); 26 pList->SortItems(funCmpare,&hditem.iOrder); 27 return true; 28 } 29 //以上代码来自soui4 demo
soui4js包含了一个SConnect方法,可以方便的订阅一个窗口的事件:
函数原型下下:
/** * 将指定IWindow的指定事件对象连接到指定对象的事件处理方法 * @param pObj IWindow窗口 * @param evtId 事件类型 * @param jsThis 处理事件的对象 * @param jsFun 处理事件的方法 */ export function SConnect(pObj:IWindow,evtId:number,jsThis:object,jsFun:(evt:IEvtArgs)=>boolean):boolean;
因此在js中可以使用下面的代码来实现事件订阅:
class MainDialog extend soui4.JsHostWnd { //... init(){
soui4.SConnect(this.GetIRoot(),soui4.EVT_MENU_CMD,this,this.onMenuCmd); } onMenuCmd(e){ let menuCmd = soui4.toEventMenuCmd(e); return true; } //... }
具体代码,参考 https://github.com/soui4js-app/somine