【发布时间】:2020-12-03 03:33:58
【问题描述】:
只是为了好玩,我在玩 @ekhumoro 的 a demo code(原始 Qt4 代码的所有功劳归他所有),他在其中插入了一行新的 QLineEdit 小部件进入QTableView 的QHeaderview。我将代码移植到 Qt5 并开始向标题添加不同的小部件。 QComboBox、QCheckBox、空白空间 (QWidget) 和 QPushButton 没有问题。
但是,当我创建一个组合 QWidget 时,它包含一个 QHBoxLayout 和一个 QPushButton(它是带有“=”符号的那个,在“三”列中)和一个 QLineEdit。所有控件都链接到相关插槽并且运行良好,包括来自第三列中组合字段的QLineEdit,但来自该组合小部件的QPushButton 除外。 ChangeIntButtonSymbol(self) 插槽定义应该在 值之间循环按钮的 Text。我总是得到一个错误:
AttributeError: 'FilterHeader' object has no attribute 'text'
这表明,与其他情况不同,这里父小部件的上下文(由self.sender() 检索)是不同的,def 接收FilterHeader 类作为父类而不是btn。我也尝试使用 lambda 传递参数:
self.btn.clicked.connect(lambda: self.changebuttonsymbol.emit(self.btn))
...但结果完全相同(错误中的措辞不同)。
很明显,我没有完全理解这个QHeaderView 扩展的架构并犯了一些基本错误。完整的演示如下,单击“=”按钮时会出现问题,感谢任何解决方案或提示。
import sys
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QHeaderView, QWidget, QLineEdit, QApplication, QTableView, QVBoxLayout,QHBoxLayout, QLineEdit, QComboBox, QPushButton, QCheckBox
from PyQt5.QtCore import pyqtSignal
class FilterHeader(QHeaderView):
filterActivated = QtCore.pyqtSignal()
changebuttonsymbol = QtCore.pyqtSignal()
def __init__(self, parent):
super().__init__(QtCore.Qt.Horizontal, parent)
self._editors = []
self._padding = 4
self.setStretchLastSection(True)
#self.setResizeMode(QHeaderView.Stretch)
self.setDefaultAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self.setSortIndicatorShown(False)
self.sectionResized.connect(self.adjustPositions)
parent.horizontalScrollBar().valueChanged.connect(self.adjustPositions)
def setFilterBoxes(self, count):
while self._editors:
editor = self._editors.pop()
editor.deleteLater()
for index in range(count):
if index == 1: # Empty
editor = QWidget()
elif index == 2: # Number filter (>|=|<)
editor = QWidget(self.parent())
edlay = QHBoxLayout()
edlay.setContentsMargins(0, 0, 0, 0)
edlay.setSpacing(0)
self.btn = QPushButton()
self.btn.setText("=")
self.btn.setFixedWidth(20)
#self.btn.clicked.connect(lambda: self.changebuttonsymbol.emit(self.btn))
self.btn.clicked.connect(self.changebuttonsymbol.emit)
#btn.setViewportMargins(0, 0, 0, 0)
linee = QLineEdit(self.parent())
linee.setPlaceholderText('Filter')
linee.returnPressed.connect(self.filterActivated.emit)
#linee.setViewportMargins(0, 0, 0, 0)
edlay.addWidget(self.btn)
edlay.addWidget(linee)
editor.setLayout(edlay)
elif index == 3:
editor = QComboBox(self.parent())
editor.addItems(["", "Combo", "One", "Two", "Three"])
editor.currentIndexChanged.connect(self.filterActivated.emit)
elif index == 4:
editor = QPushButton(self.parent())
editor.clicked.connect(self.filterActivated.emit)
editor.setText("Button")
elif index == 5:
editor = QCheckBox(self.parent())
editor.clicked.connect(self.filterActivated.emit)
editor.setTristate(True)
editor.setCheckState(1)
editor.setText("CheckBox")
else: # string filter
editor = QLineEdit(self.parent())
editor.setPlaceholderText('Filter')
editor.returnPressed.connect(self.filterActivated.emit)
self._editors.append(editor)
self.adjustPositions()
def sizeHint(self):
size = super().sizeHint()
if self._editors:
height = self._editors[0].sizeHint().height()
size.setHeight(size.height() + height + self._padding)
return size
def updateGeometries(self):
if self._editors:
height = self._editors[0].sizeHint().height()
self.setViewportMargins(0, 0, 0, height + self._padding)
else:
self.setViewportMargins(0, 0, 0, 0)
super().updateGeometries()
self.adjustPositions()
def adjustPositions(self):
for index, editor in enumerate(self._editors):
height = editor.sizeHint().height()
CompensateY = 0
CompensateX = 0
if self._editors[index].__class__.__name__ == "QComboBox":
CompensateY = +2
elif self._editors[index].__class__.__name__ == "QWidget":
CompensateY = -1
elif self._editors[index].__class__.__name__ == "QPushButton":
CompensateY = -1
elif self._editors[index].__class__.__name__ == "QCheckBox":
CompensateY = 4
CompensateX = 4
editor.move( self.sectionPosition(index) - self.offset() + 1 + CompensateX, height + (self._padding // 2) + 2 + CompensateY)
editor.resize(self.sectionSize(index), height)
def filterText(self, index):
if 0 <= index < len(self._editors):
if self._editors[index].__class__.__name__ == "QLineEdit":
return self._editors[index].text()
return ''
def setFilterText(self, index, text):
if 0 <= index < len(self._editors):
self._editors[index].setText(text)
def clearFilters(self):
for editor in self._editors:
editor.clear()
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = QTableView()
layout = QVBoxLayout(self)
layout.addWidget(self.view)
header = FilterHeader(self.view)
self.view.setHorizontalHeader(header)
model = QtGui.QStandardItemModel(self.view)
model.setHorizontalHeaderLabels('One Two Three Four Five Six Seven'.split())
self.view.setModel(model)
header.setFilterBoxes(model.columnCount())
header.filterActivated.connect(self.handleFilterActivated)
header.changebuttonsymbol.connect(self.ChangeIntButtonSymbol)
def handleFilterActivated(self):
header = self.view.horizontalHeader()
for index in range(header.count()):
if index != 4:
print((index, header.filterText(index)))
else:
print("Button")
def ChangeIntButtonSymbol(self):
print("Int button triggered")
nbtn = self.sender()
print(str(nbtn))
if nbtn.text() == "=":
nbtn.setText(">")
elif nbtn.text() == ">":
nbtn.setText("<")
else:
nbtn.setText("=")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.setGeometry(800, 100, 600, 300)
window.show()
sys.exit(app.exec_())
【问题讨论】:
标签: python pyqt pyqt5 qtableview qheaderview