如何解决在QHeaderView类内的Button触发的插槽中获取正确的父级
出于某种运动,我正在和 @ekhumoro 的a demo code一起玩(原始Qt4代码的所有功劳都归于他),他在其中插入了新行{{ 1}}个小部件放入QLineEdit
中的QHeaderview
中。我将代码移植到Qt5,并开始向标题添加其他小部件。 QTableView
,QComboBox
,空白(QCheckBox
)和QWidget
没问题。
但是,当我创建包含QPushButton
和QWidget
(是在“三”列中带有“ =”符号的QHBoxLayout
)的组合{ }}。所有控件都链接到相关的插槽,并且运行正常,包括第三列的组合字段中的QPushButton
,但该组合控件中的QLineEdit
除外。 QLineEdit
插槽def应该在值之间循环按钮的QPushButton
。我总是得到一个错误:
ChangeIntButtonSymbol(self)
,这表示与其他情况不同,此处的父级(由Text
检索)窗口小部件的上下文不同,def作为父级接收了AttributeError: 'FilterHeader' object has no attribute 'text'
类,而不是self.sender()
。我也尝试使用lambda传递参数:
FilterHeader
...但是结果完全相同(错误中的措词不同)。
很显然,我没有完全了解此btn
扩展的体系结构,并且犯了一些基本的错误。完整的演示下面,单击“ =”按钮时出现问题,赞赏任何解决方案或提示。
self.btn.clicked.connect(lambda: self.changebuttonsymbol.emit(self.btn))
解决方法
sender()是一种指示信号属于哪个对象的方法,很明显,changebuttonsymbol属于明显没有text()方法的标头。另一方面,每个类最好管理自己的对象,因此必须在标题中实现按钮文本的更改。
最后,如果使用复杂的小部件,最好将它放在一个类中。
import sys
from PyQt5.QtCore import pyqtSignal,Qt
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import (
QHeaderView,QWidget,QLineEdit,QApplication,QTableView,QVBoxLayout,QHBoxLayout,QComboBox,QPushButton,QCheckBox,)
class Widget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.btn = QPushButton()
self.btn.setText("=")
self.btn.setFixedWidth(20)
self.linee = QLineEdit()
self.linee.setPlaceholderText("Filter")
lay = QHBoxLayout(self)
lay.setContentsMargins(0,0)
lay.setSpacing(0)
lay.addWidget(self.btn)
lay.addWidget(self.linee)
class FilterHeader(QHeaderView):
filterActivated = pyqtSignal()
def __init__(self,parent):
super().__init__(Qt.Horizontal,parent)
self._editors = []
self._padding = 4
self.setStretchLastSection(True)
# self.setResizeMode(QHeaderView.Stretch)
self.setDefaultAlignment(Qt.AlignLeft | 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):
editor = self.create_editor(self.parent(),index)
self._editors.append(editor)
self.adjustPositions()
def create_editor(self,parent,index):
if index == 1: # Empty
editor = QWidget()
elif index == 2: # Number filter (>|=|<)
editor = Widget(parent)
editor.linee.returnPressed.connect(self.filterActivated)
editor.btn.clicked.connect(self.changebuttonsymbol)
elif index == 3:
editor = QComboBox(parent)
editor.addItems(["","Combo","One","Two","Three"])
editor.currentIndexChanged.connect(self.filterActivated)
elif index == 4:
editor = QPushButton(parent)
editor.clicked.connect(self.filterActivated)
editor.setText("Button")
elif index == 5:
editor = QCheckBox(parent)
editor.clicked.connect(self.filterActivated)
editor.setTristate(True)
editor.setCheckState(Qt.Checked)
editor.setText("CheckBox")
else:
editor = QLineEdit(parent)
editor.setPlaceholderText("Filter")
editor.returnPressed.connect(self.filterActivated)
return editor
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,height + self._padding)
else:
self.setViewportMargins(0,0)
super().updateGeometries()
self.adjustPositions()
def adjustPositions(self):
for index,editor in enumerate(self._editors):
if not isinstance(editor,QWidget):
continue
height = editor.sizeHint().height()
compensate_y = 0
compensate_x = 0
if type(editor) is QComboBox:
compensate_y = +2
elif type(editor) in (QWidget,Widget):
compensate_y = -1
elif type(editor) is QPushButton:
compensate_y = -1
elif type(editor) is QCheckBox:
compensate_y = 4
compensate_x = 4
editor.move(
self.sectionPosition(index) - self.offset() + 1 + compensate_x,height + (self._padding // 2) + 2 + compensate_y,)
editor.resize(self.sectionSize(index),height)
def filterText(self,index):
for editor in self._editors:
if hasattr(editor,"text") and callable(editor.text):
return editor.text()
return ""
def setFilterText(self,index,text):
for editor in self._editors:
if hasattr(editor,"setText") and callable(editor.setText):
editor.setText(text)
def clearFilters(self):
for editor in self._editors:
editor.clear()
def changebuttonsymbol(self):
nbtn = self.sender()
if nbtn.text() == "=":
nbtn.setText(">")
elif nbtn.text() == ">":
nbtn.setText("<")
else:
nbtn.setText("=")
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 = 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)
def handleFilterActivated(self):
header = self.view.horizontalHeader()
for index in range(header.count()):
if index != 4:
print(index,header.filterText(index))
else:
print("Button")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.setGeometry(800,100,600,300)
window.show()
sys.exit(app.exec_())
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。