Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTreeWidget indexAt() doesn't work



  • Hey!

    I wanna use the indexAt() method in the eventFilter method() of my application. The problem is that it is that the resulting ModelIndex isn't valid, even if I click on an item. Could someone help me? I have already tried setMouseTracking(true) but that didn't help either.

    Thanks!


  • Lifetime Qt Champion

    Hi,

    Did you map properly the mouse position you got from the event to the widget you want to manipulate ?



  • Yeah, I did. I casted the event to a mouseEvent and used the pos() method to get the coordinates. I already verified them by printing them out.


  • Lifetime Qt Champion

    Did you map the coordinates ?



  • Are you filtering the events from a itemWidget?
    The pos from the mouse events is in the coordinate system of that itemWidget, not the treeWidget.
    You can:

    1. map the pos from itemWidget to treeWidget's viewport
    QPoint pos = itemWidget->mapTo(treeWidget->viewport(), e->pos());
    
    1. map the global pos to treeWidget's viewport
    QPoint pos = treeWidget->viewport()->mapFromGlobal(e->globalPos());
    

    P.S.setMouseTracking(true) does not affect the pos value. It only makes you receiving mouse move events from the widget even no buttons are pressed.



  • Ouch, I'm filtering them from the window because I want to check if I click away from a QTableWidget globally. I'll try it out :D Thanks, @Bonnie!



  • @FluentCoding Hmm..if you are not filtering from treeWidget's child widgets, then the first option need some change...



  • Which? But I could use the second method as well?


  • Lifetime Qt Champion

    What about the focusOutEvent ?



  • @FluentCoding Yes, the second is ok to use. It maps from global pos, so nothing to do with their child/parent relation.
    The first one must map from child to a parent (recursively).
    If you'are filtering the window, and the window is a parent of treeWidget, then it should be changed to

    QPoint pos = treeWidget->viewport()->mapFrom(window, e->pos());
    


  • @Bonnie Thank you for the solution! Both work but have the same problem - when I'm scrolling a bit down in my QTableWidget, then I have the problem that the item gets shown as valid although I don't click on the widget.

    My Code:

    bool MainWindow::eventFilter(QObject* obj, QEvent* event) {
        if (event->type() == QEvent::MouseButtonPress) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
    
            QPoint pos = ui->treeWidget->viewport()->mapFromGlobal(mouseEvent->globalPos());
            QModelIndex index = ui->treeWidget->indexAt(pos);
    
            if (!index.isValid() && ui->treeWidget->selectedItems().count() == 1) {
                ui->treeWidget->clearSelection();
            }
        }
    }
    


  • @SGaist Didn't try it out yet, but I don't think that it would be better than the eventFilter()-solution :/



  • @FluentCoding Yes, the viewport is partly invisible, so the index got from indexAt may be not visible.
    That's what you need to do when you map the pos not from treeWidget's child.
    You need to see whether it is contained in treeWidget's rect, whether it is on the scrollbar or not...
    I think it's a bit complicated, maybe you should try what @SGaist suggest, use the focusOutEvent.
    This is what I think to solve the problem (but not usable when you have set any itemWidget)

    QPoint pos = ui->treeWidget->mapFromGlobal(e->globalPos());  //map pos to treeWidget
    if(ui->treeWidget->rect().contains(pos) &&  //pos is inside of treeWidget
        ui->treeWidget->childAt(pos) == ui->treeWidget->viewport() &&  //pos is not on scrollbars
        ui->treeWidget->indexAt(ui->treeWidget->viewport()->mapFromParent(pos)).isValid()) {  //get index from viewport, maybe you don't need this line
        //valid index
    } else {
        //invalid index
    }
    


  • @Bonnie Thank you so much, Bonnie! It worked!


Log in to reply