如何同步ListView的checkbox和selection?(WIN32)
How to sync ListView checkbox with selection?(WIN32)
我正在编写一个简单的 Win32 程序,它有一个带有复选框和启用多行选择的 ListView。 :
复选框检查和行选择似乎是两种截然不同的行为。有没有一种方法可以同步这两种行为,只要选中一个复选框,就会选中该行,而只要选中一行,就会选中相应的复选框?
"whenever a row is selected, the corresponding checkbox will be checked"
选中 WM_NOTIFY
and LVIS_SELECTED
flag to detect when user selects a row. And use ListView_SetCheckState
以选中复选框:
BOOL CALLBACK DialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hListView;
switch (msg)
{
case WM_INITDIALOG:
hListView = GetDlgItem(hWnd, IDC_LIST1);
break;
case WM_NOTIFY:
{
NMHDR* header = (NMHDR*)lParam;
NMLISTVIEW* nmlist = (NMLISTVIEW*)lParam;
if (header && header->idFrom == IDC_LIST1 && header->code == LVN_ITEMCHANGED)
if (nmlist->uNewState & LVIS_SELECTED)
ListView_SetCheckState(hListView, nmlist->iItem, 1);
break;
}
...
}
"whenever a check box is checked that row will be selected"
检查 WM_NOTIFY
和 LVIS_STATEIMAGEMASK
标志以检测复选框何时被选中,然后使用 ListView_SetItemState
到 select 该行。
这也可能导致递归调用,因为我们更改行以响应复选框,我们更改复选框以响应行 selection。使用 busy
变量停止递归调用。
case WM_NOTIFY:
if (lParam)
{
NMHDR* header = (NMHDR*)lParam;
NMLISTVIEW* nmlist = (NMLISTVIEW*)lParam;
//use `busy` as a flag to prevent recursive calls:
static BOOL busy = FALSE;
if (!busy && header->hwndFrom == hListView && header->code == LVN_ITEMCHANGED)
{
busy = TRUE;
if (nmlist->uNewState & LVIS_SELECTED)
{
//row has been selected => check the checkbox
ListView_SetCheckState(hListView, nmlist->iItem, 1);
}
else if (nmlist->uNewState & LVIS_STATEIMAGEMASK)
{
//checkbox has been changed => select/unselect the row
BOOL checked = ListView_GetCheckState(hListView, nmlist->iItem);
ListView_SetItemState(hListView, nmlist->iItem,
checked ? LVIS_SELECTED : 0, LVIS_SELECTED);
}
busy = FALSE;
}
}
break;
我正在编写一个简单的 Win32 程序,它有一个带有复选框和启用多行选择的 ListView。 :
复选框检查和行选择似乎是两种截然不同的行为。有没有一种方法可以同步这两种行为,只要选中一个复选框,就会选中该行,而只要选中一行,就会选中相应的复选框?
"whenever a row is selected, the corresponding checkbox will be checked"
选中 WM_NOTIFY
and LVIS_SELECTED
flag to detect when user selects a row. And use ListView_SetCheckState
以选中复选框:
BOOL CALLBACK DialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hListView;
switch (msg)
{
case WM_INITDIALOG:
hListView = GetDlgItem(hWnd, IDC_LIST1);
break;
case WM_NOTIFY:
{
NMHDR* header = (NMHDR*)lParam;
NMLISTVIEW* nmlist = (NMLISTVIEW*)lParam;
if (header && header->idFrom == IDC_LIST1 && header->code == LVN_ITEMCHANGED)
if (nmlist->uNewState & LVIS_SELECTED)
ListView_SetCheckState(hListView, nmlist->iItem, 1);
break;
}
...
}
"whenever a check box is checked that row will be selected"
检查 WM_NOTIFY
和 LVIS_STATEIMAGEMASK
标志以检测复选框何时被选中,然后使用 ListView_SetItemState
到 select 该行。
这也可能导致递归调用,因为我们更改行以响应复选框,我们更改复选框以响应行 selection。使用 busy
变量停止递归调用。
case WM_NOTIFY:
if (lParam)
{
NMHDR* header = (NMHDR*)lParam;
NMLISTVIEW* nmlist = (NMLISTVIEW*)lParam;
//use `busy` as a flag to prevent recursive calls:
static BOOL busy = FALSE;
if (!busy && header->hwndFrom == hListView && header->code == LVN_ITEMCHANGED)
{
busy = TRUE;
if (nmlist->uNewState & LVIS_SELECTED)
{
//row has been selected => check the checkbox
ListView_SetCheckState(hListView, nmlist->iItem, 1);
}
else if (nmlist->uNewState & LVIS_STATEIMAGEMASK)
{
//checkbox has been changed => select/unselect the row
BOOL checked = ListView_GetCheckState(hListView, nmlist->iItem);
ListView_SetItemState(hListView, nmlist->iItem,
checked ? LVIS_SELECTED : 0, LVIS_SELECTED);
}
busy = FALSE;
}
}
break;