Python 返回QtCore.QVariant() 如果列>自检列: index=index.sibling(index.row(),col-1) 返回super().数据(索引、角色) def setData(自身、索引、值、角色): 如果可自检_列!=-1: 行,
返回QtCore.QVariant() 如果列>自检列: index=index.sibling(index.row(),col-1) 返回super().数据(索引、角色) def setData(自身、索引、值、角色): 如果可自检_列!=-1: 行,列=index.row(),index.column() 如果col==self.checkable_列: 如果角色==QtCore.Qt.CheckStateRole: 如果行中有可自检的_值: 自我检查_值。放弃(行) 其他: self.checkable_values.add(行) self.dataChanged.emit(索引,索引,(角色,)) 返回真值 返回错误 如果列>自检列: index=index.sibling(index.row(),col-1) return super().setData(索引、值、角色) def headerData(self、section、orientation、role=QtCore.Qt.DisplayRole): 如果可自检_列!=-1: 如果节==self.checkable_列且方向==QtCore.Qt.Horizontal: 返回QtCore.QVariant() 如果节>可自检_列和方向==QtCore.Qt.Horizontal: 截面-=1 return super().headerData(节、方向、角色) def标志(自、索引): 如果可自检_列!=-1: col=index.column() 如果col==self.checkable_列: 返回QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled 如果列>自检列: index=index.sibling(index.row(),col-1) 返回super().标志(索引) 类CustomProxyModel(QtCore.QSortFilterProxyModel): def uuu init uuu(self,parent=None): super()。\uuuu init\uuuu(父级) self.\u filters=dict() @财产 def过滤器(自): 返回自我过滤器 def setFilter(自身、表达式、列): 如果是扩展: self.filters[column]=expresion self.filters中的elif列: del self.filters[列] self.invalidateFilter() def filterAcceptsRow(自身、源行、源父行): 对于列,在self.filters.items()中进行表达式: text=self.sourceModel().index(源\行、列、源\父级).data() regex=QtCore.QRegExp( expresion,QtCore.Qt.case不敏感,QtCore.QRegExp.RegExp ) 如果正则表达式indexIn(文本)=-1: 返回错误 返回真值 类myWindow(QtWidgets.QMainWindow): def uuu init uuu(self,parent=None): 超级(myWindow,self)。\uuuuu init\uuuuuu(父级) self.centralwidget=qtwidts.QWidget() self.lineEdit=qtwidts.QLineEdit() self.view=qtwidts.QTableView() self.comboBox=qtwidts.QComboBox() self.label=qtwidts.QLabel() self.gridLayout=qtwidts.QGridLayout(self.centralwidget) self.gridLayout.addWidget(self.lineEdit,0,1,1) self.gridLayout.addWidget(self.view,1,0,1,3) self.gridLayout.addWidget(self.comboBox,0,2,1,1) self.gridLayout.addWidget(self.label,0,0,1,1) self.setCentralWidget(self.centralwidget) self.label.setText(“正则表达式过滤器”) self.load_站点() self.comboBox.addItems([“{0}”.format(col)表示self.model.\u df.columns中的col]) self.lineEdit.textChanged.connect(self.on\u lineEdit\u textChanged) self.horizontalHeader=self.view.horizontalHeader() self.horizontalHeader.sectionClicked.connect( 单击self.on\u视图\u水平标题\u部分 ) def加载_站点(自身): df=pd.DataFrame( { “现场代码”:[“01”、“02”、“03”、“04”], “状态”:[“打开”、“打开”、“打开”、“关闭”], “位置”:[“东”、“北”、“南”、“东”], “数据质量”:[“差”、“中等”、“高”、“高”], } ) self.model=CheckablePandasModel(df) self.model.checkable_列=0 self.proxy=CustomProxyModel(self) self.proxy.setSourceModel(self.model) self.view.setModel(self.proxy) self.view.resizeColumnsToContents()的大小 @QtCore.pyqtSlot(int) 单击“视图”“水平标题”“部分”上的def(自,逻辑索引): 如果logicalIndex==self.model.checkable_列: 返回 self.menuValues=qtwidts.QMenu(self) self.comboBox.blockSignals(真) self.comboBox.setCurrentIndex( logicalIndex-1 如果logicalIndex>self.model.checkable\u列 else逻辑索引 ) self.comboBox.blockSignals(真) 值SIQUE=set( self.proxy.index(i,logicalIndex.data)() 对于范围内的i(self.proxy.rowCount()) ) actionAll=qtwidts.QAction(“全部”,self) self.menuValues.addAction(actionAll) self.menuValues.addSeparator() 对于i,枚举中的名称(valuesUnique): action=qtwidts.QAction(名称,self) 行动.设置数据(i) self.menuValues.addAction(操作) headerPos=self.view.mapToGlobal(self.horizontalHeader.pos()) pos=headerPos+QtCore.QPoint( 自水平收割台分段位置(logicalIndex), self.horizontalHeader.height(), ) action=self.menuValues.exec\uPOS 如果操作不是无: font=QtGui.QFont() 如果action.data()为None:#all self.proxy.setFilter(“,logicalIndex) 其他: font.setBold(真) self.proxy.setFilter(action.text(),logicalIndex) self.model.setFont(logicalIndex-1,字体) @QtCore.pyqtSlot(str) def on_lineEdit_textChanged(自我,文本): self.proxy.setFilter(文本,self.comboBox.currentIndex()+1) 如果名称=“\uuuuu main\uuuuuuuu”: 导入系统 app=qtwidts.QApplication(sys.argv)Python 返回QtCore.QVariant() 如果列>自检列: index=index.sibling(index.row(),col-1) 返回super().数据(索引、角色) def setData(自身、索引、值、角色): 如果可自检_列!=-1: 行,,python,pyqt,pyqt5,qsortfilterproxymodel,Python,Pyqt,Pyqt5,Qsortfilterproxymodel,返回QtCore.QVariant() 如果列>自检列: index=index.sibling(index.row(),col-1) 返回super().数据(索引、角色) def setData(自身、索引、值、角色): 如果可自检_列!=-1: 行,列=index.row(),index.column() 如果col==self.checkable_列: 如果角色==QtCore.Qt.CheckStateRole: 如果行中有可自检的_值: 自我检查_值。放弃(行) 其他: self.c
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
import pandas as pd
class PandasModel(QtCore.QAbstractTableModel):
def __init__(self, df=pd.DataFrame(), parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._df = df.copy()
self.bolds = dict()
def toDataFrame(self):
return self._df.copy()
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if orientation == QtCore.Qt.Horizontal:
if role == QtCore.Qt.DisplayRole:
try:
return self._df.columns.tolist()[section]
except (IndexError,):
return QtCore.QVariant()
elif role == QtCore.Qt.FontRole:
return self.bolds.get(section, QtCore.QVariant())
elif orientation == QtCore.Qt.Vertical:
if role == QtCore.Qt.DisplayRole:
try:
# return self.df.index.tolist()
return self._df.index.tolist()[section]
except (IndexError,):
return QtCore.QVariant()
return QtCore.QVariant()
def setFont(self, section, font):
self.bolds[section] = font
self.headerDataChanged.emit(QtCore.Qt.Horizontal, 0, self.columnCount())
def data(self, index, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if not index.isValid():
return QtCore.QVariant()
return QtCore.QVariant(str(self._df.iloc[index.row(), index.column()]))
def setData(self, index, value, role):
row = self._df.index[index.row()]
col = self._df.columns[index.column()]
if hasattr(value, 'toPyObject'):
# PyQt4 gets a QVariant
value = value.toPyObject()
else:
# PySide gets an unicode
dtype = self._df[col].dtype
if dtype != object:
value = None if value == '' else dtype.type(value)
self._df.set_value(row, col, value)
return True
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self._df.index)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self._df.columns)
def sort(self, column, order):
colname = self._df.columns.tolist()[column]
self.layoutAboutToBeChanged.emit()
self._df.sort_values(colname, ascending= order == QtCore.Qt.AscendingOrder, inplace=True)
self._df.reset_index(inplace=True, drop=True)
self.layoutChanged.emit()
class CustomProxyModel(QtCore.QSortFilterProxyModel):
def __init__(self, parent=None):
super().__init__(parent)
self._filters = dict()
@property
def filters(self):
return self._filters
def setFilter(self, expresion, column):
if expresion:
self.filters[column] = expresion
elif column in self.filters:
del self.filters[column]
self.invalidateFilter()
def filterAcceptsRow(self, source_row, source_parent):
for column, expresion in self.filters.items():
text = self.sourceModel().index(source_row, column, source_parent).data()
regex = QtCore.QRegExp(
expresion, QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp
)
if regex.indexIn(text) == -1:
return False
return True
class CheckBoxDelegate(QtWidgets.QItemDelegate):
"""
A delegate that places a fully functioning QCheckBox cell of the column to which it's applied.
"""
def __init__(self, parent):
QtWidgets.QItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
"""
Important, otherwise an editor is created if the user clicks in this cell.
"""
return None
def paint(self, painter, option, index):
"""
Paint a checkbox without the label.
"""
self.drawCheck(painter, option, option.rect, QtCore.Qt.Unchecked if int(index.data()) == 0 else QtCore.Qt.Checked)
def editorEvent(self, event, model, option, index):
'''
Change the data in the model and the state of the checkbox
if the user presses the left mousebutton and this cell is editable. Otherwise do nothing.
'''
if not int(index.flags() & QtCore.Qt.ItemIsEditable) > 0:
return False
if event.type() == QtCore.QEvent.MouseButtonRelease and event.button() == QtCore.Qt.LeftButton:
# Change the checkbox-state
self.setModelData(None, model, index)
return True
return False
def setModelData (self, editor, model, index):
'''
The user wanted to change the old state in the opposite.
'''
model.setData(index, 1 if int(index.data()) == 0 else 0, QtCore.Qt.EditRole)
class TableView(QtWidgets.QTableView):
"""
A simple table to demonstrate the QComboBox delegate.
"""
def __init__(self, *args, **kwargs):
QtWidgets.QTableView.__init__(self, *args, **kwargs)
self.setItemDelegateForColumn(0, CheckBoxDelegate(self))
class myWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(myWindow, self).__init__(parent)
self.centralwidget = QtWidgets.QWidget(self)
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.view = TableView(self)
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.label = QtWidgets.QLabel(self.centralwidget)
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1)
self.gridLayout.addWidget(self.view, 1, 0, 1, 3)
self.gridLayout.addWidget(self.comboBox, 0, 2, 1, 1)
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.setCentralWidget(self.centralwidget)
self.label.setText("Regex Filter")
self.load_sites()
self.comboBox.addItems(["{0}".format(col) for col in self.model._df.columns])
self.lineEdit.textChanged.connect(self.on_lineEdit_textChanged)
self.comboBox.currentIndexChanged.connect(self.on_comboBox_currentIndexChanged)
self.horizontalHeader = self.view.horizontalHeader()
self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
def load_sites(self):
df = pd.DataFrame({'site_codes': ['01', '02', '03', '04'],
'status': ['open', 'open', 'open', 'closed'],
'Location': ['east', 'north', 'south', 'east'],
'data_quality': ['poor', 'moderate', 'high', 'high']})
self.model = PandasModel(df)
self.proxy = CustomProxyModel(self)
self.proxy.setSourceModel(self.model)
self.view.setModel(self.proxy)
self.view.resizeColumnsToContents()
# delegate = CheckBoxDelegate(None)
# self.view.setItemDelegateForColumn(0, delegate)
@QtCore.pyqtSlot(int)
def on_view_horizontalHeader_sectionClicked(self, logicalIndex):
self.logicalIndex = logicalIndex
self.menuValues = QtWidgets.QMenu(self)
self.signalMapper = QtCore.QSignalMapper(self)
self.comboBox.blockSignals(True)
self.comboBox.setCurrentIndex(self.logicalIndex)
self.comboBox.blockSignals(True)
valuesUnique = self.model._df.iloc[:, self.logicalIndex].unique()
actionAll = QtWidgets.QAction("All", self)
actionAll.triggered.connect(self.on_actionAll_triggered)
self.menuValues.addAction(actionAll)
self.menuValues.addSeparator()
for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))):
action = QtWidgets.QAction(actionName, self)
self.signalMapper.setMapping(action, actionNumber)
action.triggered.connect(self.signalMapper.map)
self.menuValues.addAction(action)
self.signalMapper.mapped.connect(self.on_signalMapper_mapped)
headerPos = self.view.mapToGlobal(self.horizontalHeader.pos())
posY = headerPos.y() + self.horizontalHeader.height()
posX = headerPos.x() + self.horizontalHeader.sectionPosition(self.logicalIndex)
self.menuValues.exec_(QtCore.QPoint(posX, posY))
@QtCore.pyqtSlot()
def on_actionAll_triggered(self):
filterColumn = self.logicalIndex
self.proxy.setFilter("", filterColumn)
font = QtGui.QFont()
self.model.setFont(filterColumn, font)
@QtCore.pyqtSlot(int)
def on_signalMapper_mapped(self, i):
stringAction = self.signalMapper.mapping(i).text()
filterColumn = self.logicalIndex
self.proxy.setFilter(stringAction, filterColumn)
font = QtGui.QFont()
font.setBold(True)
self.model.setFont(filterColumn, font)
@QtCore.pyqtSlot(str)
def on_lineEdit_textChanged(self, text):
self.proxy.setFilter(text, self.proxy.filterKeyColumn())
@QtCore.pyqtSlot(int)
def on_comboBox_currentIndexChanged(self, index):
self.proxy.setFilterKeyColumn(index)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
main = myWindow()
main.show()
main.resize(2000, 800)
sys.exit(app.exec_())