Problems with Open-Source Downloads read https://www.qt.io/blog/problem-with-open-source-downloads and https://forum.qt.io/post/638946

How to set Checkbox in header of one column in QtreeView



  • Hi All
    We need to set checkbox in header of one of the columns . I have following class

    class MyHeader : public QHeaderView
    {
    public:
    MyHeader(Qt::Orientation orientation, QWidget * parent = 0) : QHeaderView(orientation, parent)
    {}

    protected:
    void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
    {
    painter->save();
    QHeaderView::paintSection(painter, rect, logicalIndex);
    painter->restore();
    if (logicalIndex == 0)
    {
    QStyleOptionButton option;
    option.rect = QRect(10,10,10,10);
    if (isOn)
    option.state = QStyle::State_On;
    else
    option.state = QStyle::State_Off;
    this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
    }

    }
    void mousePressEvent(QMouseEvent *event)
    {
    if (isOn)
    isOn = false;
    else
    isOn = true;
    this->update();
    QHeaderView::mousePressEvent(event);
    }
    private:
    bool isOn;
    };

    class myView::QTreeView {

    }

    MyView::GQInstView(QWidget* dparent)
    : QTreeView(dparent), {

    }

    The tree View has three columns . How to set header for first column in treeView




  • Lifetime Qt Champion

    • The tree View has three columns . How to set header for first column in treeView

    Hi
    I do not think you can replace for just column 1
    You can set for treeview using
    http://doc.qt.io/qt-5/qtreeview.html#setHeader
    and that be for all columns.


  • Moderators

    @Qt-Enthusiast

    1. set your custom header view to your items widget like @mrjj said
    2. instead of using "isOn" in the header class, query the model's headerData() method for the Qt::CheckStateRole
    3. in your model return the corresponding check state in headerData(). For column 1 return Qt::Checked, when you don't want to display a checkbox at all return an invalid QVariant


  • @raven-worx said:

    odel's headerData() method for the Qt::CheckStateRole
    in your model return the corresponding check state in

    how to get model pointer

    class MyHeader : public QHeaderView
    {
    public:
    MyHeader(Qt::Orientation orientation, QWidget * parent = 0) : QHeaderView(orientation, parent)
    {}

    protected:
    void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
    {
    painter->save();
    QHeaderView::paintSection(painter, rect, logicalIndex);
    painter->restore();
    if (logicalIndex == 0)
    {
    QStyleOptionButton option;
    option.rect = QRect(10,10,10,10);
    if (isOn)
    option.state = QStyle::State_On;
    else
    option.state = QStyle::State_Off;
    this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
    }

    }
    void mousePressEvent(QMouseEvent *event)
    {
    if (isOn)
    isOn = false;
    else
    isOn = true;
    this->update();
    QHeaderView::mousePressEvent(event);
    }
    private:
    bool isOn;
    };


  • Moderators

    @Qt-Enthusiast said:

    how to get model pointer

    since QHeaderView derives from QAbstractItemView, you are doing it the same way you would do for table/trees/lists/... with the model() method
    This model is the same as the item view widget has also set.



  • @raven-worx

    #include <QApplication>
    #include <QAbstractTableModel>
    #include <QSortFilterProxyModel>
    #include <QInputDialog>
    #include <QTableView>
    #include <QGridLayout>
    #include <QPushButton>
    #include <QDebug>
    #include <QHeaderView>
    #include <QStyle>
    #include <QPainter>
    #include <QMouseEvent>
    #include <QTreeView>

    class MyHeader : public QHeaderView
    {
    public:
    MyHeader(Qt::Orientation orientation, QWidget * parent = 0) : QHeaderView(orientation, parent)
    {}

    protected:
    void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
    {
    painter->save();
    QHeaderView::paintSection(painter, rect, logicalIndex);
    painter->restore();
    if (logicalIndex == 1 )
    {
    QStyleOptionButton option;
    option.rect = QRect(10,10,10,10);
    isOn = model()->headerData(1,Qt::Horizontal, Qt::CheckStateRole);
    if (isOn)
    option.state = QStyle::State_On;
    else
    option.state = QStyle::State_Off;
    this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
    }

    }
    void mousePressEvent(QMouseEvent *event)
    {

    if (isOn)
      isOn = false;
    else
      isOn = true;
    this->update();
    QHeaderView::mousePressEvent(event);
    

    }
    private:
    bool isOn;
    };

    class Vehicle {
    QString m_make, m_model, m_registrationNumber;
    public:
    Vehicle(const QString & make, const QString & model, const QString & registrationNumber = QString()) :
    m_make(make), m_model(model), m_registrationNumber(registrationNumber) {}
    QString make() const { return m_make; }
    QString model() const { return m_model; }
    QString registrationNumber() const { return m_registrationNumber; }
    bool isRegistered() const { return !m_registrationNumber.isEmpty(); }
    };

    class VehicleModel : public QAbstractTableModel {
    QList<Vehicle> m_data;
    public:
    VehicleModel(QObject * parent = 0) : QAbstractTableModel(parent) {}
    int rowCount(const QModelIndex &) const { return m_data.count(); }
    int columnCount(const QModelIndex &) const { return 3; }
    QVariant data(const QModelIndex &index, int role) const {
    if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant();
    const Vehicle & vehicle = m_data[index.row()];
    switch (index.column()) {
    case 0: return vehicle.make();
    case 1: return vehicle.model();
    case 2: return vehicle.registrationNumber();
    default: return QVariant();
    };
    }
    QVariant headerData(int section, Qt::Orientation orientation, int role) const {
    if(role == Qt::CheckStateRole && orientation == Qt::Horizontal) {
    switch (section) {
    case 0: return Qt::Unchecked;
    case 1: return Qt::Checked;
    case 2: return Qt::Unchecked;
    default: return QVariant();
    }

        }
        if (orientation != Qt::Horizontal) return QVariant();
        if (role != Qt::) return QVariant();
        switch (section) {
        case 0: return "Make";
        case 1: return "Model";
        case 2: return "Reg.#";
        default: return QVariant();
        }
    }
    void append(const Vehicle & vehicle) {
        beginInsertRows(QModelIndex(), m_data.count(), m_data.count());
        m_data.append(vehicle);
        endInsertRows();
    }
    

    };

    class Widget : public QWidget {

    VehicleModel m_model;
    QSortFilterProxyModel m_proxy;
    Q_SLOT void setFilter() {
        QInputDialog * dialog = new QInputDialog(this);
        dialog->setLabelText("Enter registration number fragment to filter on. Leave empty to clear filter.");
        dialog->setInputMode(QInputDialog::TextInput);
        dialog->open(&m_proxy, SLOT(setFilterFixedString(QString)));
        dialog->setAttribute(Qt::WA_DeleteOnClose);
    }
    

    public:
    Widget() {
    QGridLayout * layout = new QGridLayout(this);
    QTreeView view = new QTreeView;
    MyHeader
    myH = new MyHeader(Qt::Horizontal);
    view->setHeader(myH);
    layout->addWidget(view, 0, 0, 1, 1);
    QPushButton * btn = new QPushButton("Filter");
    layout->addWidget(btn, 1, 0, 1, 1);
    m_model.append(Vehicle("Volvo", "240", "SQL8941"));
    m_model.append(Vehicle("Volvo", "850"));
    m_model.append(Vehicle("Volvo", "940", "QRZ1321"));
    m_model.append(Vehicle("Volvo", "960", "QRZ1628"));
    view->setModel(&m_model);
    }
    };

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
    }

    could you guide me on the same how to have checkbox in above code as per your inputs




  • Moderators

    @Qt-Enthusiast said:

    could you guide me on the same how to have checkbox in above code as per your inputs

    i just give you some snippets. I leave it to you to check the rest out, since it's pretty simple.

    in the header:

    void MyHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
    {
    painter->save();
    QHeaderView::paintSection(painter, rect, logicalIndex);
    painter->restore();
    
    QVariant headerCheckState = model()->headerData(logicalIndex, Qt::Horizontal, Qt::CheckStateRole);
    
    if( headerCheckState .isValid() )  //only paint the checkbox if the model returned a valid qvariant
    {
    Qt::CheckState check = static_cast<Qt::CheckState>( headerCheckState.toInt() );
    QStyleOptionButton option;
    option.rect = QRect(10,10,10,10);
    if ( checkState == Qt::Checked )
          option.state = QStyle::State_On;
    else
          option.state = QStyle::State_Off;
    this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
    }
    

    in the model:

    QVariant MyModel::headerData(int section, Qt::Orientation orientation, int role ) const
    {
         if( orientation == Qt::Horizontal )
         {
                   switch( role )
                   {
                          case Qt::CheckStateRole:
                          {
                                     if( section == XXX )  // here you need to check which columns you want to display the checkbox
                                     {
                                            return QVariant::fromValue<int>(Qt::Checked);
                                     }
                          }
                          break;
                   }
         }
    
          return QHeaderView::headerData(section,orientation,role);
    }
    

    This way a checkbox is only displayed when you return a valid QVariant:

    Invalid QVariant -> no checkbox
    QVariant with Qt::CheckedState -> checked checkbox
    QVariant with other value -> unchecked checkbox


Log in to reply