单击一个按钮并更改 MainWindow

Click a button and change MainWindow

我正在学习 Qt,我对如何更改 MainWindow 的某些功能很感兴趣。

我正在尝试这段代码,但是当我点击第一个按钮时出现了一些错误:

Traceback (most recent call last):
File "\main.py", line 15, in run_the_first_button_was_clicked
the_first_button_was_clicked(self)
File "clickedButton.py", line 15, in the_first_button_was_clicked
self.button2.clicked.connect(self.the_second_button_was_clicked) 

AttributeError: 'MainWindow' object has no attribute 'the_second_button_was_clicked'

我做错了什么(我怎么能做到'the_second_button_was_clicked'可调用)?

main.py

from PySide2.QtWidgets import QApplication, QMainWindow, QPushButton
import sys
from clickedButton import the_first_button_was_clicked, the_second_button_was_clicked


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("MainWindow")
        self.button1 = QPushButton("button1")
        self.button1.clicked.connect(self.run_the_first_button_was_clicked)
        self.setCentralWidget(self.button1)

    def run_the_first_button_was_clicked(self):
        the_first_button_was_clicked(self)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

clickedButton.py

from PySide2.QtWidgets import QPushButton
from PySide2 import QtCore


def the_first_button_was_clicked(self):
    self.setWindowTitle("the_first_button_was_clicked next will be the_second_button_was_clicked")
    self.resize(800, 600)

    self.button1.setText("the_first_button_was_clicked")
    self.button1.setEnabled(False)

    self.button2 = QPushButton("button2")
    self.button2.setGeometry(QtCore.QRect(100, 100, 150, 150))
    self.button2.setVisible(True)
    self.button2.clicked.connect(self.the_second_button_was_clicked)


def the_second_button_was_clicked(self):
    self.setWindowTitle("the_second_button_was_clicked")
    self.resize(600, 800)

此问题与 PyQt 无关,但与 classes 和实例的工作方式有关。

实例方法的第一个参数总是引用class的实例,它被称为self只是为了约定:它实际上可能是以任何方式命名,只要其语法有效,就像任何其他变量一样。

当使用在外部 a class声明的函数时,最好避免这种命名约定(主要是为了避免在阅读代码时造成混淆)。

发生的事情是 def the_first_button_was_clicked(self): 中的 self 引用 MainWindow 的实例,它没有 the_second_button_was_clicked 方法,因此出现 AttributeError 异常。

重点是你的两个函数只是函数,而不是方法(它们是实例或class): 他们 不是 class.

的成员

另请注意,创建与函数的直接连接将不起作用,因为 self 参数仅在函数是方法时才“创建”。
正如 Heike 在评论中指出的那样,一种可能性是使用 lambda,它允许保留对实例的实际引用,同时直接调用将使用提供的 self 参数执行的函数,恰好正如您在 run_the_first_button_was_clicked.

中所做的那样

在下面的示例中,我将 self 替换为 mainWinInstance 以使事情更清楚(这就是在这些情况下不应使用 self 的原因).

def the_first_button_was_clicked(mainWinInstance):
    # we reference the function locally to this script, adding the "self" argument
    mainWinInstance.button2.clicked.connect(lambda: 
        the_second_button_was_clicked(<b>mainWinInstance</b>))

def the_second_button_was_clicked(mainWinInstance):
    # "self" (mainWinInstance) was manually added to the function arguments
    mainWinInstance.setWindowTitle("the_second_button_was_clicked")
    mainWinInstance.resize(600, 800)

另一种可能性是使第二个函数成为实例的成员:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # ...
        <b>self.the_second_button_was_clicked = the_second_button_was_clicked</b>

:

def the_first_button_was_clicked(mainWinInstance):
    # ...
    <b>mainWinInstance.the_second_button_was_clicked = the_second_button_was_clicked</b>
    mainWinInstance.button2.clicked.connect(mainWinInstance.the_second_button_was_clicked)

两种情况下,必须在连接之前创建实例属性(这也意味着在第一个调用第一个函数之前例)。

考虑到这种“猴子修补”方法只应在特殊情况下使用(主要是由于对象无法被子class编辑,因为是自主创建的),尤其是在 class 之外完成的情况下甚至脚本。

在大多数情况下,您所做的事情被认为是不好的做法,如果您使用自己创建的 class 进行此操作,则可能您的实施确实有问题:您最好重新考虑您的逻辑并在 class 本身内实施所有内容。