Lor*_*sum 6 python pyqt qdockwidget pyqt5 qtpy
当小部件停靠时,我希望它改变方向并具有相对于停靠扩展方式的最小尺寸。
那是,
问题是,每当方向改变时,码头就会呈现出看似任意的宽度或高度。我无法找到一种方法来调整停靠小部件的大小/强制停靠时的特定大小。我尝试了无数种重写sizeHint、minimumSizeHint调用adjustSize和摆弄的变体sizePolicy。
如何确定初始dock大小?
我的基本应用程序如下所示:
该应用程序显示主要和次要信息以及相应的控件集。包含主要和次要内容的选项卡小部件被设置为中央小部件。包含相应仪表板中控件的 QStackedWidget 位于扩展坞中。当选项卡更改时,会显示相应的仪表板。下面的基本应用程序代码中给出了此操作的代码。
困难在于改变仪表板的方向会扰乱扩展坞的大小。
要调整仪表板方向,我能想到两个合理的解决方案:
resizeEvent或dockLocationChanged信号resizeEvent对我来说,这似乎是更好的选择。它为用户提供了最大的灵活性。如果他们不喜欢码头的方向,将其拖过特定限制将允许他们更改码头的方向。在这里我检查它的宽度是否大于高度。
class MyDock(QtWidgets.QDockWidget):
def __init__(self):
super(MyDock, self).__init__()
def resizeEvent(self, event):
size = event.size()
is_wide = size.width() > size.height()
container_object = self.widget().currentWidget()
if is_wide:
container_object.setDirection(QtWidgets.QBoxLayout.LeftToRight)
else:
container_object.setDirection(QtWidgets.QBoxLayout.TopToBottom)
Run Code Online (Sandbox Code Playgroud)
下面的调整大小方法中给出了完整的代码。
dockLocationChange由于调整大小事件始终发生,另一种方法可能是仅在停靠位置发生变化时才更改方向。为此,请将功能连接到信号dockLocationChanged并根据坞站调整方向。
class MyDock(QtWidgets.QDockWidget):
def __init__(self):
super(MyDock, self).__init__()
self.dockLocationChanged.connect(self.dock_location_changed)
def dock_location_changed(self, area):
top = QtCore.Qt.DockWidgetArea.TopDockWidgetArea
bottom = QtCore.Qt.DockWidgetArea.BottomDockWidgetArea
container_object = self.widget().currentWidget()
if area in [top, bottom]:
container_object.setDirection(QtWidgets.QBoxLayout.LeftToRight)
else:
container_object.setDirection(QtWidgets.QBoxLayout.TopToBottom)
Run Code Online (Sandbox Code Playgroud)
该计划由 5 个独立的课程组成。
为了
MyWindow,PrimaryDashboard, 和SecondaryDashboard 分手的原因应该足够清楚。
为了
MyDock和DockContainer分离是为了方便重写sizeHint、setDirection或其他方法。
import qtpy
from qtpy import QtWidgets, QtGui, QtCore
import sys
class PrimaryDashboard(QtWidgets.QWidget):
def __init__(self):
super(PrimaryDashboard, self).__init__()
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.label = QtWidgets.QLabel('Primary dashboard')
self.ok = QtWidgets.QPushButton('OK')
self.cancel = QtWidgets.QPushButton('Cancel')
def init_layout(self):
self.layout = QtWidgets.QHBoxLayout()
self.layout.addWidget(self.label)
self.layout.addWidget(self.ok)
self.layout.addWidget(self.cancel)
self.setLayout(self.layout)
def setDirection(self, direction):
self.layout.setDirection(direction)
class SecondaryDashboard(QtWidgets.QWidget):
def __init__(self):
super(SecondaryDashboard, self).__init__()
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.label = QtWidgets.QLabel('Secondary dashboard')
self.descr1 = QtWidgets.QLabel('Thing 1')
self.check1 = QtWidgets.QCheckBox()
self.descr2 = QtWidgets.QLabel('Thing 2')
self.check2 = QtWidgets.QCheckBox()
def init_layout(self):
self.layout = QtWidgets.QVBoxLayout()
self.grid = QtWidgets.QGridLayout()
self.grid.addWidget(self.descr1, 0, 0)
self.grid.addWidget(self.check1, 0, 1)
self.grid.addWidget(self.descr2, 1, 0)
self.grid.addWidget(self.check2, 1, 1)
self.layout.addWidget(self.label)
self.layout.addLayout(self.grid)
self.setLayout(self.layout)
def setDirection(self, direction):
self.layout.setDirection(direction)
class DockContainer(QtWidgets.QStackedWidget):
def __init__(self):
super(DockContainer, self).__init__()
class MyDock(QtWidgets.QDockWidget):
def __init__(self):
super(MyDock, self).__init__()
class MyWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent=parent)
self.resize(600, 400)
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.tab_widget = QtWidgets.QTabWidget()
self.tab1 = QtWidgets.QLabel('Primary content')
self.tab2 = QtWidgets.QLabel('Secondary content')
self.tab_widget.addTab(self.tab1, 'Primary')
self.tab_widget.addTab(self.tab2, 'Secondary')
self.tab_widget.currentChanged.connect(self.tab_selected)
self.primary_dashboard = PrimaryDashboard()
self.secondary_dashboard = SecondaryDashboard()
self.dashboard = DockContainer()
self.dashboard.addWidget(self.primary_dashboard)
self.dashboard.addWidget(self.secondary_dashboard)
self.dashboard.setCurrentWidget(self.primary_dashboard)
self.dock = MyDock()
self.dock.setWidget(self.dashboard)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dock)
def init_layout(self):
self.main_layout = QtWidgets.QVBoxLayout()
self.main_layout.addWidget(self.tab_widget)
self.main_widget = QtWidgets.QWidget()
self.main_widget.setLayout(self.main_layout)
self.setCentralWidget(self.main_widget)
def tab_selected(self):
tab_index = self.tab_widget.currentIndex()
if self.tab_widget.tabText(tab_index) == 'Secondary':
self.dashboard.setCurrentWidget(self.secondary_dashboard)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock)
else: # Primary
self.dashboard.setCurrentWidget(self.primary_dashboard)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dock)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
此代码与基本应用程序代码相同,但resizeEvent在停靠小部件中被覆盖。
import qtpy
from qtpy import QtWidgets, QtGui, QtCore
import sys
class PrimaryDashboard(QtWidgets.QWidget):
def __init__(self):
super(PrimaryDashboard, self).__init__()
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.label = QtWidgets.QLabel('Primary dashboard')
self.ok = QtWidgets.QPushButton('OK')
self.cancel = QtWidgets.QPushButton('Cancel')
def init_layout(self):
self.layout = QtWidgets.QHBoxLayout()
self.layout.addWidget(self.label)
self.layout.addWidget(self.ok)
self.layout.addWidget(self.cancel)
self.setLayout(self.layout)
def setDirection(self, direction):
self.layout.setDirection(direction)
class SecondaryDashboard(QtWidgets.QWidget):
def __init__(self):
super(SecondaryDashboard, self).__init__()
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.label = QtWidgets.QLabel('Secondary dashboard')
self.descr1 = QtWidgets.QLabel('Thing 1')
self.check1 = QtWidgets.QCheckBox()
self.descr2 = QtWidgets.QLabel('Thing 2')
self.check2 = QtWidgets.QCheckBox()
def init_layout(self):
self.layout = QtWidgets.QVBoxLayout()
self.grid = QtWidgets.QGridLayout()
self.grid.addWidget(self.descr1, 0, 0)
self.grid.addWidget(self.check1, 0, 1)
self.grid.addWidget(self.descr2, 1, 0)
self.grid.addWidget(self.check2, 1, 1)
self.layout.addWidget(self.label)
self.layout.addLayout(self.grid)
self.setLayout(self.layout)
def setDirection(self, direction):
self.layout.setDirection(direction)
class DockContainer(QtWidgets.QStackedWidget):
def __init__(self):
super(DockContainer, self).__init__()
class MyDock(QtWidgets.QDockWidget):
def __init__(self):
super(MyDock, self).__init__()
def resizeEvent(self, event):
size = event.size()
is_wide = size.width() > size.height()
container_object = self.widget().currentWidget()
if is_wide:
container_object.setDirection(QtWidgets.QBoxLayout.LeftToRight)
else:
container_object.setDirection(QtWidgets.QBoxLayout.TopToBottom)
class MyWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent=parent)
self.resize(600, 400)
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.tab_widget = QtWidgets.QTabWidget()
self.tab1 = QtWidgets.QLabel('Primary content')
self.tab2 = QtWidgets.QLabel('Secondary content')
self.tab_widget.addTab(self.tab1, 'Primary')
self.tab_widget.addTab(self.tab2, 'Secondary')
self.tab_widget.currentChanged.connect(self.tab_selected)
self.primary_dashboard = PrimaryDashboard()
self.secondary_dashboard = SecondaryDashboard()
self.dashboard = DockContainer()
self.dashboard.addWidget(self.primary_dashboard)
self.dashboard.addWidget(self.secondary_dashboard)
self.dashboard.setCurrentWidget(self.primary_dashboard)
self.dock = MyDock()
self.dock.setWidget(self.dashboard)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dock)
def init_layout(self):
self.main_layout = QtWidgets.QVBoxLayout()
self.main_layout.addWidget(self.tab_widget)
self.main_widget = QtWidgets.QWidget()
self.main_widget.setLayout(self.main_layout)
self.setCentralWidget(self.main_widget)
def tab_selected(self):
tab_index = self.tab_widget.currentIndex()
if self.tab_widget.tabText(tab_index) == 'Secondary':
self.dashboard.setCurrentWidget(self.secondary_dashboard)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock)
else: # Primary
self.dashboard.setCurrentWidget(self.primary_dashboard)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dock)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
dockLocationChanged方法此代码与基本应用程序代码相同,但dockLocationChanged信号连接到根据当前停靠位置调整方向的方法。
import qtpy
from qtpy import QtWidgets, QtGui, QtCore
import sys
class PrimaryDashboard(QtWidgets.QWidget):
def __init__(self):
super(PrimaryDashboard, self).__init__()
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.label = QtWidgets.QLabel('Primary dashboard')
self.ok = QtWidgets.QPushButton('OK')
self.cancel = QtWidgets.QPushButton('Cancel')
def init_layout(self):
self.layout = QtWidgets.QHBoxLayout()
self.layout.addWidget(self.label)
self.layout.addWidget(self.ok)
self.layout.addWidget(self.cancel)
self.setLayout(self.layout)
def setDirection(self, direction):
self.layout.setDirection(direction)
class SecondaryDashboard(QtWidgets.QWidget):
def __init__(self):
super(SecondaryDashboard, self).__init__()
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.label = QtWidgets.QLabel('Secondary dashboard')
self.descr1 = QtWidgets.QLabel('Thing 1')
self.check1 = QtWidgets.QCheckBox()
self.descr2 = QtWidgets.QLabel('Thing 2')
self.check2 = QtWidgets.QCheckBox()
def init_layout(self):
self.layout = QtWidgets.QVBoxLayout()
self.grid = QtWidgets.QGridLayout()
self.grid.addWidget(self.descr1, 0, 0)
self.grid.addWidget(self.check1, 0, 1)
self.grid.addWidget(self.descr2, 1, 0)
self.grid.addWidget(self.check2, 1, 1)
self.layout.addWidget(self.label)
self.layout.addLayout(self.grid)
self.setLayout(self.layout)
def setDirection(self, direction):
self.layout.setDirection(direction)
class DockContainer(QtWidgets.QStackedWidget):
def __init__(self):
super(DockContainer, self).__init__()
class MyDock(QtWidgets.QDockWidget):
def __init__(self):
super(MyDock, self).__init__()
self.dockLocationChanged.connect(self.dock_location_changed)
def dock_location_changed(self, area):
top = QtCore.Qt.DockWidgetArea.TopDockWidgetArea
bottom = QtCore.Qt.DockWidgetArea.BottomDockWidgetArea
# left = QtCore.Qt.DockWidgetArea.LeftDockWidgetArea
# right = QtCore.Qt.DockWidgetArea.RightDockWidgetArea
container_object = self.widget().currentWidget()
if area in [top, bottom]:
container_object.setDirection(QtWidgets.QBoxLayout.LeftToRight)
else:
container_object.setDirection(QtWidgets.QBoxLayout.TopToBottom)
class MyWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent=parent)
self.resize(600, 400)
self.init_widgets()
self.init_layout()
def init_widgets(self):
self.tab_widget = QtWidgets.QTabWidget()
self.tab1 = QtWidgets.QLabel('Primary content')
self.tab2 = QtWidgets.QLabel('Secondary content')
self.tab_widget.addTab(self.tab1, 'Primary')
self.tab_widget.addTab(self.tab2, 'Secondary')
self.tab_widget.currentChanged.connect(self.tab_selected)
self.primary_dashboard = PrimaryDashboard()
self.secondary_dashboard = SecondaryDashboard()
self.dashboard = DockContainer()
self.dashboard.addWidget(self.primary_dashboard)
self.dashboard.addWidget(self.secondary_dashboard)
self.dashboard.setCurrentWidget(self.primary_dashboard)
self.dock = MyDock()
self.dock.setWidget(self.dashboard)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dock)
def init_layout(self):
self.main_layout = QtWidgets.QVBoxLayout()
self.main_layout.addWidget(self.tab_widget)
self.main_widget = QtWidgets.QWidget()
self.main_widget.setLayout(self.main_layout)
self.setCentralWidget(self.main_widget)
def tab_selected(self):
tab_index = self.tab_widget.currentIndex()
if self.tab_widget.tabText(tab_index) == 'Secondary':
self.dashboard.setCurrentWidget(self.secondary_dashboard)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock)
else: # Primary
self.dashboard.setCurrentWidget(self.primary_dashboard)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dock)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
将应用程序视为一组俄罗斯套娃。内部娃娃的尺寸决定了后续外部娃娃的尺寸。显然,内部娃娃不能比包含它的娃娃大! QWidget 的建模方式类似。
\n\n\n\n\n默认情况下,不提供大小提示的复合小部件将根据其子小部件的空间要求调整大小。
\n
QWidget.sizeHint()的文档继续说,
\n\n\n\n\n如果此小部件没有布局,则 QWidget.sizeHint() 的默认实现返回\n 无效大小,否则返回\n 布局\xe2\x80\x99s 首选大小。
\n
总而言之,小部件的大小是根据布局由内而外决定的。
\n\n如果您要为基础应用程序代码中的每个对象实现resizeEvent1,您将看到以下大小调整序列,
PrimaryDashboard调整大小事件DockContainer调整大小事件MyDock调整大小事件这就是我们所期望的嵌套。PrimaryDashboard首先查询 的大小,然后查询,DockContainer最后查询MyDock。从技术上讲,它一直都是小部件。但是,PrimaryDashboard在大多数情况下,包含的按钮和标签应小于主窗口的宽度/高度。序列中第一个显着影响码头尺寸的玩偶是PrimaryDashboard。
resizeEvent使用 进行检查event.size(),我们可以看到水平仪表板的合理最小值是像素高度,120而垂直方向的合理最小宽度是146。然后可以将其sizeHint()设置为返回并且对于每个仪表板2minimumSizeHint()具有最小返回。实际上,这告诉应用程序首选最小尺寸,同时通常仍然允许调整大小。(146, 120)(146, 120)
def sizeHint(self):\n return self.minimumSizeHint()\n\ndef minimumSizeHint(self):\n return QtCore.QSize(146, 120)\nRun Code Online (Sandbox Code Playgroud)\n\n诚然,使用固定大小可能很危险,因为绝对的大小是无情的,而且根据定义也不灵活。然而,内容可能具有自然的最小大小3。我们可以简单地setMinimumSize()在整个应用程序上不允许调整大小小于我们的minimumSizeHint().
要更改停靠小部件内容的方向,我们可以使用该dockLocationChanged信号。我们还可以使代码比问题中呈现的方式更简洁一些。我们可以在MyWindow. 事实上,根本没有必要定义MyDock。普通的QDockWidget就足够了。
import qtpy\nfrom qtpy import QtWidgets, QtGui, QtCore\nimport sys\n\n\nclass PrimaryDashboard(QtWidgets.QWidget):\n\n def __init__(self):\n\n super(PrimaryDashboard, self).__init__()\n\n self.init_widgets()\n self.init_layout()\n\n def init_widgets(self):\n self.label = QtWidgets.QLabel(\'Primary dashboard\')\n self.ok = QtWidgets.QPushButton(\'OK\')\n self.cancel = QtWidgets.QPushButton(\'Cancel\')\n\n def init_layout(self):\n self.layout = QtWidgets.QHBoxLayout()\n self.layout.addWidget(self.label)\n self.layout.addWidget(self.ok)\n self.layout.addWidget(self.cancel)\n self.setLayout(self.layout)\n\n def setDirection(self, direction):\n self.layout.setDirection(direction)\n\n def sizeHint(self):\n return self.minimumSizeHint()\n\n def minimumSizeHint(self):\n return QtCore.QSize(146, 120)\n\n\nclass SecondaryDashboard(QtWidgets.QWidget):\n\n def __init__(self):\n\n super(SecondaryDashboard, self).__init__()\n\n self.init_widgets()\n self.init_layout()\n\n def init_widgets(self):\n self.label = QtWidgets.QLabel(\'Secondary dashboard\')\n\n self.descr1 = QtWidgets.QLabel(\'Thing 1\')\n self.check1 = QtWidgets.QCheckBox()\n\n self.descr2 = QtWidgets.QLabel(\'Thing 2\')\n self.check2 = QtWidgets.QCheckBox()\n\n def init_layout(self):\n self.layout = QtWidgets.QVBoxLayout()\n\n self.grid = QtWidgets.QGridLayout()\n self.grid.addWidget(self.descr1, 0, 0)\n self.grid.addWidget(self.check1, 0, 1)\n self.grid.addWidget(self.descr2, 1, 0)\n self.grid.addWidget(self.check2, 1, 1)\n\n self.layout.addWidget(self.label)\n self.layout.addLayout(self.grid)\n self.setLayout(self.layout)\n\n def setDirection(self, direction):\n self.layout.setDirection(direction)\n\n def sizeHint(self):\n return self.minimumSizeHint()\n\n def minimumSizeHint(self):\n return QtCore.QSize(146, 120)\n\n\nclass DockContainer(QtWidgets.QStackedWidget):\n\n def __init__(self):\n\n super(DockContainer, self).__init__()\n\n def dock_location_changed(self, area):\n top = QtCore.Qt.DockWidgetArea.TopDockWidgetArea\n bottom = QtCore.Qt.DockWidgetArea.BottomDockWidgetArea\n\n container_object = self.currentWidget()\n\n if area in [top, bottom]:\n container_object.setDirection(QtWidgets.QBoxLayout.LeftToRight)\n else:\n container_object.setDirection(QtWidgets.QBoxLayout.TopToBottom)\n\n\nclass MyWindow(QtWidgets.QMainWindow):\n\n def __init__(self, parent=None):\n super(MyWindow, self).__init__(parent=parent)\n\n # Force minimumSize to ensure a sensible dashboard size\n self.setMinimumSize(QtCore.QSize(600, 400))\n\n self.init_widgets()\n self.init_layout()\n\n def init_widgets(self):\n\n self.tab_widget = QtWidgets.QTabWidget()\n self.tab1 = QtWidgets.QLabel(\'Primary content\')\n self.tab2 = QtWidgets.QLabel(\'Secondary content\')\n self.tab_widget.addTab(self.tab1, \'Primary\')\n self.tab_widget.addTab(self.tab2, \'Secondary\')\n self.tab_widget.currentChanged.connect(self.tab_selected)\n\n self.primary_dashboard = PrimaryDashboard()\n self.secondary_dashboard = SecondaryDashboard()\n\n self.dashboard = DockContainer()\n self.dashboard.addWidget(self.primary_dashboard)\n self.dashboard.addWidget(self.secondary_dashboard)\n self.dashboard.setCurrentWidget(self.primary_dashboard)\n\n self.dock = QtWidgets.QDockWidget()\n self.dock.setWidget(self.dashboard)\n self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dock)\n\n # Connect signal at the main application level\n self.dock.dockLocationChanged.connect(self.dashboard.dock_location_changed)\n\n def init_layout(self):\n self.main_layout = QtWidgets.QVBoxLayout()\n self.main_layout.addWidget(self.tab_widget)\n\n self.main_widget = QtWidgets.QWidget()\n self.main_widget.setLayout(self.main_layout)\n self.setCentralWidget(self.main_widget)\n\n def tab_selected(self):\n tab_index = self.tab_widget.currentIndex()\n if self.tab_widget.tabText(tab_index) == \'Secondary\':\n self.dashboard.setCurrentWidget(self.secondary_dashboard)\n self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock)\n else: # Primary\n self.dashboard.setCurrentWidget(self.primary_dashboard)\n self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.dock)\n\n\nif __name__ == \'__main__\':\n app = QtWidgets.QApplication(sys.argv)\n\n window = MyWindow()\n window.show()\n sys.exit(app.exec_())\n\nRun Code Online (Sandbox Code Playgroud)\n\n1.如何实现这样的方法resizeEvent来查看谁在调整大小:
def resizeEvent(self, event):\n print(\'resizeEvent for \', self, flush=True)\nRun Code Online (Sandbox Code Playgroud)\n\n2.一个自然的问题是,“为什么不简单地设置sizeHint()返回最小大小而不是调用minimumSizeHint()? 我得到的最佳回答是,“它不会那样工作。” 仅设置sizeHint()不会调整扩展坞的大小如您所料,达到最低限度。
和sizeHint()方法minimumSizeHint()是虚函数。我的猜测是 Qt 还有其他我们不知道的功能,它们独立地引用这些方法,要求我们以这种方式定义事物。
3.例如,如果内容是地图,则用户不太可能希望地图是10px x 10px。600 x 400此外,合理的假设是,除非用户使用移动设备,否则用户不会使用低于该分辨率的屏幕分辨率。但如果您正在使用 PySide 或 PyQt5 进行移动开发,则您应该问自己一些重要的问题,例如“为什么?” 。
| 归档时间: |
|
| 查看次数: |
3680 次 |
| 最近记录: |