PyQt5 使用来自 Designer ui 文件的自定义 QDockWidget
PyQt5 using custom QDockWidget from Designer ui file
我正在尝试开发一个广泛使用 QDockwidgets 的应用程序。uild。但是,我发现我无法使用 Qt Designer 中制作的 QDockwidgets。
这是我在设计器中显示的自定义 dockwidget.ui:
这是 QMainWindow 窗体 main2.ui 带有提升的小部件(称为 DockWidget,实例名称为 dw)
这是完成的应用程序的样子。 dockwidget 完全是空的。从 Designer 获取 QDockWidget 表单(ui 文件)以在 PyQt5 中正确显示是否有任何技巧?
main2.py
import sys
from PyQt5 import uic, QtWidgets
from PyQt5.QtWidgets import QApplication
class Main(QtWidgets.QMainWindow, uic.loadUiType('main2.ui')[0]):
def __init__(self, parent=None):
super().__init__()
self.setupUi(self)
app = QApplication(sys.argv)
main = Main(None)
main.show()
sys.exit(app.exec_())
dockwidget.py
from PyQt5 import uic
from PyQt5.QtWidgets import QDockWidget
# ~ form_class = uic.loadUiType('dockwidget.ui')[0]
class DockWidget(QDockWidget):
def __init__(self, parent=None):
super().__init__()
uic.loadUi('dockwidget.ui', self)
main2.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>390</width>
<height>233</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="maximumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout"/>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>390</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="DockWidget" name="dw">
<attribute name="dockWidgetArea">
<number>4</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents"/>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>DockWidget</class>
<extends>QDockWidget</extends>
<header>dockwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
dockwidget.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DockWidget</class>
<widget class="QDockWidget" name="DockWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>328</width>
<height>303</height>
</rect>
</property>
<property name="features">
<set>QDockWidget::DockWidgetClosable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="allowedAreas">
<set>Qt::BottomDockWidgetArea|Qt::TopDockWidgetArea</set>
</property>
<property name="windowTitle">
<string>My Custom Dock Widget</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="2" column="0">
<widget class="QRadioButton" name="radioButton_2">
<property name="text">
<string>RadioButton</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="radioButton">
<property name="text">
<string>RadioButton</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QRadioButton" name="radioButton_3">
<property name="text">
<string>RadioButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
与滚动区域类似,Designer 为新的 QDockWidgets 创建了一个“内容”小部件。该小部件实际上是在加载主要 window UI 时使用 setWidget()
设置的,并且无法从 Designer 中删除。
您的自定义 QDockWidget 中已经有一个内容小部件,但是当它被主 ui 添加时,它被它“覆盖”了。
考虑作为容器的提升的 classes 应该只在 class 中设置其内容 只要提升的小部件 不要 change/override他们,否则之前设置的内容会被移除。例如,如果您创建一个带有布局和按钮的自定义小部件,并将其用作设计器中的升级 class,则您无法设置另一个布局并从那里向该小部件添加其他子项。
避免此问题并实际创建已设置基本内容并可添加到 Designer 中的 QMainWindow 的可自定义 QDockWidget 的唯一方法是创建 Designer 插件。这并不容易,文档很复杂,尤其是 python,非常差(甚至缺少对某些 classes 的支持)。
虽然这里有多种可能性:
- 最简单:不要将停靠小部件添加到 Designer 中的主要 window,但只能通过在代码中显式调用
addDockWidget()
;
- 为停靠小部件内容创建一个提升的class(一个基本的QWidget/form),并提升停靠小部件的
dockWidgetContents
添加到主 window ui;
- 只要您完全确定您将永远不会再次调用
setWidget()
停靠小部件,并且您真的 需要 Designer 主 window 中的停靠小部件,以类似的方式覆盖 setWidget()
:
class DockWidget(QDockWidget):
def __init__(self, parent=None):
super().__init__()
uic.loadUi('dockwidget.ui', self)
def setWidget(self, widget):
if self.widget() is None:
super().setWidget(widget)
使用上面的代码,主 window 的 uic/setupUi 发出的 setWidget()
调用将被忽略,因为此时 dock 小部件已经有一个小部件由其设置拥有 loadUi
.
我正在尝试开发一个广泛使用 QDockwidgets 的应用程序。uild。但是,我发现我无法使用 Qt Designer 中制作的 QDockwidgets。
这是我在设计器中显示的自定义 dockwidget.ui:
这是 QMainWindow 窗体 main2.ui 带有提升的小部件(称为 DockWidget,实例名称为 dw)
这是完成的应用程序的样子。 dockwidget 完全是空的。从 Designer 获取 QDockWidget 表单(ui 文件)以在 PyQt5 中正确显示是否有任何技巧?
main2.py
import sys
from PyQt5 import uic, QtWidgets
from PyQt5.QtWidgets import QApplication
class Main(QtWidgets.QMainWindow, uic.loadUiType('main2.ui')[0]):
def __init__(self, parent=None):
super().__init__()
self.setupUi(self)
app = QApplication(sys.argv)
main = Main(None)
main.show()
sys.exit(app.exec_())
dockwidget.py
from PyQt5 import uic
from PyQt5.QtWidgets import QDockWidget
# ~ form_class = uic.loadUiType('dockwidget.ui')[0]
class DockWidget(QDockWidget):
def __init__(self, parent=None):
super().__init__()
uic.loadUi('dockwidget.ui', self)
main2.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>390</width>
<height>233</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="maximumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout"/>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>390</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="DockWidget" name="dw">
<attribute name="dockWidgetArea">
<number>4</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents"/>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>DockWidget</class>
<extends>QDockWidget</extends>
<header>dockwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
dockwidget.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DockWidget</class>
<widget class="QDockWidget" name="DockWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>328</width>
<height>303</height>
</rect>
</property>
<property name="features">
<set>QDockWidget::DockWidgetClosable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="allowedAreas">
<set>Qt::BottomDockWidgetArea|Qt::TopDockWidgetArea</set>
</property>
<property name="windowTitle">
<string>My Custom Dock Widget</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QGridLayout" name="gridLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="2" column="0">
<widget class="QRadioButton" name="radioButton_2">
<property name="text">
<string>RadioButton</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="radioButton">
<property name="text">
<string>RadioButton</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QRadioButton" name="radioButton_3">
<property name="text">
<string>RadioButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
与滚动区域类似,Designer 为新的 QDockWidgets 创建了一个“内容”小部件。该小部件实际上是在加载主要 window UI 时使用 setWidget()
设置的,并且无法从 Designer 中删除。
您的自定义 QDockWidget 中已经有一个内容小部件,但是当它被主 ui 添加时,它被它“覆盖”了。
考虑作为容器的提升的 classes 应该只在 class 中设置其内容 只要提升的小部件 不要 change/override他们,否则之前设置的内容会被移除。例如,如果您创建一个带有布局和按钮的自定义小部件,并将其用作设计器中的升级 class,则您无法设置另一个布局并从那里向该小部件添加其他子项。
避免此问题并实际创建已设置基本内容并可添加到 Designer 中的 QMainWindow 的可自定义 QDockWidget 的唯一方法是创建 Designer 插件。这并不容易,文档很复杂,尤其是 python,非常差(甚至缺少对某些 classes 的支持)。
虽然这里有多种可能性:
- 最简单:不要将停靠小部件添加到 Designer 中的主要 window,但只能通过在代码中显式调用
addDockWidget()
; - 为停靠小部件内容创建一个提升的class(一个基本的QWidget/form),并提升停靠小部件的
dockWidgetContents
添加到主 window ui; - 只要您完全确定您将永远不会再次调用
setWidget()
停靠小部件,并且您真的 需要 Designer 主 window 中的停靠小部件,以类似的方式覆盖setWidget()
:
class DockWidget(QDockWidget):
def __init__(self, parent=None):
super().__init__()
uic.loadUi('dockwidget.ui', self)
def setWidget(self, widget):
if self.widget() is None:
super().setWidget(widget)
使用上面的代码,主 window 的 uic/setupUi 发出的 setWidget()
调用将被忽略,因为此时 dock 小部件已经有一个小部件由其设置拥有 loadUi
.