QScrollArea children 无法访问 parent
QScrollArea children cannot access parent
我有 QScrollArea,里面有几个 QPushButton。我无法让 parent() 方法在子小部件上工作,因此它 return 是父对象。在创建子按钮时,我确实将 self.scroll 作为父级传递,但这似乎不起作用。
为什么我需要使用 parent() 3 次才能到达 QScrollArea 对象?我希望单亲()会给我那个。
这是代码。我借用了 https://www.learnpyqt.com/courses/adanced-ui-features/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()
按下按钮的return是:
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>
因此在您的情况下,ChildWidget 是构造函数末尾“self.widget”的子项。
提示:如果您想了解结构,请使用 dumpObjectTree()
方法:
main = MainWindow()
print(main.dumpObjectTree())
输出:
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 和 QScrollArea 的层次结构。
设置父级不是“最终的”。
来自QLayout.addWidget()
(以及所有 QLayout 子类的重新实现):
[...] This function uses addItem().
Note: The ownership of item is transferred to the layout, and it's the layout's responsibility to delete it.
当布局已经设置为小部件时,所有权将转移到布局的小部件(如果布局新设置为小部件,也会发生同样的情况)。
此外,当您使用 QAbstractScrollArea 后代(显然包括 QScrollArea)时,您有一个 QWidget 用作“视口”(在滚动区域内滚动的小部件),它具有滚动区域作为父级。使用 QScrollArea 时,setWidget(widget)
将 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)
我有 QScrollArea,里面有几个 QPushButton。我无法让 parent() 方法在子小部件上工作,因此它 return 是父对象。在创建子按钮时,我确实将 self.scroll 作为父级传递,但这似乎不起作用。
为什么我需要使用 parent() 3 次才能到达 QScrollArea 对象?我希望单亲()会给我那个。
这是代码。我借用了 https://www.learnpyqt.com/courses/adanced-ui-features/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()
按下按钮的return是:
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>
因此在您的情况下,ChildWidget 是构造函数末尾“self.widget”的子项。
提示:如果您想了解结构,请使用 dumpObjectTree()
方法:
main = MainWindow()
print(main.dumpObjectTree())
输出:
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 和 QScrollArea 的层次结构。
设置父级不是“最终的”。
来自QLayout.addWidget()
(以及所有 QLayout 子类的重新实现):
[...] This function uses addItem().
Note: The ownership of item is transferred to the layout, and it's the layout's responsibility to delete it.
当布局已经设置为小部件时,所有权将转移到布局的小部件(如果布局新设置为小部件,也会发生同样的情况)。
此外,当您使用 QAbstractScrollArea 后代(显然包括 QScrollArea)时,您有一个 QWidget 用作“视口”(在滚动区域内滚动的小部件),它具有滚动区域作为父级。使用 QScrollArea 时,setWidget(widget)
将 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)