QDockWidget tabify / splitDockWidget怪异的行为/错误? [英] QDockWidget tabify/splitDockWidget weird behavior / bug?

查看:2392
本文介绍了QDockWidget tabify / splitDockWidget怪异的行为/错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序与MdiChilds应该包含多个QDockWidgets。但我有麻烦分裂/制表的小部件,使他们产生所需的默认布局。
我基本上想要一个这样的布局:





最后创建小部件4,需要移动到标签小部件2&但是,插入它会导致自己和另一个小部件失踪:





下面是生成第二个屏幕截图的代码:



主窗口(或mdi childs,没有什么关系)我做以下:

  QDockWidgetTest :: QDockWidgetTest * parent)
:QMainWindow(parent)
{
ui.setupUi(this);
setCentralWidget(0); //只有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 :: Horizo​​ntal);
}

其中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 );
}
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是一个简单的包装到QDockWidget任何QWidget:

  #include< QDockWidget> 
#include< QVBoxLayout>

类DockWidgetWrapper:public QDockWidget
{
public:
DockWidgetWrapper(QWidget * widget,QString const& windowTitle,QString const& objectName)
{
setWindowTitle(windowTitle);
setFeatures(DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable);
setWidget(widget);
setObjectName(objectName);
}
};

小部件3和4在最后一次splitDockWidget调用后完全消失,因此调用 splitDockWidget 在一个制表符的小部件上,使得要插入的和制表的小部件消失。如果我在QDockWidget头部打开上下文菜单,并使Widget2消失通过它,应用程序看起来更奇怪:





因此,有一个空白区域,其中小部件3和4是(Qt似乎是在他们仍然显示的印象,根据上下文菜单!)。只有当禁用这两个,以及Widget1下面的空白区域消失。



如果我先分裂,然后tabify,很好。问题是,我想在软件的一般部分做标签,然后拆分后,当我加载它的一个专门的部分。所以重新排序这两个不是真的一个选择我。 在文档中,我只能找到以下内容:


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


这绝对不会发生什么。此外,这个描述留下了一些想要的东西:在我的例子中,这意味着一旦我有选项卡窗口小部件2和3,没有办法(以编程方式)获取窗口小部件4在这两个的右边,或者有另一种方法来实现这一点吗?



对我来说,这个问题始终发生在Qt 4.8和5.3。我想这可能是Qt中的一个错误?这是一个已知的错误(我的搜索到目前为止已经变空了)?

解决方案

我相信你的评估错误是正确的,所以这是一个可能的解决方法。



我发现我可以通过显式添加dock窗口部件到窗体并指定他们的停靠区,然后制表。我知道你想要相反的顺序,但至少这会摆脱奇怪的工件。



首先,确保dock嵌套和tabbing通过设计器或程序像这样(你可以选择包括动画在这里):

  setDockOptions(DockOption :: AllowNestedDocks | DockOption :: AllowTabbedDocks); 

然后显式添加每个基座。您只添加一个。

  addDockWidget(Qt :: TopDockWidgetArea,testQWidget1); 
addDockWidget(Qt :: LeftDockWidgetArea,testQWidget2);
addDockWidget(Qt :: LeftDockWidgetArea,testQWidget3);
addDockWidget(Qt :: RightDockWidgetArea,testQWidget4);

通过将最后一个设置为:

  Qt :: RightDockWidgetArea 

想。然后调用:

  tabifyDockWidget(testQWidget2,testQWidget3); 

如果您希望再次调用addDockWidget(),您可以通过编程将docks移动到新位置。 Qt是聪明的,以意识到你正在重新添加一个现有的,所以它不会重复。



我唯一的问题,运行这个测试代码是顶部码头似乎是巨大的,占据了大部分的空间。我相信一旦你添加控件到每个,他们将适当地调整大小。



我很好奇知道你的解决方案是什么,因为我即将开始一些



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


I have an application with MdiChilds which should contain multiple QDockWidgets. I am however having troubles splitting/tabbing up the Widgets so that they produce the desired default layout. I basically want a layout like this:

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:

Here's the code producing the second screenshot:

In the constructor of the main window (or the mdi childs, doesn't really matter) I do the following:

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);
}

where TestWidget is defined as a simple Widget just painting itself in the given color, and the caption in the middle:

#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);
    }
};

and DockWidgetWrapper is a simple wrapper into QDockWidget for any QWidget:

#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);
    }
};

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:

So there is an empty area where widget 3 and 4 are supposed to be (Qt 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 do the tabbing in a general part of the software, and the splitting afterwards when I load a specialized part of it. So reordering the two is not really an option for me. In the documentation I could only find the following on that:

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 definitely not what happens. And in addition, this description 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 me this problem consistently occurs with Qt 4.8 and 5.3. I suppose this might be a bug in Qt? Is it a known bug (my search so far has turned up empty)? Or is there any other reasonable explanation for this or a way to "get back" the two lost widgets?

解决方案

I believe your assessment of the bug is correct, so this is a possible workaround.

I find that I can get the results you want by explicitly adding the dock widgets to the form and specifying their dock area, then tabifying. I know you wanted the reverse order, but at least this gets rid of the weird artifacts.

First, make sure dock nesting and tabbing are enabled either through the designer or programmatically like so (you can optionally include animation here):

setDockOptions(DockOption::AllowNestedDocks | DockOption::AllowTabbedDocks);

Then explicitly add each dock. You were only adding one.

addDockWidget(Qt::TopDockWidgetArea, testQWidget1);
addDockWidget(Qt::LeftDockWidgetArea, testQWidget2);
addDockWidget(Qt::LeftDockWidgetArea, testQWidget3);
addDockWidget(Qt::RightDockWidgetArea, testQWidget4);

By setting that last one to:

Qt::RightDockWidgetArea

it appears to position it where you want. Then call:

tabifyDockWidget(testQWidget2, testQWidget3);

You can later programmatically move the docks to new locations if you desire by calling addDockWidget() again. Qt is smart enough to realize you are re-adding an existing one, so it won't duplicate it.

My only problem when running this test code is that the top dock seems to be huge and take up most of the space. I believe that once you add controls to each, they will resize appropriately.

I'm curious to know what your solution ended up being because I am about to embark on some dock related work myself.

Hope that helps.

PS - This is my first SO answer after lurking for many years, so go easy on me =)

这篇关于QDockWidget tabify / splitDockWidget怪异的行为/错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆