Python PyQt 信号并不总是有效
Python PyQt signals are not always working
希望我在回答第一个问题时正确地遵循了此处的指南。我正在尝试创建一个具有 MVC 结构的 GUI。我很难理解为什么我的信号并不总是被控制器接收到。我知道我缺少一些简单的东西。我附上了我用作指南的简单计算器的代码。我删除了大部分功能以尽可能简化它。它现在只有 3 个原始按钮和我自己的按钮。为了调试,我只是在你按下按钮时打印出按钮上的值。
import sys
# Import QApplication and the required widgets from PyQt5.QtWidgets
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QMainWindow
from PySide2.QtWidgets import QWidget
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QGridLayout
from PySide2.QtWidgets import QLineEdit
from PySide2.QtWidgets import QPushButton
from PySide2.QtWidgets import QVBoxLayout
from functools import partial
ERROR_MSG = 'ERROR'
# Create a subclass of QMainWindow to setup the calculator's GUI
class PyCalcUi(QMainWindow):
"""PyCalc's View (GUI)."""
def __init__(self):
"""View initializer."""
super().__init__()
# Set some main window's properties
self.setWindowTitle('PyCalc')
self.setFixedSize(235, 235)
# Set the central widget and the general layout
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
# Create the display and the buttons
self._createDisplay()
self._createButtons()
def _createDisplay(self):
"""Create the display."""
# Create the display widget
self.display = QLineEdit()
# Set some display's properties
self.display.setFixedHeight(35)
self.display.setAlignment(Qt.AlignRight)
self.display.setReadOnly(True)
# Add the display to the general layout
self.generalLayout.addWidget(self.display)
def _createButtons(self):
"""Create the buttons."""
self.buttons = {}
buttonsLayout = QGridLayout()
# Button text | position on the QGridLayout
buttons = {'7': (0, 0),
'8': (0, 1),
'9': (0, 2),
}
# Create the buttons and add them to the grid layout
for btnText, pos in buttons.items():
self.buttons[btnText] = QPushButton(btnText)
self.buttons[btnText].setFixedSize(40, 40)
buttonsLayout.addWidget(self.buttons[btnText], pos[0], pos[1])
self.mybutton = QPushButton("5")
buttonsLayout.addWidget(self.mybutton,1,0)
# Add buttonsLayout to the general layout
self.generalLayout.addLayout(buttonsLayout)
# Create a Controller class to connect the GUI and the model
class PyCalcCtrl:
"""PyCalc Controller class."""
def __init__(self, model, view):
"""Controller initializer."""
self._evaluate = model
self._view = view
# Connect signals and slots
self._connectSignals()
def _printthis(self):
print("Hi")
def _printthat(self, buttonvalue):
print(buttonvalue)
def _connectSignals(self):
"""Connect signals and slots."""
self._view.mybutton.clicked.connect(self._printthis)
for btnText, btn in self._view.buttons.items():
btn.clicked.connect(partial(self._printthat, btnText))
# Create a Model to handle the calculator's operation
def evaluateExpression(expression):
"""Evaluate an expression."""
try:
result = str(eval(expression, {}, {}))
except Exception:
result = ERROR_MSG
return result
# Client code
def main():
"""Main function."""
# Create an instance of QApplication if it doesn't exist
pycalc = QApplication.instance()
if pycalc is None:
pycalc = QApplication(sys.argv)
# Show the calculator's GUI
view = PyCalcUi()
view.show()
# Create instances of the model and the controller
model = evaluateExpression
PyCalcCtrl(model=model, view=view)
# Execute the calculator's main loop
sys.exit(pycalc.exec_())
if __name__ == '__main__':
main()
这组代码有效,但是如果我注释掉
for btnText, btn in self._view.buttons.items():
btn.clicked.connect(partial(self._printthat, btnText))
self._view.mybutton.clicked.connect(self._printthis)
将不再有效。
btn.clicked.connect(partial(self._printthat, btnText))
行允许我在 def _connectSignals(self): 中输入的任何其他信号起作用。该行的哪个方面正在实现 mybutton 信号没有做的事情?
问题是因为PyCalcCtrl对象没有分配给变量,所以它会被销毁,因此“_printthis”方法将无法访问。另一方面,当使用 functools.partial 时,PyCalcCtrl 的对象 class 被分配给该函数的范围,这就是它起作用的原因。
解决方法是将 PyCalcCtrl 对象赋值给一个变量:
<b>ctrl =</b> PyCalcCtrl(model=model, view=view)
希望我在回答第一个问题时正确地遵循了此处的指南。我正在尝试创建一个具有 MVC 结构的 GUI。我很难理解为什么我的信号并不总是被控制器接收到。我知道我缺少一些简单的东西。我附上了我用作指南的简单计算器的代码。我删除了大部分功能以尽可能简化它。它现在只有 3 个原始按钮和我自己的按钮。为了调试,我只是在你按下按钮时打印出按钮上的值。
import sys
# Import QApplication and the required widgets from PyQt5.QtWidgets
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QMainWindow
from PySide2.QtWidgets import QWidget
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QGridLayout
from PySide2.QtWidgets import QLineEdit
from PySide2.QtWidgets import QPushButton
from PySide2.QtWidgets import QVBoxLayout
from functools import partial
ERROR_MSG = 'ERROR'
# Create a subclass of QMainWindow to setup the calculator's GUI
class PyCalcUi(QMainWindow):
"""PyCalc's View (GUI)."""
def __init__(self):
"""View initializer."""
super().__init__()
# Set some main window's properties
self.setWindowTitle('PyCalc')
self.setFixedSize(235, 235)
# Set the central widget and the general layout
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
# Create the display and the buttons
self._createDisplay()
self._createButtons()
def _createDisplay(self):
"""Create the display."""
# Create the display widget
self.display = QLineEdit()
# Set some display's properties
self.display.setFixedHeight(35)
self.display.setAlignment(Qt.AlignRight)
self.display.setReadOnly(True)
# Add the display to the general layout
self.generalLayout.addWidget(self.display)
def _createButtons(self):
"""Create the buttons."""
self.buttons = {}
buttonsLayout = QGridLayout()
# Button text | position on the QGridLayout
buttons = {'7': (0, 0),
'8': (0, 1),
'9': (0, 2),
}
# Create the buttons and add them to the grid layout
for btnText, pos in buttons.items():
self.buttons[btnText] = QPushButton(btnText)
self.buttons[btnText].setFixedSize(40, 40)
buttonsLayout.addWidget(self.buttons[btnText], pos[0], pos[1])
self.mybutton = QPushButton("5")
buttonsLayout.addWidget(self.mybutton,1,0)
# Add buttonsLayout to the general layout
self.generalLayout.addLayout(buttonsLayout)
# Create a Controller class to connect the GUI and the model
class PyCalcCtrl:
"""PyCalc Controller class."""
def __init__(self, model, view):
"""Controller initializer."""
self._evaluate = model
self._view = view
# Connect signals and slots
self._connectSignals()
def _printthis(self):
print("Hi")
def _printthat(self, buttonvalue):
print(buttonvalue)
def _connectSignals(self):
"""Connect signals and slots."""
self._view.mybutton.clicked.connect(self._printthis)
for btnText, btn in self._view.buttons.items():
btn.clicked.connect(partial(self._printthat, btnText))
# Create a Model to handle the calculator's operation
def evaluateExpression(expression):
"""Evaluate an expression."""
try:
result = str(eval(expression, {}, {}))
except Exception:
result = ERROR_MSG
return result
# Client code
def main():
"""Main function."""
# Create an instance of QApplication if it doesn't exist
pycalc = QApplication.instance()
if pycalc is None:
pycalc = QApplication(sys.argv)
# Show the calculator's GUI
view = PyCalcUi()
view.show()
# Create instances of the model and the controller
model = evaluateExpression
PyCalcCtrl(model=model, view=view)
# Execute the calculator's main loop
sys.exit(pycalc.exec_())
if __name__ == '__main__':
main()
这组代码有效,但是如果我注释掉
for btnText, btn in self._view.buttons.items():
btn.clicked.connect(partial(self._printthat, btnText))
self._view.mybutton.clicked.connect(self._printthis)
将不再有效。
btn.clicked.connect(partial(self._printthat, btnText))
行允许我在 def _connectSignals(self): 中输入的任何其他信号起作用。该行的哪个方面正在实现 mybutton 信号没有做的事情?
问题是因为PyCalcCtrl对象没有分配给变量,所以它会被销毁,因此“_printthis”方法将无法访问。另一方面,当使用 functools.partial 时,PyCalcCtrl 的对象 class 被分配给该函数的范围,这就是它起作用的原因。
解决方法是将 PyCalcCtrl 对象赋值给一个变量:
<b>ctrl =</b> PyCalcCtrl(model=model, view=view)