zezo
zezo

Reputation: 455

How to correctly position the QDockWidgets, with a size hint

How to correctly position a different Dockwidgets inside a QMainwindow based on the size hint given to each of the dockwidgets. I tried to position based on addDockWidget and setAllowedAreas, but seems I am missing up the concept. And turn off the tabified when moving the QDockwidgets (prevent them from group in tabs).

from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys

class Dock_1(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
    
    def sizeHint(self):
        return QSize(.2*self.width(), .7*self.height()) 

class Dock_2(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
    
    def sizeHint(self):
        return QSize(.2*self.width(), .3*self.height()) 
    
class Dock_3(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
    
    def sizeHint(self):
        return QSize(.6*self.width(), .7*self.height()) 

class Dock_4(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
    
    def sizeHint(self):
        return QSize(.6*self.width(), .3*self.height()) 
    
class Dock_5(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
    
    def sizeHint(self):
        return QSize(.1*self.width(), self.height()) 
    
class Window(QMainWindow):
 
    def __init__(self):
        super().__init__()
        self.setGeometry(200, 200, 800, 800)
        self.UiComponents()
        self.show()
 
    def UiComponents(self):
        
        dock1 = QDockWidget("Dock_1", self)
        dock2 = QDockWidget("Dock_2", self)
        dock3 = QDockWidget("Dock_3", self)
        dock4 = QDockWidget("Dock_4", self)
        dock5 = QDockWidget("Dock_5", self)
        
        dock1.setAllowedAreas(Qt.LeftDockWidgetArea)
        dock2.setAllowedAreas(Qt.BottomDockWidgetArea)
        dock3.setAllowedAreas(Qt.TopDockWidgetArea)
        dock4.setAllowedAreas(Qt.BottomDockWidgetArea)
        dock5.setAllowedAreas(Qt.RightDockWidgetArea)

        w_1   = Dock_1(self)
        w_2   = Dock_2(self)
        w_3   = Dock_3(self)
        w_4   = Dock_4(self)
        w_5   = Dock_5(self) 

        dock1.setWidget(w_1)
        dock2.setWidget(w_2)
        dock3.setWidget(w_3)
        dock4.setWidget(w_4)
        dock5.setWidget(w_5)

        self.addDockWidget(Qt.LeftDockWidgetArea, dock1)
        self.addDockWidget(Qt.LeftDockWidgetArea, dock2)
        self.addDockWidget(Qt.RightDockWidgetArea, dock3)
        self.addDockWidget(Qt.RightDockWidgetArea, dock4)
        self.addDockWidget(Qt.RightDockWidgetArea, dock5)
        
 
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

enter image description here

Upvotes: 1

Views: 1307

Answers (1)

musicamante
musicamante

Reputation: 48543

Size hints are almost useless for dock widgets, since precedence is given to the central widget and the main window layout, but your approach is in any case wrong for two reasons:

  1. the size hint is called before resizing, and returning a hint based on the current size wouldn't be valid since it could cause some sort of recursion (this doesn't normally happen as sizeHint() is generally called only when the layout structure is changed and then cached, but that's not the point);
  2. when any widget is initialized it has a default size (100x30 if the parent is in the constructor, otherwise 640x480), so the results from your implementation would be invalid anyway;

Since what you want completely depends on the size of the main window, the only possibility is to resize the docks in the resizeEvent().

Also note that:

  • in order to have dock widgets side by side you must use splitDockWidget();
  • to have dock 3 and 4 vertically aligned with 1 and 2 (or 5) you can only put them in (and allow) the left or right dock area;
  • the allowed areas should match the area in which the dock is added;
  • creating the "inner" widget of a dock with the main window as a parent is pointless, since the dock will take ownership of that widget;

Considering the above, you should remove all sizeHint() overrides, set the proper allowed areas and then lay out the docks as required.

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setGeometry(200, 200, 800, 800)
        self.UiComponents()
        self.show()

    def UiComponents(self):
        dock1 = QDockWidget("Dock_1", self)
        dock2 = QDockWidget("Dock_2", self)
        dock3 = QDockWidget("Dock_3", self)
        dock4 = QDockWidget("Dock_4", self)
        dock5 = QDockWidget("Dock_5", self)

        dock1.setAllowedAreas(Qt.LeftDockWidgetArea)
        dock2.setAllowedAreas(Qt.LeftDockWidgetArea)
        dock3.setAllowedAreas(Qt.RightDockWidgetArea)
        dock4.setAllowedAreas(Qt.RightDockWidgetArea)
        dock5.setAllowedAreas(Qt.RightDockWidgetArea)

        w_1 = Dock_1()
        w_2 = Dock_2()
        w_3 = Dock_3()
        w_4 = Dock_4()
        w_5 = Dock_5()

        dock1.setWidget(w_1)
        dock2.setWidget(w_2)
        dock3.setWidget(w_3)
        dock4.setWidget(w_4)
        dock5.setWidget(w_5)

        self.addDockWidget(Qt.LeftDockWidgetArea, dock1)
        self.addDockWidget(Qt.LeftDockWidgetArea, dock2)
        self.addDockWidget(Qt.RightDockWidgetArea, dock3)
        self.addDockWidget(Qt.RightDockWidgetArea, dock4)
        self.addDockWidget(Qt.RightDockWidgetArea, dock5)

        self.splitDockWidget(dock1, dock2, Qt.Vertical)
        self.splitDockWidget(dock3, dock5, Qt.Horizontal)
        self.splitDockWidget(dock3, dock4, Qt.Vertical)

        self.docks = dock1, dock2, dock3, dock4, dock5

    def resizeEvent(self, event):
        super().resizeEvent(event)
        side = self.width() // 5 # 2 / 10
        center = side * 3 # 6 / 10
        widths = side, side, center, center, side
        self.resizeDocks(self.docks, widths, Qt.Horizontal)
        vUnit = self.height() // 10
        top = vUnit * 7
        bottom = vUnit * 3
        heights = top, bottom, top, bottom, top + bottom
        self.resizeDocks(self.docks, heights, Qt.Vertical)

Upvotes: 2

Related Questions