int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow) { ListMainForm* pFrame = new ListMainForm(); pFrame->Create(NULL, _T("ListDemo"), UI_WNDSTYLE_FRAME, WS_EX_STATICEDGE | WS_EX_APPWINDOW , 0, 0, 600, 320); pFrame->CenterWindow(); ::ShowWindow(*pFrame, SW_SHOW); CPaintManagerUI::MessageLoop(); return 0; }
这里面也没啥看的,因为是ui,所以消息很重要,来看看
INotifyUI: void Notify(TNotifyUI& msg) { if( msg.sType == _T("windowinit") ) OnPrepare(msg); else if( msg.sType == _T("click") ) { else if( msg.pSender == m_pMinBtn ) { SendMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0); return; } else if(msg.pSender == m_pSearch) { OnSearch(); } } else if( msg.sType == _T("itemactivate") ) { int iIndex = msg.pSender->GetTag(); CDuiString sMessage = _T("Click: ");; sMessage += domain[iIndex].c_str(); ::MessageBox(NULL, sMessage.GetData(), _T("提示(by tojen)"), MB_OK); } else if(msg.sType == _T("menu")) { if( msg.pSender->GetName() != _T("domainlist") ) return; CMenuWnd* pMenu = new CMenuWnd(); if( pMenu == NULL ) { return; } POINT pt = {msg.ptMouse.x, msg.ptMouse.y}; ::ClientToScreen(*this, &pt); pMenu->Init(msg.pSender, pt); } else if( msg.sType == _T("menu_Delete") ) { CListUI* pList = static_cast<CListUI*>(msg.pSender); int nSel = pList->GetCurSel(); if( nSel < 0 ) return; pList->RemoveAt(nSel); domain.erase(domain.begin() + nSel); desc.erase(desc.begin() + nSel); } }
一步一步来看这里显示
一开始是
if( msg.sType == _T("windowinit") ) OnPrepare(msg);
OnPrepare函数没有做什么事情,所以忽略
其他的消息我们在后面继续看=============
在继承了CWindowWnd之后可以通过覆盖LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)的实现,添加自己的消息响应
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT lRes = 0; BOOL bHandled = TRUE; switch( uMsg ) { case WM_ADDLISTITEM: lRes = OnAddListItem(uMsg, wParam, lParam, bHandled); break; case WM_CREATE: lRes = OnCreate(uMsg, wParam, lParam, bHandled); break; case WM_CLOSE: lRes = OnClose(uMsg, wParam, lParam, bHandled); break; case WM_DESTROY: lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break; case WM_NCACTIVATE: lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break; case WM_NCCALCSIZE: lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break; case WM_NCPAINT: lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break; case WM_NCHITTEST: lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break; case WM_SIZE: lRes = OnSize(uMsg, wParam, lParam, bHandled); break; case WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break; case WM_SYSCOMMAND: lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break; default: bHandled = FALSE; } if( bHandled ) return lRes; if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes; return CWindowWnd::HandleMessage(uMsg, wParam, lParam); }
======当客户区将要显示激活或者非激活时,WM_NCACTIVATE消息就会发送给窗口。一个窗口通过它的WindowProc函数来获取该消息。
LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if( ::IsIconic(*this) ) bHandled = FALSE; return (wParam == 0) ? TRUE : FALSE; }
判断一下窗体是否是最小化,如果是则设置标志bHandled,然后返回wParam
======窗口创建CreateWindow时,系统给消息处理程序发送的消息,每次窗口创建,有且只有1个WM_CREATE消息
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LONG styleValue = ::GetWindowLong(*this, GWL_STYLE); styleValue &= ~WS_CAPTION; ::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); Init(); }
这里是创建一个窗口并执行Init的操作:
void Init() { m_pCloseBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("closebtn"))); m_pMaxBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("maxbtn"))); m_pRestoreBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("restorebtn"))); m_pMinBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("minbtn"))); m_pSearch = static_cast<CButtonUI*>(m_pm.FindControl(_T("btn"))); }
Init是找到对应的控件
Create完毕之后,窗口就起来了
记得我们在void Notify(TNotifyUI& msg)中绑定了一个消息,消息类型为:
if( msg.sType == _T("click") ) { else if(msg.pSender == m_pSearch) { OnSearch(); } }
主要是这个OnSearch(),当点击了页面上面的Search按钮,那么相对应的消息便会发出来,m_pSearch在Init的时候和UI上的Search按钮绑定(在这里再判断一下消息的发送者),如果对应 则执行了OnSearch()
void OnSearch() { struct Prama *prama = new Prama; CListUI* pList = static_cast<CListUI*>(m_pm.FindControl(_T("domainlist"))); CEditUI* pEdit = static_cast<CEditUI*>(m_pm.FindControl(_T("input"))); pEdit->SetEnabled(false); CDuiString input = pEdit->GetText(); m_pSearch->SetEnabled(false); pList->RemoveAll(); domain.empty(); domain.resize(0); desc.empty(); desc.resize(0); DWORD dwThreadID = 0; pList->SetTextCallback(this);//[1] prama->hWnd = GetHWND(); prama->pList = pList; prama->pSearch = m_pSearch; prama->tDomain = input; HANDLE hThread = CreateThread(NULL,0,&ListMainForm::Search, (LPVOID)prama, 0,&dwThreadID); }
Prama是定义的一个结构体,因为在最底下需要开辟线程去执行Add的操作,所以通过这个结构体把所以需要到的东西都传过去。
pList为对应的List列表,pEdit为最上面的文本框
在ListMainForm::Search中(也就是线程的回调方法):
static DWORD WINAPI Search(LPVOID lpParameter) { try { struct Prama* prama = (struct Prama *)lpParameter; CListUI* pList = prama->pList; CButtonUI* pSearch = prama->pSearch; CDuiString tDomain = prama->tDomain; //------------------------------------- /* * 添加数据循环 */ for(int i=0; i<100; i++) { std::stringstream ss; ss << "www." << i << ".com"; domain.push_back(ss.str()); ss.clear(); ss << "it's " << i; desc.push_back(ss.str()); CListTextElementUI* pListElement = new CListTextElementUI; pListElement->SetTag(i); if (pListElement != NULL) { ::PostMessage(prama->hWnd, WM_ADDLISTITEM, 0L, (LPARAM)pListElement); } /* * Sleep 为了展示添加的动态效果,故放慢了添加速度,同时可以看到添加过程中界面仍然可以响应 */ ::Sleep(100); } //------------------------------------------ delete prama; pSearch->SetEnabled(true); return 0; } }
取出上面的参数,发送WM_ADDLIST消息往里边加入Item:
::PostMessage(prama->hWnd, WM_ADDLISTITEM, 0L, (LPARAM)pListElement);
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { switch( uMsg ) { case WM_ADDLISTITEM: lRes = OnAddListItem(uMsg, wParam, lParam, bHandled); break; }
对应的OnAddListItem就是往List添加Item的
LRESULT OnAddListItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { CListTextElementUI* pListElement = (CListTextElementUI*)lParam; CListUI* pList = static_cast<CListUI*>(m_pm.FindControl(_T("domainlist"))); if( pList ) pList->Add(pListElement); return 0; }
在回头看看void Notify(TNotifyUI& msg)里面:
双击每一个Item则会发出消息itemactivate
else if( msg.sType == _T("itemactivate") ) { int iIndex = msg.pSender->GetTag(); CDuiString sMessage = _T("Click: ");; sMessage += domain[iIndex].c_str(); ::MessageBox(NULL, sMessage.GetData(), _T("提示(by tojen)"), MB_OK); }
msg.pSender->GetTag()获取当前List的Index
对着List右键,则会发出消息menu
else if(msg.sType == _T("menu")) { if( msg.pSender->GetName() != _T("domainlist") ) return; CMenuWnd* pMenu = new CMenuWnd(); if( pMenu == NULL ) { return; } POINT pt = {msg.ptMouse.x, msg.ptMouse.y}; ::ClientToScreen(*this, &pt); pMenu->Init(msg.pSender, pt); }
menu里边有个delete,对应的消息是menu_Delete:
else if( msg.sType == _T("menu_Delete") ) { CListUI* pList = static_cast<CListUI*>(msg.pSender); int nSel = pList->GetCurSel(); if( nSel < 0 ) return; pList->RemoveAt(nSel); domain.erase(domain.begin() + nSel); desc.erase(desc.begin() + nSel); } }
好了 这个例子就看完了
这个例子中还有两外一个文件MenuWnd.h他其实是对的CMenuWnd描述,也是一个class CMenuWnd : public CWindowWnd, public INotifyUI窗口,他的分析和上面说的差不多。
最后,来看看这里:
else if(msg.sType == _T("menu")) { if( msg.pSender->GetName() != _T("domainlist") ) return; CMenuWnd* pMenu = new CMenuWnd(); if( pMenu == NULL ) { return; } POINT pt = {msg.ptMouse.x, msg.ptMouse.y}; ::ClientToScreen(*this, &pt); pMenu->Init(msg.pSender, pt); }
==========最后delete this==========