c++qtuser-interfaceqt4qt4.7

How to show QAbstractTableModel's status in a QStatusBar?


I have my custom implementation of QAbstractTableModel and of QSortFilterProxyModel, used for filtering. The table is shown in a QTableView.

The parent dialog of my QTableView has a QStatusBar, with a read-only QLineEdit widget.

In my overriding data() method of QAbstractTableModel, I'm setting the pertinent values for the Qt::StatusTipRole role.

Now I'm missing part of the plumbing: how do I get my per-cell StatusTipRole data to show up in my widget inside QStatusBar?


Solution

  • There is no need to override the view widget. Qt provides built-in support to show status tips for items in a model.

    Normally, You just need to return a QString from your model's data() when role is QStatusTipRole, and that QString will be shown in the status bar when you hover your item.

    You also need to turn on mouse tracking for the QTableView so that you get status bar updates without the mouse button being pressed. This is because when mouse tracking is disabled (by default), the widget receives mouse move events only while a mouse button is pressed.

    Now, in order to display those status tips in your QLineEdit instead of the default status bar, You can override your main window's event function, intercept QStatusTipEvents, and show tips in your QLineEdit.

    Here is an example implementation:

    screenshot

    #include <QtWidgets>
    
    //model to provide dummy data
    class MyModel : public QAbstractTableModel{
    public:
        explicit MyModel(QObject* parent= nullptr):QAbstractTableModel(parent){}
        ~MyModel() = default;
        int columnCount(const QModelIndex &parent) const{
            if(parent.isValid()) return 0;
            return 4;
        }
        int rowCount(const QModelIndex &parent) const{
            if(parent.isValid()) return 0;
            return 20;
        }
        QVariant data(const QModelIndex &index, int role) const{
            QVariant val;
            switch(role){
            case Qt::DisplayRole: case Qt::EditRole:
                val= QString("Display (%1, %2)")
                        .arg(index.row(), 2, 10, QChar('0'))
                        .arg(index.column(), 2, 10, QChar('0'));
                break;
            case Qt::ToolTipRole:
                val= QString("Tooltip (%1, %2)")
                        .arg(index.row(), 2, 10, QChar('0'))
                        .arg(index.column(), 2, 10, QChar('0'));
                break;
            case Qt::StatusTipRole:
                val= QString("StatusTip (%1, %2)")
                        .arg(index.row(), 2, 10, QChar('0'))
                        .arg(index.column(), 2, 10, QChar('0'));
                break;
    
            }
            return val;
        }
    };
    
    
    class MainWindow : public QMainWindow{
        Q_OBJECT
    public:
        explicit MainWindow(QWidget* parent= nullptr):QMainWindow(parent){
            //set up GUI
            layout.addWidget(&lineEditFilter);
            layout.addWidget(&tableView);
            setCentralWidget(&cw);
            lineEditStatusBar.setReadOnly(true);
            statusBar()->addPermanentWidget(&lineEditStatusBar);
    
            //set up models
            filterModel.setSourceModel(&model);
            tableView.setModel(&filterModel);
            connect(&lineEditFilter, &QLineEdit::textChanged, this, &MainWindow::updateFilter);
    
            //turn on mouse tracking for the table view
            tableView.setMouseTracking(true);
    
        }
        ~MainWindow()= default;
    
        Q_SLOT void updateFilter(const QString& text){
            filterModel.setFilterFixedString(text);
        }
    protected:
    
        //in order to intercept QStatusTipEvents
        //and show tips in the line edit instead of the normal status bar
        bool event(QEvent *event){
            if(event->type() != QEvent::StatusTip) return QMainWindow::event(event);
            QStatusTipEvent* statusTipEvent= static_cast<QStatusTipEvent*>(event);
            lineEditStatusBar.setText(statusTipEvent->tip());
            statusTipEvent->ignore();
            return true;
        }
    
    private:
        QWidget cw;
        QVBoxLayout layout{&cw};
        QLineEdit lineEditFilter;
        QTableView tableView;
        MyModel model;
        QSortFilterProxyModel filterModel;
        QLineEdit lineEditStatusBar;
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        MainWindow mw;
        mw.show();
    
    
        return a.exec();
    }
    
    #include "main.moc"