Why is QTreeView highlighting wrong row (different than selection)



  • Hi,
    Does any one know how is it posible, that when I hover over a item in my tree view, Qt thinks, I'm hovering over a different one?
    It's always correct about the item on the top of visible part of the list(tree view without indentation), but every other is like ++ (when I select the second, the blue rectangle is on the third; when I select the third, its on the fifth; its on the ninth).
    I have a custom delegate and QTreeView, but I did not touch the model index in any way.
    I'm using Qt 5.71 with MSVC 2015 64bit

    Any idea where I should look for bugs?

    Below are two examples of my widget

    two examples of my widget

    mouse was howering over the row where the two buttons (rectangles) are


  • Qt Champions 2016

    Hi
    Without code its just random guessing but it does work sometimes :)
    The distance from the Hover target to the wrong blue seems to be directly
    the same as from top to the hover target. In both cases.

    This makes we wonder if you use x,y of mouse event for anything and either call
    mapFromGlobal or not before using them or that the x,y is already convert to client space but its
    the wrong client. Kinda situation. Like the TreeView has a viewport etc.

    Sp do you have any code related to hover event and selecting an item?



  • Thank You for Your answer mrjj.
    I have this related to mouse hover:

    MyTreeView::MyTreeView(QWidget *parent) : QTreeView(parent)
    {
        setMouseTracking(true);
    }
    
    void MyTreeView::mouseMoveEvent(QMouseEvent *event){
        mousePressEvent(event);
    }
    
    void MyTreeView::leaveEvent(QEvent *event)
    {
    //    setMouseTracking(false);
        qDebug() << "left treeView";
    
        emit saveToModelFromEditor();
    
        QTreeView::leaveEvent(event);
    }
    
    void MyTreeView::resizeEvent(QResizeEvent *e)
    {
        if(model() != Q_NULLPTR){
            model()->layoutChanged();
        }
        QTreeView::resizeEvent(e);
    }
    

    and in main window:

    void MainWindow::mouseMoveEvent(QMouseEvent *event)
    {
        {
            if (event->buttons() & Qt::LeftButton)
            {
                move(event->globalPos() - dragPosition);
                event->accept();
            }
        }
        QWidget::mouseMoveEvent(event);
    }
    

  • Qt Champions 2016

    Hi
    Just note first
    void MyTreeView::mouseMoveEvent(QMouseEvent *event){
    mousePressEvent(event);
    }

    why are you calling mousePressEvent when you move the mouse?

    I dont spot any code that should give this offset.

    you dont use enterEvent ?



  • I use it to select a row for editing.
    So that when I hover the mouse over a row the editor is trigered.
    I need it, because I have a view, that needs to handle over 10 000 rows.
    When I draw editors for every item at once the UI slows down drasticaly.

    void MainWindow::setupTreeView()
    {
        itemDelegate = new MyItemDelegate(this);
        treeView->setItemDelegate(itemDelegate);
        treeView->header()->hide();
        treeView->setIndentation(0);
        treeView->setModel(aModel);
        treeView->setSelectionMode(QAbstractItemView::SingleSelection);  // this line here
        treeView->setEditTriggers(QAbstractItemView::CurrentChanged);  // and this line here
        treeView->expandAll();
    }
    

    Do You have any other solution?


  • Qt Champions 2016

    @michalos
    I think the offset might come from this passing of event variable from move to press.
    Must be tested to know if its that.

    I was expecting something like
    EnterEvent()
    Find item under x,y via itemAt and then treeView->setCurrentIndex to select it.

    Nothing wrong with your way but i think the offset comes from selecting it this way but
    only test can tell.



  • I've commented out mose related events in my View, and then in mainwindow.
    The behaviour is the same, only now I need to click for it to occur.

    Funny thing is, that it was working about two weeks ago.

    Is it posible, that the latest Qt update (5.71) did it?


  • Qt Champions 2016

    @michalos
    Well if it used to work then its possible the update did something.

    Just so im sure I test the right thing.
    When you hover an item, it should be selected and put into edit mode?



  • Yes.
    When I hover over an item in the View, the styledItemDelegate is called and depending on one of the item userRole's the correct editor is selected.

    It's the same in Qt 5.6_2

    I don't have acces to older versions right now.

    I setup my model from an SQLite query, like this:

    
        rootNode = model->invisibleRootItem();
        groupNameItem = Q_NULLPTR;
        contactItem = Q_NULLPTR;
    
        groupId = 0;
        contactId = 0;
        phoneNo = 0;
        phoneRole = 100;
    
        /////////////////////////////////////////////////// setup model dla wszystkich kontaktów
        queryHasAnswer = false;
    
        groupNameItem = new QStandardItem("DelleteThisInMainwindow"); //group_names.name
        groupNameItem->setData(0,Qt::UserRole);  //group_names.id
        groupNameItem->setData(0,Qt::UserRole+1);  //group_names.favorite
        groupNameItem->setData(1,Qt::UserRole+9);
        while (query.next()) {
        queryHasAnswer = true;
    
    
        if (contactId != query.value(0))  {
            if(contactItem != Q_NULLPTR){
                groupNameItem->appendRow(contactItem);
                contactItem = Q_NULLPTR; //niepowinno być potrzebne
            }
            phoneRole = 100;
            contactId = query.value(0);
            contactItem = new QStandardItem(query.value(1).toString()); //contact name
            contactItem->setData(contactId, Qt::UserRole); //contact id
            contactItem->setData(query.value(2), Qt::UserRole+1);  //extNo
            contactItem->setData(query.value(3), Qt::UserRole+2);   //favorite
            contactItem->setData(2, Qt::UserRole+9); // determinuje, że Contacts - dla itemDelegate::paint
            phoneNo = query.value(4);  //numer telefonu do kontaktu
            contactItem->setData(phoneNo, Qt::UserRole+phoneRole++);    //phone number
        } else if (contactItem != Q_NULLPTR) {
            phoneNo = query.value(4);  //numer telefonu do kontaktu
            contactItem->setData(phoneNo, Qt::UserRole+phoneRole++);    //phone number
        }
    
        } //while(query.next())
    
        if(queryHasAnswer){
        groupNameItem->appendRow(contactItem); //ostatni z contacts
        rootNode->appendRow(groupNameItem); //ostatni z group_names
        }
    

  • Qt Champions 2016

    Ok. seems fine. I dont think its related to the data as such.
    Just seems to be confused about Y from mouse Event.
    But i am just guessing. only debugger will know :)

    Update:
    Hmm. I made small sample with TreeView and called MouseDown from MouseMove
    but i dont get any offset-ish effect. All you move over is just in edit mode.

    https://www.dropbox.com/s/9ee7171vcam12re/myhover.zip?dl=0

    So i guess its something else. Just to be be sure. can u run sample.

    Do you have a smaller sample that has this issue ?



  • in your delegate, do you reimplement updateEditorGeometry? if so, could you post the code?



  • There it is:

    void MyItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        editor->setGeometry(option.rect);
    }
    


  • I've found, that there is no problem for the parent, only for the children.
    The parrent has no highlight at all.

    Also without seting my delegate to the treeView [treeView->setItemDelegate(itemDelegate) ] the selection works fine.

    It would suggest that I might messed something up.. but I do not now what could cause such behaviour.

    Here is the code:

           QStyleOptionViewItem options = option;
            initStyleOption(&options, index);
    
            painter->save();
    
            int scrollBarrWidth = options.widget->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
    
            QRect rectLeft(0,0,26,26);
            QRect rectCenter(30,0,(options.rect.right()-40-scrollBarrWidth),26); 
            QRect rectRight((options.widget->rect().right()-30-scrollBarrWidth),0,26,26);
            QRect boundingRect;
    
            QString nameText(index.data(Qt::DisplayRole).toString());
            QString extNoText(index.data(Qt::UserRole+1).toString());
            QString phoneText(index.data(Qt::UserRole+100).toString());
    
            painter->translate(options.rect.left(), options.rect.top());
    
            painter->drawPixmap(rectLeft.adjusted(4,4,-4,-4),icoGreenPhone); 
            painter->drawPixmap(rectRight.adjusted(4,4,-4,-4), icoMessage); 
            painter->setFont(QFont("Segoe UI",9,50));
                    QTextDocument textDoc;
                    textDoc.setTextWidth(rectCenter.width());
    
                    QTextCursor textCursor(&textDoc);
                    QString wholeText("");
    
                    bool wczytajfote = !stanPoint.isNull();
    
                    wholeText.append("<b>");
                    wholeText.append(nameText);
                    wholeText.append("</b>");
                    textCursor.insertHtml(wholeText);
                    if(wczytajfote){
                        textCursor.insertHtml("&nbsp");
                    textCursor.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor);
                    textCursor.insertImage(stanPoint);
                    textCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
                    textCursor.insertHtml("&nbsp");
                    }
                    wholeText.clear();
                    if(!extNoText.isEmpty()){
    
                        wholeText.append("<font color = blue>");
                        wholeText.append(QString(" ("+extNoText+") "));
                        wholeText.append("</font><br><i>");
                        wholeText.append("infoStr trzeba dostarczyć z tagu Status, a nie z bazy danych");
                        wholeText.append("</i>");
                    } else {
                        wholeText.append("<font color = blue>");
                        wholeText.append("<br>");
                        wholeText.append(QString(" ("+phoneText+") "));
                    }
                    textCursor.insertHtml(wholeText);
    
                    options.text = "";
                    options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);
                    painter->translate(rectCenter.left(), rectCenter.top());
    
                    QRect clip(0,0,textDoc.size().width(), textDoc.size().height());
                    textDoc.drawContents(painter, clip);
    
            painter->restore();
    

    edit: I've left only the paint method



  • delete all the contents of the destructor, the widgets inside are managed by the parent-child system, don't delete them manually.

    The code is quite complex so I'd suggest narrowing it down to 1 function. comment the reimplemented methods out then uncomment them back and see if it still works, when it doesn't you found the method responsible



  • The problem is with the MyItemDelegate::paint method.

    I've found out that commenting out the line, that translates the painters coordinates fixes the highlighting problem.

     painter->translate(options.rect.left(), options.rect.top());
    

    The question I do not have the answer to is why...
    Why is this line Ok, when I use a different, similar paint method, and not in this method?

    Anyone has a clue?

    edit:
    I got over the problem by removing the highlight rectangle. I do not need it, so the problem is solved.
    But I still would be grateful for an answer why the error occurred.

      //I've commented out
       options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);
    

  • Moderators

    @michalos said in Why is QTreeView highlighting wrong row (different than selection):

    The problem is with the MyItemDelegate::paint method.

    I've found out that commenting out the line, that translates the painters coordinates fixes the highlighting problem.

     painter->translate(options.rect.left(), options.rect.top());
    

    The question I do not have the answer to is why...
    Why is this line Ok, when I use a different, similar paint method, and not in this method?

    Anyone has a clue?

    edit:
    I got over the problem by removing the highlight rectangle. I do not need it, so the problem is solved.
    But I still would be grateful for an answer why the error occurred.

      //I've commented out
       options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);
    

    It looks to me like your translate rectangles are wrong. I would check in a debugger or with qDebug() to see why they are so off compared to the actual location of the item.

    Usually when this stuff happens it's a failure to translate coordinates from screen to widget or vice versa.


  • Lifetime Qt Champion

    Hi,

    IIRC, you receive the geometry of the cell you clicked so you are already painting on the right rectangle, no need to move anything around.



  • Solved it by drawing the highlighting rectangle before the painter->translate.

    Thank You All for Your help.
    Now it seems logical, but I don't think I could figure out this by my self.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.