2011-10-12 75 views
1

似乎CListCtrl不发送鼠标事件,除非有双击。MFC CListCtrl吃鼠标事件?

我试图从鼠标向下处理程序发送丢失的消息来弥补,但这会导致其他不良行为。然后,我想我可以通过检查状态来发送鼠标移动处理程序中的消息以更准确一些。然而,这些都是可怕的黑客攻击,除了丑陋之外,它们可能无法正确执行派生控制的每个可能的实现。

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

编辑:我知道LVN_BEGINDRAGLVN_BEGINRDRAG等但为了使用这些,我需要防止WM_LBUTTONDOWNWM_RBUTTONDOWNWM_MOUSEMOVE从去勾搭成CWinAppEx/CMDIFrameWndEx父窗口或DragDropManager,所以我可以做这个控制与现有系统一起工作的特殊情况。

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

+0

-1如果您有与社区共享的代码与您的问题直接相关,则需要在问题的主体中发生 - 并非答案。这显然不是一个有效的答案,或者候选人是一个答案。它让你更难理解你的问题,因为通常不会为问题的额外部分搜索答案。 – Mordachai

+0

我把它作为答案,因为没有人有任何适用的答案,更好,显然这是我将与之合作的解决方案。 – AJG85

回答

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); 
} 
+0

好的,你是CListCtrl的子类 - 那是什么问题呢? – Mordachai

+0

由于默认情况下不会发送虚假鼠标消息。 – AJG85

0

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

从你的代码中我收集到你想要在列表控件中实现drag'n'drop。 而不是黑客一起反正无法正常工作和恶臭MS,反而做正确的方式:

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

+0

这个想法是为源和目标设置一个中央拖放管理器和接口,以便它可以使用SM_CXDRAG和SM_CYDRAG的系统指标在3D视图,树,编辑,列表等中工作,而无需重复编写相同的逻辑。 CListCtrl是唯一存在问题的地方。树的 – AJG85

+0

控制其TVN_BEGINDRAG而不是LVN_BEGINDRAG。其他控件提供类似的通知。 – Stefan

+0

我想我可以制作一些自定义消息,并让控件在他们想要拖动的时候通知管理员,而不是通知管理员通知控件。我认为问题仍然存在,即开始拖拽需要在一个控件上,而拖拽可能在另一个控件上。 – AJG85

-1

您可以通过Stefan的回答可以提供最好的服务....

但是,你可以挂钩的CListCtrl的Winproc传(地狱,在MFC你可以继承CListCtrl的子类,提供你自己的虚拟WindowProc()并转发/拦截你想要的任何鼠标消息。

只需在运行时使用标准MFC子类控件机制,就可以在任何对话框或窗口中将您的类替换为标准CListCtrl。

我假设你知道该怎么做?

+0

你似乎错过了整个问题,就是鼠标上来的消息不是默认发送或接收的行为。 Stefan的答案只适用于'CTreeCtrl'和'CListCtrl'我需要自定义控件,3d视图,其他应用程序等。 – AJG85

+0

您似乎无法理解Win32的工作原理。 “CTreeCtrl”不发送WM_LBUTTONUP消息 - 它从操作系统接收它们。所以如果你直接从操作系统截获这条消息,那么你不会错过它。它不能被隐藏。只有当你依赖消息链中的某些点时,它才能隐藏起来。 您的回复和-1对于过去13年来一直在编写MFC应用程序的人来说非常烦人。 – Mordachai

0

请您通过以下链接,让我们知道它是否工作。

http://support.microsoft.com/kb/147842

你可以从那里得到一个想法。

+0

在鼠标上不起作用的'NM_CLICK' /'NM_RCLICK'不会启动鼠标。这对于命中测试是有利的,并且可以检查或修改选择,因为它不是鼠标事件的通知,但它与其他方面无关。之前我在Google上搜索过类似的文章,并试图无效。 – AJG85

+0

问题是您无法收到鼠标事件。让我试试这个。 –

+0

是的,我做了一个单独的测试应用程序,只是有一个'CListCtrl'对话框,并发现相同的行为。这就是我现在使用的合成鼠标信息的方法。 – AJG85