Python 项目在QTableView中的可视位置
我正在使用PyQt5/PySide2。我有一个带有Python 项目在QTableView中的可视位置,python,pyqt,pyside,Python,Pyqt,Pyside,我正在使用PyQt5/PySide2。我有一个带有QSortFilterProxyModel的QTableView,数据由QStandardItemModel处理 我正在使用QStandardItemModel.findItems()方法在第一个表行中查找一些单元格。结果是QStandardItems的列表。现在我想按GUI表中显示的行(即用户看到它们的方式)对这些项目进行排序。有什么办法可以存档吗?。将代理或模型索引转换为“视图”索引 我认为这可以使用QSortFilterProxyModel
QSortFilterProxyModel
的QTableView
,数据由QStandardItemModel
处理
我正在使用QStandardItemModel.findItems()
方法在第一个表行中查找一些单元格。结果是QStandardItem
s的列表。现在我想按GUI表中显示的行(即用户看到它们的方式)对这些项目进行排序。有什么办法可以存档吗?。将代理或模型索引转换为“视图”索引
我认为这可以使用QSortFilterProxyModel.mapFromSource()
方法完成,但代理索引似乎没有所需的顺序
以下是一个用PyQt5编写的最小可复制示例:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from collections import deque
from random import randint
class Splash(QWidget):
def __init__(self):
super().__init__()
# create model
self.model = QStandardItemModel(self)
self.model.setHorizontalHeaderLabels(["column 1", "column 2"])
# create sort proxy
self.proxy = NumberSortModel()
self.proxy.setSourceModel(self.model)
# create view
self.table = CustomQTableView(self)
self.table.setGeometry(0, 0, 275, 575)
self.table.setModel(self.proxy)
self.table.setSortingEnabled(True)
# create buttons
button = QPushButton('Find cells containing 1', self)
button.move(300, 70)
button.clicked.connect(lambda: self.table.search_string("1"))
button1 = QPushButton('next', self)
button1.move(300, 100)
button1.clicked.connect(self.table._search_next)
button2 = QPushButton('previous', self)
button2.move(300, 130)
button2.clicked.connect(self.table._search_previous)
# fill model
for i in range(15):
self.model.appendRow([QStandardItem(str(i)),
QStandardItem(str(randint(1, 100)))])
self.show()
# takes care of the coloring of results
class _HighlightDelegate(QStyledItemDelegate):
def __init__(self, parent=None) -> None:
QStyledItemDelegate.__init__(self, parent)
self._parent = parent
def paint(self, painter: "QPainter", option: "QStyleOptionViewItem",
index: "QModelIndex"):
painter.save()
if len(self._parent.proxy_indices) > 0:
if index == self._parent.proxy_indices[0]:
painter.fillRect(option.rect, Qt.red)
elif index in self._parent.proxy_indices:
painter.fillRect(option.rect, option.palette.highlight())
else:
if (option.state & QStyle.State_Selected):
painter.fillRect(option.rect, option.palette.highlight())
elif (option.state & QStyle.State_None):
painter.fillRect(option.rect, option.palette.base())
painter.drawText(option.rect, Qt.AlignLeft, index.data(Qt.DisplayRole))
painter.restore()
class CustomQTableView(QTableView):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.real_indices = deque()
self.proxy_indices = deque()
self.horizontalHeader().sortIndicatorChanged.connect(self._re_sort)
self.setItemDelegate(_HighlightDelegate(self))
def _re_sort(self):
# pretty print indices
def ind_to_py(indices):
py_ind = list()
for i in indices:
py_ind.append((i.row(), i.column(), i.data(Qt.DisplayRole)))
return py_ind
print("real ", ind_to_py(self.real_indices))
print("proxy ", ind_to_py(self.proxy_indices))
real_ind, proxy_ind = zip(*sorted(zip(self.real_indices, self.proxy_indices),
key=lambda x: (x[1].row(),
x[1].column())))
self.real_indices = deque(real_ind)
self.proxy_indices = deque(proxy_ind)
print("sorted real ", ind_to_py(self.real_indices))
print("sorted proxy", ind_to_py(self.proxy_indices))
print("---------------------------------------------------")
self.re_draw()
@property
def _model(self):
return self.model().sourceModel()
def re_draw(self):
self.viewport().update()
# we are always searching only in first column
def search_string(self, string: str):
indices = self._model.findItems(string, Qt.MatchContains, 0)
# get QModelIndex from found data
self.real_indices = deque([i.index() for i in indices])
self.proxy_indices = [QPersistentModelIndex(self.model().mapFromSource(i))
for i in self.real_indices]
# sort indeces according to their row and column
self._re_sort()
# update the view to highlight data
self.re_draw()
def _search_next(self):
self.real_indices.rotate(-1)
self.proxy_indices.rotate(-1)
self.re_draw()
def _search_previous(self):
self.real_indices.rotate(1)
self.proxy_indices.rotate(1)
self.re_draw()
# custom implementation to sort according to numbers not strings
class NumberSortModel(QSortFilterProxyModel):
def lessThan(self, left_index: "QModelIndex",
right_index: "QModelIndex") -> bool:
left_var: str = left_index.data(Qt.EditRole)
right_var: str = right_index.data(Qt.EditRole)
try:
return float(left_var) < float(right_var)
except (ValueError, TypeError):
pass
try:
return left_var < right_var
except TypeError: # in case of NoneType
return True
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
ex = Splash()
sys.exit(app.exec_())
从PyQt5.QtWidgets导入*
从PyQt5.QtGui导入*
从PyQt5.QtCore导入*
从集合导入deque
从随机导入randint
类启动(QWidget):
定义初始化(自):
super()。\uuuu init\uuuuu()
#创建模型
self.model=QStandardItemModel(self)
self.model.setHorizontalHeaderLabels([“第1列”、“第2列”])
#创建排序代理
self.proxy=NumberSortModel()
self.proxy.setSourceModel(self.model)
#创建视图
self.table=CustomQTableView(self)
self.table.setGeometry(0,0275575)
self.table.setModel(self.proxy)
self.table.setSortingEnabled(真)
#创建按钮
button=QPushButton('查找包含1'的单元格,self)
按钮。移动(300,70)
按钮。单击。连接(lambda:self.table.search_字符串(“1”))
button1=QPushButton(“下一步”,自我)
按钮1.移动(300100)
按钮1.单击.连接(self.table.\u搜索\u下一步)
button2=QPushButton('上一个',自身)
按钮2.移动(300130)
按钮2。单击。连接(self.table.\u搜索\u上一个)
#填充模型
对于范围(15)内的i:
self.model.appendRow([QStandardItem(str(i)),
QStandardItem(str(randint(1100)))]
self.show()
#负责结果的着色
类\u HighlightDelegate(QStyledItemDelegate):
def uuu init uuu(self,parent=None)->None:
QStyledItemDelegate.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
self.\u parent=父
def油漆(自身,油漆工:“QPaint”,选项:“QStyleOptionViewItem”,
索引:“QModelIndex”):
保存
如果len(self.\u parent.proxy\u索引)>0:
如果索引==self.\u parent.proxy\u索引[0]:
painter.fillRect(option.rect,Qt.red)
elif索引在self.\u parent.proxy\u索引中:
painter.fillRect(option.rect,option.palete.highlight())
其他:
如果(选择option.state和QStyle.state):
painter.fillRect(option.rect,option.palete.highlight())
elif(option.state和QStyle.state\u None):
painter.fillRect(option.rect,option.palete.base())
painter.drawText(option.rect、Qt.AlignLeft、index.data(Qt.DisplayRole))
恢复
类CustomQTableView(QTableView):
定义初始化(self,*args,**kwargs)->无:
super()
self.real_index=deque()
self.proxy_index=deque()
self.horizontalHeader().sortInderChanged.connect(self.\u re\u sort)
self.setItemDelegate(_HighlightDelegate(self))
定义重新排序(自):
#漂亮的打印索引
定义索引到索引(索引):
py_ind=list()
对于指数中的i:
py_ind.append((i.row()、i.column()、i.data(Qt.DisplayRole)))
返回py_ind
打印(“真实”,索引到副本(self.real索引))
打印(“代理”,索引到副本(自代理索引))
实索引,代理索引=zip(*已排序(zip(self.real\u索引,self.proxy\u索引),
key=lambda x:(x[1]。行(),
x[1]。列())
self.real\u index=deque(real\u ind)
self.proxy\u index=deque(proxy\u ind)
打印(“已排序的实数”,ind_to_py(self.real_索引))
打印(“排序的代理”,索引到副本(自代理索引))
打印(“--------------------------------------------------------------”)
self.re_draw()
@财产
def_型号(自):
返回self.model().sourceModel()
def重新绘制(自):
self.viewport().update()
#我们总是只在第一列搜索
定义搜索字符串(self,字符串:str):
index=self.\u model.findItems(字符串,Qt.MatchContains,0)
#从找到的数据中获取QModelIndex
self.real_index=deque([i.index()表示索引中的i])
self.proxy_index=[QPersistentModelIndex(self.model().mapFromSource(i))
对于我自己来说,真实的指数]
#根据索引的行和列对索引进行排序
self.\u re\u sort()
#更新视图以突出显示数据
self.re_draw()
定义搜索下一步(自我):
自实数索引旋转(-1)
self.proxy_索引旋转(-1)
self.re_draw()
定义搜索上一个(自我):
自实指数旋转(1)
self.proxy_索引旋转(1)
self.re_draw()
#根据数字而不是字符串进行排序的自定义实现
类别编号排序模型(QSortFilterProxyModel):
def lessThan(自左索引:“QModelIndex”,
右索引:“QModelIndex”)->bool:
left_var:str=left_index.data(Qt.EditRole)
right\u var:str=right\u index.data(Qt.EditRole)
尝试:
返回浮点(左变量)<浮点(右变量)
除了(ValueError、TypeError):
通过
尝试:
返回左变量<右变量
类型错误除外:#如果为非类型
返回真值
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
导入系统
app=QApplication(sys.argv)
ex=飞溅()
sys.exit(app.exec_())