Mousehover entire row selection in QTableView



  • Hi All,

    I want to know that how to do the row selection of QTableView on Mousehover event.
    I am able to do the itemhover selection in QTableView through stylesheet
    QTableView::item:hover{
    }

    But i am not able to do the entire row selection based on Mousehover event in QTableView.
    Can anyone tell me how to do that ?

    Thanks,
    Neel



  • I have written following delegate to display the mouse hover effect for item.

    @#include <QtGui>

    class Delegate : public QItemDelegate {
    public:
    Delegate(QObject *parent=0) : QItemDelegate(parent){}
    void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const {
    if(option.state & QStyle::State_MouseOver){
    painter->fillRect(option.rect, Qt::red);
    }
    QItemDelegate::paint(painter, option, index);
    }
    };

    int main(int argc, char **argv){
    QApplication app(argc, argv);
    QTableView tv;
    tv.viewport()->setAttribute(Qt::WA_Hover);
    QStandardItemModel model(8,8);
    tv.setModel(&model);
    tv.setItemDelegate(new Delegate(&tv));
    tv.show();
    return app.exec();
    }
    @

    I want the chage in above code that will select the entire row on mouse over.
    Any suggestion ?

    Thanks,
    Neel



  • Delegate is responsible for the cell only, so you need to report to highlight the view that the entire row.
    You can do this in many ways ( for example )

    @
    class IView {
    public:
    virtual void setMouseOver(bool flag, const QModelIndex& index) = 0;
    }

    class MyView : public QTreeView, public IView {
    public:
    void setMouseOver(bool flag, const QModelIndex& index){
    int row = index.row();

            for ( int col = 0; i < columnCount(); col++ ) {
                QStandartItem *item = model->item(row, col);
    
                if (flag ) item->setBackground(QBrush(QCloro("red")));
                else item->setBackground(QBrush(QCloro("red")));
            }
        }
    

    };

    class Delegate : public QSyledItemDelegate {
    IView *view;

    void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const {
                bool isOver = option.state & QStyle::State_MouseOver;
    
                view->setMouseOver(isOver, index);
    }
    

    };
    @

    or something like this

    @
    class Delegate : public QSyledItemDelegate {
    private:
    int hoveredRow;

       void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const {
                if(option.state & QStyle::State_MouseOver) {
                         hoveredRow = index.row();
                }
    
                if ( hoveredRow == index.row(); ) {
                         ///
                } else {
    
                }
    
                QSyledItemDelegate::paint(painter, option, index);
                 
        }
    

    };

    @



  • Thanks for your reply.

    As i have checked that in QTreeView we are able to see the mousehover effect of the row.
    But in QTableView we are not able to do row selection based on mousehover.

    Can you please give me some idea for how to do in QTableView ?



  • hm...puts you code with table view here.



  • Above i have already given my code. I have tried with sample given by you it gives some compiler warning but i have resolved some of t and tried but not able to see the expected output.

    Can you please change my above code and give some inputs ?



  • @
    #include <QtGui/QApplication>

    #include "TableView.h"
    #include <QStandardItem>
    #include <QStandardItemModel>

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);

    QStandardItemModel model;
    
    for ( int col = 0; col < 3; col++ )
    {
        QList<QStandardItem*> list;
        for ( int row = 0; row < 5; row++ )
        {
            list.append(new QStandardItem);
        }
        model.appendColumn(list);
    }
    
    TableView view;
    
    view.setModel(&model);
    view.show();
    
    return a.exec&#40;&#41;;
    

    }
    @

    @
    #ifndef IVIEW_H
    #define IVIEW_H

    class IView {

    public:
    virtual void setMouseOver(const int) =0;
    };

    #endif // IVIEW_H

    #ifndef TABLEVIEW_H
    #define TABLEVIEW_H

    #include <QTableView>
    #include <QMouseEvent>
    #include <QStandardItem>

    #include "IView.h"
    #include "Delegate.h"

    class TableView : public QTableView, public IView {
    Q_OBJECT

    private:
    int currHovered;

    void mouseMoveEvent(QMouseEvent *event&#41;;
    void disableMouseOver();
    

    public:
    TableView(QWidget *parent = 0);

    void setMouseOver(const int);
    

    };

    #endif // TABLEVIEW_H

    #include "TableView.h"

    #include <QDebug>

    TableView::TableView(QWidget *parent) : QTableView(parent), currHovered(-1)
    {
    Delegate *delegate = new Delegate;
    delegate->setView(this);

    setItemDelegate(delegate);
    setMouseTracking(true);
    

    }

    void TableView::setMouseOver(const int row)
    {
    if ( row == currHovered) return;

    QStandardItemModel *_model = static_cast<QStandardItemModel*>(model());
    for ( int col = 0; col < _model->columnCount(); col++ )
    {
        QStandardItem *item = _model->item(row, col);
    
        item->setBackground(QBrush(QColor("red")));
    }
    
    if ( currHovered != -1 )
    {
        disableMouseOver();
    }
    
    currHovered = row;
    

    }

    void TableView::disableMouseOver()
    {
    QStandardItemModel _model = static_cast<QStandardItemModel>(model());
    for ( int col = 0; col < _model->columnCount(); col++ )
    {
    QStandardItem *item = _model->item(currHovered, col);

        item->setBackground(QBrush(QColor("white")));
    }
    

    }

    void TableView::mouseMoveEvent(QMouseEvent *event)
    {

    // TODO: you need know when mouse are not in table rect
    // then you need disable over
    
    QTableView::mouseMoveEvent(event);
    

    }
    @

    @
    #ifndef DELEGATE_H
    #define DELEGATE_H

    #include <QStyledItemDelegate>

    #include "IView.h"

    class Delegate : public QStyledItemDelegate {

    private:
    IView *view;

    public:
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;

    void setView(IView *view) { this->view = view; }
    

    };

    #endif // DELEGATE_H

    #include "Delegate.h"

    #include <QDebug>

    void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
    QStyleOptionViewItemV4 o = option;
    initStyleOption(&o, index);

    if ( o.state & QStyle::State_MouseOver )
    {
        view->setMouseOver(index.row());
    }
    
    o.state &= ~QStyle::State_MouseOver;
    
    QStyledItemDelegate::paint(painter, o, index);
    

    }
    @

    p.s. I don't put this in the archive because it's very popular question.
    p.s.s about previous code it was just idea ... not a full implementation.
    p.s.s.s About this code, I'm sure it's not perfect (yes working, but not perfect), you can find a different idea or change the implementation.



  • Thanks a lot stima ..... i have checked above given code and it is working as expected ..
    Again thanks a lot ....

    Thanks,
    Neel



  • Hi Stima,

    As mousehover is done but if i want selection and mousehover then how can we achieve this. As in Folder structure in windows 7 we can do selection (select one of the folder) and also mousehover we can do. How to achieve selection as well as mousehover ?

    Thanks,
    Neel



  • Hi everyone, I have a problem with if ( o.state & QStyle::State_MouseOver ) ...
    When mouse leaves a widget, it is still true...
    I mean if we take a look on source code of QTableView, we can find there that a method drawCell
    and two lines
    @ if (index == hover)
    opt.state |= QStyle::State_MouseOver;
    @

    so it only sets the state up and not sets it down other hand, is it a BUG ?
    And what can i do to not write a horrible scrap something like
    @
    void setHoveredIndex( QModelIndex index )
    @

    into soure of my delegate



  • The state is not kept between drawing calls, so that's not a problem. If your mouse leaving the widget doesn't trigger a redraw, then that seems to be the issue to me.



  • Hi Andre, thank you for quick reply.
    So as you sad state is not keeping between drawing calls, but when mouse is leaving the widget it does not refresh the state, even if I call repaint after leaveEvent.
    For example if we create a simple QComboBox, the behaviour on it's "popup-list" is absolutely the same, when mouse is leaving, it's still keeping last hovered index selected...



  • You are right, it is. Interesting issue then. I have no idea how the item view keeps the "hover" state for items that are not actually hovered anymore, and less so how to reset this state.


Log in to reply
 

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