Qt 中的退出应用程序

Posted

技术标签:

【中文标题】Qt 中的退出应用程序【英文标题】:Exit Application in Qt 【发布时间】:2012-10-01 14:13:07 【问题描述】:

我在 Qt 中构建了一个包含两个按钮的应用程序:一个退出按钮和一个导入按钮。按下导入按钮时,屏幕上的滚动区域中会显示一个按钮列表(文件 loggers.csv 包含数据 1;2;3;4;5;)。

一切正常,但是当我按下退出按钮(当然应该关闭所有内容)时,应用程序没有正确停止(Qt 的停止按钮仍然处于活动状态,而播放按钮没有)。当我运行调试器并按下退出按钮时,它会给出一个错误:指定给 RtlFreeHeap(0ADF0000, 0028FE40) 的地址无效。有人可以帮帮我吗?

主要

#include <QtGui/QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])

    QApplication a(argc, argv);

    MainWindow w;

    w.showFullScreen();

    return a.exec();

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtGui>
#include "logger.h"

namespace Ui 
class MainWindow;


class MainWindow : public QMainWindow

    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    QPushButton exit_btn;
    QPushButton import_btn;

private slots:

    void createMenus();
    void exit();
    void import();

private:

    int window_width;
    int window_height;

    int numLoggers;
    int numSelected;

    QVector<Logger*> loggers;

    QScrollArea * scroll_area;

    QVBoxLayout scrollLayout;

    QWidget viewport;

    Ui::MainWindow *ui;
;

#endif // MAINWINDOW_H

主窗口.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QtGui"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)

    ui->setupUi(this);

    window_width = QApplication::desktop()->width();
    window_height = QApplication::desktop()->height();

    createMenus();

    connect(&exit_btn,SIGNAL(clicked()),this,SLOT(exit()));
    connect(&import_btn,SIGNAL(clicked()),this,SLOT(import()));


MainWindow::~MainWindow()

   delete ui;


void MainWindow::createMenus()

    import_btn.setParent(ui->centralWidget);
    import_btn.setGeometry(400,300,100,100);
    import_btn.setText("IMPORT");

    exit_btn.setText("EXIT");
    exit_btn.setParent(ui->centralWidget);
    exit_btn.setGeometry(window_width-50,12,32,32);

    viewport.setLayout(&scrollLayout);
    viewport.resize(0,0);

    scroll_area = new QScrollArea(ui->centralWidget);
    scroll_area->setGeometry(0,66,317,window_height-116);
    scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scroll_area->setWidget(&viewport);
    scroll_area->setGeometry(0,97,317,window_height-228);

    scrollLayout.setMargin(0);
    scrollLayout.setSpacing(0);


void MainWindow::exit()

    close();
    qApp->quit();


void MainWindow::import()

    numSelected=0;

    QFile f("Loggers3.csv");

    if (f.open(QIODevice::ReadOnly))
    
        numLoggers=0;

        QString data;
        data = f.readAll();
        QStringList vals = data.split(';');

        while(vals.size()>=1)
        
            Logger * logger = new Logger;

            logger->setNumber(vals[0].toInt());
            vals.removeAt(0);

            loggers<<logger;

            numLoggers++;
        
        f.close();


        for(int i=0; i<numLoggers;i++)
        
            loggers[i]->createButtons();
            scrollLayout.addWidget(loggers[i]->button);
        

        viewport.resize(367,numLoggers*60);
    

logger.h

#ifndef LOGGER_H
#define LOGGER_H

#include <QtGui>

class Logger : public QWidget

    Q_OBJECT
public:
    explicit Logger(QWidget *parent = 0);

    ~Logger();
    int number;
    QLabel num;
    QToolButton * button;
    bool checked;

signals:

public slots:

    void setNumber(int number);
    void createButtons();
;

#endif // LOGGER_H

logger.cpp

#include "logger.h"
#include <QtGui>

Logger::Logger(QWidget *parent) :
    QWidget(parent)

    button = new QToolButton;
    button->setCheckable(true);
    button->setMinimumSize(317,60);
    button->setStyleSheet("QToolButtonbackground-image: url(images/btn_bg); border:none");


Logger::~Logger()



void Logger::setNumber(int logNumber)

    number=logNumber;


void Logger::createButtons()

    QLayout * layout = new QHBoxLayout;

    QSpacerItem *spacer = new QSpacerItem(120, 31, QSizePolicy::Maximum, SizePolicy::Maximum);

    num.setStyleSheet("color: white; font: bold 16px");
    num.setText(QString::number(number));

    layout->addWidget(&num);
    layout->addItem(spacer);

    button->setLayout(layout);

【问题讨论】:

【参考方案1】:

我不完全确定您要达到的目标...但是您的问题在于以下两行:

viewport.setLayout(&scrollLayout);
viewport.resize(0,0);

在 QWidget 类的文档中指出:

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

这就是你的问题所在。不信,在这两行代码之前加上这个检查。

 if(layout())
        qDebug() << "Another layout exists";
    

来源:QVBoxLayout Class Reference

QVBoxLayout 类垂直排列小部件。

该类用于构造垂直框布局对象。详见 QBoxLayout。

类最简单的用法是这样的:

 QWidget *window = new QWidget;
 QPushButton *button1 = new QPushButton("One");
 QPushButton *button2 = new QPushButton("Two");
 QPushButton *button3 = new QPushButton("Three");
 QPushButton *button4 = new QPushButton("Four");
 QPushButton *button5 = new QPushButton("Five");

 QVBoxLayout *layout = new QVBoxLayout;
 layout->addWidget(button1);
 layout->addWidget(button2);
 layout->addWidget(button3);
 layout->addWidget(button4);
 layout->addWidget(button5);

 window->setLayout(layout);
 window->show();

首先,我们在布局中创建我们想要的小部件。然后,我们创建 QVBoxLayout 对象并将小部件添加到布局中。最后,我们调用 QWidget::setLayout() 将 QVBoxLayout 对象安装到小部件上。此时,布局中的小部件将重新设置父级以将窗口作为其父级。


项目中的关键错误来源:

小部件应该在堆上构建,因为当它们的父级被删除时它们将被自动删除。您有一个在堆上实例化的自定义小部件类。成员也应该放在堆上。此外,您应该考虑在 GUI 代码中使用父/子层次结构,以确保正确的内存管理和正确的删除。

【讨论】:

好的,但是如果是这样的话,我在哪里设置第一个布局?导入按钮只被按下一次,所以我看不出第一个布局是从哪里来的。 您添加的那段代码返回主窗口的布局,不是吗?如果我使用viewport.layout() 而不是layout(),那么在我第一次单击导入按钮时,它不会进入 qDebug 部分。 阅读我的编辑。特别是关于小部件和堆/堆栈内存分配的最后一节。希望对您有所帮助。 谢谢!确实,当我将button 布局中的QLabel num 更改为指针时,问题就消失了!【参考方案2】:

根据我的经验,如果您的程序在 RtlFreeHeap 停止,这是内存损坏的好兆头。

调用时

import_btn.setParent(ui->centralWidget);

centralWidget 拥有import_btn 的所有权。这意味着,当 centralWidget 被删除时(这是 delete ui; 在您的 MainWindow 的析构函数中的一部分),它将在您的成员变量上调用 delete

这会导致报告的内存损坏。

您需要动态分配QPushButton,而不是作为普通成员变量。所以让他们QPushButton*

【讨论】:

感谢您的提示!最后,import_btn 不是问题,而是这个按钮导入的按钮。在logger.h 中,我声明了一个带有布局的button*,并在此布局中声明了QLabel num。当我将其更改为指针时,问题就消失了。所以从现在开始,我只会在布局中使用指针。感谢大家的帮助!【参考方案3】:

以下是我从 mainwindow.cpp 执行此操作的方法,感谢这个问题:How to create a correct exit button in qt

QPushButton * quit_btn = new QPushButton(this);
quit_btn->setGeometry(540,440,93,27);
quit_btn->setText("Exit");
QObject::connect(quit_btn,SIGNAL(clicked()),qApp,SLOT(quit()));

完美运行:D

【讨论】:

以上是关于Qt 中的退出应用程序的主要内容,如果未能解决你的问题,请参考以下文章

qt的程序异常退出 求救

无法在 Qt 中退出 exec 循环

Qt 创建者中的“collect2:ld 返回 1 个退出状态”

Qt:退出应用程序->正确清理的清单

QT:禁用退出mac应用程序的键盘快捷键或识别只允许closebutton事件退出应用程序

QT:如何退出应用程序并关闭 UI