Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-60093

Splitting tabified QDockWidget makes tabified and new widget disappear

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P3: Somewhat important P3: Somewhat important
    • None
    • 4.8.7, 5.8.0
    • Widgets: Layout
    • None
    • Windows 7 Visual Studio (2013/15/17) x64

      I have an application which should contain multiple QDockWidgets.
      Along the way, I am splitting and tabbing widgets (along with allowing the user to do the same to adapt the layout to his needs).
      Somewhere down the line, I then want to be able to split an existing widget to show a new one, but when splitting a currently tabifyed window, I see a strange bug.

      Let's say I want to create the layout shown in Figure "qt-desired-layout".
      Widget 4 is created last and needs to go next to the tabified widgets 2 & 3. However, inserting it causes itself and another widget to go missing, as shown in Figure "qt-actual-layout".
      Here's code to reproduce the problem (TestWidget simply displays the given text with background in the given color, and DockWidgetWrapper is a simple wrapper into QDockWidget for any QWidget, see below):

      Test.cpp
          QWidget* testWidget1 = new TestWidget("1", QColor("red"));
          QWidget* testWidget2 = new TestWidget("2", QColor("green"));
          QWidget* testWidget3 = new TestWidget("3", QColor("blue"));
          QWidget* testWidget4 = new TestWidget("4", QColor("yellow"));
          DockWidgetWrapper* testQWidget1 = new DockWidgetWrapper(testWidget1, "Test Widget 1", "TestWidget1");
          DockWidgetWrapper* testQWidget2 = new DockWidgetWrapper(testWidget2, "Test Widget 2", "TestWidget2");
          DockWidgetWrapper* testQWidget3 = new DockWidgetWrapper(testWidget3, "Test Widget 3", "TestWidget3");
          DockWidgetWrapper* testQWidget4 = new DockWidgetWrapper(testWidget4, "Test Widget 4", "TestWidget4");
          addDockWidget(Qt::LeftDockWidgetArea, testQWidget1);
          splitDockWidget(testQWidget1, testQWidget2, Qt::Vertical);
          tabifyDockWidget(testQWidget2, testQWidget3);
          splitDockWidget(testQWidget3, testQWidget4, Qt::Horizontal);
      

      Widgets 3 and 4 are completely gone after the last splitDockWidget call, so calling splitDockWidget on a tabified widget makes both the to-be-inserted and the tabified widget disappear. If I bring up the context menu on a QDockWidget header, and make Widget2 disappear through it, the app looks even more strange: There is an empty area where widget 3 and 4 are supposed to be (see Figure "qt-hiding-dockwidget"). The layout seems to be under the impression they are still shown, according to the context menu. Only when disabling those two as well, then the empty area below Widget1 disappears.

      If I split first and then tabify, it's fine. The problem is that I would like to be independent of any order (and users can modify the layout in between too, so I really can't depend on any widget not being tabbed at any point).
      In the documentation to splitDockWidget I could find the following:

          Note: if first is currently in a tabbed docked area, second will be added as a new tab, not as a neighbor of first. This is because a single tab can contain only one dock widget.
      

      This is however not what happens.

      For me this problem consistently occured first with Qt 4.8, and still in 5.8. Note that rearranging the calls is not a solution for me, as I open a wide variety of different dock widgets in my application, depending on the specific tools the user wants to use. Once the widgets are "gone", the only way to get them back is to load a layout where they are visible, or to "reset" the layout (by first saving the "original" layout of the mainwindow via saveState before any widgets are shown, and then restoring that via restoreState; then all widgets will be lined up vertically).

      Is there a fix or workaround for this? The only workaround I see at the moment is a bit tedious - to find out if a dock widget is tabified (via QMainWindow::tabifiedDockWidgets, and if it is, then tabify, otherwise split.

      EDIT: Played around now with this workaround, yet even tabifiedDockWidgets() does not seem to do in my case what it should - it returns a list of size 0 for my tabified dock widget. Does it maybe make a difference here how the tabification took place, whether it was via tabifyDockWidgets directly, or done by the user or by the restoreState() method? Possibly another bug? I cannot pin this one down though in a simple example yet.

      Note that if this problem were fixed as per the splitDockWidget note mentioned above, this leaves something to be desired: In my example, it means that once I have tabbed widgets 2 and 3, there is no way to (programmatically) get widget 4 to be to the right of the two - or is there another way to achieve that?

      For completeness, here are the definitions of TestWidget and DockWidgetWrapper classes:

      TestWidget.cpp
      #include <QWidget>
      #include <QPainter>
      #include <QPaintEvent>
      #include <QFontMetrics>
      
      class TestWidget: public QWidget
      {
      Q_OBJECT
      private:
          QString m_content;
          QColor m_fillColor;
      public:
          TestWidget(QString content, QColor color):
              m_content(content),
              m_fillColor(color)
          {
              m_fillColor.setAlpha(50);
          }
      protected:
          void paintEvent(QPaintEvent* e)
          {
              QPainter p(this);
              QFontMetrics fm(p.font());
              QRect g(geometry());
              p.fillRect(g, m_fillColor);
              p.drawText(g.width()/2 - fm.width(m_content), g.height()/2 + fm.height(), m_content);
          }
      };
      
      DockWidgetWrapper.cpp
      
      #include <QDockWidget>
      #include <QVBoxLayout>
      
      class DockWidgetWrapper: public QDockWidget
      {
      Q_OBJECT
      public:
          DockWidgetWrapper(QWidget* widget, QString const & windowTitle, QString const & objectName)
          {
              setWindowTitle(windowTitle);
              setFeatures(DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable);
              setWidget(widget);
              setObjectName(objectName);
          }
      };
      

        1. qt-actual-layout.png
          13 kB
          Bernhard Froehler
        2. qt-desired-layout.png
          17 kB
          Bernhard Froehler
        3. qt-hiding-dockwidget.png
          15 kB
          Bernhard Froehler
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            qt.team.quick.subscriptions Qt Quick and Widgets Team
            codeling Bernhard Froehler
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:

                There are no open Gerrit changes