Size policy control for a QDockWidget



  • My application has a dock widget that is positioned at the bottom and may only dock at the bottom. Inside the dock is a QTextEdit that I use to display status messages from the application. I really only need ~4 lines visible, but I would like the text widget to be resizable when the dock is floating. In the MainWindow's layout there are only the dock widget and a QTabWidget. I cannot figure out how to make the dock widget follow the size policy correctly when the application starts up initially.

    @
    Size policies:
    QTabWidget
    Horizontal - Expanding
    Vertical - Expanding
    QDockWidget
    Horizontal - Expanding
    Vertical - Expanding
    QTextEdit ( embedded in the dock's layout )
    Horizontal - Expanding
    Vertical - Minimum
    Minimum Height - 50
    @

    Since the dock has an expanding vertical policy and it's only embedded widget, the text edit, has a minimum vertical policy, it seems like the dock should initially show the widget at its minimum height. Instead, when the application is first run, it shows the text edit with a much larger vertical size. The dock is easily resizeable, but I want it to be shown at the correct size when it first appears.

    I'm pretty frustrated, and haven't had a lot of luck with Qt's size policies. I'll post links to some pictures of the applications behavior.

    I'm using QtDesigner embedded in QtCreator to create the UI:
    QtCreator 2.0.0
    Qt 4.7.0

    !http://lh3.ggpht.com/_BpBCOVaCeXU/TT4Do9gtyNI/AAAAAAAAAGE/l60PjhPhR38/s400/lep0.png(Initial Display)!
    !http://lh5.ggpht.com/_BpBCOVaCeXU/TT4DowNLjJI/AAAAAAAAAGI/AB0hUyqvx9Y/s400/lep1.png(Manually Resized)!
    !http://lh4.ggpht.com/_BpBCOVaCeXU/TT4Dpf4k8NI/AAAAAAAAAGM/XOnq76sGxS4/s400/lep2.png(Floating)!

    mainwindow.ui (irrelevant stuff cleared)
    @
    <?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>983</width>
    <height>814</height>
    </rect>
    </property>
    <property name="windowTitle">
    <string>Leprechaun</string>
    </property>
    <widget class="QWidget" name="centralWidget">
    <layout class="QGridLayout" name="gridLayout_8">
    <item row="0" column="0">
    <widget class="QTabWidget" name="viewTabs">
    <property name="sizePolicy">
    <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
    <horstretch>0</horstretch>
    <verstretch>9</verstretch>
    </sizepolicy>
    </property>
    <property name="currentIndex">
    <number>6</number>
    </property>

      ...
    
     </widget>
    </item>
    

    </layout>
    </widget>
    <widget class="QMenuBar" name="menuBar"/>
    <widget class="QStatusBar" name="statusBar"/>
    <widget class="QDockWidget" name="outputDock">
    <property name="sizePolicy">
    <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
    <horstretch>0</horstretch>
    <verstretch>0</verstretch>
    </sizepolicy>
    </property>
    <property name="minimumSize">
    <size>
    <width>112</width>
    <height>100</height>
    </size>
    </property>
    <property name="baseSize">
    <size>
    <width>0</width>
    <height>0</height>
    </size>
    </property>
    <property name="floating">
    <bool>false</bool>
    </property>
    <property name="allowedAreas">
    <set>Qt::BottomDockWidgetArea</set>
    </property>
    <property name="windowTitle">
    <string>Status Output Window</string>
    </property>
    <attribute name="dockWidgetArea">
    <number>8</number>
    </attribute>
    <widget class="QWidget" name="dockWidgetContents">
    <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0">
    <widget class="QTextEdit" name="outputViewBox">
    <property name="sizePolicy">
    <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
    <horstretch>0</horstretch>
    <verstretch>0</verstretch>
    </sizepolicy>
    </property>
    <property name="minimumSize">
    <size>
    <width>0</width>
    <height>50</height>
    </size>
    </property>
    <property name="maximumSize">
    <size>
    <width>16777215</width>
    <height>16777215</height>
    </size>
    </property>
    <property name="baseSize">
    <size>
    <width>0</width>
    <height>75</height>
    </size>
    </property>
    </widget>
    </item>
    </layout>
    </widget>
    </widget>
    </widget>
    <layoutdefault spacing="6" margin="11"/>
    </ui>
    @

    Thanks in advance for your help!



  • I'm not sure what the dock widget does when it is shown for the first time. Will it expand to it's own preferred size or will it honor it's child widgets' size wishes?

    Maybe a stupid question, but have you tried setting a size policy or an initial size on the dock itself?



  • @Franzk
    yes, I have tried, and it doesn't seem to do anything



  • Hm, docks and imposed sizes are nasty it seems. The dock widget will be scaled to whatever seems to be a decent size at start up.



  • Well, that's irritating, but not really a problem for my app. Maybe I could force it using a setGeometry() ??



  • You could try that, yea.



  • There have been various posts over the years regarding control of the size of a QDockWidget in a QMainWindow dock area. I, too, have been struggling with this issue and have only been able to achieve a partial, and somewhat unsatisfactory, solution. The main problem (if you'll excuse the pun) is the inability to get a grip on the docking mechanism from the context of the QMainWindow that does the work of managing its dock areas. Attempts to use layout management - size policy and size hint controls - are not effective; the QMainWindow does its own thing when changing dock area sizes.

    First, what limited success I have had:

    Starting with a QMainWindow subclass (MW) and a QDockWidget subclass (DW). The DW has a QWidget, with a QHBoxLayout, that is setWidget in the DW. This layout has two widgets - I'll call them panels - with one of these panels intended to be shown or hidden depending on context: shown when the DW is in the bottom or top dock areas or floating, hidden otherwise. The sizeHint of the other panel after construction is used (along with appropriate margin spacing) to set the "base size" of the DW, with the constructed sizeHint width of the panel that will change visibility providing the increment to the base size when appropriate: the DW implementation is provided with a panel_visible method that is used to enable or disable the variable panel by applying setVisible to the panel and changing the value of the sizeHint by the increment value. The size policy of the DW and its panels are set to Minimum.

    In the MW the DW dockLocationChanged and topLevelChanged signals are connected to a DW_resize slot. Here, when the DW isVisible, isWindow is false and MW::dockWidgetArea reports either LeftDockWidgetArea or RightDockWidgeArea, DW::panel_visible(false) is called to change the effective DW size (when the above conditions are not met DW::panel_visible(true) is called, of course). Invoking DW::resize, and updateGeometry and update in the MW has no effect on the dock area size. However if DW::setMaximumSize(DW::sizeHint()) is called the dock area is correctly resized (no updateGeometry or update needed). This works as desired when the DW is floated (by dragging or double-clicking its title bar) and then redocked (by double-clicking its title bar or dragging it back over a side dock area). So far, so good.

    Now the catch:

    Having coerced the MW to fit its dock area to the prescribed DW size the DW needs to be released from its fixed size constraint so the user can resize the dock area by dragging the spit handle provided by the MW between to the dock area and the central area. The obvious answer is to just call DW::setMaximumSize(0xFFFFFF, 0xFFFFFF) to "release" the DW constraints. Yes, except that update painting optimization that goes on behind the scenes coalesces the two sizing events with the result that the initial dock shrink action is lost. By putting a qApp->sendPostedEvents() and qApp->flush() between the two setMaxmimumSize calls this optimizing effect is avoided, the dock area is fit to the DW size and then left released so the dock area can be resized by the user ... sometimes.

    This solution works when the DW goes from floating to docked by double-clicking the DW title bar, but not when the DW is dragged to a side dock in the MW. So, for example, if the user drags the DW from the left dock to the right dock the right dock area is not resized as expected; the receiving dock area remains the size of the floating DW that is produced during the drag from one side to another. If the DW in the receiving dock area has its title bar double-clicked (to become floating again) and then double-clicked again (to return it to the same dock area) the MW now fits the dock area as intended. On close inspection - by monitoring the MW::paintEvent - I see that when the dock area ends up the intended size the flush() is immediately followed by a paintEvent where the DW reports having the intended size and after the second setMaximumSize that unconstrains the DW a paintEvent occurs with the DW still the intended sized. But when the DW is dragged into the dock area the flush() is again immediately followed by paintEvent where the DW reports having the intended size, but after the second setMaximumSize in this case there are two paintEvents with the DW now surprisingly having its previous floating size!

    I have yet to find a way to prevent this unexplained overriding of the DW size after it has been correctly sized. It seems clear that an additional resize event is being generated by the MW after the DW_resize slot processing has returned, from size information that the MW has been holding from before the signals were emitted that lead to the slot. Monitoring the MW::eventFilter does indeed reveal a Resize event occurring after DW_resize has returned that changes the DW size from what it had been set to in the slot code back to its size when it was floating. When double-clicking the DW tile bar is used to move the DW from floating back into the side dock no additional Resize event occurs after the DW_resize slot returns.

    The challenge, then, is how to prevent the unexpected resize reversion from happening after the DW has been correctly sized in the DW_resize slot. Perhaps some coercion in DW::resizeEvent will avoid this problem ....

    Better, of course, would be if the Qt developers would provide the application developer thorough controls in the QMainWindow API over its dock management activities - especially dock area sizing - and/or access to the widgets that it uses for dock area management.

    I am currently using Qt 4.6.2 on Linux, OS X and MS/Windows. The debug reports, above, were done on an Intel OS X 10.6.7 system; results differ somewhat on the different platforms, but the basic problem is the same. Perhaps these QMainWindow/QDockWidget issues have been dealt with in a later version of Qt? Perhaps someone has deeper insight into what is going on here and can offer a simple solution?



  • Hi, does anyone know if this has been addressed yet? I still have this problem.



  • Hello,

    as i looked for an easy way to resize my dockwindows, and that took my time (eventhough it should be a simple thing)! I would like to post my solution here, maybe it helps someone:

    my scenario : i have only two dockwidgets (there s no centralwidget), one on the left and one on the right side of the main window (QMainWindow). I wanted to resize the left one, so that it should occupy about 1/5 of the main window. In the left one, i put a QTreeWidgets in it.

    So here is my solution: (the information in qt-Documents, that the size of the child widget changes the size of the dockwindow worked for me)

    //creating dock left
    dockList = new QDockWidget(tr("Components"), this);
    dockList->setAllowedAreas(Qt::LeftDockWidgetArea);
    //putting my qtreewidget in the dock
    componentList = new QTreeWidget(dockList);
    componentList->header()->close();
    componentList->setColumnCount(1);

    //setting now dock size
    componentList->resizeColumnToContents(1); //this is to have an idea of the size of the tree
    dockList->setMinimumSize(componentList->size().width(), 0); // 0 just to give a min size
    dockList->setMaximumSize(componentList->size().width()*2, this->size().height()*2); // and here also multiply wth 2 to give any max number

    // now add the list to dockwidget
    topLevelComponent = new QTreeWidgetItem(QStringList() << "project");
    componentList->addTopLevelItem(topLevelComponent);
    dockList->setWidget(componentList);
    dockList->setFeatures(QDockWidget::DockWidgetClosable);
    addDockWidget(Qt::LeftDockWidgetArea, dockList);


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.