Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Catch (imitate) mouse event on tree widget item in QTreeWidget
Forum Updated to NodeBB v4.3 + New Features

Catch (imitate) mouse event on tree widget item in QTreeWidget

Scheduled Pinned Locked Moved Solved General and Desktop
3 Posts 1 Posters 2.3k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Aleksey_KA Offline
    Aleksey_KA Offline
    Aleksey_K
    wrote on last edited by
    #1

    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:<br>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

    Possible solution:

    Created event filter like this:

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

    Install it to a button in tree widget item. It creates and sends (imitates) mouse event to tree widget, however tree widget still does not send itemClicked(QTreeWidgetItem*, int) signal. What is the problem could be? Wrong mouse pos? Tried to send event to viewport() - no luck as well. Any way to solve this?

    Aleksey_KA 1 Reply Last reply
    0
    • Aleksey_KA Aleksey_K

      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:<br>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

      Possible solution:

      Created event filter like this:

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

      Install it to a button in tree widget item. It creates and sends (imitates) mouse event to tree widget, however tree widget still does not send itemClicked(QTreeWidgetItem*, int) signal. What is the problem could be? Wrong mouse pos? Tried to send event to viewport() - no luck as well. Any way to solve this?

      Aleksey_KA Offline
      Aleksey_KA Offline
      Aleksey_K
      wrote on last edited by
      #2

      Workaround could be to create own itemClicked(QTreeWidgetItem*, int) signal and send it directly from event filter class to QTreeWidget->itemClicked(QTreeWidgetItem*, int) signal. But why current implementation does not work? :)

      1 Reply Last reply
      0
      • Aleksey_KA Offline
        Aleksey_KA Offline
        Aleksey_K
        wrote on last edited by
        #3

        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.

        1 Reply Last reply
        1

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved