1

CListCtrl除非双击,否则似乎不会发送鼠标向上事件。

我已尝试从鼠标按下处理程序发送丢失的消息以进行补偿,但这会导致其他不良行为。然后我想我可以通过检查状态来更准确地在鼠标移动处理程序中发送消息。然而,这些都是可怕的 hack,除了丑陋之外,它们可能无法在派生控件的每个可能实现中正常工作。

如果有人知道为什么没有收到鼠标事件,我会很好奇。更重要的是,我如何CListCtrl使用该LVS_OWNERDATA样式像其他控件一样发送鼠标向上消息?

编辑:我知道LVN_BEGINDRAG,LVN_BEGINRDRAG等 但是为了使用这些我需要防止WM_LBUTTONDOWN,WM_RBUTTONDOWNWM_MOUSEMOVE进入父窗口或DragDropManager连接到CWinAppEx/CMDIFrameWndEx所以我可以为这个控件制作一个特殊的一次性案例与现有系统。

这是因为我有一个中央拖放管理器,它可以通知各种类型的控件何时开始拖动操作、何时结束、取消、更改动画、在自定义消息中传递源和目标的显示对象等。它需要足够灵活,可以根据控件、输入、选择或目标项目的类型、包括 3D 在内的不同控件类型,甚至不同的应用程序等来具有不同的启动方式和不同的操作。

4

4 回答 4

2

作为参考,这是我所拥有的,但这是一个可耻的黑客攻击。如果没有人能想出比这更好的东西,那真是太可悲了。

标题:

#pragma once

// CListCtrlEx
class CListCtrlEx : public CListCtrl
{
    DECLARE_DYNAMIC(CListCtrlEx)

public:
    CListCtrlEx();
    virtual ~CListCtrlEx();

    bool IsSelected(int index);
    BOOL SelectDropTarget(int item);

protected:
    DECLARE_MESSAGE_MAP()

    afx_msg void OnStateChanged(NMHDR* pNMHDR, LRESULT* pResult);

    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);

private:
    bool m_lbDown;
    bool m_rbDown;
};

执行:

#include "stdafx.h"
#include "ListCtrlEx.h"

// CListCtrlEx
IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl)

CListCtrlEx::CListCtrlEx() : m_lbDown(false), m_rbDown(false)
{
}

CListCtrlEx::~CListCtrlEx()
{
}

BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
    ON_WM_LBUTTONDOWN()
    ON_WM_RBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_RBUTTONUP()
    ON_WM_MOUSEMOVE()

    ON_NOTIFY_REFLECT(LVN_ODSTATECHANGED, &CListCtrlEx::OnStateChanged)
END_MESSAGE_MAP()

// CListCtrlEx message handlers
void CListCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
{
    m_lbDown = true;
    CListCtrl::OnLButtonDown(nFlags, point);
}

void CListCtrlEx::OnRButtonDown(UINT nFlags, CPoint point)
{
    m_rbDown = true;
    CListCtrl::OnRButtonDown(nFlags, point);
}

void CListCtrlEx::OnLButtonUp(UINT nFlags, CPoint point)
{
    m_lbDown = false;
    CListCtrl::OnLButtonUp(nFlags, point);
}

void CListCtrlEx::OnRButtonUp(UINT nFlags, CPoint point)
{
    m_rbDown = false;
    CListCtrl::OnRButtonUp(nFlags, point);
}

void CListCtrlEx::OnMouseMove(UINT nFlags, CPoint point)
{
    if (m_lbDown && ((nFlags & MK_LBUTTON) == 0))
    {
        PostMessage(WM_LBUTTONUP,
            MAKEWPARAM(LOWORD(nFlags), HIWORD(nFlags)),
            MAKELPARAM(point.x, point.y));
    }

    if (m_rbDown && ((nFlags & MK_RBUTTON) == 0))
    {
        PostMessage(WM_RBUTTONUP,
            MAKEWPARAM(LOWORD(nFlags), HIWORD(nFlags)),
            MAKELPARAM(point.x, point.y));
    }

    CListCtrl::OnMouseMove(nFlags, point);
}

bool CListCtrlEx::IsSelected(int index)
{
    return (GetItemState(index, LVIS_SELECTED) & LVIS_SELECTED) != 0;
}

// highlight drop targets sort of like CTreeCtrl
BOOL CListCtrlEx::SelectDropTarget(int item)
{
    static int prevHighlight(-1);
    if (item >= 0 && item < GetItemCount())
    {
        if (item != prevHighlight)
        {
            if (prevHighlight >= 0)
            {
                SetItemState(prevHighlight, 0, LVIS_DROPHILITED); // remove highlight from previous target
                RedrawItems(prevHighlight, prevHighlight);
            }

            prevHighlight = item;
            SetItemState(item, LVIS_DROPHILITED, LVIS_DROPHILITED); // highlight target
            RedrawItems(item, item);

            UpdateWindow();
            return TRUE;
        }
    }
    else
    {
        for (int i(0); i < GetItemCount(); ++i)
            SetItemState(i, 0, LVIS_DROPHILITED); // un-highlight all
        prevHighlight = -1;
    }

    return FALSE;
}

void CListCtrlEx::OnStateChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
// MSDN:
// If a list-view control has the LVS_OWNERDATA style,
// and the user selects a range of items by holding down the SHIFT key and clicking the mouse,
// LVN_ITEMCHANGED notification codes are not sent for each selected or deselected item.
// Instead, you will receive a single LVN_ODSTATECHANGED notification code,
// indicating that a range of items has changed state.

    NMLVODSTATECHANGE* pStateChanged = (NMLVODSTATECHANGE*)pNMHDR;

    // redraw newly selected items
    if (pStateChanged->uNewState == LVIS_SELECTED)
        RedrawItems(pStateChanged->iFrom, pStateChanged->iTo);
}
于 2011-10-25T15:25:32.923 回答
0

你不需要那些事件。该控件为您提供所需的一切。

从您的代码中,我了解到您想要在列表控件中实现拖放项目。不要将无论如何都不起作用的东西和 badmouth MS 拼凑在一起,而是以正确的方式去做:

处理LVN_BEGINDRAG通知以开始拖动操作。

于 2011-10-14T15:55:15.600 回答
-1

Stefan的回答可能会为您提供最好的服务....

但是,您可以挂钩 CListCtrl 的 winproc(见鬼,在 MFC 中,您可以只继承 CListCtrl,提供您自己的虚拟 WindowProc() 并转发/拦截您想要的任何鼠标消息。

只需在运行时使用标准 MFC 子类控制机制,即可在您希望的任何对话框或窗口上“替换”您的类来替换标准 CListCtrl。

我想你知道怎么做吗?

于 2011-10-25T15:28:34.610 回答
-1

你可以使用 LVS_OWNERDRAWFIXED 风格,它让所有的鼠标事件都来找你

于 2021-09-28T15:37:00.413 回答