【问题标题】:Qt: Widget method addButtons() does NOT work as needed [duplicate]Qt:小部件方法 addButtons() 不能按需要工作 [重复]
【发布时间】:2016-08-14 20:26:52
【问题描述】:

我在 Windows7 上使用 Qt5(初学者)。
在我的应用程序的主窗口中,我想显示和删除一些按钮。

widget = new ButtonWidget(ui->frame); // frame is a QScrollArea
connect(ui->addBtns,    SIGNAL(clicked()), widget, SLOT(addButtons()));
connect(ui->deleteBtns, SIGNAL(clicked()), widget, SLOT(deleteButtons()));

ButtonWidget 课程在这里:

ButtonWidget::ButtonWidget(QWidget * parent) : QWidget(parent)
{
   //addButtons();
}

void ButtonWidget::addButtons()
{
   QStringList texts{"1\nok", "2\nok", "3\nok", "4\nok", "5\nok", "6\nok"};
   gridLayout = new QGridLayout;
   for(int i = 0; i < texts.size(); i++)
   {
      QPushButton * button = new QPushButton(texts[i]);
      gridLayout->addWidget(button, i / 5, i % 5);
   }
   setLayout(gridLayout);
}

// I'm not sure this method/function is ok... :(
void ButtonWidget::deleteButtons()
{
    QLayoutItem * child;
    while((child = gridLayout->takeAt(0)) != 0)
    {
        gridLayout->removeWidget(child->widget());
        delete child->widget();
        delete child;
    }
    delete gridLayout;
}

问题是:当我点击add_buttons 时,我会显示所有按钮,但它们是缩小、缩小 之类的...... :

OTOH...如果我从构造函数中的 addButtons() 调用中删除注释(因此从构造函数中调用),结果正常:

所以,最后我有 2 个问题:
1)如何修复代码以便能够正确添加这些按钮(当点击 add_buttons 时)?
2) deleteButtons() 方法可以吗?

【问题讨论】:

  • 您可能必须在您的 ButtonWidget 类上实现 sizeHint() 或者在 addButtons 末尾实现 resize(sizeHint());
  • 我想你可能是对的,但是作为一个 qt/c++ 初学者我不知道该怎么做...我会深入研究文档,也许我会弄清楚或找到在这件事上有用的东西。
  • 我认为您可以更改问题的标题,因为它是从您有问题的布局中删除项目。添加工作正常。那我就给你的问题加分。
  • 嗯,有点意思...拥有那些微小的按钮远非“工作”好:)

标签: c++ qt user-interface button widget


【解决方案1】:

首先,我建议这样做

gridLayout = new QGridLayout(this);

在构造函数中。您无需删除所有网格,重新创建并设置为布局,此时您可以删除其内容(例如使用删除按钮)并在之后再次填充。

EDIT:Werner Erasmus 的评论:无需设置布局。它有一个父小部件这一事实意味着它会自行设置。

问题是你不修改 addButtons() 你会替换以前的按钮而不知道它们去哪里。

另外,尝试给 QPushButton 一个父级:

new QPushButton(texts[i],this);

第二点:Removing widgets from QGridLayout

【讨论】:

  • 不需要设置布局。它有一个父小部件这一事实意味着它会自行设置。
  • 确实,感谢您的评论,我编辑了我的答案。
【解决方案2】:

编辑:

经过更多的测试(没有看源码,但怀疑删除按钮一定是安全的,否则事情会很脆弱),我实现了removeButtons如下:

void ButtonWidget::deleteButtons()
{
    while(myLayout->count())
    {
        delete myLayout->itemAt(0)->widget();
    }
}

这是可行的,它证明删除小部件也会从其父小部件以及与父小部件关联的布局中删除该小部件(通过连接到当子小部件被删除时的插槽)。上面的代码证实了这一点,因为 count(),它指的是布局项的数量,减少到零(这些布局项由 Layout 管理)。 takeAt(x) 永远不会被调用,也不需要 - 只需删除小部件(按钮)。哇!

原始答案

正如我在另一篇文章中提到的,您只需要删除按钮(它会自动从其父级中删除)。但是,如果将小部件添加到布局,则该布局的父级将成为小部件的父级,并创建由布局本身管理的关联 QLayoutItem。要删除按钮,最安全的方法是获取所有布局项(所有权接受者的责任),删除每个项目关联的小部件,然后删除每个项目。我会尝试找到除了来源之外的相关参考资料......

以下代码有效:

//ButtonWidget.h
#include <QWidget>
#include <QScrollArea>
#include <QHBoxLayout>

class ButtonWidget : public QScrollArea
{
    Q_OBJECT

  public:
    ButtonWidget(QWidget *parent = 0);
    ~ButtonWidget();
    void addButtons();
    void deleteButtons();
  private:
    QHBoxLayout* myLayout;
};

//ButtonWidget.cpp

#include "ButtonWidget.h"
#include <QGridLayout>
#include <QPushButton>
#include <QLayoutItem>

ButtonWidget::ButtonWidget(QWidget * parent) :
  QScrollArea(parent),
  myLayout(new QHBoxLayout(this))
{
}

ButtonWidget::~ButtonWidget()
{
}

void ButtonWidget::addButtons()
{
   QStringList texts{"1\nok", "2\nok", "3\nok", "4\nok", "5\nok", "6\nok"};

   for(int i = 0; i < texts.size(); i++)
   {
      myLayout->addWidget(new QPushButton(texts[i]));
   }
}

void ButtonWidget::deleteButtons()
{
    QLayoutItem * child;

    while((child = myLayout->takeAt(0)) != 0)
    {
      delete child->widget();
      delete child;
    }
}

#include "ButtonWidget.h"
#include <QApplication>
#include <QScrollArea>
#include <QPushButton>
#include <QGridLayout>
#include <QHBoxLayout>
#include <memory>

std::unique_ptr<QScrollArea> makeArea()
{
  std::unique_ptr<QScrollArea> area(new QScrollArea);
  auto layout = new QGridLayout(area.get());
  auto addButton  = new QPushButton("Add");
  auto removeButton  = new QPushButton("Remove");
  layout->addWidget(addButton, 0, 0);
  layout->addWidget(removeButton, 0, 1);
  auto btnWidget = new ButtonWidget;
  layout->addWidget(btnWidget,1,0,1,2);


  QObject::connect(addButton, &QPushButton::clicked, [=]()
  {
    btnWidget->addButtons();
  });

  QObject::connect(removeButton, &QPushButton::clicked, [=]()
  {
    btnWidget->deleteButtons();
  });
  return move(area);
}

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  auto area = makeArea();
  area->show();
  return a.exec();
}

您需要在配置 (.pro) 中启用 c++11 才能使 lambda 工作。

CONFIG += c++11

我已经为您的按钮使用了 QHBoxLayout,因为它可以更好地模拟您想要的内容。虽然完全没有必要,但我从 main 中的 makeArea 返回 unique_ptr,因为它没有父级,我不确定它是否有父级,因为它是创建的第一个小部件,但 unique_ptr 显示了意图。

注意:

显然布局项不是小部件的父级,但与布局本身关联的小部件是属于其布局项的小部件的父级。

【讨论】:

  • 非常感谢您的出色努力!明天我一定会试一试,我到办公室的第一件事。启用了 C++11 并且编译/构建工具包是 msvc2012 或 msvc2013,所以肯定知道 lambdas 等。亲切的问候,SG。
  • takeAt 已经从布局中删除了 layoutItem。我不确定如果您在此之后调用 removeWidget 会发生什么,但我怀疑在您的 deleteWidget 中某处发生了双重删除。当我测试它时它崩溃了
  • @groenhen。如果您满意,也请保持礼貌,并将我的答案打勾为“已接受的答案”(另一个也是)。
  • 我虔诚地这样做。不用担心,我总是很有礼貌:从不投反对票(小例外),总是给答案投反对票(小例外)等。明天给我时间测试一下,我会打勾“接受的答案”比现在盲目投票更快乐。你有我的话 :) 亲切的问候,SG。
  • 我的方法和使用的想法都取得了一些进展。它有效,但是......我遇到了其他一些问题:stackoverflow.com/questions/36792633/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-26
  • 2017-12-26
  • 1970-01-01
  • 1970-01-01
  • 2014-03-19
  • 1970-01-01
相关资源
最近更新 更多