在 QTreeWidget 中的树小部件项目上捕获鼠标事件

Catch mouse event on tree widget item in QTreeWidget

在树形小部件中,我连接了以下信号:

  connect(mTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
          SLOT(onItemClicked(QTreeWidgetItem*, int)));

其中 onItemClicked() 插槽如下:

void WidgetBox::onItemClicked(QTreeWidgetItem *item, int )
{
  int index = getPageIndex(item);
  setCurrentIndex(index);
}

int WidgetBox::getPageIndex(QTreeWidgetItem *item)
{
  if (!item) return -1;

  QTreeWidgetItem *parent = item->parent();
  if(parent)  // Parent is top level item
  {
    return mTreeWidget->indexOfTopLevelItem(parent);
  }
  else        // Current item is top level
  {
    return item->treeWidget()->indexOfTopLevelItem(item);
  }
}

void WidgetBox::setCurrentIndex(int index)
{
  if (index != currentIndex() && checkIndex(index))
  {
    mTreeWidget->setCurrentItem(mTreeWidget->topLevelItem(index));
    emit currentIndexChanged(index);
  }
}

但是我无法捕获 itemClicked() 信号并且 onItemClicked() 从未执行过,因为顶级项目有按钮小部件(使用 setItemWidget() 方法设置)拦截鼠标事件和子项目包含容器小部件,其中可能包含任何小部件组合。

这里有没有一种好的方法可以为树形小部件的顶级项和子项调用此 itemClicked() 信号?

如何更好地组织此类过程,以便所有小部件根据需要处理鼠标事件以及 TreeWidget 问题 SIGNAL(itemClicked())

Full sources to reproduce: https://github.com/akontsevich/WidgetBox

像这样创建了事件过滤器:

class PageEventFilter : public QObject
{
  Q_OBJECT
public:
  PageEventFilter(QObject *parent, QTreeWidgetItem *item);

protected:
  bool eventFilter(QObject *obj, QEvent *event);

private:
  QTreeWidgetItem *mItem;
};

bool PageEventFilter::eventFilter(QObject *obj, QEvent *event)
{
  if (event->type() == QEvent::MouseButtonPress)
  {
    // Emitate mouse event for parent QTreeWidget
    QMouseEvent *oldEvent = (QMouseEvent *)event;
    QRect itemRect = mItem->treeWidget()->visualItemRect(mItem);
    QPointF mousePos(itemRect.x() + 1, itemRect.y() + 1);
    QMouseEvent *newEvent = new QMouseEvent(oldEvent->type(),
                                            mousePos,
                                            oldEvent->button(),
                                            oldEvent->buttons(),
                                            oldEvent->modifiers());
    QCoreApplication::postEvent(mItem->treeWidget(), newEvent);
    return false; // Sent event to the object (do not filter it)
  }
  else
  {
    // standard event processing
    return QObject::eventFilter(obj, event);
  }
}

将其安装到树形小部件项目中的按钮。它创建鼠标事件并将其发送(模仿)到树形小部件,但是树形小部件仍然不发送 itemClicked(QTreeWidgetItem*, int) 信号。可能是什么问题?鼠标位置不对?试图将事件发送到 viewport() - 也不走运。有什么办法解决这个问题吗?

所以解决方案很简单,只需在 PageEventFilter 中重新发送 void itemClicked(QTreeWidgetItem *item, int column); 信号即可:

PageEventFilter::PageEventFilter(QObject *parent, QTreeWidgetItem *item)
  : QObject(parent)
  , mItem(item)
{
  connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
          mItem->treeWidget(), SIGNAL(itemClicked(QTreeWidgetItem*,int)));
}

bool PageEventFilter::eventFilter(QObject *obj, QEvent *event)
{
  if (event->type() == QEvent::MouseButtonPress)
  {
    // Resend signal to QTreeWidget
    emit itemClicked(mItem, 0);
    return false; // Send event to the object (do not filter it)
  }
  else
  {
    // standard event processing
    return QObject::eventFilter(obj, event);
  }
}

P.S. Will leave previous answer as well if somebody needs code or idea.