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. How to change the text background in QTableView
QtWS25 Last Chance

How to change the text background in QTableView

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 4 Posters 1.1k 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.
  • D Offline
    D Offline
    deleted385
    wrote on 10 Nov 2021, 06:23 last edited by
    #1

    I've a QLineEdit to filter items in the QTableView:

    Window::Window(QWidget *parent) : QWidget(parent){
        aModel = new QStandardItemModel();
        aModel->setColumnCount(2);
        for (int i = 0; i < 3; i++) {
            auto col1 = new QStandardItem("Left " + QString::number(i + 1));
            auto col2 = new QStandardItem("Right " + QString::number(i + 1));
            col2->setTextAlignment(Qt::AlignVCenter|Qt::AlignRight);
            aModel->appendRow(QList<QStandardItem*>() << col1 << col2);
            col1 = new QStandardItem("Right " + QString::number(i + 1));
            col2 = new QStandardItem("Left " + QString::number(i + 1));
            col2->setTextAlignment(Qt::AlignVCenter|Qt::AlignRight);
            aModel->appendRow(QList<QStandardItem*>() << col1 << col2);
        }
        auto lay = new QVBoxLayout(this);
        auto combo = new CustomCombo(aModel);
        auto line = new QLineEdit(this);
        line->setPlaceholderText("Filter");
        line->setClearButtonEnabled(true);
        auto table = new QTableView(this);
        auto tableProxy = new QSortFilterProxyModel(this);
        tableProxy->setSourceModel(aModel);
        tableProxy->setFilterKeyColumn(0);
        tableProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
        table->setModel(tableProxy);
        table->horizontalHeader()->hide();
        table->verticalHeader()->hide();
        lay->addWidget(combo);
        lay->addWidget(line);
        lay->addWidget(table);
        setLayout(lay);
        connect(line, &QLineEdit::textChanged, [=]{tableProxy->setFilterFixedString(line->text());});
    }
    

    and it does the filter correctly:

    x1.gif

    What I want is highlight the matching string in the QTableView. Something like this:

    x2.gif

    J 1 Reply Last reply 10 Nov 2021, 08:05
    0
    • D deleted385
      10 Nov 2021, 06:23

      I've a QLineEdit to filter items in the QTableView:

      Window::Window(QWidget *parent) : QWidget(parent){
          aModel = new QStandardItemModel();
          aModel->setColumnCount(2);
          for (int i = 0; i < 3; i++) {
              auto col1 = new QStandardItem("Left " + QString::number(i + 1));
              auto col2 = new QStandardItem("Right " + QString::number(i + 1));
              col2->setTextAlignment(Qt::AlignVCenter|Qt::AlignRight);
              aModel->appendRow(QList<QStandardItem*>() << col1 << col2);
              col1 = new QStandardItem("Right " + QString::number(i + 1));
              col2 = new QStandardItem("Left " + QString::number(i + 1));
              col2->setTextAlignment(Qt::AlignVCenter|Qt::AlignRight);
              aModel->appendRow(QList<QStandardItem*>() << col1 << col2);
          }
          auto lay = new QVBoxLayout(this);
          auto combo = new CustomCombo(aModel);
          auto line = new QLineEdit(this);
          line->setPlaceholderText("Filter");
          line->setClearButtonEnabled(true);
          auto table = new QTableView(this);
          auto tableProxy = new QSortFilterProxyModel(this);
          tableProxy->setSourceModel(aModel);
          tableProxy->setFilterKeyColumn(0);
          tableProxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
          table->setModel(tableProxy);
          table->horizontalHeader()->hide();
          table->verticalHeader()->hide();
          lay->addWidget(combo);
          lay->addWidget(line);
          lay->addWidget(table);
          setLayout(lay);
          connect(line, &QLineEdit::textChanged, [=]{tableProxy->setFilterFixedString(line->text());});
      }
      

      and it does the filter correctly:

      x1.gif

      What I want is highlight the matching string in the QTableView. Something like this:

      x2.gif

      J Offline
      J Offline
      JonB
      wrote on 10 Nov 2021, 08:05 last edited by JonB 11 Oct 2021, 17:15
      #2

      @Emon-Haque
      You would need to write your own QStyledItemDelegate to do whatever highlighting and attach it to the QTableView via QAbstractItemView::setItemDelegate(QAbstractItemDelegate *delegate).

      You will then need to persuade the view to redraw every time you type a new character causing the view to want to change its highlighting. Normally a QTableView only redraws in response to a model data change.

      D 1 Reply Last reply 11 Nov 2021, 01:05
      4
      • J JonB
        10 Nov 2021, 08:05

        @Emon-Haque
        You would need to write your own QStyledItemDelegate to do whatever highlighting and attach it to the QTableView via QAbstractItemView::setItemDelegate(QAbstractItemDelegate *delegate).

        You will then need to persuade the view to redraw every time you type a new character causing the view to want to change its highlighting. Normally a QTableView only redraws in response to a model data change.

        D Offline
        D Offline
        deleted385
        wrote on 11 Nov 2021, 01:05 last edited by
        #3

        @JonB, sounds complicated. Could you please provide an example to help me understand it better?

        1 Reply Last reply
        0
        • D Offline
          D Offline
          deleted385
          wrote on 28 Nov 2021, 17:39 last edited by deleted385
          #4

          found a solution in other forum that works with this delegate:

          Delegate::Delegate(){ selection.setBackground(Qt::green); /*QTextCharFormat*/}
          void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{
              if(index.column() == 0){
                  QTextDocument doc(index.model()->data(index, Qt::DisplayRole).toString());
                  int position = 0;
                  QTextCursor cur;
                  do {
                      cur = doc.find(query, position); // query is private QString
                      cur.setCharFormat(selection);
                      cur.movePosition(QTextCursor::Right);
                      position = cur.position();
                  } while (!cur.isNull());
                  painter->save();
                  painter->translate(option.rect.x(), option.rect.y());
                  doc.drawContents(painter);
                  painter->restore();
                  if(option.state == QStyle::State_Selected){
                      qDebug() << "here";
                      painter->fillRect(option.rect, Qt::red);
                  }
              }
              else QStyledItemDelegate::paint(painter, option, index);
          }
          

          and these in mainwindow:

          Window::Window(QWidget *parent) : QWidget(parent){
              auto lay = new QVBoxLayout(this);
              auto hlay = new QHBoxLayout;
              auto textBox = new QLineEdit(this);
              auto label = new QLabel(this);
              label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
              hlay->addWidget(textBox);
              hlay->addWidget(label);
              auto table = new QTableView(this);
              lay->addLayout(hlay);
              lay->addWidget(table);
              auto model = new QStandardItemModel;
              for (int i = 0; i < 50000; i++) {
                  auto col1 = new QStandardItem("Column 1 : " + QString::number(i));
                  auto col2 = new QStandardItem("Column 2 : " + QString::number(i));
                  model->appendRow(QList<QStandardItem*>() << col1 << col2);
              }
              proxy = new QSortFilterProxyModel(table);
              proxy->setSourceModel(model);
              proxy->setFilterKeyColumn(0);
              table->setModel(proxy);
              delegate = new Delegate();
              table->setItemDelegate(delegate);
              table->horizontalHeader()->hide();
              table->verticalHeader()->hide();
              label->setText(locale().toString(proxy->rowCount()));
              connect(textBox, &QLineEdit::textChanged, [=]{
                  auto query = textBox->text();
                  delegate->setQuery(query);
                  proxy->setFilterFixedString(query);
                  proxy->invalidate();
                  label->setText(locale().toString(proxy->rowCount()));
              });
          }
          

          x1.gif

          Now, when I click on an item in column 1, it doesn't highlight and doesn't print qDebug() << "here";.

          mrjjM 1 Reply Last reply 28 Nov 2021, 19:17
          0
          • D Offline
            D Offline
            deleted385
            wrote on 28 Nov 2021, 19:03 last edited by deleted385
            #5

            Another problem is when I've long text in the column I want to highlight. Here's what I wanted to achieve:

            x2.gif

            When I typed the word heard in search textbox it found 752 occurrences in this WPF app. Now here's the table without delegate:

            x3.gif

            No idea why does it get 750 matches instead of 752! If I use delegate, I don't see any content in 7th column:

            x4.gif

            the delegate is same as before except the first line in paint instead of if(index.column() == 0), I, now have, if(index.column() == 6) and here's the content of Window:

            Window::Window(QWidget *parent) : QWidget(parent){
                auto lay = new QVBoxLayout(this);
                auto hlay = new QHBoxLayout;
                auto textBox = new QLineEdit(this);
                auto label = new QLabel(this);
                label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
                hlay->addWidget(textBox);
                hlay->addWidget(label);
                auto table = new QTableView(this);
                lay->addLayout(hlay);
                lay->addWidget(table);
                auto db = QSqlDatabase::addDatabase("QSQLITE");
                db.setDatabaseName("bukhari.db");
                db.open();
                auto model = new QSqlTableModel;
                model->setTable("Hadith");
                model->select();
                while (model->canFetchMore()) model->fetchMore();
                db.close();
                proxy = new QSortFilterProxyModel(table);
                proxy->setSourceModel(model);
                proxy->setFilterKeyColumn(6);
                table->setModel(proxy);
                delegate = new Delegate();
                table->setItemDelegate(delegate);
                table->verticalHeader()->hide();
                label->setText(locale().toString(proxy->rowCount()));
                connect(textBox, &QLineEdit::textChanged, [=]{
                    auto query = textBox->text();
                    delegate->setQuery(query);
                    proxy->setFilterFixedString(query);
                    proxy->invalidate();
                    label->setText(locale().toString(proxy->rowCount()));
                });
                table->setVerticalScrollMode(QTableView::ScrollPerPixel);
                //table->resizeRowsToContents();
            }
            

            wanted to see the whole content in the last column BUT couldn't make it work.

            EDIT

            Found the difference 2, In WPF I actually have converted string to lower before applying filter BUT in Qt I didn't and there is two Heard.

            1 Reply Last reply
            0
            • D deleted385
              28 Nov 2021, 17:39

              found a solution in other forum that works with this delegate:

              Delegate::Delegate(){ selection.setBackground(Qt::green); /*QTextCharFormat*/}
              void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{
                  if(index.column() == 0){
                      QTextDocument doc(index.model()->data(index, Qt::DisplayRole).toString());
                      int position = 0;
                      QTextCursor cur;
                      do {
                          cur = doc.find(query, position); // query is private QString
                          cur.setCharFormat(selection);
                          cur.movePosition(QTextCursor::Right);
                          position = cur.position();
                      } while (!cur.isNull());
                      painter->save();
                      painter->translate(option.rect.x(), option.rect.y());
                      doc.drawContents(painter);
                      painter->restore();
                      if(option.state == QStyle::State_Selected){
                          qDebug() << "here";
                          painter->fillRect(option.rect, Qt::red);
                      }
                  }
                  else QStyledItemDelegate::paint(painter, option, index);
              }
              

              and these in mainwindow:

              Window::Window(QWidget *parent) : QWidget(parent){
                  auto lay = new QVBoxLayout(this);
                  auto hlay = new QHBoxLayout;
                  auto textBox = new QLineEdit(this);
                  auto label = new QLabel(this);
                  label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
                  hlay->addWidget(textBox);
                  hlay->addWidget(label);
                  auto table = new QTableView(this);
                  lay->addLayout(hlay);
                  lay->addWidget(table);
                  auto model = new QStandardItemModel;
                  for (int i = 0; i < 50000; i++) {
                      auto col1 = new QStandardItem("Column 1 : " + QString::number(i));
                      auto col2 = new QStandardItem("Column 2 : " + QString::number(i));
                      model->appendRow(QList<QStandardItem*>() << col1 << col2);
                  }
                  proxy = new QSortFilterProxyModel(table);
                  proxy->setSourceModel(model);
                  proxy->setFilterKeyColumn(0);
                  table->setModel(proxy);
                  delegate = new Delegate();
                  table->setItemDelegate(delegate);
                  table->horizontalHeader()->hide();
                  table->verticalHeader()->hide();
                  label->setText(locale().toString(proxy->rowCount()));
                  connect(textBox, &QLineEdit::textChanged, [=]{
                      auto query = textBox->text();
                      delegate->setQuery(query);
                      proxy->setFilterFixedString(query);
                      proxy->invalidate();
                      label->setText(locale().toString(proxy->rowCount()));
                  });
              }
              

              x1.gif

              Now, when I click on an item in column 1, it doesn't highlight and doesn't print qDebug() << "here";.

              mrjjM Offline
              mrjjM Offline
              mrjj
              Lifetime Qt Champion
              wrote on 28 Nov 2021, 19:17 last edited by
              #6

              hi

              try with

              if (option.state & QStyle::State_Selected)

              and not

              if(option.state == QStyle::State_Selected){

              to see if you get the qDebug() << "here";

              D 1 Reply Last reply 28 Nov 2021, 19:32
              2
              • mrjjM mrjj
                28 Nov 2021, 19:17

                hi

                try with

                if (option.state & QStyle::State_Selected)

                and not

                if(option.state == QStyle::State_Selected){

                to see if you get the qDebug() << "here";

                D Offline
                D Offline
                deleted385
                wrote on 28 Nov 2021, 19:32 last edited by
                #7

                @mrjj, yes that works, now I get the red background and debug output. The paint is called twice when I click an item.

                mrjjM 1 Reply Last reply 28 Nov 2021, 20:12
                0
                • D deleted385
                  28 Nov 2021, 19:32

                  @mrjj, yes that works, now I get the red background and debug output. The paint is called twice when I click an item.

                  mrjjM Offline
                  mrjjM Offline
                  mrjj
                  Lifetime Qt Champion
                  wrote on 28 Nov 2021, 20:12 last edited by
                  #8

                  @Emon-Haque said in How to change the text background in QTableView:

                  @mrjj, yes that works, now I get the red background and debug output. The paint is called twice when I click an item.

                  The reason that it works is that option.state also have other states like item is editable and
                  enabled SET already (default values) so you should use the & to test for other states as its a bit flag thing.

                  Im not sure it means anything the paint is called twice. there can be many reasons for that.

                  1 Reply Last reply
                  2
                  • D Offline
                    D Offline
                    deleted385
                    wrote on 28 Nov 2021, 20:17 last edited by deleted385
                    #9

                    Had to set the document size to get some content:

                    Delegate::Delegate(){ selection.setBackground(Qt::green); /*QTextCharFormat*/}
                    void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{
                        if(index.column() == 6){
                            if(option.state & QStyle::State_Selected)
                                painter->fillRect(option.rect, Qt::gray);
                    
                            QTextDocument doc(index.model()->data(index, Qt::DisplayRole).toString());
                            doc.setPageSize(QSizeF(option.rect.width(), option.rect.height()));
                            int position = 0;
                            QTextCursor cur;
                            do {
                                cur = doc.find(query, position); // query is private QString
                                cur.setCharFormat(selection);
                                cur.movePosition(QTextCursor::Right);
                                position = cur.position();
                            } while (!cur.isNull());
                            painter->save();
                            painter->translate(option.rect.x(), option.rect.y());
                            doc.drawContents(painter);
                            painter->restore();
                        }
                        else QStyledItemDelegate::paint(painter, option, index);
                    }
                    

                    and have hidden all columns except the last and also set stretch and resizemode at the end of Window constructor:

                    ...
                    table->setVerticalScrollMode(QTableView::ScrollPerPixel);
                    table->hideColumn(0);
                    table->hideColumn(1);
                    table->hideColumn(2);
                    table->hideColumn(3);
                    table->hideColumn(4);
                    table->hideColumn(5);
                    table->horizontalHeader()->setStretchLastSection(true);
                    table->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
                    

                    and now it's like this:

                    x5.gif

                    1. it takes a long time to respond when I resize,
                    2. content is jumbled,
                    3. when I select an item it takes a while to response,
                    4. it doesn't show whole content in the cell,
                    5. feels like it doesn't scroll per pixel, and
                    6. when I type in search box it shows up those text after a long time.

                    EDIT

                    Here's link of the project in GitHub for testing. The sample database, bukhari.db, has been included.

                    1 Reply Last reply
                    1
                    • D Offline
                      D Offline
                      deleted385
                      wrote on 29 Nov 2021, 18:10 last edited by
                      #10

                      It's performance is similar without the delegate and with plain single column QListView. Looks like Qt model view architecture still isn't able to handle medium size dataset.

                      1 Reply Last reply
                      0
                      • U Offline
                        U Offline
                        uart
                        wrote on 30 Mar 2022, 06:51 last edited by
                        #11

                        Hello, I'm designing a combobox that contains 2 column items, and can do filters and shorting based on what is typed in the combobox, the problem is that the combobox doesn't always appear when I write a search.

                        void Dialog_Sell::getCmbStock(){
                        QStandardItemModel *model= new QStandardItemModel(arrStock.size(), 2, this);
                        for(int i=0; i<arrStock.size(); i++){
                        QStandardItem *kol1 = new QStandardItem( QString("%0").arg(code[i]) );
                        QStandardItem *kol2 = new QStandardItem( QString("%0").arg(name[i]) );
                        model->setItem(i, 0, kol1);
                        model->setItem(i, 1, kol2);
                        }

                        delegate = new Delegate();
                        QTableView* tableView = new QTableView( this );
                        QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
                        
                        proxyModel->setSourceModel(model);
                        proxyModel->setFilterKeyColumn(-1);
                        tableView->setModel( proxyModel);
                        tableView->setItemDelegate(delegate);
                        tableView->verticalHeader()->setVisible(false);
                        tableView->horizontalHeader()->setVisible(false);
                        tableView->setColumnWidth ( 0, 60 );
                        tableView->setColumnWidth ( 1, 260 );
                        tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
                        //tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
                        tableView->setStyleSheet("background-color: rgb(255, 255, 255);");
                        tableView->setAutoScroll(false);
                        tableView->setShowGrid(false);
                        tableView->setAlternatingRowColors(true);
                        tableView->setSortingEnabled(false);
                        tableView->setVerticalScrollMode(QTableView::ScrollPerPixel);
                        
                        
                        connect(ui->cmbStock, &QComboBox::editTextChanged, [=]{
                            QString query = ui->cmbStock->currentText();
                            delegate->setQuery(query);
                            //proxyModel->setFilterRegularExpression(query);
                            proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
                            proxyModel->invalidate();
                            //return ;
                        });
                        
                        
                        ui->cmbStock->setModel(proxyModel);
                        ui->cmbStock->setView( tableView );
                        ui->cmbStock->setStyleSheet("QComboBox QAbstractItemView {min-width: 250px;}"
                                                    "QComboBox { background-color: white; }");
                        

                        }

                        qt combo.png

                        1 Reply Last reply
                        0

                        • Login

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