Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Problem while applying filter on QTableView with a button column
Forum Update on Monday, May 27th 2025

Problem while applying filter on QTableView with a button column

Scheduled Pinned Locked Moved Solved General and Desktop
18 Posts 3 Posters 4.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    Lati
    wrote on 17 Oct 2019, 08:36 last edited by Lati
    #1

    Dear QT community,

    I have a QTableView which's last column consists of buttons (pictures are at the end of the post).

    I am applying filtering on the first column using QSortFilterProxyModel basically using the method described here (https://stackoverflow.com/questions/17044688/qtableview-real-time-filtering).

    Filtering works well, however, when the filter is removed, buttons on the last column disappears . What might be the issue here and how can I refresh the last column after filter is removed to have the buttons back?

    Thanks for your responses in advance!

    Before filtering:
    Before_filtering.PNG .

    When filtered:
    Filtered.PNG

    After filter is removed:
    After_filter_removed.PNG

    J 1 Reply Last reply 17 Oct 2019, 08:40
    0
    • L Lati
      17 Oct 2019, 08:36

      Dear QT community,

      I have a QTableView which's last column consists of buttons (pictures are at the end of the post).

      I am applying filtering on the first column using QSortFilterProxyModel basically using the method described here (https://stackoverflow.com/questions/17044688/qtableview-real-time-filtering).

      Filtering works well, however, when the filter is removed, buttons on the last column disappears . What might be the issue here and how can I refresh the last column after filter is removed to have the buttons back?

      Thanks for your responses in advance!

      Before filtering:
      Before_filtering.PNG .

      When filtered:
      Filtered.PNG

      After filter is removed:
      After_filter_removed.PNG

      J Offline
      J Offline
      JonB
      wrote on 17 Oct 2019, 08:40 last edited by
      #2

      @Lati
      Since the example you reference does not have something like a button column, I think you should show minimal code for what you are doing. I would not expect you to have to take "special action", the buttons should either be there or not, it sounds like something is wrong in your "After filter is removed:" code?

      L 1 Reply Last reply 17 Oct 2019, 08:54
      0
      • J JonB
        17 Oct 2019, 08:40

        @Lati
        Since the example you reference does not have something like a button column, I think you should show minimal code for what you are doing. I would not expect you to have to take "special action", the buttons should either be there or not, it sounds like something is wrong in your "After filter is removed:" code?

        L Offline
        L Offline
        Lati
        wrote on 17 Oct 2019, 08:54 last edited by
        #3

        @JonB Thanks Jon for such a quick response! :)

        First, I am using QT Creator v4.10.0 and QT v5.13.1.

        I update the model of the QTableView as:

        QStandardItemModel *model = new QStandardItemModel();
        // filter proxy model
        filter_proxy_model = new QSortFilterProxyModel();
        filter_proxy_model->setSourceModel(model);
        filter_proxy_model->setFilterKeyColumn(0);   // # first column
            
        ui->_tableView->setModel( filter_proxy_model );
        ui->_tableView->show();
        

        And filter using LineEdit_textChanged signal as:

        void MainWindow::on_filtersetTableViewLineEdit_textChanged(const QString &arg1)
        {
            filter_proxy_model->setFilterRegExp(arg1);
        }
        

        Last column's buttons are created as following:

        auto item = filter_proxy_model->index(i, 6);
        QPushButton* addIntervalButton = new QPushButton("Add interval");
        ui->_tableView->setIndexWidget(item, addIntervalButton);
        
        

        This is actually everything related to the filtering and button column.

        J 1 Reply Last reply 17 Oct 2019, 08:59
        0
        • L Lati
          17 Oct 2019, 08:54

          @JonB Thanks Jon for such a quick response! :)

          First, I am using QT Creator v4.10.0 and QT v5.13.1.

          I update the model of the QTableView as:

          QStandardItemModel *model = new QStandardItemModel();
          // filter proxy model
          filter_proxy_model = new QSortFilterProxyModel();
          filter_proxy_model->setSourceModel(model);
          filter_proxy_model->setFilterKeyColumn(0);   // # first column
              
          ui->_tableView->setModel( filter_proxy_model );
          ui->_tableView->show();
          

          And filter using LineEdit_textChanged signal as:

          void MainWindow::on_filtersetTableViewLineEdit_textChanged(const QString &arg1)
          {
              filter_proxy_model->setFilterRegExp(arg1);
          }
          

          Last column's buttons are created as following:

          auto item = filter_proxy_model->index(i, 6);
          QPushButton* addIntervalButton = new QPushButton("Add interval");
          ui->_tableView->setIndexWidget(item, addIntervalButton);
          
          

          This is actually everything related to the filtering and button column.

          J Offline
          J Offline
          JonB
          wrote on 17 Oct 2019, 08:59 last edited by JonB
          #4

          @Lati
          But when/where are those "last column's buttons" created? If your "the filter is removed" is a change in the regular expression to empty, are you doing this code again at that instant, when the extra new rows appear? Put a debug in the code so you can see the i loop creating for each row when needed.

          L 1 Reply Last reply 17 Oct 2019, 09:09
          1
          • J JonB
            17 Oct 2019, 08:59

            @Lati
            But when/where are those "last column's buttons" created? If your "the filter is removed" is a change in the regular expression to empty, are you doing this code again at that instant, when the extra new rows appear? Put a debug in the code so you can see the i loop creating for each row when needed.

            L Offline
            L Offline
            Lati
            wrote on 17 Oct 2019, 09:09 last edited by
            #5

            @JonB Last column's buttons are created when all table is filled (yes, using a loop but code is long and not related). Filtering is done through "QSortFilterProxyModel", so table is not filled again while filtering or after filter is removed (or the text in the textbox is changed). Therefore I cannot debug in the loop when the table is filled where i exists, while or after filtering.

            I wonder if I need to refresh the table after filter is removed

            J 1 Reply Last reply 17 Oct 2019, 09:18
            0
            • L Lati
              17 Oct 2019, 09:09

              @JonB Last column's buttons are created when all table is filled (yes, using a loop but code is long and not related). Filtering is done through "QSortFilterProxyModel", so table is not filled again while filtering or after filter is removed (or the text in the textbox is changed). Therefore I cannot debug in the loop when the table is filled where i exists, while or after filtering.

              I wonder if I need to refresh the table after filter is removed

              J Offline
              J Offline
              JonB
              wrote on 17 Oct 2019, 09:18 last edited by
              #6

              @Lati
              I don't understand. The view is "filled again" when the filter changes, so the push buttons need to be created then.

              Separately, I don't know if setIndexWidget() is the right thing to do. https://doc.qt.io/qt-5/qabstractitemview.html#setIndexWidget

              This function should only be used to display static content within the visible area corresponding to an item of data. If you want to display custom dynamic content or implement a custom editor widget, subclass QStyledItemDelegate instead.

              L 1 Reply Last reply 17 Oct 2019, 09:28
              1
              • J JonB
                17 Oct 2019, 09:18

                @Lati
                I don't understand. The view is "filled again" when the filter changes, so the push buttons need to be created then.

                Separately, I don't know if setIndexWidget() is the right thing to do. https://doc.qt.io/qt-5/qabstractitemview.html#setIndexWidget

                This function should only be used to display static content within the visible area corresponding to an item of data. If you want to display custom dynamic content or implement a custom editor widget, subclass QStyledItemDelegate instead.

                L Offline
                L Offline
                Lati
                wrote on 17 Oct 2019, 09:28 last edited by
                #7

                @JonB It seems then the issue is related to the setIndexWidget() . I missed that setIndexWidget should only be used for static content and thank you for pointing this. I will update the code with QStyledItemDelegate instead and see if it works.

                Thanks again.

                J 1 Reply Last reply 17 Oct 2019, 09:30
                1
                • L Lati
                  17 Oct 2019, 09:28

                  @JonB It seems then the issue is related to the setIndexWidget() . I missed that setIndexWidget should only be used for static content and thank you for pointing this. I will update the code with QStyledItemDelegate instead and see if it works.

                  Thanks again.

                  J Offline
                  J Offline
                  JonB
                  wrote on 17 Oct 2019, 09:30 last edited by JonB
                  #8

                  @Lati
                  If I'm not mistaken, if @VRonin [call for him to confirm?] sees your setIndexWidget() he will go apoplectic :) He advocates styled item delegates/paint events only..... !

                  L 1 Reply Last reply 17 Oct 2019, 09:34
                  0
                  • J JonB
                    17 Oct 2019, 09:30

                    @Lati
                    If I'm not mistaken, if @VRonin [call for him to confirm?] sees your setIndexWidget() he will go apoplectic :) He advocates styled item delegates/paint events only..... !

                    L Offline
                    L Offline
                    Lati
                    wrote on 17 Oct 2019, 09:34 last edited by Lati
                    #9

                    @JonB :) I am sorry for him but unfortunately such beginners exist in every coding community like me. Let's see if @VRonin forgives me :D

                    (though I guess TableView's column headers are programmed properly! ;) )

                    1 Reply Last reply
                    0
                    • VRoninV Offline
                      VRoninV Offline
                      VRonin
                      wrote on 17 Oct 2019, 10:32 last edited by VRonin
                      #10

                      Who summoned my whrath?!

                      In this case you have to fill a QStyleOptionButton in the delegate's paint method and simply react to the clicked event of the view. It's just a bit tedious to type in the code but it's not complicated

                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                      ~Napoleon Bonaparte

                      On a crusade to banish setIndexWidget() from the holy land of Qt

                      L 1 Reply Last reply 17 Oct 2019, 11:20
                      2
                      • VRoninV VRonin
                        17 Oct 2019, 10:32

                        Who summoned my whrath?!

                        In this case you have to fill a QStyleOptionButton in the delegate's paint method and simply react to the clicked event of the view. It's just a bit tedious to type in the code but it's not complicated

                        L Offline
                        L Offline
                        Lati
                        wrote on 17 Oct 2019, 11:20 last edited by
                        #11

                        @VRonin Ask for your forgiveness your highness! :)

                        Thank you for your suggestion, can you please show me an example code or a sample project?

                        1 Reply Last reply
                        0
                        • VRoninV Offline
                          VRoninV Offline
                          VRonin
                          wrote on 17 Oct 2019, 11:49 last edited by VRonin
                          #12

                          Something like this

                          class ButtonDelegate : public QStyledItemDelegate {
                              Q_OBJECT
                              Q_DISABLE_COPY(ButtonDelegate)
                          private:
                          	QStyleOptionButton prepareButtonOption(const QStyleOptionViewItem &option) const{
                          		QStyleOptionButton buttonOption;
                                  buttonOption.text = tr("Add Interval");
                                  buttonOption.rect = option.rect
                                  buttonOption.features = QStyleOptionButton::None;
                                  buttonOption.direction = option.direction;
                                  buttonOption.fontMetrics = option.fontMetrics;
                                  buttonOption.palette = option.palette;
                                  buttonOption.styleObject = option.styleObject;
                          		return buttonOption;
                          	}
                          public:
                              explicit ButtonDelegate(QObject* parent = Q_NULLPTR)
                                  :QStyledItemDelegate(parent)
                              {}
                          
                              void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                                  Q_ASSERT(index.isValid());
                                  QStyleOptionViewItem opt = option;
                                  initStyleOption(&opt, index);
                                  const QWidget *widget = option.widget;
                                  QStyle *style = widget ? widget->style() : QApplication::style();
                                  QStyleOptionButton btnOption=prepareButtonOption(opt);
                                  style->drawControl(QStyle::CE_PushButton, &btnOption, painter, widget);
                              }
                          	QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                          		QStyleOptionButton btnOpt=prepareButtonOption(opt);
                                  const QSize fntSize = fontMetrics().size(Qt::TextShowMnemonic,btnOpt.text);
                          		const QWidget *widget = option.widget;
                                  QStyle *style = widget ? widget->style() : QApplication::style();
                          		return style->sizeFromContents(CT_PushButton,&btnOpt,fntSize,this);
                              }
                          }
                          

                          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                          ~Napoleon Bonaparte

                          On a crusade to banish setIndexWidget() from the holy land of Qt

                          J L 3 Replies Last reply 17 Oct 2019, 13:00
                          2
                          • VRoninV VRonin
                            17 Oct 2019, 11:49

                            Something like this

                            class ButtonDelegate : public QStyledItemDelegate {
                                Q_OBJECT
                                Q_DISABLE_COPY(ButtonDelegate)
                            private:
                            	QStyleOptionButton prepareButtonOption(const QStyleOptionViewItem &option) const{
                            		QStyleOptionButton buttonOption;
                                    buttonOption.text = tr("Add Interval");
                                    buttonOption.rect = option.rect
                                    buttonOption.features = QStyleOptionButton::None;
                                    buttonOption.direction = option.direction;
                                    buttonOption.fontMetrics = option.fontMetrics;
                                    buttonOption.palette = option.palette;
                                    buttonOption.styleObject = option.styleObject;
                            		return buttonOption;
                            	}
                            public:
                                explicit ButtonDelegate(QObject* parent = Q_NULLPTR)
                                    :QStyledItemDelegate(parent)
                                {}
                            
                                void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                                    Q_ASSERT(index.isValid());
                                    QStyleOptionViewItem opt = option;
                                    initStyleOption(&opt, index);
                                    const QWidget *widget = option.widget;
                                    QStyle *style = widget ? widget->style() : QApplication::style();
                                    QStyleOptionButton btnOption=prepareButtonOption(opt);
                                    style->drawControl(QStyle::CE_PushButton, &btnOption, painter, widget);
                                }
                            	QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                            		QStyleOptionButton btnOpt=prepareButtonOption(opt);
                                    const QSize fntSize = fontMetrics().size(Qt::TextShowMnemonic,btnOpt.text);
                            		const QWidget *widget = option.widget;
                                    QStyle *style = widget ? widget->style() : QApplication::style();
                            		return style->sizeFromContents(CT_PushButton,&btnOpt,fntSize,this);
                                }
                            }
                            
                            J Offline
                            J Offline
                            JonB
                            wrote on 17 Oct 2019, 13:00 last edited by
                            #13

                            @VRonin
                            That is indeed a lot of code compared against the original setIndexWidget(item, new QPushButton("..."));! Makes me want to stick with that approach ;-)

                            VRoninV L 2 Replies Last reply 17 Oct 2019, 13:07
                            0
                            • J JonB
                              17 Oct 2019, 13:00

                              @VRonin
                              That is indeed a lot of code compared against the original setIndexWidget(item, new QPushButton("..."));! Makes me want to stick with that approach ;-)

                              VRoninV Offline
                              VRoninV Offline
                              VRonin
                              wrote on 17 Oct 2019, 13:07 last edited by VRonin
                              #14

                              @JonB said in Problem while applying filter on QTableView with a button column:

                              Makes me want to stick with that approach

                              Teasing eh?! Cheeky sod!

                              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                              ~Napoleon Bonaparte

                              On a crusade to banish setIndexWidget() from the holy land of Qt

                              J 1 Reply Last reply 17 Oct 2019, 13:13
                              0
                              • VRoninV VRonin
                                17 Oct 2019, 13:07

                                @JonB said in Problem while applying filter on QTableView with a button column:

                                Makes me want to stick with that approach

                                Teasing eh?! Cheeky sod!

                                J Offline
                                J Offline
                                JonB
                                wrote on 17 Oct 2019, 13:13 last edited by
                                #15

                                @VRonin
                                I'm not the one who is teasing! When I discovered them I was quite happy with setIndexWidget() and whatever other methods which let you set a widget in a table etc. Simple, easy to use. Then you came along and put the fear of God into me & anyone else who chooses to use this approach, saying we would run out of memory and be damned for eternity, be kicked out of the EU, etc. ;-) So now I wouldn't dare use them....

                                1 Reply Last reply
                                0
                                • VRoninV VRonin
                                  17 Oct 2019, 11:49

                                  Something like this

                                  class ButtonDelegate : public QStyledItemDelegate {
                                      Q_OBJECT
                                      Q_DISABLE_COPY(ButtonDelegate)
                                  private:
                                  	QStyleOptionButton prepareButtonOption(const QStyleOptionViewItem &option) const{
                                  		QStyleOptionButton buttonOption;
                                          buttonOption.text = tr("Add Interval");
                                          buttonOption.rect = option.rect
                                          buttonOption.features = QStyleOptionButton::None;
                                          buttonOption.direction = option.direction;
                                          buttonOption.fontMetrics = option.fontMetrics;
                                          buttonOption.palette = option.palette;
                                          buttonOption.styleObject = option.styleObject;
                                  		return buttonOption;
                                  	}
                                  public:
                                      explicit ButtonDelegate(QObject* parent = Q_NULLPTR)
                                          :QStyledItemDelegate(parent)
                                      {}
                                  
                                      void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                                          Q_ASSERT(index.isValid());
                                          QStyleOptionViewItem opt = option;
                                          initStyleOption(&opt, index);
                                          const QWidget *widget = option.widget;
                                          QStyle *style = widget ? widget->style() : QApplication::style();
                                          QStyleOptionButton btnOption=prepareButtonOption(opt);
                                          style->drawControl(QStyle::CE_PushButton, &btnOption, painter, widget);
                                      }
                                  	QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                                  		QStyleOptionButton btnOpt=prepareButtonOption(opt);
                                          const QSize fntSize = fontMetrics().size(Qt::TextShowMnemonic,btnOpt.text);
                                  		const QWidget *widget = option.widget;
                                          QStyle *style = widget ? widget->style() : QApplication::style();
                                  		return style->sizeFromContents(CT_PushButton,&btnOpt,fntSize,this);
                                      }
                                  }
                                  
                                  L Offline
                                  L Offline
                                  Lati
                                  wrote on 17 Oct 2019, 14:04 last edited by
                                  #16

                                  @VRonin Thanks for the code! I will try to implement after few modifications.

                                  1 Reply Last reply
                                  0
                                  • J JonB
                                    17 Oct 2019, 13:00

                                    @VRonin
                                    That is indeed a lot of code compared against the original setIndexWidget(item, new QPushButton("..."));! Makes me want to stick with that approach ;-)

                                    L Offline
                                    L Offline
                                    Lati
                                    wrote on 17 Oct 2019, 14:07 last edited by
                                    #17

                                    @JonB Absolutely agree and disagree :) Wish filtering would work with setIndexWidget and I wouldn't loose time to implement the same thing with 100x more codes
                                    But for static tables, I will use setIndexWidget :)

                                    1 Reply Last reply
                                    0
                                    • VRoninV VRonin
                                      17 Oct 2019, 11:49

                                      Something like this

                                      class ButtonDelegate : public QStyledItemDelegate {
                                          Q_OBJECT
                                          Q_DISABLE_COPY(ButtonDelegate)
                                      private:
                                      	QStyleOptionButton prepareButtonOption(const QStyleOptionViewItem &option) const{
                                      		QStyleOptionButton buttonOption;
                                              buttonOption.text = tr("Add Interval");
                                              buttonOption.rect = option.rect
                                              buttonOption.features = QStyleOptionButton::None;
                                              buttonOption.direction = option.direction;
                                              buttonOption.fontMetrics = option.fontMetrics;
                                              buttonOption.palette = option.palette;
                                              buttonOption.styleObject = option.styleObject;
                                      		return buttonOption;
                                      	}
                                      public:
                                          explicit ButtonDelegate(QObject* parent = Q_NULLPTR)
                                              :QStyledItemDelegate(parent)
                                          {}
                                      
                                          void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                                              Q_ASSERT(index.isValid());
                                              QStyleOptionViewItem opt = option;
                                              initStyleOption(&opt, index);
                                              const QWidget *widget = option.widget;
                                              QStyle *style = widget ? widget->style() : QApplication::style();
                                              QStyleOptionButton btnOption=prepareButtonOption(opt);
                                              style->drawControl(QStyle::CE_PushButton, &btnOption, painter, widget);
                                          }
                                      	QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                                      		QStyleOptionButton btnOpt=prepareButtonOption(opt);
                                              const QSize fntSize = fontMetrics().size(Qt::TextShowMnemonic,btnOpt.text);
                                      		const QWidget *widget = option.widget;
                                              QStyle *style = widget ? widget->style() : QApplication::style();
                                      		return style->sizeFromContents(CT_PushButton,&btnOpt,fntSize,this);
                                          }
                                      }
                                      
                                      L Offline
                                      L Offline
                                      Lati
                                      wrote on 22 Oct 2019, 08:52 last edited by Lati
                                      #18

                                      @VRonin It is implemented, working good. However, I have an issue. When setItemDelegateForColumn is used, all created buttons at the column have the same properties (the last row button's properties). How will I know the row number of the button I clicked?

                                      I create the buttons as following:

                                      ButtonDelegateTableView * addIntervalButton =
                                              new ButtonDelegateTableView(ui->tableView,
                                                                          project,
                                                                          wellName,
                                                                          rowNumber);
                                      

                                      And, when I clicked on the button at the first row, I get the properties (well name, row number etc.) of the last row buttons.

                                      Capture.PNG

                                      1 Reply Last reply
                                      0

                                      1/18

                                      17 Oct 2019, 08:36

                                      • Login

                                      • Login or register to search.
                                      1 out of 18
                                      • First post
                                        1/18
                                        Last post
                                      0
                                      • Categories
                                      • Recent
                                      • Tags
                                      • Popular
                                      • Users
                                      • Groups
                                      • Search
                                      • Get Qt Extensions
                                      • Unsolved