Qt小部件将子布局堆叠在彼此之上

时间:2017-08-14 10:36:38

标签: c++ qt

Qt有一个与小部件分开的布局系统,这引起了我的问题。我知道当我有一个QSplitter时,我可以通过

添加内容
new SomeCustomQWidget(splitter);

但是,如果我有一个QWidget,我不应该做类似的事吗? Qt网页仅解释了如何将layoutItems添加到布局中,只通过在子类中继承它们来将它们连接到窗口小部件。所以,不,我没有做这样的事情

item = new QWidget(parentsplitter); //this works
subitem = new customWidget(item); //this too
subitem2 = new QSlider(item); //this isn't laid out with subitem

然而,这导致滑块位于子项目的顶部而不是在它旁边(正确或低于我预期)。致电

//either
new QVBoxLayout(item);
//or
item->setLayout(new QVBoxLayout());
//or
item->setLayout(new QVBoxLayout(item));

初始化项目后没有帮助。 (我的逻辑是该项目将布局作为其子项,并将后续子项添加到其中)。

我之前解决了这个问题,但现在我在QGraphicsView中创建一个小部件时遇到了完全相同的问题。我觉得没有必要为我想要动态添加到那些小部件的每个项目创建一个自定义子类,就像Qt网站似乎期望的那样。 (如果我只是想添加一些文本和几个按钮,我真的需要制作2个自定义子类吗?)我使用.ui文件进行基本布局,但这些项目需要动态创建。

解决方案

忘记在用于布局的小部件上调用item->show();

事实证明,我已经测试了其他正确的代码,但由于我的一些子类名为show()而其他子类没有,所以它似乎对我来说很糟糕。

然而,这不是graphicswidgets的问题,因为graphicslayout只能用于添加graphicslayoutitems,不包括例如graphicstextitems。

解决方案2 使用QGraphicsProxyWidget而不是QGraphicsWidget修复了问题!

2 个答案:

答案 0 :(得分:1)

QWidget *parent = new QWidget();
QVBoxLayout *rootLayout = new QVBoxLayout(parent);
QHBoxLayout *subLayout1 = new QHBoxLayout();
QHBoxLayout *subLayout2 = new QHBoxLayout();
rootLayout->addLayout(subLayout1);
rootLayout->addLayout(subLayout2);

subLayout1->addWidget(new QLabel("Foo"));
subLayout1->addWidget(new QLabel("Bar"));

subLayout2->addWidget(new QPushButton("Foo button"));
subLayout2->addWidget(new QPushButton("Bar button"));

parent->show();

注意一旦布局通过setLayout分配给窗口小部件,或者当widger传递给构造函数布局时,它们将以1对1关系持续到窗口小部件或布局被销毁为止。见documentation

  

如果此窗口小部件上已安装布局管理器,QWidget将不允许您安装另一个布局管理器。您必须首先删除现有布局管理器(由layout()返回),然后才能使用新布局调用setLayout()。

这就是subitem2 = new QSlider(item)不适合你的原因。

答案 1 :(得分:0)

我认为你将父/子关系与管理布局混为一谈。

让我们从布局开始。在窗口小部件上设置时,布局将成为该窗口小部件的子项。使用窗口小部件父项构造时,窗口小部件将成为父窗口,并在窗口小部件上设置布局。在布局中添加窗口小部件时,它们将成为布局设置的窗口小部件的子项,而不是布局本身。在窗口小部件上设置父窗口或使用父窗口构建窗口小部件不会自动将窗口小部件添加到其父布局。删除布局不会删除由其管理的小部件,因为它们不是它的子级。

总结一下 - 布局和父母是两种截然不同的机制。第一个用于控制窗口小部件的位置和大小,另一个用于对象层次结构和资源管理(父项删除其子项)。布局有一个方便的构造函数,它同时做两个 - 设置布局的父级并在父窗口小部件上设置该布局。

在代码中:

item = new QWidget()
layout = new QVBoxLayout(item);

相当于:

item = new QWidget();
layout = new QVBoxLayout();

layout->setParent(item);
item->setLayout(layout);

此代码将子项添加到布局,项目成为其父项:

item = new QWidget();
layout = new QVBoxLayout(item);
child = new QWidget();
layout->addWidget(child);

这会将子项添加到父项,但将子项添加到布局:

item = new QWidget();
layout = new QVBoxLayout(item);
child = new QWidget(item);

QSplitter的特殊之处在于它是一个小部件并且它有自己的子级布局,即当您使用拆分器作为小部件的父级时,小部件的几何结构由拆分器控制。其他小部件不会表现得那样。

所以要评论你的代码:

item = new QWidget(parentsplitter); //this works because splitter does layout
subitem = new customWidget(item); //item is not splitter so subitem geometry is not managed
subitem2 = new QSlider(item); //item is not splitter so subitem2 geometry is not managed

如果您想在项目中布置子项目,那么项目也必须是分割器,或者具有管理子项目的布局,所以:

childsplitter = new QWidget(parentsplitter); //note that parentsplitter has only 1 item
subitem  = new customWidget(childsplitter);
subitem2 = new customWidget(childsplitter);

widget = new QWidget(parentsplitter); //note that parentsplitter has only 1 item
lay    = new QHBoxLayout(widget);
subItem  = new customWidget();
subItem2 = new customWidget();
lay->addWidget(subItem);
lay->addWidget(subItem2);

如果您希望父分割器有两个项目,那么您可以:

item  = new customWidget(parentsplitter);
item2 = new customWidget(parentsplitter);