Exit Application in Qt

27,989

Solution 1

I'm not entirely certain about what you are trying to achieve... but your problem lies with these two lines:

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

In the documentation for the QWidget class it states that:

If there already is a layout manager installed on this widget, QWidget won't let you install another. You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.

This is where your problem lies. Don't believe me, add this check before those two lines of code.

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

Source: QVBoxLayout Class Reference

The QVBoxLayout class lines up widgets vertically.

This class is used to construct vertical box layout objects. See QBoxLayout for details.

The simplest use of the class is like this:

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

First, we create the widgets we want in the layout. Then, we create the QVBoxLayout object and add the widgets into the layout. Finally, we call QWidget::setLayout() to install the QVBoxLayout object onto the widget. At that point, the widgets in the layout are reparented to have window as their parent.


Critical source of error in your project:

Widgets should be constructed on the heap because they will be deleted automatically when their parents are deleted. You have a custom widget class that you instantiate on the heap. The members should also go on the heap. Also, you should consider using the parent /child hierarchy in your GUI code to ensure proper memory management and proper deletion.

Solution 2

In my experience, if your program stops in RtlFreeHeap it is a good sign of memory corruption.

When calling

import_btn.setParent(ui->centralWidget);

centralWidget takes ownership of import_btn. That means, when centralWidget is deleted (which happens as part of delete ui;in your MainWindow's destructor), it will call delete on your member variable!

This leads to the reported memory corruption.

You need to allocate your QPushButton's dynamically, not as a plain member variable. So make them QPushButton*.

Share:
27,989
Frank
Author by

Frank

Embedded software enthusiast

Updated on March 14, 2020

Comments

  • Frank
    Frank about 4 years

    I have built an app in Qt that contains two buttons: an exit button and an import button. When the import button is pushed, a list of buttons is shown in a scrollarea on the screen (the file loggers.csv contains the data 1;2;3;4;5;).

    It all works fine, but when I push the exit button (which of course should close everything), the app is not stopped properly (the stop button of Qt is still active, and the play button isn't). When I run the debugger and push the exit button it gives an error: Invalid address specified to RtlFreeHeap( 0ADF0000, 0028FE40 ). Can anybody help me?

    main

    #include <QtGui/QApplication>
    #include "mainwindow.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        MainWindow w;
    
        w.showFullScreen();
    
        return a.exec();
    }
    

    Mainwindow.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
    

    Mainwindow.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("QToolButton{background-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);
    }