How to change the text background in QTableView
-
I've a
QLineEdit
to filter items in theQTableView
: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:
What I want is highlight the matching string in the
QTableView
. Something like this: -
@Emon-Haque
You would need to write your ownQStyledItemDelegate
to do whatever highlighting and attach it to theQTableView
viaQAbstractItemView::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. -
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())); }); }
Now, when I click on an item in column 1, it doesn't highlight and doesn't print
qDebug() << "here";
. -
Another problem is when I've long text in the column I want to highlight. Here's what I wanted to achieve:
When I typed the word
heard
in search textbox it found 752 occurrences in this WPF app. Now here's the table without delegate:No idea why does it get 750 matches instead of 752! If I use delegate, I don't see any content in 7th column:
the delegate is same as before except the first line in
paint
instead ofif(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
. -
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";
-
@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.
-
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:
- it takes a long time to respond when I resize,
- content is jumbled,
- when I select an item it takes a while to response,
- it doesn't show whole content in the cell,
- feels like it doesn't scroll per pixel, and
- 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. -
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. -
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; }");
}