Python 使用鼠标或键盘单击按钮时,PyQt小部件刷新行为不同
我不熟悉使用PyQt;我试图设置一个非常简单的主窗口,有3行编辑和1个按钮 以下是我想要的行为: 当前两个按钮的内容变为有效时,该按钮被启用 单击该按钮时,第二行编辑的内容将重置为空sting,并禁用该按钮 下面是代码-视图代码是使用Qt设计器和PUIC5生成的 一切似乎都很好,除了用鼠标单击按钮外-行编辑的内容显示为未擦除(实际上是),按钮显示为启用(实际上是禁用)。如果触发了窗口刷新(即最小化和还原),窗口小部件将正确显示。使用键盘单击按钮时,所有内容都正确刷新 我不知道是什么原因造成了这个奇怪的东西。。。任何帮助都将不胜感激 [编辑]:我刚刚发现,只有用回车键“点击”按钮时,它才能正常工作,如果使用空格,则会注意到相同的缺陷行为。。。这让我想知道“回车”和其他点击的意思有什么区别 先谢谢你 主要python代码:Python 使用鼠标或键盘单击按钮时,PyQt小部件刷新行为不同,python,pyqt,pyqt5,Python,Pyqt,Pyqt5,我不熟悉使用PyQt;我试图设置一个非常简单的主窗口,有3行编辑和1个按钮 以下是我想要的行为: 当前两个按钮的内容变为有效时,该按钮被启用 单击该按钮时,第二行编辑的内容将重置为空sting,并禁用该按钮 下面是代码-视图代码是使用Qt设计器和PUIC5生成的 一切似乎都很好,除了用鼠标单击按钮外-行编辑的内容显示为未擦除(实际上是),按钮显示为启用(实际上是禁用)。如果触发了窗口刷新(即最小化和还原),窗口小部件将正确显示。使用键盘单击按钮时,所有内容都正确刷新 我不知道是什么原因造成了这个
from PyQt5 import QtWidgets, QtCore
import sys
import view1
class Model(QtCore.QObject):
text1_changed = QtCore.pyqtSignal(str)
text2_changed = QtCore.pyqtSignal(str)
text3_changed = QtCore.pyqtSignal(str)
canprocess_changed = QtCore.pyqtSignal(bool)
def __init__(self):
super().__init__()
self._text1 = ''
self._text2 = ''
self._text3 = ''
self._canprocess = False
@property
def text1(self):
return self._text1
@text1.setter
def text1(self, value):
self._text1 = value
self.text1_changed.emit(value)
@property
def text2(self):
return self._text2
@text2.setter
def text2(self, value):
self._text2 = value
self.text2_changed.emit(value)
@property
def text3(self):
return self._text3
@text3.setter
def text3(self, value):
self._text3 = value
self.text3_changed.emit(value)
@property
def canprocess(self):
return self._canprocess
@canprocess.setter
def canprocess(self, value):
self._canprocess = value
self.canprocess_changed.emit(value)
class Controller(QtCore.QObject):
def __init__(self, model: Model):
super().__init__()
self._model = model
self._text1valid = False
self._text2valid = False
def istext1valid(self, text) -> bool:
return text[:3] == 'abc'
def istext2valid(self, text) -> bool:
return text[:3] == 'def'
def _validity_update(self):
self._model.canprocess = self._text1valid and self._text2valid
@QtCore.pyqtSlot(str)
def change_text1(self, text):
self._text1valid = self.istext1valid(text)
self._validity_update()
if self._text1valid:
self._model.text1 = text
@QtCore.pyqtSlot(str)
def change_text2(self, text):
self._text2valid = self.istext2valid(text)
self._validity_update()
if self._text2valid:
self._model.text2 = text
@QtCore.pyqtSlot(str)
def change_text3(self, text):
self._model.text3 = text
@QtCore.pyqtSlot()
def process(self):
# do real stuff
self._text2valid = False
self._validity_update()
self._model.text2 = ''
def init_view(self):
self._text1valid = False
self._text2valid = False
self._validity_update()
self._model.text1=''
self._model.text2=''
self._model.text3='an init value'
class MainAppWindow(QtWidgets.QMainWindow, view1.Ui_MainWindow):
def __init__(self, model: Model, controller: Controller):
super().__init__()
self._model = model
self._controller = controller
self.setupUi(self)
def setupUi(self, window):
super().setupUi(self)
self.bProceed.clicked.connect(self._controller.process)
self.ledit1.editingFinished.connect(lambda: self._controller.change_text1(self.ledit1.text()))
self.ledit2.editingFinished.connect(lambda: self._controller.change_text2(self.ledit2.text()))
self.ledit3.editingFinished.connect(lambda: self._controller.change_text3(self.ledit3.text()))
self._model.text1_changed.connect(self.ledit1.setText)
self._model.text2_changed.connect(self.ledit2.setText)
self._model.text3_changed.connect(self.ledit3.setText)
self._model.canprocess_changed.connect(self.bProceed.setEnabled)
self._controller.init_view()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
mainmodel = Model()
maincontroller = Controller(mainmodel)
MainWindow = MainAppWindow(mainmodel, maincontroller)
MainWindow.show()
sys.exit(app.exec_())
生成的用户界面:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(435, 204)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.formLayout = QtWidgets.QFormLayout(self.centralwidget)
self.formLayout.setObjectName("formLayout")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setObjectName("label")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
self.ledit1 = QtWidgets.QLineEdit(self.centralwidget)
self.ledit1.setObjectName("ledit1")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.ledit1)
self.ledit2 = QtWidgets.QLineEdit(self.centralwidget)
self.ledit2.setObjectName("ledit2")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.ledit2)
self.bProceed = QtWidgets.QPushButton(self.centralwidget)
self.bProceed.setFocusPolicy(QtCore.Qt.StrongFocus)
self.bProceed.setDefault(True)
self.bProceed.setObjectName("bProceed")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.bProceed)
self.ledit3 = QtWidgets.QLineEdit(self.centralwidget)
self.ledit3.setObjectName("ledit3")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.ledit3)
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setObjectName("label_3")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_3)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 435, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
MainWindow.setTabOrder(self.ledit1, self.ledit2)
MainWindow.setTabOrder(self.ledit2, self.bProceed)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_2.setText(_translate("MainWindow", "Text2"))
self.label.setText(_translate("MainWindow", "Text1"))
self.bProceed.setText(_translate("MainWindow", "Proceed"))
self.label_3.setText(_translate("MainWindow", "Text3"))
事实证明,自从MacOSX特定的v5.10版本以来,这一直是PyQt5的一个已知错误,它影响到几乎所有通过编程更改内容的小部件 解决方案是对任何内容已更改的小部件进行子类化,并显式调用repaint() 例如,以下是我用于按钮的代码:
class OSxPushButton(QtWidgets.QPushButton):
"""
A class to correct an OSX bug affecting widgets update when attributes are
programmatically modified.
"""
def __init__(self, parent=None):
super().__init__(parent)
def setEnabled(self, a0: bool) -> None:
super().setEnabled(a0)
self.repaint()
对于如此复杂的结构,有没有具体的原因?您可以通过一个单独的函数来实现相同的结果(启用/禁用按钮),该函数在任何行编辑发生更改时只检查所有行编辑的内容,而无需调用大量函数和不必要地连接太多信号。在任何情况下,你有什么PyQt版本,在什么操作系统上?@musicamante:发布的代码只是真实代码的一个模型-我只是试图重现真实应用程序的机制。Os:OSX catalina PyQT:5.15.0 Python:3.6Hi@Christian,你能添加一个到bug报告的链接吗?另外,
update()
通常优于repaint()
(请参阅)您好,@JKSH-我不确定pyQT是否有bug报告跟踪器。我从邮件列表中得到了答案和解决方案。下面是相应存档的链接:在PyQt==5.15.1的Windows上有相同的问题。update()和/或.repaint()对我来说很好@JKSH