如何使用TVS_checkboxes样式删除特定树状视图项目上的复选框
How to remove checkboxes on specific tree view items with the TVS_CHECKBOXES style
我找不到在TreeView控件中禁用特定项目的复选框的方法(实际上我只需要在特定项目上启用复选框)。
我读过这个,这个和这个答案,都没有用。
当创建树视图项目(不需要复选框)时,我尝试将标志设置为:
tvinsert.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; // attributes
tvinsert.item.stateMask = TVIS_STATEIMAGEMASK;
tvinsert.item.state = INDEXTOSTATEIMAGEMASK(0);
本应隐藏项目的复选框,但MSDN文档中显示
版本5.80。即使没有图像与关联,也会显示复选框项目。
我正在使用创建树状视图窗口控件
g_WindowHandleTreeView = CreateWindow(
WC_TREEVIEW,
"", //caption not required
TVS_TRACKSELECT | WM_NOTIFY | WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | WS_VISIBLE/* | TVS_CHECKBOXES*/,
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
550,
g_WindowHandlePannelStructure,
NULL,
(HINSTANCE)GetWindowLong(g_WindowHandlePannelStructure, GWL_HINSTANCE),
NULL);
DWORD dwStyle = GetWindowLong(g_WindowHandleTreeView, GWL_STYLE);
dwStyle |= TVS_CHECKBOXES;
SetWindowLongPtr(g_WindowHandleTreeView, GWL_STYLE, dwStyle);
然后使用创建树视图项目
// Clear the treeview
TreeView_DeleteAllItems(hwnd);
// Tree items
std::vector<HTREEITEM> root_sub;
std::vector<HTREEITEM> mesh_items;
std::vector<HTREEITEM> mesh_items_sub;
TV_INSERTSTRUCT tvinsert = { 0 }; // struct to config the tree control
tvinsert.hParent = TVI_ROOT; // top most level Item
tvinsert.hInsertAfter = TVI_LAST; // root level item attribute.
tvinsert.item.mask = TVIF_TEXT | TVIF_PARAM; // attributes
tvinsert.item.stateMask = TVIS_STATEIMAGEMASK;
tvinsert.item.state = INDEXTOSTATEIMAGEMASK(0);
// ^^^ here trying to disable the checkbox but only prior to Version 5.80. ?
// Create root item
std::string rootTxt = "Model";
tvinsert.item.pszText = (LPSTR)rootTxt.c_str();
tvinsert.item.lParam = ID_MESH_ALL;
HTREEITEM Root = (HTREEITEM)SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&tvinsert);
// Create path item
std::string pathTxt = std::string("Path : ") + pModel->objPath;
tvinsert.hParent = Root;
tvinsert.item.pszText = (LPSTR)pathTxt.c_str();
tvinsert.item.lParam = 0;
root_sub.push_back((HTREEITEM)SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&tvinsert));
// More items....................
// Now attempting to change flags to ENABLE+CHECK the checkbox (which are always enabled anyways...)
tvinsert.item.state = INDEXTOSTATEIMAGEMASK(2);
// Create mesh header
std::string meshTxt = std::string("Mesh #") + std::to_string(mesh_items.size() + 1) + std::string(" - ") + std::to_string(mesh.v.size()) + std::string(" vertices");
tvinsert.hInsertAfter = mesh_root;
tvinsert.hParent = mesh_root;
tvinsert.item.pszText = (LPSTR)meshTxt.c_str();
tvinsert.item.lParam = ID_MESH_0 + mesh_items.size();
mesh_items.push_back((HTREEITEM)SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&tvinsert));
// Disable flags
tvinsert.item.state = INDEXTOSTATEIMAGEMASK(0);
// ...
那么反过来呢?除了给TreeView控件一个不同的windows进程之外,我不明白将其子类化意味着什么。
预期的行为是只在选择树视图项目的旁边显示一个复选框。我目前有一个所有项目的复选框。
感谢您的真知灼见。
以下是如何创建一个带有复选框的树视图控件,并删除选择节点上的复选框。
首先创建一个不带TVS_CHECKBOXES
复选框样式的窗口控件。例如:
g_WindowHandleTreeView = CreateWindow(
WC_TREEVIEW,
"",
TVS_TRACKSELECT | WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | WS_VISIBLE | TVS_HASBUTTONS,
CW_USEDEFAULT,
CW_USEDEFAULT,
300,
550,
g_WindowHandlePannelStructure, // is the parent window control
NULL,
(HINSTANCE)GetWindowLong(g_WindowHandlePannelStructure, GWL_HINSTANCE),
NULL);
然后添加复选框样式:
DWORD dwStyle = GetWindowLong(g_WindowHandleTreeView, GWL_STYLE);
dwStyle |= TVS_CHECKBOXES;
SetWindowLongPtr(g_WindowHandleTreeView, GWL_STYLE, dwStyle);
现在用插入结构为树视图准备一个项目,例如:
TV_INSERTSTRUCT tvinsert = { 0 }; // struct to config the tree control
tvinsert.hParent = TVI_ROOT; // root item
tvinsert.hInsertAfter = TVI_LAST; // last current position
tvinsert.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE; // attributes
tvinsert.item.stateMask = TVIS_STATEIMAGEMASK;
tvinsert.item.state = 0;
tvinsert.item.pszText = (LPSTR)"Root node";
tvinsert.item.lParam = SOME_ID; // ID for the node
并插入带有SendMessage(...)
调用的节点:
HTREEITEM Root = (HTREEITEM)SendMessage(hwnd, TVM_INSERTITEM, 0, (LPARAM)&tvinsert);
节点此时将显示一个复选框(即使item.state
设置为0),因此只需将其删除即可:
TVITEM tvi;
tvi.hItem = Root; // The item to be "set"/modified
tvi.mask = TVIF_STATE;
tvi.stateMask = TVIS_STATEIMAGEMASK;
tvi.state = 0; // setting state to 0 again
TreeView_SetItem(hwnd, &tvi);
就是这样。
这里有一个小演示,展示了如何实现NM_TVSTATEIMAGECHANGING
:
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#pragma comment( linker, "/manifestdependency:"type='win32'
name='Microsoft.Windows.Common-Controls' version='6.0.0.0'
processorArchitecture='*' publicKeyToken='6595b64144ccf1df'
language='*'"")
#pragma comment( lib, "comctl32.lib")
// control IDs
#define IDC_TREEVIEW 2000
// init treeview
BOOL InitTreeView(HWND hwndTV)
{
// enable checkboxes, the way it was recommended in MSDN documentation
DWORD dwStyle = GetWindowLong(hwndTV, GWL_STYLE);
dwStyle |= TVS_CHECKBOXES;
SetWindowLongPtr(hwndTV, GWL_STYLE, dwStyle);
TVINSERTSTRUCT tvis = { 0 };
tvis.item.mask = TVIF_TEXT | TVIF_STATE;
tvis.hInsertAfter = TVI_FIRST;
tvis.hParent = NULL;
tvis.item.pszText = L"Root item";
HTREEITEM hti = (HTREEITEM)TreeView_InsertItem(hwndTV, &tvis);
if (NULL == hti)
return FALSE;
tvis.hParent = hti;
tvis.item.pszText = L"Second child node";
tvis.item.stateMask = TVIS_STATEIMAGEMASK;
tvis.item.state = 0 << 12;
HTREEITEM htiChild = TreeView_InsertItem(hwndTV, &tvis);
if (NULL == htiChild)
return FALSE;
tvis.item.pszText = L"First child node";
tvis.item.stateMask = TVIS_STATEIMAGEMASK;
tvis.item.state = 0 << 12;
htiChild = TreeView_InsertItem(hwndTV, &tvis);
if (NULL == htiChild)
return FALSE;
// remove checkbox
TreeView_SetItemState(hwndTV, htiChild, 0, TVIS_STATEIMAGEMASK);
// expand the root node
TreeView_Expand(hwndTV, hti, TVE_EXPAND);
// if we came all the way here then all is fine, report success
return TRUE;
}
// main window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
//================ create controls
RECT rec = { 0 };
GetClientRect(hwnd, &rec);
HWND hwndTV = CreateWindowEx(0, WC_TREEVIEW, L"TreeView",
WS_CHILD | WS_VISIBLE | WS_BORDER |
TVS_FULLROWSELECT | TVS_HASBUTTONS |
TVS_HASLINES | TVS_LINESATROOT |
TVS_DISABLEDRAGDROP,
10, 10, 200, 200,
hwnd, (HMENU)IDC_TREEVIEW,
((LPCREATESTRUCT)lParam)->hInstance, NULL);
// initialize treeview
if (!InitTreeView(hwndTV))
return -1;
}
return 0L;
case WM_NOTIFY:
{
switch (((LPNMHDR)lParam)->code)
{
case NM_TVSTATEIMAGECHANGING:
{
// if item did not have checkbox, prevent state image change
// NOTE: this approach does not work if you programatically change item's state !!!
return (((LPNMTVSTATEIMAGECHANGING)lParam)->iOldStateImageIndex == 0);
}
break;
default:
break;
}
}
break;
case WM_CLOSE:
::DestroyWindow(hwnd);
return 0L;
case WM_DESTROY:
{
::PostQuitMessage(0);
}
return 0L;
default:
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
// WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
// register main window class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"Main_Window";
wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
// simple error indication
MessageBeep(0);
return 0;
}
// initialize common controls
INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_TREEVIEW_CLASSES | ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES;
InitCommonControlsEx(&iccex);
// create main window
hwnd = CreateWindowEx(0, L"Main_Window", L"Demonstration App",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, 0);
if (NULL == hwnd)
{
// simple error indication
MessageBeep(0);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
它在Windows7上对我有效,你所要做的就是将这些代码复制/粘贴到.cpp
文件中,并在Windows10上运行。
根据评论,NM_TVSTATEIMAGECHANGING没有捕捉到程序更改(请参阅最底部的评论)。
如果您考虑以编程方式更改状态(例如单击按钮或其他…),那么使用TVN_ITEMCHANGING
可能会更好,如评论中所建议的那样。
相关文章:
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 如何维护资源管理器项目视图中当前可见的项目列表
- Visual Studio 2015资源视图和资源编译器使用不同的方法在项目目录中查找图标文件.如何修复
- 如何确定网格视图中单击的项目
- 过滤期间,在树视图中扩展特定项目
- LVM_GETNEXTITEM在列表视图中找不到项目
- 如何:在C++的导航视图中选择项目
- 资源管理器在 TILE 视图模式下不显示 shell 命名空间扩展的项目详细信息
- 自定义图形列表视图项目不更改文本颜色
- Qt:模型/视图-定义项目持有日期的格式
- 如何在列表视图中显示每个项目的所有QComboBoxes
- 如何在Qt小工具项目中更新图形视图(Qt Creator)
- 在GUI中创建非常大的树状视图(超过1M个项目)
- 在不同的视图中上下移动QListWidget中的项目
- QListView:当从顶部删除项目时,如何自动滚动视图并保持视图中正确项目的当前选择
- 如何使用TVS_checkboxes样式删除特定树状视图项目上的复选框
- 列表视图-资源管理器如何在小图标视图中获得相同大小的所有项目
- c++ Win32 -跟踪列表视图项目的私人聊天
- 滚动QListView以在列表开始插入时保持项目在视图中
- 哪个函数可以用来在Qt的树视图中选择一个项目