Qt:小部件方法 addButtons() 不能按需要工作
我在 Windows7 上使用 Qt5(初学者).
在我的应用程序的主窗口中,我想显示和删除一些按钮.
I am using Qt5 (beginner) on Windows7.
In the main window of my app I want to display and remove some push-buttons.
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
ok", "2
ok", "3
ok", "4
ok", "5
ok", "6
ok"};
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
时,我会显示所有按钮,但它们是 缩小的、很小的 之类的...... :
Problem is: when I click on add_buttons
, I get all buttons displayed, but they are shrunk, tiny or something... :
OTOH...如果我从构造函数中的 addButtons()
调用中删除注释(因此从构造函数中调用),结果正常:
OTOH... if I remove the comment from addButtons()
call in the constructor (hence calling from within the constructor), the result is ok:
所以,最后我有两个问题:
1) 如何修复代码以正确添加这些按钮(当单击 add_buttons
时)?
2) deleteButtons()
方法可以吗?
So, finally I have 2 questions:
1) How to fix the code to be able to add those buttons properly (when add_buttons
is clicked)?
2) Is the deleteButtons()
method ok?
推荐答案
经过一些测试(没有看源码,但怀疑删除按钮一定是安全的,否则事情会很脆弱),我实现了removeButtons如下:
After some more testing (without looking at the source code, but suspecting that it must be safe to delete button, else things would be brittle), I've implemented removeButtons as follows:
void ButtonWidget::deleteButtons()
{
while(myLayout->count())
{
delete myLayout->itemAt(0)->widget();
}
}
这是有效的,它证明删除一个小部件也会从它的父级中删除该小部件,以及与父级关联的布局(通过连接到删除子小部件时的插槽).上面的代码证实了这一点,因为 count(),它指的是布局项的数量,减少到零(这些布局项由 Layout 管理).takeAt(x) 永远不会被调用,也不需要 - 只需删除小部件(按钮).哇!
This works, and it proves that deleting a widget also removes the widget from it's parent, and layouts associated with the parent (by slots hooked up to when a child widget is deleted). The above code confirms this, as count(), which refers to number of layout items, decrease to zero (and those layout items are managed by the Layout). takeAt(x) is never called, and doesn't need to be - simply delete the widgets (buttons). Wholla!
原始答案
正如我在另一篇文章中提到的,您只需要删除按钮(它会自动从其父级中删除).但是,如果将小部件添加到布局中,则该布局的父级将成为小部件的父级,并创建由布局本身管理的关联 QLayoutItem.要删除按钮,最安全的方法是获取所有布局项目(所有权接受者的责任),删除每个项目关联的小部件,然后删除每个项目.我会尝试在来源之外找到相关的参考资料...
As mentioned in my other post, you only need to delete the buttons (it is removed from its parent automatically). However, if a widget was added to a layout, the parent of that layout becomes the parent of the widget, and an associated QLayoutItem is created that is managed by the layout itself. To the delete the buttons, the safest way is to take all the layout items (ownership the taker's responsibility), delete each items associated widget, and the delete each item. I'll try and find relevant references apart from the sources...
以下代码有效:
//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
ok", "2
ok", "3
ok", "4
ok", "5
ok", "6
ok"};
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 工作.
You need to enable c++11 in your config (.pro) to get the lambdas working.
CONFIG += c++11
我已经为您的按钮使用了 QHBoxLayout,因为它可以更好地模拟您想要的内容.虽然完全没有必要,但我从 main 中的 makeArea 返回 unique_ptr,因为它没有父级,我不确定它是否有父级,因为它是创建的第一个小部件,但 unique_ptr 显示了意图.
I've used QHBoxLayout for your buttons, as it better models what you want. Although strictly not necessary, I'm returning unique_ptr from the makeArea in main, as it has not parent, I'm not sure whether it gets some parent because it is the first widget created, but unique_ptr shows intent.
注意:
显然布局项不是小部件的父级,但与布局本身关联的小部件是属于其布局项的小部件的父级.
Apparently the layout item is not the parent of the widget, but the widget associated with the layout itself is the parent of widgets belonging to its layout item.
相关文章