Qt:小部件方法 addButtons() 不能按需要工作
Qt: Widget method addButtons() does NOT work as needed
我正在 Windows7.
使用 Qt5(初学者)
在我的应用程序的主要 window 中,我想显示和删除一些按钮。
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
class 在这里:
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
时,我显示了所有按钮,但它们 缩小了,变小了 之类的...:[=32= ]
OTOH...如果我从构造函数中的 addButtons()
调用中删除注释(因此从构造函数中调用),结果是好的:
所以,最后我有两个问题:
1) 如何修复代码以便能够正确添加这些按钮(单击 add_buttons
时)?
2)deleteButtons()
方法可以吗?
首先,我建议做
gridLayout = new QGridLayout(this);
在构造函数中。您不需要删除所有网格,重新创建它并设置为布局,您只需删除其内容(例如使用删除按钮)并在之后再次填充它。
EDIT:Werner Erasmus 的评论:无需设置布局。它有父小部件的事实意味着它会自行设置。
问题是您不修改 addButtons(),您将替换之前的按钮而不知道它们去哪里了。
此外,尝试给 QPushButton 一个父级:
new QPushButton(texts[i],this);
第二点:Removing widgets from QGridLayout
编辑:
经过更多测试(没有查看源代码,但怀疑删除按钮一定是安全的,否则事情会很脆弱),我按如下方式实现了 removeButtons:
void ButtonWidget::deleteButtons()
{
while(myLayout->count())
{
delete myLayout->itemAt(0)->widget();
}
}
这行得通,它证明删除小部件也会从其父部件中删除小部件,以及与父部件关联的布局(通过与删除子部件时连接的插槽)。上面的代码证实了这一点,因为 count() 指的是布局项的数量,减少到零(这些布局项由 Layout 管理)。 takeAt(x) 永远不会被调用,也不需要被调用 - 只需删除小部件(按钮)。哇哦!
原始答案
如我的另一篇 post 所述,您只需删除按钮(它会自动从其父项中删除)。但是,如果将一个小部件添加到布局中,则该布局的父级将成为该小部件的父级,并创建一个由布局本身管理的关联 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显示意图。
注意:
显然布局项不是小部件的父级,但与布局相关联的小部件本身是属于其布局项的小部件的父级。
我正在 Windows7.
使用 Qt5(初学者)
在我的应用程序的主要 window 中,我想显示和删除一些按钮。
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
class 在这里:
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
时,我显示了所有按钮,但它们 缩小了,变小了 之类的...:[=32= ]
OTOH...如果我从构造函数中的 addButtons()
调用中删除注释(因此从构造函数中调用),结果是好的:
所以,最后我有两个问题:
1) 如何修复代码以便能够正确添加这些按钮(单击 add_buttons
时)?
2)deleteButtons()
方法可以吗?
首先,我建议做
gridLayout = new QGridLayout(this);
在构造函数中。您不需要删除所有网格,重新创建它并设置为布局,您只需删除其内容(例如使用删除按钮)并在之后再次填充它。
EDIT:Werner Erasmus 的评论:无需设置布局。它有父小部件的事实意味着它会自行设置。
问题是您不修改 addButtons(),您将替换之前的按钮而不知道它们去哪里了。
此外,尝试给 QPushButton 一个父级:
new QPushButton(texts[i],this);
第二点:Removing widgets from QGridLayout
编辑:
经过更多测试(没有查看源代码,但怀疑删除按钮一定是安全的,否则事情会很脆弱),我按如下方式实现了 removeButtons:
void ButtonWidget::deleteButtons()
{
while(myLayout->count())
{
delete myLayout->itemAt(0)->widget();
}
}
这行得通,它证明删除小部件也会从其父部件中删除小部件,以及与父部件关联的布局(通过与删除子部件时连接的插槽)。上面的代码证实了这一点,因为 count() 指的是布局项的数量,减少到零(这些布局项由 Layout 管理)。 takeAt(x) 永远不会被调用,也不需要被调用 - 只需删除小部件(按钮)。哇哦!
原始答案
如我的另一篇 post 所述,您只需删除按钮(它会自动从其父项中删除)。但是,如果将一个小部件添加到布局中,则该布局的父级将成为该小部件的父级,并创建一个由布局本身管理的关联 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显示意图。
注意:
显然布局项不是小部件的父级,但与布局相关联的小部件本身是属于其布局项的小部件的父级。