Python QScrollArea子项无法访问父项

Python QScrollArea子项无法访问父项,python,pyqt,pyqt5,qscrollarea,Python,Pyqt,Pyqt5,Qscrollarea,我有一个内部有几个按钮的QScrollArea。我无法使parent()方法在子窗口小部件上工作,以便它返回parent对象。在创建子按钮时,我确实将self.scroll作为父级传递,但这似乎不起作用 为什么我需要使用parent()3次才能访问QScrollArea对象?我希望单亲()会给我这样的机会 这是代码。我从中借用了代码作为示例 from PyQt5.QtWidgets import (QWidget, QScrollArea, QVBoxLayout, QMainWindow) f

我有一个内部有几个按钮的QScrollArea。我无法使parent()方法在子窗口小部件上工作,以便它返回parent对象。在创建子按钮时,我确实将self.scroll作为父级传递,但这似乎不起作用

为什么我需要使用parent()3次才能访问QScrollArea对象?我希望单亲()会给我这样的机会

这是代码。我从中借用了代码作为示例

from PyQt5.QtWidgets import (QWidget, QScrollArea, QVBoxLayout, QMainWindow)
from PyQt5.QtCore import Qt
from PyQt5 import QtWidgets
import sys


class ChildWidget(QtWidgets.QPushButton):

    def __init__(self, parent):
        super(ChildWidget, self).__init__(parent)

    def mousePressEvent(self, event):
        print(self.parent().metaObject().className())
        print(self.parent().parent().metaObject().className())
        print(self.parent().parent().parent().metaObject().className())


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.scroll = QScrollArea()
        self.widget = QWidget()
        self.vbox = QVBoxLayout()

        for i in range(1, 5):
            object = ChildWidget(self.scroll)
            self.vbox.addWidget(object)

        self.widget.setLayout(self.vbox)

        self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scroll.setWidgetResizable(True)
        self.scroll.setWidget(self.widget)

        self.setCentralWidget(self.scroll)

        self.setGeometry(600, 100, 1000, 900)
        self.setWindowTitle('Scroll Area Demonstration')
        self.show()

        return


def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
按钮按下的返回为:

QWidget
QWidget
QScrollArea

将小部件添加到布局时,该小部件是处理布局的容器(QWidget)的子部件

在您的情况下,只需添加一些打印即可了解父项何时更改:

# ...
# variable that stores the first ChildWidget:
first_widget = None

for i in range(1, 5):
    object = ChildWidget(self.scroll)
    if first_widget is None:
        first_widget = object

    self.vbox.addWidget(object)

print(first_widget.parent())

self.widget.setLayout(self.vbox)

print(first_widget.parent())
输出:

<PyQt5.QtWidgets.QScrollArea object at 0x7fb699721dc0>
<PyQt5.QtWidgets.QWidget object at 0x7fb699721e50>
MainWindow:: 
    QMainWindowLayout::_layout 
    QScrollArea:: 
        QWidget::qt_scrollarea_viewport 
            QWidget:: 
                QVBoxLayout:: 
                ChildWidget:: 
                ChildWidget:: 
                ChildWidget:: 
                ChildWidget:: 
        QWidget::qt_scrollarea_hcontainer 
            QScrollBar:: 
            QBoxLayout:: 
        QPropertyAnimation:: 
        QPropertyAnimation:: 
        QWidget::qt_scrollarea_vcontainer 
            QScrollBar:: 
            QBoxLayout:: 
输出:

<PyQt5.QtWidgets.QScrollArea object at 0x7fb699721dc0>
<PyQt5.QtWidgets.QWidget object at 0x7fb699721e50>
MainWindow:: 
    QMainWindowLayout::_layout 
    QScrollArea:: 
        QWidget::qt_scrollarea_viewport 
            QWidget:: 
                QVBoxLayout:: 
                ChildWidget:: 
                ChildWidget:: 
                ChildWidget:: 
                ChildWidget:: 
        QWidget::qt_scrollarea_hcontainer 
            QScrollBar:: 
            QBoxLayout:: 
        QPropertyAnimation:: 
        QPropertyAnimation:: 
        QWidget::qt_scrollarea_vcontainer 
            QScrollBar:: 
            QBoxLayout:: 

观察到ChildWidget和QScrolArea的层次结构的地方。

将小部件添加到布局时,该小部件是处理布局的容器(QWidget)的子部件

在您的情况下,只需添加一些打印即可了解父项何时更改:

# ...
# variable that stores the first ChildWidget:
first_widget = None

for i in range(1, 5):
    object = ChildWidget(self.scroll)
    if first_widget is None:
        first_widget = object

    self.vbox.addWidget(object)

print(first_widget.parent())

self.widget.setLayout(self.vbox)

print(first_widget.parent())
输出:

<PyQt5.QtWidgets.QScrollArea object at 0x7fb699721dc0>
<PyQt5.QtWidgets.QWidget object at 0x7fb699721e50>
MainWindow:: 
    QMainWindowLayout::_layout 
    QScrollArea:: 
        QWidget::qt_scrollarea_viewport 
            QWidget:: 
                QVBoxLayout:: 
                ChildWidget:: 
                ChildWidget:: 
                ChildWidget:: 
                ChildWidget:: 
        QWidget::qt_scrollarea_hcontainer 
            QScrollBar:: 
            QBoxLayout:: 
        QPropertyAnimation:: 
        QPropertyAnimation:: 
        QWidget::qt_scrollarea_vcontainer 
            QScrollBar:: 
            QBoxLayout:: 
输出:

<PyQt5.QtWidgets.QScrollArea object at 0x7fb699721dc0>
<PyQt5.QtWidgets.QWidget object at 0x7fb699721e50>
MainWindow:: 
    QMainWindowLayout::_layout 
    QScrollArea:: 
        QWidget::qt_scrollarea_viewport 
            QWidget:: 
                QVBoxLayout:: 
                ChildWidget:: 
                ChildWidget:: 
                ChildWidget:: 
                ChildWidget:: 
        QWidget::qt_scrollarea_hcontainer 
            QScrollBar:: 
            QBoxLayout:: 
        QPropertyAnimation:: 
        QPropertyAnimation:: 
        QWidget::qt_scrollarea_vcontainer 
            QScrollBar:: 
            QBoxLayout:: 
观察到ChildWidget和QScrolArea的层次结构。

设置父项不是“最终的”

来自(以及所有QLayout子类的重新实现):

[…]此函数使用addItem()

发件人:

注意:项目的所有权转移到版面,版面有责任删除它

当版面已经设置为小部件时,所有权转移到版面的小部件(如果版面新设置为小部件,也会发生同样的情况)

此外,当您使用QabStretchScrollArea子体(显然包括QScrollArea)时,您将使用一个QWidget作为“视口”(滚动区域内的小部件),它将滚动区域作为父对象。使用QScrollArea时,
setWidget(widget)
小部件重新复制到视口

因此,实际的层次结构是:

scrollarea
   viewport
       "container" widget
           button
如果要查找父滚动区域(假设未使用嵌套滚动区域,包括项目视图子体),可以执行以下操作:

class ChildWidget(QtWidgets.QPushButton):

    def __init__(self, parent):
        super(ChildWidget, self).__init__(parent)

    def mousePressEvent(self, event):
        obj = self
        while not isinstance(obj.parent(), QAbstractScrollArea):
            parent = obj.parent()
            if not parent:
                break
            obj = parent
        print(obj)
设置父项不是“最终的”

来自(以及所有QLayout子类的重新实现):

[…]此函数使用addItem()

发件人:

注意:项目的所有权转移到版面,版面有责任删除它

当版面已经设置为小部件时,所有权转移到版面的小部件(如果版面新设置为小部件,也会发生同样的情况)

此外,当您使用QabStretchScrollArea子体(显然包括QScrollArea)时,您将使用一个QWidget作为“视口”(滚动区域内的小部件),它将滚动区域作为父对象。使用QScrollArea时,
setWidget(widget)
小部件重新复制到视口

因此,实际的层次结构是:

scrollarea
   viewport
       "container" widget
           button
如果要查找父滚动区域(假设未使用嵌套滚动区域,包括项目视图子体),可以执行以下操作:

class ChildWidget(QtWidgets.QPushButton):

    def __init__(self, parent):
        super(ChildWidget, self).__init__(parent)

    def mousePressEvent(self, event):
        obj = self
        while not isinstance(obj.parent(), QAbstractScrollArea):
            parent = obj.parent()
            if not parent:
                break
            obj = parent
        print(obj)

谢谢你的dumpObjectTree(),我正准备要它呢!谢谢你的dumpObjectTree(),我正准备要它呢!