0

I have placed 2 QDockWidgets in a QMainWindow, one on the left and one on the right.

Here is my code:

test_dock_widget.py

# -*- coding: utf-8 -*-
import sys

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QApplication, QDockWidget, QWidget


class WindowMain(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowFlags(Qt.WindowType.WindowMinimizeButtonHint
                            | Qt.WindowType.WindowMaximizeButtonHint
                            | Qt.WindowType.WindowCloseButtonHint)
        self.resize(800, 600)
        self.setWindowTitle('Symptoms')

        self.dock1 = QDockWidget('DockWidget1', self)
        self.dock2 = QDockWidget('DockWidget2', self)

        self.dock1.setWidget(QWidget())
        self.dock1.widget().setStyleSheet('background: #FFC0C0')
        self.dock2.setWidget(QWidget())
        self.dock2.widget().setStyleSheet('background: #C0FFC0')

        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock1)
        self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.dock2)


def main():
    app = QApplication(sys.argv)

    wndMain = WindowMain()
    wndMain.show()

    app.exec_()


if __name__ == '__main__':
    main()

The problem is that when the program runs, they seem to prefer to evenly distribute the entire width of QMainWindow. For example, every time I manually reduce the width of the left QDockWidget, maximize and restore the window, both QDockWidgets will again evenly distribute across the entire width of QMainWindow.

reduce left one

maximize and restore

How can I avoid this situation?

I hope that the width allocation of these two QDockWidgets can be restored to what I adjusted before maximizing, but the result is that they are evenly distributed. I don't want to set a minimum or maximum width for any QDockWidget because users should be able to adjust them as they wish. I also don't want to set a fixed scaling ratio for these two QDockWidgets.

Thank you in advance!

Environment: Windows 11, Python 3, PyQt5

Dawn Wren
  • 3
  • 1
  • It's because you didn't set a central widget with the ```QMainWindow.setCentralWidget()```. If you don't want the central widget, use the ```QSplitter```. – relent95 Apr 26 '23 at 03:12
  • @relent95 Yes, I don't want a central widget because I hope all the widgets in QMainWindow can be freely dragged and floated, giving users maximum flexibility in the application interface. That's also why I cannot use QSpliter to replace QDockWidget. Thank you! – Dawn Wren Apr 26 '23 at 05:06
  • The builtin docking system(```QMainWindow``` and ```QDockWidget```) does not have that feature. When the size of the window is changed, previous geometries of left and right docks cannot be preserved without a variable width central widget. You have to hack it or implement a new docking system. It's out of scope of SO. See [this](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System). – relent95 Apr 26 '23 at 05:54
  • I got an idea of only constraining one dock. See my answer below. – relent95 Apr 27 '23 at 03:27

1 Answers1

0

The space was evenly distributed between two docks because you placed two docks in different docking areas. You need to place them in the same docking area horizontally as in the following example. With this, the ratio of widths of the docks will be preserved when the window is resized, and the previous geometry will be restored after the window is maximized and restored to the normal state.

...
class WindowMain(QMainWindow):
    def __init__(self):
        super().__init__()
        ...
        self.dock1 = QDockWidget('DockWidget1', self)
        self.dock2 = QDockWidget('DockWidget2', self)
        ...
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock1, Qt.Horizontal)
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.dock2, Qt.Horizontal)

Now about preserving the widths of the docks when the window is resized, it's impossible to do it for both docks without a central widget of variable width. But it's possible to preserve the width of only one dock. For example, you can place two docks like the above example and additionally set the size policy of the left dock to Fixed or Maximum, as in the following example.

        ...
        sp = self.dock1.sizePolicy()
        sp.setHorizontalPolicy(QSizePolicy.Maximum)
        self.dock1.setSizePolicy(sp)
relent95
  • 3,703
  • 1
  • 14
  • 17
  • Thank you! I ran your code, but now the two QDockWidgets are arranged vertically. Did you make any changes that you didn't post? – Dawn Wren Apr 28 '23 at 07:06
  • My mistake for missing orientation arguments for the ```addDockWidget()``` calls. Check the updated answer. – relent95 Apr 28 '23 at 08:17
  • I found that there are three situations in total: 1. When calling `addDockWidget` without the `Qt.Horizontal` parameter (just like my original code), this causes both sub-windows to unconditionally split the width of the main window when maximized, and cannot be restored to the width adjusted by the user when restored. – Dawn Wren Apr 30 '23 at 15:14
  • 2. When calling `addDockWidget` with the `Qt.Horizontal` parameter added, but without adding those last three lines in your final answer, in this case, when maximized, the width of both sub-windows will expand according to the proportion adjusted by the user, and can still be restored to the width adjusted by the user when restored. – Dawn Wren Apr 30 '23 at 15:14
  • 3. As your final answer, when maximized, left sub-window can maintain its width adjusted by users and can be restored to it. – Dawn Wren Apr 30 '23 at 15:24
  • Yes you are right. I missed the question is focused on how to restore geometry when the window is restored. I'll edit the answer. Thanks. – relent95 Apr 30 '23 at 23:23