【问题标题】:Qt widget stacking child layouts on top of each otherQt 小部件将子布局堆叠在一起
【发布时间】:2017-08-14 21:14:28
【问题描述】:

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() 而其他的没有,所以它对我来说似乎是坏的。

但这不是图形小部件的问题,因为图形布局只能用于添加图形布局项,例如不包括图形文本项。

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

【问题讨论】:

    标签: c++ qt


    【解决方案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) 不适合你的原因。

    【讨论】:

      【解决方案2】:

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

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

      总而言之 - 布局和育儿是两种不同的机制。第一个是用于控制小部件的位置和大小,另一个是用于对象层次结构和资源管理(父母删除他们的孩子)。不过,布局有一个方便的构造函数,它可以同时进行 - 设置布局的父级并在父窗口小部件上设置该布局。

      在代码中:

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

      【讨论】:

        猜你喜欢
        • 2017-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-18
        • 1970-01-01
        • 2014-12-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多