如何迭代 QTreeView 并为所有匹配的单元格着色? [英] How to iterate over a QTreeView and color all matched cells?
本文介绍了如何迭代 QTreeView 并为所有匹配的单元格着色?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
按下搜索按钮时,我想在 QTreeView 的所有项目(又名单元格)中进行搜索,并通过 CSS 样式为与搜索到的文本单元格匹配的所有单元格着色.
when pressing the search button, I would like to search in all items (aka cells) of a QTreeView and color all cells matching the searched text cells via a CSS style.
这可能吗?
当前代码(完整的工作示例):
Code currently (full working example):
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class App(QtWidgets.QWidget):
MAIL_RANGE = 4
ID, FROM, SUBJECT, DATE = range(MAIL_RANGE)
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(10, 10, 640, 240)
self.dataGroupBox = QtWidgets.QGroupBox("Inbox")
self.dataView = QtWidgets.QTreeView(
rootIsDecorated=False,
alternatingRowColors=True,
selectionMode=QtWidgets.QAbstractItemView.ExtendedSelection,
editTriggers=QtWidgets.QAbstractItemView.NoEditTriggers,
selectionBehavior=QtWidgets.QAbstractItemView.SelectRows,
)
dataLayout = QtWidgets.QHBoxLayout()
dataLayout.addWidget(self.dataView)
self.dataGroupBox.setLayout(dataLayout)
model = App.createMailModel(self)
self.dataView.setModel(model)
for i in range(0, 2):
self.dataView.resizeColumnToContents(i)
self.addMail(model, 1, 'service@github.com', 'Your Github Donation','03/25/2017 02:05 PM')
self.addMail(model, 2, 'support@github.com', 'Github Projects','02/02/2017 03:05 PM')
self.addMail(model, 3, 'service@phone.com', 'Your Phone Bill','01/01/2017 04:05 PM')
self.addMail(model, 4, 'service@abc.com', 'aaaYour Github Donation','03/25/2017 02:05 PM')
self.addMail(model, 5, 'support@def.com', 'bbbGithub Projects','02/02/2017 03:05 PM')
self.addMail(model, 6, 'service@xyz.com', 'cccYour Phone Bill','01/01/2017 04:05 PM')
self.dataView.setColumnHidden(0, True)
self.leSearch = QtWidgets.QLineEdit()
self.pbSearch = QtWidgets.QPushButton(
"Search", clicked=self.on_pbSearch_clicked
)
hlay = QtWidgets.QHBoxLayout()
hlay.addWidget(self.leSearch)
hlay.addWidget(self.pbSearch)
mainLayout = QtWidgets.QVBoxLayout(self)
mainLayout.addLayout(hlay)
mainLayout.addWidget(self.dataGroupBox)
@staticmethod
def createMailModel(parent):
model = QtGui.QStandardItemModel(0, App.MAIL_RANGE, parent)
for c, text in zip(
(App.ID, App.FROM, App.SUBJECT, App.DATE),
("ID", "From", "Subject", "Date"),
):
model.setHeaderData(c, QtCore.Qt.Horizontal, text)
return model
def addMail(self, model, mailID, mailFrom, subject, date):
model.insertRow(0)
for c, text in zip(
(App.ID, App.FROM, App.SUBJECT, App.DATE),
(mailID, mailFrom, subject, date),
):
model.setData(model.index(0, c), text)
@QtCore.pyqtSlot()
def on_pbSearch_clicked(self):
text = self.leSearch.text()
self.leSearch.clear()
if text:
start = self.dataView.model().index(0, 2)
# find index
ixs = self.dataView.model().match(
start,
QtCore.Qt.DisplayRole,
text,
flags=QtCore.Qt.MatchStartsWith,
)
if ixs:
ix = ixs[0]
# scroll to index
self.dataView.scrollTo(ix)
ix_from = ix.sibling(ix.row(), 0)
ix_to = ix.sibling(
ix.row(), self.dataView.model().columnCount() - 1
)
# select row
self.dataView.selectionModel().select(
QtCore.QItemSelection(ix_from, ix_to),
QtCore.QItemSelectionModel.SelectCurrent,
)
else:
self.dataView.clearSelection()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())
参见方法 on_pbSearch_clicked
-> 这里所有匹配的行都被标记为选中.相反,我想通过 CSS 样式为单元格着色.
See method on_pbSearch_clicked
-> here all the matched rows are flagged as selected. Instead I would like to color the cells via a CSS style.
推荐答案
您可以使用委托设置背景和文本颜色,并且您可以使用角色来指示应该绘制哪个单元格.
You can set the background and text color using a delegate, and to indicate which cell should be painted you can use a role.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
MatchRole = QtCore.Qt.UserRole + 1000
class HighlightDelegate(QtWidgets.QStyledItemDelegate):
@property
def background(self):
if not hasattr(self, "_background"):
self._background = QtGui.QBrush()
return self._background
@background.setter
def background(self, brush):
self._background = QtGui.QBrush(brush)
@property
def foreground(self):
if not hasattr(self, "_foreground"):
self._foreground = QtGui.QBrush()
return self._foreground
@foreground.setter
def foreground(self, brush):
self._foreground = QtGui.QBrush(brush)
def initStyleOption(self, option, index):
super(HighlightDelegate, self).initStyleOption(option, index)
if index.data(MatchRole):
if self.background != QtGui.QBrush():
option.backgroundBrush = self.background
if self.foreground != QtGui.QBrush():
option.palette.setBrush(QtGui.QPalette.Text, self.foreground)
class App(QtWidgets.QWidget):
MAIL_RANGE = 4
ID, FROM, SUBJECT, DATE = range(MAIL_RANGE)
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(10, 10, 640, 240)
self.dataGroupBox = QtWidgets.QGroupBox("Inbox")
self.dataView = QtWidgets.QTreeView(
rootIsDecorated=False,
alternatingRowColors=True,
selectionMode=QtWidgets.QAbstractItemView.ExtendedSelection,
editTriggers=QtWidgets.QAbstractItemView.NoEditTriggers,
selectionBehavior=QtWidgets.QAbstractItemView.SelectRows,
)
delegate = HighlightDelegate(self.dataView)
self.dataView.setItemDelegate(delegate)
delegate.background = QtGui.QColor("gray")
delegate.foreground = QtGui.QColor("salmon")
self.dataView.viewport().update()
dataLayout = QtWidgets.QHBoxLayout()
dataLayout.addWidget(self.dataView)
self.dataGroupBox.setLayout(dataLayout)
model = App.createMailModel(self)
self.dataView.setModel(model)
for i in range(0, 2):
self.dataView.resizeColumnToContents(i)
self.addMail(model, 1, 'service@github.com', 'Your Github Donation','03/25/2017 02:05 PM')
self.addMail(model, 2, 'support@github.com', 'Github Projects','02/02/2017 03:05 PM')
self.addMail(model, 3, 'service@phone.com', 'Your Phone Bill','01/01/2017 04:05 PM')
self.addMail(model, 4, 'service@abc.com', 'aaaYour Github Donation','03/25/2017 02:05 PM')
self.addMail(model, 5, 'support@def.com', 'bbbGithub Projects','02/02/2017 03:05 PM')
self.addMail(model, 6, 'service@xyz.com', 'cccYour Phone Bill','01/01/2017 04:05 PM')
self.dataView.setColumnHidden(0, True)
for i in range(self.dataView.model().columnCount()):
self.dataView.header().setSectionResizeMode(i, QtWidgets.QHeaderView.Stretch)
self.leSearch = QtWidgets.QLineEdit()
self.pbSearch = QtWidgets.QPushButton(
"Search", clicked=self.on_pbSearch_clicked
)
hlay = QtWidgets.QHBoxLayout()
hlay.addWidget(self.leSearch)
hlay.addWidget(self.pbSearch)
mainLayout = QtWidgets.QVBoxLayout(self)
mainLayout.addLayout(hlay)
mainLayout.addWidget(self.dataGroupBox)
@staticmethod
def createMailModel(parent):
model = QtGui.QStandardItemModel(0, App.MAIL_RANGE, parent)
for c, text in zip(
(App.ID, App.FROM, App.SUBJECT, App.DATE),
("ID", "From", "Subject", "Date"),
):
model.setHeaderData(c, QtCore.Qt.Horizontal, text)
return model
def addMail(self, model, mailID, mailFrom, subject, date):
model.insertRow(0)
for c, text in zip(
(App.ID, App.FROM, App.SUBJECT, App.DATE),
(mailID, mailFrom, subject, date),
):
model.setData(model.index(0, c), text)
@QtCore.pyqtSlot()
def on_pbSearch_clicked(self):
text = self.leSearch.text()
# self.leSearch.clear()
model = self.dataView.model()
# clear
for column in range(model.columnCount()):
for row in range(model.rowCount()):
ix = model.index(row, column)
model.setData(ix, False, MatchRole)
if text:
for column in range(model.columnCount()):
start = self.dataView.model().index(0, column)
ixs = self.dataView.model().match(
start,
QtCore.Qt.DisplayRole,
text,
hits=-1,
flags=QtCore.Qt.MatchContains,
)
for ix in ixs:
model.setData(ix, True, MatchRole)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())
这篇关于如何迭代 QTreeView 并为所有匹配的单元格着色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文