2013/07/08

[MFC]CButton類如何響應WM_LBUTTONDOWN or WM_LBUTTONUP

建立一個button在dialog上的時候,他預設只有兩種事件可以響應,一是BN_CLICKED,另一則是BN_DOUBLECLICKED,那我要滑鼠左鍵按下與彈上的事件該怎麼做呢?

VC6是這樣做的:
1.在原Dialog下新增一CMyButton類別,其父類別為CButton。
2.為MyButton類別添加WM_LBUTTONDOWN與WM_LBUTTONUP的消息響應。
3.在Dialog下宣告一個MyButton的成員變數。
4.在MyButton.cpp->CMyButton::OnLButtonDown 內編輯你要滑鼠左鍵按下時,要做什麼事。

2013/07/04

[MFC] Tree Control Item 如何辨識唯一值

當我們在TreeCtrl上新增Item完後,若要在之後的操作中,判別此Item是否為唯一項目,目前只知道能用ItemText來判斷,但萬一ItemText非唯一值時,這樣的判斷方式就會有問題!
為了避免這樣的狀況發生,我在新增Item時,偷用一個欄位:lParam
先在.h定義一個與Item相關的其他訊息結構:
typedef struct _treeItemInfo;
{
long nId;
//也可以放入其他需要紀錄的資訊,如 char sTextEx[8];
} ITEMINFO, *PITEMINFO;

然後在.cpp內修改tree insert的部份:

void CMyDlg::InsertNewItem()
{
HTREEITEM hSubItem;//新增Item後會回傳Item handle
TV_INSERTSTRUCT tvis;
TV_ITEM tvi;//set item member data
tvi.mask= TVIF_TEXT;
tvi.pszText= "test";//顯示在Item上的文字
//set insert struct;
member data
tvis.item= tvi;//insert items into CTreeCtrl
tvis.hParent= NULL;//此為根結點,故父節點為NULL
tvis.hInsertAfter= TVI_ROOT;//此為根結點
hSubItem = m_tree.InsertItem(tvis);

//方法1
PITEMINFO l_pItemEx = new ITEMINFO;
l_pItemEx->nId = 1000;
strcpy(l_pItemEx->sTextEx,"MyInfo");
m_tree.SetItemData( hSubItem, l_pItemEx);//將序號結構地址與此節點綁在一起
//方法2
DWORD dItemId = 1000;//表示Item序號
m_tree.SetItemData( hSubItem, dItemId);//將序號與此節點綁在一起
}

當滑鼠拖曳某項Item時,會響應TVN_BEGINDRAG消息,這時從響應函式內將ID取出。
void CMyDlg::OnTvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast LPNMTREEVIEW(pNMHDR);
*pResult = 0;
// TODO: 在此加入控制項告知處理常式程式碼

DWORD tmpId;
//方法1
HTREEITEM hDragItem = ((NM_TREEVIEW*)pNMHDR)->itemNew.hItem;
PITEMINFO l_pTmpItemEx = (PITEMINFO)m_tree.GetItemData(hDragItem);
tmpId = m_tree.GetItemData(hDragItem);
}

//方法2
TVITEM tvitem= ((NM_TREEVIEW*)pNMHDR)->itemNew;
tmpId = tvitem.lParam;
//取得ID後,作你想做的事吧!

ps.方法1&2選一個用即可。

參考:StackOverflow  how to create new Property for MFC(VC++) treeview Control?

[MFC]多消息響應同一函式

以前的寫法都是 one message mapping one function,
但有時候其實多個消息要做的事情,都會對到同一個對象,只是做的動作不同,
例如對同一個表單做新增、刪除、修改、查詢這樣的狀況,
這時候就可以用 ON_COMMAND_RANGE囉~

舊做法:
ON_COMMAND(ID_TREEITEM_ADD, &CMyDialog::OnTreeItemAdd)
ON_COMMAND(ID_TREEITEM_DEL, &CMyDialog::OnTreeItemDel)
ON_COMMAND(ID_TREEITEM_MODIFY, &CMyDialog::OnTreeItemModify)

void CMyDialog::OnTreeItemAdd()
{
m_tree.add(hItem);
}

void CMyDialog::OnTreeItemDel()
{
m_tree.delete(hItem);
}


void CMyDialog::OnTreeItemModify()
{
m_tree.Modify(hItem);
}

改為:

ON_COMMAND_RANGE(ID_TREEITEM_ADD,ID_TREEITEM_MODIFY, &CMyDialog::OnTreeItem)

//此作法需注意:ID_TREEITEM_ADD、ID_TREEITEM_DEL、ID_TREEITEM_MODIFY在resource.h中必須為連續數,如1、2、3。

void CMyDialog::OnTreeItem(UINT nID)
{
    switch(nID)
    {
    case ID_TREEITEM_ADD:
    m_tree.add(hItem);
    break;
    case ID_TREEITEM_DEL:
        m_tree.del(hItem);
        break;
    case ID_TREEITEM_MODIFY:
        m_tree.Modify(hItem);
        break;
    default:
        break;
    }
}

//m_tree的add del modify只是示意,並非真的有此member function,詳見msdn CTreeCtrl

本篇參考:msdn ON_MESSAGE_RANGE