热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

我的子类过程中未收到WM_LBUTTONUP-WM_LBUTTONUPisnotreceivedinmysubclassprocedure

Iamtryingtocatchtheeventwhenuserreleasesleftmousebuttonafterclickingonlistview.当用户在

I am trying to catch the event when user releases left mouse button after clicking on listview.

当用户在单击listview后释放鼠标左键时,我试图捕获事件。

In the code below, I need to double click in order to get beep. The desired behavior is to get the beep as soon as the user releases left mouse button.

在下面的代码中,我需要双击才能发出哔哔声。一旦用户释放鼠标左键,所需的行为就是发出蜂鸣声。

Code speaks better than the words, so here is the smallest example that illustrates the problem:

代码说的比单词更好,所以这里是说明问题的最小例子:

#include 
#include    // various listview macros etc
#include 
#include       // 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(&lvi));
                else            // sub-item
                    SendDlgItemMessage(hwnd, 2000, LVM_SETITEM, 0, reinterpret_cast(&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;
}

After clicking on a row in listview, no beep occurs. What am I doing wrong?

单击listview中的行后,不会发出蜂鸣声。我究竟做错了什么?

1 个解决方案

#1


Per this discussion:

根据这个讨论:

ListView control eats mouse messages:

ListView控件吃掉鼠标消息:

...I am sub-classing the ListView to watch for WM_LBUTTONDOWN and WM_LBUTTONUP... My problem: I see the WM_LBUTTONDOWN, but never the WM_LBUTTONUP. Spy++ tells me that both messages are going to the control. I am baffled as to how the control 'eats up' the WM_LBUTTONUP.

...我正在对ListView进行子类化以观察WM_LBUTTONDOWN和WM_LBUTTONUP ...我的问题:我看到了WM_LBUTTONDOWN,但从未看过WM_LBUTTONUP。 Spy ++告诉我这两条消息都会转向控件。我很困惑控件如何'吃掉'WM_LBUTTONUP。

...

The problem is that the list control itself is designed with some fairly sophisticated click-handling. When the list control's default windowproc receives a WM_LBUTTONDOWN or WM_RBUTTONDOWN message, it goes into a modal message loop of its own, which lasts until the corresponding WM_LBUTTONUP or WM_RBUTTONUP message is received. So yes, essentially, this modal message loop eats the WM_LBUTTONUP/WM_RBUTTONUP message; your window code never gets a chance at it.

问题是列表控件本身设计有一些相当复杂的点击处理。当列表控件的默认windowproc收到WM_LBUTTONDOWN或WM_RBUTTONDOWN消息时,它将进入自己的模态消息循环,该循环将持续到收到相应的WM_LBUTTONUP或WM_RBUTTONUP消息。所以是的,基本上,这个模态消息循环吃了WM_LBUTTONUP / WM_RBUTTONUP消息;你的窗口代码永远不会有机会。

The solution to this: If you need to handle the button-up messages, then you need to handle the button-down messages as well, and your button- down message handler should not call the base window proc. Essentially, your own code will need to take over all the click-handling logic; so your handler will want to check the state of the Shift and Control keys using GetKeyState, and select and deselect list items accordingly. (To handle Shift-clicks correctly, you can use ListView_GetSelectionMark and ListView_SetSelectionMark to get and set the "anchor" point for multiple selections.)

解决方案:如果你需要处理按钮消息,那么你也需要处理按钮消息,你的按钮消息处理程序不应该调用基本窗口proc。从本质上讲,您自己的代码需要接管所有的点击处理逻辑;因此,您的处理程序将要使用GetKeyState检查Shift和Control键的状态,并相应地选择和取消选择列表项。 (要正确处理Shift-clicks,您可以使用ListView_GetSelectionMark和ListView_SetSelectionMark获取并设置多个选择的“锚点”。)

The MSDN documentation actually mentions this:

MSDN文档实际上提到了这一点:

Default List-View Message Processing:

默认列表 - 查看消息处理:

WM_LBUTTONDOWN

Processed in different ways depending on whether a click or drag operation is being initiated. To determine which operation is involved, the list-view control enters a modal message loop until either the button is released or the mouse is moved. In the case of a click, the list-view control might change which item has the focus and which items are selected, taking into account the cursor position, the state of the SHIFT and CTRL keys, and so on. Then the list-view control sends its parent window an NM_CLICK (list view) notification code.

根据是否启动单击或拖动操作,以不同方式处理。要确定涉及哪个操作,列表视图控件将进入模态消息循环,直到释放按钮或移动鼠标。在单击的情况下,列表视图控件可能会更改哪个项目具有焦点以及选择了哪些项目,同时考虑了光标位置,SHIFT和CTRL键的状态等。然后列表视图控件向其父窗口发送NM_CLICK(列表视图)通知代码。

If dragging begins over an item, the list-view control selects and sets the focus to the item. Then it sends an LVN_BEGINDRAG notification code to the parent window. The parent window is responsible for actually carrying out the drag operation.

如果在项目上开始拖动,则列表视图控件将选择焦点并将焦点设置为项目。然后它将LVN_BEGINDRAG通知代码发送到父窗口。父窗口负责实际执行拖动操作。

If dragging begins over the window background, the list-view control enters another modal message loop, enabling the user to form a rectangle by dragging the mouse. Items within the rectangle are selected.

如果在窗口背景上开始拖动,则列表视图控件进入另一个模态消息循环,使用户能够通过拖动鼠标来形成矩形。选择矩形内的项目。

...

WM_RBUTTONDOWN

Processed the same way as the WM_LBUTTONDOWN message, except that the control sends an NM_RCLICK (list view) notification code (instead of NM_CLICK (list view)) and an LVN_BEGINRDRAG notification code (instead of LVN_BEGINDRAG). Note that the control processes the corresponding WM_RBUTTONUP message, and does not dispatch it. Applications thus cannot see this message, even by subclassing the control.

处理方式与WM_LBUTTONDOWN消息相同,只是控件发送NM_RCLICK(列表视图)通知代码(而不是NM_CLICK(列表视图))和LVN_BEGINRDRAG通知代码(而不是LVN_BEGINDRAG)。请注意,该控件处理相应的WM_RBUTTONUP消息,并且不会对其进行分派。因此,即使通过子类化控件,应用程序也无法看到此消息。


推荐阅读
  • 在尝试加载支持推送通知的iOS应用程序的Ad Hoc构建时,遇到了‘no valid aps-environment entitlement found for application’的错误提示。本文将探讨此错误的原因及多种可能的解决方案。 ... [详细]
  • C/C++ 应用程序的安装与卸载解决方案
    本文介绍了如何使用Inno Setup来创建C/C++应用程序的安装程序,包括自动检测并安装所需的运行库,确保应用能够顺利安装和卸载。 ... [详细]
  • 【MySQL】frm文件解析
    官网说明:http:dev.mysql.comdocinternalsenfrm-file-format.htmlfrm是MySQL表结构定义文件,通常frm文件是不会损坏的,但是如果 ... [详细]
  • 视觉Transformer综述
    本文综述了视觉Transformer在计算机视觉领域的应用,从原始Transformer出发,详细介绍了其在图像分类、目标检测和图像分割等任务中的最新进展。文章不仅涵盖了基础的Transformer架构,还深入探讨了各类增强版Transformer模型的设计思路和技术细节。 ... [详细]
  • 尽管在WPF中工作了一段时间,但在菜单控件的样式设置上遇到了一些基础问题,特别是关于如何正确配置前景色和背景色。 ... [详细]
  • 长期从事ABAP开发工作的专业人士,在面对行业新趋势时,往往需要重新审视自己的发展方向。本文探讨了几位资深专家对ABAP未来走向的看法,以及开发者应如何调整技能以适应新的技术环境。 ... [详细]
  • 本文探讨了如何将个人经历,特别是非传统的职业路径,转化为职业生涯中的优势。通过作者的亲身经历,展示了舞蹈生涯对商业思维的影响。 ... [详细]
  • HTML前端开发:UINavigationController与页面间数据传递详解
    本文详细介绍了如何在HTML前端开发中利用UINavigationController进行页面管理和数据传递,适合初学者和有一定基础的开发者学习。 ... [详细]
  • Android开发:巧妙运用ViewStub写出类似Tab选项卡
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • Excel技巧:单元格中显示公式而非结果的解决方法
    本文探讨了在Excel中如何通过简单的方法解决单元格显示公式而非计算结果的问题,包括使用快捷键和调整单元格格式两种方法。 ... [详细]
  • Gradle 是 Android Studio 中默认的构建工具,了解其基本配置对于开发效率的提升至关重要。本文将详细介绍如何在 Gradle 中定义和使用共享变量,以确保项目的一致性和可维护性。 ... [详细]
  • 本文分享了作者在使用LaTeX过程中的几点心得,涵盖了从文档编辑、代码高亮、图形绘制到3D模型展示等多个方面的内容。适合希望深入了解LaTeX高级功能的用户。 ... [详细]
  • 本文详细介绍了如何利用 Bootstrap Table 实现数据展示与操作,包括数据加载、表格配置及前后端交互等关键步骤。 ... [详细]
  • 本文通过具体示例探讨了如何在iOS应用中有效使用scrollView,并解决了常见的无法滚动问题。不仅介绍了基础的使用方法,还详细讲解了代码实现的具体步骤。 ... [详细]
  • 本文介绍了蓝牙低功耗(BLE)中的通用属性配置文件(GATT),包括其角色、层次结构、属性、特性和服务等内容。 ... [详细]
author-avatar
无心睡眠tuo_295
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有