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
Forum Updated to NodeBB v4.3 + New Features

How to change the text background in QTableView

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 4 Posters 1.1k Views 3 Watching
  • 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 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

    JonBJ 1 Reply Last reply
    0
    • D deleted385

      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

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #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
      4
      • JonBJ JonB

        @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 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 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
          0
          • D Offline
            D Offline
            deleted385
            wrote on 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

              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 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
              2
              • mrjjM mrjj

                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 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
                0
                • D deleted385

                  @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 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 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 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 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