我试图在用户在点击列表视图后释放鼠标左键时捕获该事件。
在下面的代码中,我需要双击才能发出哔哔声。一旦用户释放鼠标左键,所需的行为就是发出蜂鸣声。
代码说的比单词更好,所以这是说明问题的最小例子:
#include <windows.h>
#include <windowsx.h> // various listview macros etc
#include <CommCtrl.h>
#include <stdio.h> // swprintf_s()
// enable Visual Styles
#pragma comment( linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"")
// link with Common Controls library
#pragma comment( lib, "comctl32.lib")
//global variables
HINSTANCE hInst;
// subclass procedure for listview -> implements drag and drop
LRESULT CALLBACK Example(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (message)
{
case WM_LBUTTONUP:
{
MessageBeep(0); // so I know it is received
}
return DefSubclassProc(hwnd, message, wParam, lParam);
case WM_NCDESTROY:
::RemoveWindowSubclass(hwnd, Example, 0);
return DefSubclassProc(hwnd, message, wParam, lParam);
}
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
// main window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
//================ create an example listview
RECT rec = { 0 };
GetClientRect(hwnd, &rec);
HWND hwndLV = CreateWindowEx(0, WC_LISTVIEW,
L"", WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT | WS_CLIPCHILDREN,
50, 50, 250, 200, hwnd, (HMENU)2000, hInst, 0);
// set extended listview styles
ListView_SetExtendedListViewStyle(hwndLV, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
// add some columns
LVCOLUMN lvc = { 0 };
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
for (long nIndex = 0; nIndex < 5; nIndex++)
{
wchar_t txt[50];
swprintf_s(txt, 50, L"Column %d", nIndex);
lvc.iSubItem = nIndex;
lvc.cx = 60;
lvc.pszText = txt;
ListView_InsertColumn(hwndLV, nIndex, &lvc);
}
// add some items
LVITEM lvi;
lvi.mask = LVIF_TEXT;
for (lvi.iItem = 0; lvi.iItem < 10000; lvi.iItem++)
{
for (long nIndex = 0; nIndex < 5; nIndex++)
{
wchar_t txt[50];
swprintf_s(txt, 50, L"Item %d%d", lvi.iItem, nIndex);
lvi.iSubItem = nIndex;
lvi.pszText = txt;
if (!nIndex) // item
SendDlgItemMessage(hwnd, 2000, LVM_INSERTITEM, 0, reinterpret_cast<LPARAM>(&lvi));
else // sub-item
SendDlgItemMessage(hwnd, 2000, LVM_SETITEM, 0, reinterpret_cast<LPARAM>(&lvi));
}
}
//============================ subclass it
SetWindowSubclass(hwndLV, Example, 0, 0);
}
return 0L;
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)
{
// store hInstance in global variable for later use
hInst = hInstance;
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 = hInst;
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))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!", MB_ICONEXCLAMATION |
MB_OK);
return 0;
}
// initialize common controls
INITCOMMONCONTROLSEX iccex;
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&iccex);
// create main window
hwnd = CreateWindowEx(0, L"Main_Window", L"Listview Drag and Drop",
WS_OVERLAPPEDWINDOW,
50, 50, 400, 400, NULL, NULL, hInstance, 0);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
单击listview中的行后,不会发出蜂鸣声。我做错了什么?
答案 0 :(得分:3)
根据这个讨论:
ListView control eats mouse messages:
...我正在对ListView进行子类化以监视WM_LBUTTONDOWN和 WM_LBUTTONUP ...我的问题:我看到了WM_LBUTTONDOWN,但从未看过WM_LBUTTONUP。 Spy ++告诉我这两条消息都会转向控件。我很困惑控件如何'吃掉'WM_LBUTTONUP。
...
问题是列表控件本身是用一些设计的 相当复杂的点击处理。当列表控件的默认值 windowproc收到WM_LBUTTONDOWN或WM_RBUTTONDOWN消息,它进入 一个自己的模态消息循环,持续到相应的 收到WM_LBUTTONUP或WM_RBUTTONUP消息。所以是的,基本上,这个 模态消息循环吃WM_LBUTTONUP / WM_RBUTTONUP消息;你的窗口 代码永远不会有机会。
解决方案:如果您需要处理按钮消息, 那么你还需要处理按钮消息,你的按钮 - down消息处理程序应该不调用基本窗口proc。实质上, 你自己的代码需要接管所有的点击处理逻辑;所以你的 处理程序将要使用检查Shift和Control键的状态 GetKeyState,并相应地选择和取消选择列表项。 (处理 Shift-clicks正确,您可以使用ListView_GetSelectionMark和 ListView_SetSelectionMark获取并设置多个“锚点” 选择。)
MSDN文档实际上提到了这一点:
Default List-View Message Processing:
WM_LBUTTONDOWN
根据是否启动了单击或拖动操作,以不同方式处理。 要确定涉及哪个操作,列表视图控件将进入模态消息循环,直到释放按钮或移动鼠标。如果单击,列表视图控件可能会更改考虑到光标位置,SHIFT和CTRL键的状态等,哪个项目具有焦点以及选择了哪些项目。然后列表视图控件向其父窗口发送NM_CLICK(列表视图)通知代码。
如果在项目上开始拖动,则列表视图控件会选择焦点并将焦点设置为项目。然后它将LVN_BEGINDRAG通知代码发送到父窗口。父窗口负责实际执行拖动操作。
如果在窗口背景上开始拖动,则列表视图控件会进入另一个模态消息循环,使用户可以通过拖动鼠标来形成矩形。选择矩形内的项目。
...
WM_RBUTTONDOWN
处理方式与WM_LBUTTONDOWN消息相同,但控件发送NM_RCLICK(列表视图)通知代码(而不是NM_CLICK(列表视图))和LVN_BEGINRDRAG通知代码(而不是LVN_BEGINDRAG) )。 请注意,该控件处理相应的WM_RBUTTONUP消息,并且不会对其进行分派。因此,即使通过继承控件,应用程序也无法看到此消息。