QDockWidget tabify/splitDockWidget奇怪的行为/ bug?

cod*_*ing 2 c++ qt qt4.8 qt5

我有一个MdiChilds应用程序,它应该包含多个QDockWidgets.然而,我在分割/标记窗口小部件时遇到麻烦,以便它们生成所需的默认布局.我基本上想要这样的布局:

QDockWidgetTest所需的布局

窗口小部件4最后创建,需要在列表窗口小部件2和3旁边.但是,插入它会导致自身和另一个窗口小部件丢失:

QtDockWidgetTest截图

这是产生第二个屏幕截图的代码:

在主窗口的构造函数(或mdi孩子,并不重要)我执行以下操作:

QDockWidgetTest::QDockWidgetTest(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    setCentralWidget(0); // only QDockWidgets
    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);
}
Run Code Online (Sandbox Code Playgroud)

其中TestWidget被定义为一个简单的Widget,它只是用给定的颜色绘制自己,而中间的标题是:

#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QFontMetrics>

class TestWidget: public QWidget
{
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);
    }
};
Run Code Online (Sandbox Code Playgroud)

和DockWidgetWrapper是任何QWidget的QDockWidget的简单包装:

#include <QDockWidget>
#include <QVBoxLayout>

class DockWidgetWrapper: public QDockWidget
{
public:
    DockWidgetWrapper(QWidget* widget, QString const & windowTitle, QString const & objectName)
    {
        setWindowTitle(windowTitle);
        setFeatures(DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable);
        setWidget(widget);
        setObjectName(objectName);
    }
};
Run Code Online (Sandbox Code Playgroud)

在最后一次splitDockWidget调用之后,窗口小部件3和4完全消失,因此调用splitDockWidget列表窗口小部件会使待插入和窗格化窗口小部件消失.如果我在QDockWidget标题上调出上下文菜单,并让Widget2通过它消失,应用程序看起来更奇怪:

禁用Widget 2后的QtDockWidgetTest

所以有一个空白的区域,小部件3和4应该是(根据上下文菜单,Qt似乎仍然显示它们仍然显示!).只有当禁用这两个时,Widget1下面的空白区域才会消失.

如果我先拆分然后再列出,那就没关系了.问题是我想在软件的一般部分中进行跳转,然后在加载其特殊部分时进行拆分.所以重新排序这两个对我来说不是一个真正的选择.在文档中我只能找到以下内容:

注意:如果第一个当前位于选项卡式停靠区域,则第二个将添加为新选项卡,而不是第一个的邻居.这是因为单个选项卡只能包含一个停靠窗口小部件.

这绝对不是发生的事情.此外,这个描述还有待改进:在我的例子中,这意味着一旦我有选项卡式窗口小部件2和3,就没有办法(以编程方式)将窗口小部件4放在两者的右边,或者是还有另一种方法可以实现吗?

对我来说,Qt 4.8和5.3一直出现这个问题.我想这可能是Qt中的一个错误?这是一个已知的错误(到目前为止,我的搜索结果是空的)?或者是否有任何其他合理的解释或者"找回"两个丢失的小部件?

小智 6

我相信您对错误的评估是正确的,因此这是一种可能的解决方法.

我发现通过将停靠窗口小部件显式添加到窗体并指定其停靠区域,然后列表,我可以获得所需的结果.我知道你想要相反的顺序,但至少这摆脱了奇怪的文物.

首先,确保通过设计器或编程方式启用停靠嵌套和选项卡(您可以选择在此处包含动画):

setDockOptions(DockOption::AllowNestedDocks | DockOption::AllowTabbedDocks);
Run Code Online (Sandbox Code Playgroud)

然后明确添加每个dock.你只是加了一个.

addDockWidget(Qt::TopDockWidgetArea, testQWidget1);
addDockWidget(Qt::LeftDockWidgetArea, testQWidget2);
addDockWidget(Qt::LeftDockWidgetArea, testQWidget3);
addDockWidget(Qt::RightDockWidgetArea, testQWidget4);
Run Code Online (Sandbox Code Playgroud)

通过将最后一个设置为:

Qt::RightDockWidgetArea
Run Code Online (Sandbox Code Playgroud)

它似乎将它定位在你想要的位置.然后打电话:

tabifyDockWidget(testQWidget2, testQWidget3);
Run Code Online (Sandbox Code Playgroud)

如果需要,可以稍后通过再次调用addDockWidget()以编程方式将停靠点移动到新位置.Qt很聪明,意识到你正在重新添加一个现有的,所以它不会复制它.

运行此测试代码时我唯一的问题是顶部扩展坞看起来很大并且占用了大部分空间.我相信一旦你为每个人添加控件,他们就会适当调整大小.

我很想知道你的解决方案最终是什么因为我将要自己开始一些与码头相关的工作.

希望有所帮助.

PS - 这是我潜伏多年后的第一个SO答案,所以对我来说很容易=)