繁体   English   中英

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

[英]Qt widget stacking child layouts on top of each other

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(),而其他子类却没有,因此对我来说似乎已经坏了。

但是,这不是graphicswidget的问题,因为graphicslayout只能用于添加graphicslayoutitems,而其中不包括graphicsTextitems。

解决方案2使用QGraphicsProxyWidget代替QGraphicsWidget解决了该问题!

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的关系持续到窗口小部件或布局被破坏为止。 参见文档

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

这就是为什么subitem2 = new QSlider(item)对您不起作用的原因。

我认为您在将父子关系与布局管理混淆了。

让我们从布局开始。 在小部件上设置时,布局成为该小部件的子级。 与父部件一起构造时,该部件成为父部件,并且在该部件上设置了布局。 将小部件添加到布局时,它们成为设置了布局的小部件的子级,而不是布局本身。 在小部件上设置父级或与父级构造小部件不会自动将小部件添加到其父级布局。 删除布局不会删除其控制的小部件,因为它们不是其子级。

总而言之-布局和育儿是两种不同的机制。 第一个用于控制窗口小部件的位置和大小,第二个用于对象层次结构和资源管理(父级删除其子级)。 布局虽然有一个便捷的构造函数,但它既可以实现-设置布局的父级,又可以在父窗口小部件上设置该布局。

在代码中:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM