Search code examples
mouseeventqtreewidgetqtreewidgetitemqt5.6

Catch mouse event on tree widget item in QTreeWidget


In tree widget I have following signal connected:

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

where onItemClicked() slot is following:

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

However I can't catch itemClicked() signal and onItemClicked() never executed because top level items has push button widget (set with setItemWidget() method) which intercepts mouse event and child items contain container widgets which may have any widget combinations in them.

Is there a good method here to invoke this itemClicked() signal for both top level and child items of tree widget?

  • installEventFilter() for all widgets found in an item by something like following:
    QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>();?
  • Or establish mouse event propagation somehow?
  • QCoreApplication::postEvent()?

How to organize such process better so all widgets process mouse event as they need to and TreeWidget issue SIGNAL(itemClicked()) as well?

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


Solution

  • So solution is simple and following - just re-send void itemClicked(QTreeWidgetItem *item, int column); signal in PageEventFilter:

    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.