在 PyQT 中,为什么有些小部件在调用它们之前需要 "self" 参数,而其他小部件则不需要

In PyQT why somes widgets needs the "self" parameter before calling them, while others don't

我对“self”参数与一些小部件(如(QLineEdit)的使用有点困惑,事实上,在学习使用 QLabel 小部件时,我曾经调用 class 而没有self 参数,或者在使用 QLineEdit 小部件时,如果没有“self”参数,小部件将无法工作,这是我正在处理的代码:

# Import necessary modules
import sys

from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton
from PyQt5.QtCore import Qt

class EntryWindow(QWidget): # Inherits QWidget

def __init__(self): # Constructor
    super().__init__() # Initializer which calls constructor for QWidget

    self.initializeUI() # Call function used to set up window

def initializeUI(self):
    """
    Initialize the window and display its contents to the screen
    """
    self.setGeometry(400, 300, 400, 200)
    self.setWindowTitle('QLineEdit Widget')
    self.displayWidgets()

    self.show() # Show everything

def displayWidgets(self):
    '''
    Setup the QLineEdit and other widgets.
    '''
    # Create name label and line edit widgets
    QLabel("Please enter your name below.", self).move(100, 20)
    name_label = QLabel("Name:", self)
    name_label.move(55, 70)

    self.name_entry = QLineEdit(self)
    self.name_entry.move(120, 68)
    self.name_entry.resize(200, 25) # Change size of entry field

    self.name_entry.setAlignment(Qt.AlignLeft) # The default alignment

    
    text_font = self.name_entry.font() # Get font option from the Qlineedit
    text_font.setPointSize(12)         # Modify font size
    #text_font.setBold(True)           # Bold
    self.name_entry.setFont(text_font) # Apply font
    

    self.clear_button = QPushButton('Clear text', self)
    self.clear_button.clicked.connect(self.clearEntries)
    self.clear_button.move(120, 130)

    self.exit_button = QPushButton("Exit", self)
    self.exit_button.clicked.connect(self.exitApplication)
    self.exit_button.move(240, 130)

def clearEntries(self):
    
    sender = self.sender()
    if sender.text() == 'Clear text':
        self.name_entry.clear()

def exitApplication(self):

    sender = self.sender()
    if sender.text() == "Exit":
        self.close() # Close the window

   # Run program
   if __name__ == '__main__':
       app = QApplication(sys.argv)
       window = EntryWindow()
       sys.exit(app.exec_())

所以这就是我感到困惑的地方,当使用 QLabel 时,我之前不必放置“self”参数,或者当使用 QLineEdit 时,我必须放置“self”否则我的代码不会工作:

QLabel("Please enter your name below.", self).move(100, 20)
self.name_entry = QLineEdit(self)

注意顶部的导入语句

from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton

QLabel 和 QLineEdit 可以在文档中看到 https://doc.qt.io/qtforpython/PySide2/QtWidgets/QLabel.html https://doc.qt.io/qtforpython/PySide2/QtWidgets/QLineEdit.html

都以一个QWidget作为参数。作为第二个参数传递的 self 表示当前的 QWidget 类型。对于class中的其他方法,self用于调用实例方法。

self 名称是一种 Python 约定,用于指示对象的 实例 。当在对象构造函数中设置为参数时,它通常用于为新对象提供对创建它的对象的引用,通常称为“父对象”。请注意,虽然 self 通常用作父参数,但您可以将 any QWidget 实例设置为父参数。

在 Qt 术语中,它不仅表示对象结构的“父级”中的角色,而且还导致两个重要方面:

  • 在 QObjects 的世界里(QWidget 从中继承)这有助于内存管理:当一个父对象被删除时,它的所有子对象也被删除。查找子对象(使用 findChild()findChildren())也很有用,它们是另一个人的直系子女或 [曾,...] 孙辈。
  • 当创建带有 QWidget 父级的小部件时,该小部件也仅“绘制在”它内部:它只能在父级边界内可见,而不是在父级边界外可见;请注意,这通常是可选的,因为大多数时候您会将小部件添加到布局管理器(但您没有),它会自动将小部件重新设置为由该布局管理的小部件:如果它是另一个的子级小部件,它已从中删除并添加到新的小部件中。还要考虑如果一个小部件没有父级并且没有添加到布局中,它被认为是一个“顶级小部件”(一个独立的 window),并且如果 show()setVisible(True) 被调用它将有自己的 window.
    这意味着如果小部件 父项并且父项变得可见,则子项也将自动可见(除非 hide()setVisible() 被显式调用)。

请注意,虽然 没有父级 的 QWidget 始终是顶级 window,但 具有 parent 可以 是顶层 window,如果它设置了 QtCore.Qt.Window 标志(在构造函数中使用 f 关键字,或者setWindowFlags())。这在 widget 必须是顶级 window 时很有用,但父关系仍必须保留,不仅用于内存管理(当父 window 关闭并删除时,应删除任何子级以及)但出于交互目的:例如,使用 QDialogs( 独立的 windows)设置父级很重要,这样它们就可以 modal 到该父项,这意味着在对话框关闭之前不会在父项上发生 keyboard/mouse 交互。

最后,重要的是要记住,在 python 中“即时”创建小部件有一个(有时被认为是不连贯的)结果:如果没有 python 引用被提供给小部件 但是小部件父级,它不会被垃圾收集。

考虑以下几点:

def test1(self):
    someDialog = QtWidgets.QDialog()
    someDialog.show()

这可能会显示一个 window 只是一瞬间,然后它会立即消失。

def test2(self):
    someDialog = QtWidgets.QDialog(self)
    someDialog.show()

在这种情况下,对话框不会消失,那是因为它有父级,PyQt 知道它,它不会尝试删除它。

即使这实际上是有效的(但是,不,不要这样做):

def test2b(self):
    QtWidgets.QDialog(self).show()

类似的结果,但只是表面上的:

def test3(self):
    self.someDialog = QtWidgets.QDialog()
    self.someDialog.show()

在上面的例子中,视觉结果可能与test2相同,但是如果test3再次被调用 当对话框仍然可见时,它将 删除 当前对话框并创建一个新对话框:那是因为对话框没有父级,并用 self.someDialog 覆盖一个新实例将导致 python 释放前一个实例,这将告诉 Qt 它可以安全地删除它,因为它没有父级。

最后,没有必要将父级设置为小部件,只要它们被添加到布局中即可(这是首选方法,因为 非常 不鼓励使用固定几何形状),因为一旦[将]设置在实际父级上,布局就会自动设置父级。

请注意,QDialog 通常显示为 exec_(),以便将其正确显示为父模态并按应有的方式使用它。

首先,问题或差异与“自我”无关,而是它的用途,pre-established Qt设计中的规则。

在 Qt 中,QObject 之间存在层次结构树,其中确定 parent QObject 管理内存(其 children 的生命周期),因此如果 parent删除了children,它们也会被删除。这可以避免内存泄漏,因为许多 QObject 通常用于许多应用程序。

另一方面,QWidgets也有这种亲缘关系的概念,因为QWidgets也是QObjects,但还有一个特点:QWidgets一般会绘制在它的上面parent。因此,如果您希望 QLineEdit 和 QLabel 成为 window 的一部分,那么它们必须是 window 的 children,因此您必须传递 window object 是 parent.

的“自我”

因此,当您转到 window(在本例中为“self”)时,您可以避免 2 个问题:

  • object 具有更长的生命周期(与 window 相同)。
  • 然后将小部件(QLabel 或 QLineEdit)放置在 window 的顶部。