Win32 SDK TreeView 控件的基本用法,节点的编辑,拖动,添加,删除,弹出菜单
TreeView控件老是用的稀里糊涂的,写个测试程序总结一下基本用法
要注意点:
1.控件是发通知给父窗口处理,因此消息中鼠标的坐标不是相对控件的,要从屏幕坐标转换来。
2.通知消息的返回值 要参考文档,0 一般是允许默认处理,非0 则阻止默认处理。
3.通知消息参数用LPARAM传递,不同的控件起始结构是相同的,后面附加结构不同。
4.通知码是在LPARAM指向的结构中,所以在消息映射表的处理和COMMAND不同,并且通知码是UINT,和nID比较要转换为WORD。
测试程序是WIN32 SDK向导生成的C语言框架。树的操作定义成一个类。 简单起见不封装成窗口类,也不涉及消息映射表。
微软网站上TreeView_XXX 宏的说明文档好多错误,应该是返回句柄的都写成了void型,难道是SDK编程没人用,不维护了?
// Tree.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "resource.h" //xgz 扩展控件用库 #include "Commctrl.h" #pragma comment(lib,"comctl32.lib") //xgz========== #define IDC_EDIT 1001 #define IDC_STATUSBAR 1002 #define IDC_TOOLSBAR 1003 #define IDC_VIEW_TREEVIEW1 1101 HWND m_hWndEdit; HWND m_hStatusbar; HWND m_hToolsbar; int OnCreate(HWND, UINT, WPARAM, LPARAM); int OnSize(HWND, UINT, WPARAM, LPARAM); int OnPaint(HWND, UINT, WPARAM, LPARAM); int OnTimer(HWND, UINT, WPARAM, LPARAM); int OnNotify(HWND, UINT, WPARAM, LPARAM); //控件的通知是发给父窗口处理 int OnLButtonDown(HWND, UINT, WPARAM, LPARAM); int OnLButtonUp(HWND, UINT, WPARAM, LPARAM); int OnMouseMove(HWND, UINT, WPARAM, LPARAM); int OnFileNew(HWND, UINT, WPARAM, LPARAM); int OnFileOpen(HWND, UINT, WPARAM, LPARAM); int OnFileSave(HWND, UINT, WPARAM, LPARAM); int OnTreeEdit(HWND, UINT, WPARAM, LPARAM); int PRINT(const TCHAR* fmt, ...) { TCHAR buffer[1024]; va_list argptr; int cnt; int iEditTextLength; HWND hWnd = m_hWndEdit; if (NULL == hWnd) return 0; va_start(argptr, fmt); cnt = wvsprintf(buffer, fmt, argptr); // not %f va_end(argptr); iEditTextLength = GetWindowTextLength(hWnd); if (iEditTextLength + cnt > 30000) // edit text max length is 30000 { SendMessage(hWnd, EM_SETSEL, 0, 10000); SendMessage(hWnd, WM_CLEAR, 0, 0); iEditTextLength = iEditTextLength - 10000; } SendMessage(hWnd, EM_SETSEL, iEditTextLength, iEditTextLength); SendMessage(hWnd, EM_REPLACESEL, 0, (LPARAM)buffer); return(cnt); } //============ class CTree { public: CTree(); ~CTree(); HMENU m_hMenu, m_hPopMenu; HINSTANCE m_hInst; HWND m_hWnd; HTREEITEM m_hRoot; HWND CreateTreeView(HWND hWndParent); int InitTreetView(); HTREEITEM AddItemToTree(HWND hwndTV, LPTSTR lpszItem, int nLevel); HTREEITEM InsertTreeNode(HWND hWndTV, HTREEITEM hPrev, LPTSTR lpszItem); //int DeleteTreetView(); //TreeView_DeleteAllItems(m_hWndTree); void ExpandAll(HTREEITEM hItem); HTREEITEM m_hBeginDrag; //记录拖动起点的Item HIMAGELIST m_hDragImageList; //拖动的图像列表 BOOL m_bDrag; //用来判断是否进行拖动 void CopyNodes(HTREEITEM hDesItem, HTREEITEM hSrcItem);//复制节点函数 int OnTvnBegindrag(NMHDR* pNMHDR); int OnLButtonUp(HWND, UINT, WPARAM, LPARAM); int OnMouseMove(HWND, UINT, WPARAM, LPARAM); int OnTvnBeginlabeledit(LPNMHDR lphr); int OnTvnEndlabeledit(LPNMHDR lphr); int OnLClkTree(LPNMHDR lphr); int OnRClkTree(LPNMHDR lphr); int OnDBLClkTree(LPNMHDR lphr); int ItemLabelEdit(); int InsertChild(); int InsertSibling(); int DeleteItem(); }; CTree::CTree() { } CTree::~CTree() { } CTree m_Tree1; HWND CTree::CreateTreeView(HWND hWndParent) { InitCommonControls(); m_hInst = (HINSTANCE)GetWindowLong(hWndParent, GWL_HINSTANCE); HWND hWndTreeView = CreateWindow(WC_TREEVIEW, _T("Tree"), WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS | TVS_LINESATROOT | WS_BORDER | TVS_EDITLABELS, 0, 0, 0, 0, hWndParent, (HMENU)IDC_VIEW_TREEVIEW1, m_hInst, NULL); HIMAGELIST hImageList; hImageList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 15, 15); //size 16x16 X15 for (unsigned int i = 0; i < 15; i++) { HICON hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_ICON1 + i)); ImageList_AddIcon(hImageList, hIcon); DestroyIcon(hIcon); } SendMessage(hWndTreeView, TVM_SETIMAGELIST, 0, (LPARAM)hImageList); m_hWnd = hWndTreeView; //xgz 直接保存 m_hMenu = LoadMenu(m_hInst, (LPCSTR)IDC_TREE); m_hPopMenu = GetSubMenu(m_hMenu, 2); //XGZ 用主菜单的第三列菜单作为弹出菜单 return (hWndTreeView); } int CTree::InitTreetView() { HTREEITEM hti; m_hRoot = InsertTreeNode(m_hWnd, NULL, _T("Root")); hti = InsertTreeNode(m_hWnd, m_hRoot, _T("Node1")); hti = InsertTreeNode(m_hWnd, m_hRoot, _T("Node2")); hti = InsertTreeNode(m_hWnd, m_hRoot, _T("Node3")); hti = InsertTreeNode(m_hWnd, hti, _T("Node3-1")); hti = InsertTreeNode(m_hWnd, hti, _T("Node3-1-1")); //TreeView_Expand(m_hWnd, m_hRoot, TVE_EXPAND);//只展开一个节点 ExpandAll(m_hRoot); //递归展开所有节点 return 1; } HTREEITEM CTree::AddItemToTree(HWND hwndTV, LPTSTR lpszItem, int nLevel) { TVITEM tvi; TVINSERTSTRUCT tvins; static HTREEITEM hPrev = (HTREEITEM)TVI_FIRST; static HTREEITEM hPrevRootItem = NULL; static HTREEITEM hPrevLev2Item = NULL; HTREEITEM hti; tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_STATE; // Set the text of the item. tvi.pszText = lpszItem; tvi.cchTextMax = sizeof(tvi.pszText) / sizeof(tvi.pszText[0]); // Assume the item is not a parent item, so give it a // document image. tvi.iImage = 0;// g_nDocument; tvi.iSelectedImage = 0;// g_nDocument; // Save the heading level in the item's application-defined // data area. tvi.lParam = (LPARAM)nLevel; tvins.item = tvi; tvins.hInsertAfter = hPrev; // Set the parent item based on the specified level. if (nLevel == 1) tvins.hParent = TVI_ROOT; else if (nLevel == 2) tvins.hParent = hPrevRootItem; else tvins.hParent = hPrevLev2Item; // Add the item to the tree-view control. hPrev = (HTREEITEM)SendMessage(hwndTV, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); if (hPrev == NULL) return NULL; // Save the handle to the item. if (nLevel == 1) hPrevRootItem = hPrev; else if (nLevel == 2) hPrevLev2Item = hPrev; // The new item is a child item. Give the parent item a // closed folder bitmap to indicate it now has child items. if (nLevel > 1) { hti = TreeView_GetParent(hwndTV, hPrev); tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE; tvi.hItem = hti; tvi.iImage = 2;//g_nClosed; tvi.iSelectedImage = 2;// g_nClosed; TreeView_SetItem(hwndTV, &tvi); } return hPrev; } HTREEITEM CTree::InsertTreeNode(HWND hWndTV, HTREEITEM hPrev, LPTSTR lpszItem) { TVINSERTSTRUCT tvins; TVITEM tvi; tvins.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; //TVIF_TEXT| TVIF_PARAM; tvins.item.pszText = lpszItem; if (NULL != hPrev) //把上级图标改为文件夹 { tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE; //只处理 IMAGE tvi.hItem = hPrev; tvi.iImage = 10; tvi.iSelectedImage = 10; TreeView_SetItem(hWndTV, &tvi); } tvins.item.iImage = 0; //初始图标都是文件 tvins.item.iSelectedImage = 0; tvins.hParent = hPrev; tvins.hInsertAfter = TVI_LAST; return (HTREEITEM)SendMessage(hWndTV, TVM_INSERTITEM, 0, (LPARAM)(LPTVINSERTSTRUCT)&tvins); } void CTree::ExpandAll(HTREEITEM hItem) { if (!hItem) return; HTREEITEM hChild = TreeView_GetChild(m_hWnd, hItem); ExpandAll(hChild); if (hChild) TreeView_Expand(m_hWnd, hItem, TVE_EXPAND);//XGZ 有子节点的展开父节点,上个返回可能是NULL HTREEITEM hSibling = TreeView_GetNextSibling(m_hWnd, hItem); ExpandAll(hSibling); //XGZ sibling节点无需展开 return; } //复制节点,将hSrcItem及其子项目复制到下hDesItem节点下 void CTree::CopyNodes(HTREEITEM hDesItem, HTREEITEM hSrcItem) { if (hDesItem == NULL || hSrcItem == NULL) //Item为空则不进行操作 { return; } TVITEM tvItem; //定义项目信息结构体 tvItem.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM; //xgz 必须要copy param tvItem.hItem = hSrcItem; char chText[MAX_PATH] = { 0 }; tvItem.pszText = chText; tvItem.cchTextMax = MAX_PATH; //GetItem(&tvItem); //获取项目信息 TreeView_GetItem(m_hWnd, &tvItem); TVINSERTSTRUCT tvInsert; //定义插入操作的数据结构 tvInsert.hParent = hDesItem; //定义插入的父节点 tvInsert.item = tvItem; //定义插入的子节点 HTREEITEM hInsert = TreeView_InsertItem(m_hWnd, &tvInsert);//插入Item,并获取插入完之后的Item新的句柄 //Item里的所有子Item也插过来 HTREEITEM hChild = TreeView_GetChild(m_hWnd, hSrcItem);//获取子节点 while (hChild != NULL) { CopyNodes(hInsert, hChild); //递归复制子节点 hChild = TreeView_GetNextSibling(m_hWnd, hChild); //获取下一个兄弟节点 } } //WM_NOTIFY 消息在 wParam 中包含发送消息的控件的 ID,在 lParam 中包含指向结构的指针。 //该结构要么是 NMHDR 结构,要么是具有 NMHDR 结构作为其第一个成员的较大结构。 //由于 NMHDR 是第一个成员,因此指向此结构的指针可用作指向 NMHDR 的指针,也可以用作指向较大结构的指针,具体取决于转换方式。 //开始拖动时控件发通知给父窗口,父窗口须记录源树节点,捕获鼠标以便处理移动消息 int CTree::OnTvnBegindrag(NMHDR* pNMHDR) { //LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); //// TODO: Add your control notification handler code here //*pResult = 0; NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; HTREEITEM hItem = pNMTreeView->itemNew.hItem; //获取开始拖动的Item的句柄 if (hItem == TreeView_GetRoot(m_hWnd)) //根节点不能拖动 { return 0; } m_hBeginDrag = hItem; //保存拖动的树节点 POINT dragPt; //拖动位置坐标,相对树控件 dragPt.x = pNMTreeView->ptDrag.x; dragPt.y = pNMTreeView->ptDrag.y; m_hDragImageList = (HIMAGELIST)SendMessage(m_hWnd, TVM_CREATEDRAGIMAGE, 0, (LPARAM)pNMTreeView->itemNew.hItem); //创建拖动的图像列表 if (m_hDragImageList != NULL) { ImageList_BeginDrag(m_hDragImageList, 0, 8, 8); //xgz 拖动图标加个(8,8)位置偏移,避免光标遮挡 ClientToScreen(m_hWnd, &(dragPt)); //转换客户坐标到屏幕坐标 ImageList_DragEnter(m_hWnd, dragPt.x, dragPt.y); //在拖动的过程中显示拖动的图像 SetCapture(GetParent(m_hWnd)); //树的父窗口开始鼠标捕捉 m_bDrag = TRUE; //这里表示当前状态是拖动操作 } return 0; } //父窗口的鼠标消息,和控件可能有位移,所以不用lParam中的坐标,而是从屏幕坐标转换 int CTree::OnMouseMove(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if (m_bDrag) //处于拖动状态 { HTREEITEM hItem; UINT nHitFlags; POINT point; GetCursorPos(&point); ScreenToClient(m_hWnd, &point); //控件坐标 ImageList_DragMove(point.x, point.y); //设置拖动的图像位置为鼠标位置,相对于控件显示 //设置鼠标经过时高亮显示选中 TVHITTESTINFO tvhit; tvhit.pt = point; hItem = TreeView_HitTest(m_hWnd, &tvhit); if (hItem != NULL) { ImageList_DragShowNolock(FALSE); //隐藏拖动的图像 TreeView_SelectDropTarget(m_hWnd, hItem);//设置选中的项目 //若有子节点就展开 HTREEITEM hChild = TreeView_GetChild(m_hWnd, hItem); if (hChild) TreeView_Expand(m_hWnd, hItem, TVE_EXPAND);//XGZ 有子节点的展开父节点,上个返回可能是NULL ImageList_DragShowNolock(TRUE); //显示拖动的图像,展开子节点后再显示,避免残影 } return 1; } else { //CTreeCtrl::OnMouseMove(nFlags, point);//MFC如果不是拖动,就交父类默认处理 return 1; //xgz 自己封装SDK API,父类没处理,直接返回 } } //拖放完成可以用UP,也可以用Down,习惯上可能多用UP int CTree::OnLButtonUp(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { //CTreeCtrl::OnLButtonUp(nFlags, point); //FMC的基本调用格式,nFlags可以是键盘状态等,在WPARAM中, POINT point; point.x = LOWORD(lParam); point.y = HIWORD(lParam); if (m_bDrag == TRUE) //正在拖动 { m_bDrag = FALSE; //结束拖动状态 ImageList_DragLeave(m_hWnd); //隐藏拖动图像,允许窗口进行更新 (3) ImageList_EndDrag(); //结束图像的拖动 (4) ReleaseCapture(); //释放鼠标捕捉 ImageList_Destroy(m_hDragImageList); //释放图像列表 m_hDragImageList = NULL; HTREEITEM hItemDest; //拖放目的地的Item TVHITTESTINFO tvhit; GetCursorPos(&point); ScreenToClient(m_hWnd, &point); tvhit.pt = point; tvhit.flags = TVHT_TORIGHT; hItemDest = TreeView_HitTest(m_hWnd, &tvhit); if (hItemDest != NULL) //目的地有效 { BOOL blMove = TRUE; //可以移动的条件:目的节点不是源节点的父节点,目的不是源也不是源的子孙 if (hItemDest == TreeView_GetParent(m_hWnd, m_hBeginDrag)) blMove = FALSE; //目标和源的父相同 HTREEITEM hItem = hItemDest; while (hItem != NULL) { if (hItem == m_hBeginDrag) //目标或目标的父节点和源节点相同则不能移动 { blMove = FALSE; break; } hItem = TreeView_GetParent(m_hWnd, hItem); //向上查找 } if (blMove) //满足移动条件 { HTREEITEM hItemScrParent = TreeView_GetParent(m_hWnd, m_hBeginDrag); CopyNodes(hItemDest, m_hBeginDrag); //完成节点的复制 TreeView_DeleteItem(m_hWnd, m_hBeginDrag); //删除原Item,其子节点也会自动删除。 TVITEM tvi; tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE; //只处理 IMAGE tvi.hItem = hItemDest; //有了子节点图标应该是文件夹 tvi.iImage = 10; tvi.iSelectedImage = 10; TreeView_SetItem(m_hWnd, &tvi); if (TreeView_GetChild(m_hWnd, hItemScrParent) == NULL) //如果源的父没有子了 { tvi.hItem = hItemScrParent; tvi.iImage = 0; //图标改成文件 tvi.iSelectedImage = 0; TreeView_SetItem(m_hWnd, &tvi); } } TreeView_SelectDropTarget(m_hWnd, NULL); //取消移入Item的选中状态 m_hBeginDrag = NULL; } } return 1; } int CTree::OnTvnBeginlabeledit(LPNMHDR lphr) { TV_DISPINFO* pTVDispinfo = (TV_DISPINFO*)lphr; HWND hWndEdit = TreeView_GetEditControl(m_hWnd); //xgz 这是EDIT控件,可以发消息 if (pTVDispinfo->item.lParam == 0) //0 是取消了编辑 return 1; //阻止编辑 else return 0; //允许编辑 } int CTree::OnTvnEndlabeledit(NMHDR* pNMHDR) { // LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR); TV_DISPINFO* pTVDispinfo = (TV_DISPINFO*)pNMHDR; if (pTVDispinfo->item.pszText != 0) //xgz 修改了才更新,0是取消,若取消编辑保持原来的字符串 { //SetItemText(pTVDispinfo->item.hItem, pTVDispinfo->item.pszText); //TreeView_SetItem(m_hWnd, &(pTVDispinfo->item)); TVITEM tvi; //2023-05-09 这里不应该这样处理, 不必设置标签值,返回TURE由控件完成设置; tvi.mask = TVIF_TEXT; //只处理 TEXT tvi.hItem = pTVDispinfo->item.hItem; tvi.pszText = pTVDispinfo->item.pszText; TreeView_SetItem(m_hWnd, &tvi); } return 0; } int CTree::OnLClkTree(LPNMHDR lphr) { TVHITTESTINFO thti; HTREEITEM htItem; TVITEM tvi; POINT point; GetCursorPos(&point); ScreenToClient(m_hWnd, &point); thti.pt = point; thti.flags = TVHT_TORIGHT; htItem = TreeView_HitTest(m_hWnd, &thti); if (htItem == NULL) return 0; TCHAR szText[20]; memset(&tvi, 0, sizeof(tvi)); tvi.mask = TVIF_TEXT | TVIF_PARAM; tvi.hItem = htItem; tvi.pszText = szText; tvi.cchTextMax = sizeof(szText); TreeView_GetItem(m_hWnd, &tvi); PRINT(_T("\r\n<INFO>CTree::OnLClkTree= %s"), szText); return 1; } int CTree::OnRClkTree(LPNMHDR lphr) { TVHITTESTINFO thti; HTREEITEM htItem; TVITEM tvi; POINT point; GetCursorPos(&point); ScreenToClient(m_hWnd, &point); thti.pt = point; thti.flags = TVHT_TORIGHT; htItem = TreeView_HitTest(m_hWnd, &thti); if (htItem == NULL) return 0; TCHAR szText[20]; memset(&tvi, 0, sizeof(tvi)); tvi.mask = TVIF_TEXT | TVIF_PARAM; tvi.hItem = htItem; tvi.pszText = szText; tvi.cchTextMax = sizeof(szText); TreeView_GetItem(m_hWnd, &tvi); PRINT(_T("\r\n<INFO>CTree::OnRClkTree = %s"), szText); GetCursorPos(&point); TrackPopupMenu(m_hPopMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, 0, GetParent(m_hWnd), NULL); //通知是控件的父窗口处理 return 1; }
int CTree::OnDBLClkTree(LPNMHDR lphr) { HTREEITEM htItem; TVITEM tvi; htItem = TreeView_GetSelection(m_hWnd); if (htItem == NULL) return 0;
// HWND m_hWndClient = ((CXMDIFrameEx*)m_pMainFrame)->m_hWndClient; TCHAR szText[20]; memset(&tvi, 0, sizeof(tvi)); tvi.mask = TVIF_TEXT | TVIF_PARAM; tvi.hItem = htItem; tvi.pszText = szText; tvi.cchTextMax = sizeof(szText); TreeView_GetItem(m_hWnd, &tvi); PRINT(_T("\r\n<INFO>CTree::OnDBLClkTree= %s"), szText); return 1; } int CTree::ItemLabelEdit() { HTREEITEM htItem; TVITEM tvi; htItem = TreeView_GetSelection(m_hWnd); if (htItem == NULL) return 0; TreeView_EditLabel(m_hWnd, htItem); return 1; } int CTree::InsertChild() { // TODO: Add your command handler code here HTREEITEM hItem = TreeView_GetSelection(m_hWnd); HTREEITEM hItemNew = NULL; if (NULL == hItem) { PRINT(_T("\r\n<FAIL>No selected")); return 0; } else { hItemNew = InsertTreeNode(m_hWnd, hItem, _T("NewChild")); TreeView_Expand(m_hWnd, hItem, TVE_EXPAND); TreeView_SelectItem(m_hWnd, hItemNew); TreeView_EditLabel(m_hWnd, hItemNew); //插入后就编辑 return 1; } } int CTree::DeleteItem() { HTREEITEM hItem = TreeView_GetSelection(m_hWnd); HTREEITEM hItemNew = NULL; if (NULL == hItem) { PRINT(_T("\r\n<FAIL>No selected")); return 0; } else { TreeView_DeleteItem(m_hWnd, hItem); return 1; } } int CTree::InsertSibling() { HTREEITEM hItem = TreeView_GetSelection(m_hWnd); HTREEITEM hItemNew = NULL; hItem = TreeView_GetParent(m_hWnd, hItem); if (NULL == hItem) { PRINT(_T("\r\n<FAIL>No selected")); return 0; } else { hItemNew = InsertTreeNode(m_hWnd, hItem, _T("NewSibling")); TreeView_Expand(m_hWnd, hItem, TVE_EXPAND); TreeView_SelectItem(m_hWnd, hItemNew); TreeView_EditLabel(m_hWnd, hItemNew); //插入后就编辑 return 1; } } //========工具条和状态条========================== HWND CreateStatusbar(HWND hWnd) { int Rightend[3]; RECT rt; GetClientRect(hWnd, &rt); HWND hWndStatusBar = CreateWindowEx(0, STATUSCLASSNAME, _T(""), WS_CHILD | WS_VISIBLE | SBS_SIZEGRIP, 0, 0, 0, 0, hWnd, (HMENU)IDC_STATUSBAR, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); if (!hWndStatusBar) return NULL; Rightend[0] = rt.right / 2; Rightend[1] = rt.right * 3 / 4; Rightend[2] = rt.right; //set statusbar to three segment SendMessage(hWndStatusBar, SB_SETPARTS, (WPARAM)3, (LPARAM)Rightend); MoveWindow(hWndStatusBar, 0, 0, 0, 0, TRUE); //TextOut in statusbar SendMessage(hWndStatusBar, SB_SETTEXT, 0, (long)TEXT("Status 0")); SendMessage(hWndStatusBar, SB_SETTEXT, 1, (long)TEXT("========test=====")); SendMessage(hWndStatusBar, SB_SETTEXT, 2, (long)TEXT("Step 2")); return hWndStatusBar; } HWND CreateToolbar(HWND hWnd) { // image,COMMAND, STATUS, STYLE, //用系统标准图标 TBBUTTON tbButton[] = { { STD_FILENEW, IDM_FILE_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_FILEOPEN, IDM_FILE_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_FILESAVE, IDM_TEST_TEST1, TBSTATE_ENABLED , TBSTYLE_BUTTON , 0L, 0}, { STD_HELP, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0L, -1}, { STD_FIND, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_UNDO, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_REDOW, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0L, -1}, { STD_COPY, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_PASTE, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_CUT, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_DELETE, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_FILESAVE, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_PROPERTIES, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_FIND, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_REPLACE, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_PRINT, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_FILESAVE, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_FILESAVE, IDM_TEST_TEST3, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0}, { STD_PRINTPRE, IDM_EXIT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0L, 0} }; HINSTANCE hLib = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE); //It can be other DLL,here same as m_hInst HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, _T(""), //WS_VISIBLE|WS_CHILD|TBSTYLE_TOOLTIPS, //| WS_BORDER|TBSTYLE_FLAT, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS | CCS_NORESIZE | CCS_ADJUSTABLE | CCS_NODIVIDER | CCS_NOPARENTALIGN, //for rebar 0, 0, 0, 0, hWnd, (HMENU)IDC_TOOLSBAR, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL); if (!hWndToolbar) return NULL; SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); SendMessage(hWndToolbar, TB_SETEXTENDEDSTYLE, 0, (LPARAM)(DWORD)(TBSTYLE_EX_DRAWDDARROWS)); TBADDBITMAP tbBitmap1; tbBitmap1.hInst = HINST_COMMCTRL; tbBitmap1.nID = IDB_STD_SMALL_COLOR; SendMessage(hWndToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbBitmap1); SendMessage(hWndToolbar, TB_SETBITMAPSIZE, 0, (LPARAM)MAKELONG(16, 16)); //size 16x16 SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0); SendMessage(hWndToolbar, TB_ADDBUTTONS, 15, (LONG)&tbButton); //add 6 button return hWndToolbar; } //=====模板生成的WIN32 程序框架 ========================= #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text // Foward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. MSG msg; HACCEL hAccelTable; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_TREE, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_TREE); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_TREE); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = (LPCSTR)IDC_TREE; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx(&wcex); } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } InitCommonControls(); m_hToolsbar = CreateToolbar(hWnd); m_hStatusbar = CreateStatusbar(hWnd); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; TCHAR szHello[MAX_LOADSTRING]; LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); switch (message) { case WM_CREATE: OnCreate(hWnd, message, wParam, lParam); break; case WM_SIZE: OnSize(hWnd, message, wParam, lParam); break; case WM_PAINT: OnPaint(hWnd, message, wParam, lParam); break; case WM_TIMER: OnTimer(hWnd, message, wParam, lParam); break; case WM_LBUTTONDOWN: OnLButtonDown(hWnd, message, wParam, lParam); break; case WM_LBUTTONUP: OnLButtonUp(hWnd, message, wParam, lParam); break; case WM_MOUSEMOVE: OnMouseMove(hWnd, message, wParam, lParam); break; case WM_NOTIFY: OnNotify(hWnd, message, wParam, lParam); break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_FILE_NEW: OnFileNew(hWnd, message, wParam, lParam); break; case IDM_FILE_OPEN: OnFileOpen(hWnd, message, wParam, lParam); break; case IDM_FILE_SAVE: OnFileSave(hWnd, message, wParam, lParam); break; case IDM_TREE_EDIT: OnTreeEdit(hWnd, message, wParam, lParam); break; case IDM_TREE_INSERTCHILD: m_Tree1.InsertChild(); break; case IDM_TREE_INSERTSIBLING: m_Tree1.InsertSibling(); break; case IDM_ABOUT: MessageBox(hWnd, "Test", "Test",MB_OK); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } int OnCreate(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { m_hWndEdit = CreateWindow(_T("edit"), NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE | WS_VSCROLL, 0, 0, 0, 0, hWnd, (HMENU)IDC_EDIT, hInst, NULL); SetTimer(hWnd, 1, 10000, NULL); //10s m_Tree1.CreateTreeView(hWnd); m_Tree1.InitTreetView(); return 1; } //留一个状态条的位置 int OnSize(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int cxClient, cyClient; cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); MoveWindow(m_hToolsbar, 0, 0, cyClient, 25, TRUE); MoveWindow(m_hStatusbar, 0, 0, 0, 0, TRUE); MoveWindow(m_hWndEdit, 0, cyClient - 220, cxClient, 200, TRUE); MoveWindow(m_Tree1.m_hWnd, 0, 25, 220, cyClient - 200 - 50, TRUE); return DefWindowProc(hWnd, message, wParam, lParam); } int OnPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; RECT rt; hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); //DrawText(hdc, StatusText, strlen(StatusText), &rt, DT_LEFT|DT_BOTTOM|DT_SINGLELINE); EndPaint(hWnd, &ps); return 1; } int OnTimer(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return 1; } int OnFileNew(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PRINT("\r\nOnFileNew"); return 1; } int OnFileOpen(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return 1; } int OnFileSave(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return 1; } int OnTreeEdit(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PRINT("\r\nOnTreeEdit"); m_Tree1.ItemLabelEdit(); return 1; } int OnLButtonDown(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return 1; } int OnLButtonUp(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { m_Tree1.OnLButtonUp(hWnd, message, wParam, lParam); return 1; } int OnMouseMove(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { m_Tree1.OnMouseMove(hWnd, message, wParam, lParam); return 1; } int OnNotify(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int idCtrl = (int)wParam; //控件的 ID LPNMHDR lphr = (LPNMHDR)lParam; //先看是哪个控件,再决定结构 //m_hWndTree = GetDlgItem(hWnd, IDM_VIEW_TREEVIEW1); if (lphr->hwndFrom == m_Tree1.m_hWnd) { NM_TREEVIEW* pTree = (NM_TREEVIEW*)lParam; //是树控件,所以用树控件通知结构 switch (pTree->hdr.code) { case NM_CLICK: m_Tree1.OnLClkTree(lphr); break; case NM_RCLICK: m_Tree1.OnRClkTree(lphr); break; case NM_DBLCLK: m_Tree1.OnDBLClkTree(lphr); break; case TVN_BEGINDRAG: return m_Tree1.OnTvnBegindrag(lphr); case TVN_BEGINLABELEDIT: return m_Tree1.OnTvnBeginlabeledit(lphr); //是否允许编辑,是通知的返回值 case TVN_ENDLABELEDIT: return m_Tree1.OnTvnEndlabeledit(lphr); break; default: //PRINT("\r\nm_hWndTree=%d %d", m_hWndTree, pTree->hdr.code); break; } } return 0; //返回消息是给控件处理 }