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(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(m_pm.FindControl(_T("closebtn")));
m_pMaxBtn = static_cast(m_pm.FindControl(_T("maxbtn")));
m_pRestoreBtn = static_cast(m_pm.FindControl(_T("restorebtn")));
m_pMinBtn = static_cast(m_pm.FindControl(_T("minbtn")));
m_pSearch = static_cast(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(m_pm.FindControl(_T("domainlist")));
CEditUI* pEdit = static_cast(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(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(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==========