Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

application crash when setCentralWidget(chartView) at the second time...



  • Hello,

    I'm coding small app to get data from sensor on console and following button, have graph from text file where are recorded the data.

    When I start the app, all working fine, I receive data,

    0_1557083082781_appData.png

    and when I click on graph button, I have the ChartView displayed.
    0_1557083103060_appGraph.png
    After that, if I click on data button, I go back to data display until that all is fine.

    0_1557083142736_appData.png

    But when I click again to the graph button, it's crashing.

    0_1557082262617_crash.png

    the problem is apparently from read access in my function

    void MainWindow::on_actionGraph()
    

    but I don't see where...
    the only thing make it stopping crash is to remove the graphic with //setCentralWidget(chartView); inside my function on_actionGraph()
    but off course, I need this graph...

    I try to use a copy of the text file to be sure it's not used by my function

    void MainWindow::readData(const QByteArray &data)
    

    but same crash.

    here the mainwindow.h

    /****************************************************************************
    **
    ** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
    ** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
    ** Contact: https://www.qt.io/licensing/
    **
    ** This file is part of the QtSerialPort module of the Qt Toolkit.
    **
    ** $QT_BEGIN_LICENSE:BSD$
    ** Commercial License Usage
    ** Licensees holding valid commercial Qt licenses may use this file in
    ** accordance with the commercial license agreement provided with the
    ** Software or, alternatively, in accordance with the terms contained in
    ** a written agreement between you and The Qt Company. For licensing terms
    ** and conditions see https://www.qt.io/terms-conditions. For further
    ** information use the contact form at https://www.qt.io/contact-us.
    **
    ** BSD License Usage
    ** Alternatively, you may use this file under the terms of the BSD license
    ** as follows:
    **
    ** "Redistribution and use in source and binary forms, with or without
    ** modification, are permitted provided that the following conditions are
    ** met:
    **   * Redistributions of source code must retain the above copyright
    **     notice, this list of conditions and the following disclaimer.
    **   * Redistributions in binary form must reproduce the above copyright
    **     notice, this list of conditions and the following disclaimer in
    **     the documentation and/or other materials provided with the
    **     distribution.
    **   * Neither the name of The Qt Company Ltd nor the names of its
    **     contributors may be used to endorse or promote products derived
    **     from this software without specific prior written permission.
    **
    **
    ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
    **
    ** $QT_END_LICENSE$
    **
    ****************************************************************************/
    
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QSerialPort>
    #include <QWinTaskbarButton>
    #include <QSystemTrayIcon>
    
    #include <QtCharts/QChartView>
    #include <QtCharts/QLineSeries>
    #include <QtCharts/QValueAxis>
    #include <QtCharts/QCategoryAxis>
    
    QT_BEGIN_NAMESPACE
    
    class QLabel;
    
    namespace Ui {
    class MainWindow;
    }
    
    QT_END_NAMESPACE
    QT_CHARTS_USE_NAMESPACE
    
    class Console;
    class SettingsDialog;
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
        void openSerialPort();
        QSystemTrayIcon *tray;
        QIcon icon;
        QChart *chart = new QChart();
        QChartView *chartView = new QChartView(chart);
    private slots:
    
        void closeSerialPort();
        void about();
        void readData(const QByteArray &data);
        void handleError(QSerialPort::SerialPortError error);
        void on_actionGraph();
        void on_actionData();
        void toconsole();
    
    private:
        void initActionsConnections();
        void showStatusMessage(const QString &message);
        void keyPressEvent (QKeyEvent *event);
        Ui::MainWindow *m_ui = nullptr;
        QLabel *m_status = nullptr;
        Console *m_console = nullptr;
        SettingsDialog *m_settings = nullptr;
        QSerialPort *m_serial = nullptr;
    };
    
    #endif // MAINWINDOW_H
    
    

    here the mainwindow.cpp

    /****************************************************************************
    **
    ** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
    ** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
    ** Contact: https://www.qt.io/licensing/
    **
    ** This file is part of the QtSerialPort module of the Qt Toolkit.
    **
    ** $QT_BEGIN_LICENSE:BSD$
    ** Commercial License Usage
    ** Licensees holding valid commercial Qt licenses may use this file in
    ** accordance with the commercial license agreement provided with the
    ** Software or, alternatively, in accordance with the terms contained in
    ** a written agreement between you and The Qt Company. For licensing terms
    ** and conditions see https://www.qt.io/terms-conditions. For further
    ** information use the contact form at https://www.qt.io/contact-us.
    **
    ** BSD License Usage
    ** Alternatively, you may use this file under the terms of the BSD license
    ** as follows:
    **
    ** "Redistribution and use in source and binary forms, with or without
    ** modification, are permitted provided that the following conditions are
    ** met:
    **   * Redistributions of source code must retain the above copyright
    **     notice, this list of conditions and the following disclaimer.
    **   * Redistributions in binary form must reproduce the above copyright
    **     notice, this list of conditions and the following disclaimer in
    **     the documentation and/or other materials provided with the
    **     distribution.
    **   * Neither the name of The Qt Company Ltd nor the names of its
    **     contributors may be used to endorse or promote products derived
    **     from this software without specific prior written permission.
    **
    **
    ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
    **
    ** $QT_END_LICENSE$
    **
    ****************************************************************************/
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "console.h"
    #include "settingsdialog.h"
    #include <QDebug>
    #include <QLabel>
    #include <QMessageBox>
    #include <QSystemTrayIcon>
    #include <QIcon>
    #include <QPixmap>
    #include <QFileInfo>
    #include <QDateTime>
    #include <QByteArray>
    #include <QtCharts/QChartView>
    #include <QtCharts/QLineSeries>
    #include <QtCharts/QValueAxis>
    #include <QtCharts/QCategoryAxis>
    #include <QtGui/QMouseEvent>
    #include <QKeyEvent>
    
    QT_CHARTS_USE_NAMESPACE
    //! [0]
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        m_ui(new Ui::MainWindow),
        m_status(new QLabel),
        m_console(new Console),
        m_settings(new SettingsDialog),
        //! [1]
        m_serial(new QSerialPort(this))
      //! [1]
    {
        //! [0]
        m_ui->setupUi(this);
        m_console->setEnabled(false);
        setCentralWidget(m_console);
    
        m_ui->actionConnect->setEnabled(true);
        m_ui->actionDisconnect->setEnabled(false);
        m_ui->actionQuit->setEnabled(true);
        m_ui->actionConfigure->setEnabled(true);
        m_ui->actionGraph->setEnabled(true);
        m_ui->statusBar->addWidget(m_status);
    
        initActionsConnections();
    
        connect(m_serial, &QSerialPort::errorOccurred, this, &MainWindow::handleError);
        connect(m_serial, &QSerialPort::readyRead, this, &MainWindow::on_actionData);
    }
    
    MainWindow::~MainWindow()
    {
        delete m_settings;
        delete m_ui;
    }
    
    //! [4]
    void MainWindow::openSerialPort()
    {
        const SettingsDialog::Settings p = m_settings->settings();
        m_serial->setPortName(p.name);
        m_serial->setBaudRate(p.baudRate);
        m_serial->setDataBits(QSerialPort::Data8);
        m_serial->setParity(QSerialPort::NoParity);
        m_serial->setStopBits(QSerialPort::OneStop);
        m_serial->setFlowControl(QSerialPort::NoFlowControl);
        if (m_serial->open(QIODevice::ReadOnly)) {
            m_console->setEnabled(true);
            m_console->setLocalEchoEnabled(p.localEchoEnabled);
            m_ui->actionConnect->setEnabled(false);
            m_ui->actionDisconnect->setEnabled(true);
            m_ui->actionConfigure->setEnabled(false);
            m_ui->actionGraph->setEnabled(true);
            m_ui->actionData->setEnabled(false);
            showStatusMessage(tr("Connected to %1 : %2, %3")
                              .arg(p.name).arg(p.stringBaudRate).arg(p.stringDataBits));
        } else {
            QMessageBox::critical(this, tr("Error"), m_serial->errorString());
    
            showStatusMessage(tr("Open error"));
        }
        tray = new QSystemTrayIcon(this);
    
        icon.addFile(":/images/disconnect.png");
        tray->setIcon(icon);
        tray->setVisible(true);
        tray->show();
    }
    
    void MainWindow::closeSerialPort()
    {
        if (m_serial->isOpen())
            m_serial->close();
        m_console->setEnabled(false);
        m_ui->actionConnect->setEnabled(true);
        m_ui->actionDisconnect->setEnabled(false);
        m_ui->actionConfigure->setEnabled(true);
        showStatusMessage(tr("Disconnected"));
    }
    
    void MainWindow::about()
    {
        QMessageBox::about(this, tr("About Thermometer"),
                           tr(""));
    }
    
    void MainWindow::readData(const QByteArray &data)
    {
        QFile fileOut("d:/Magasin_Temp_Hygro.txt");
        fileOut.open(QFile::ReadWrite);
        QTextStream streamOut(&fileOut);
        const QChar delimeter = ';' ;
        QStringList list = streamOut.readAll().split(delimeter);
        int i=0;
        int count=list.size();
        if (!streamOut.atEnd())
        {
            for( i=0;i<count;i++)
            {
                streamOut << list[i];
            }
        }else{
            if(data.size()>10)
            {
                QDateTime timestamp;
                timestamp=QDateTime::currentDateTime();
                QString time=timestamp.toString("dd/MM/yy hh'h'mm");
                streamOut <<time;
            }
            for(int x=0;x<data.size();x++)
            {
                streamOut << data[x];
            }
        }
        fileOut.close();
    
    }
    
    void MainWindow::handleError(QSerialPort::SerialPortError error)
    {
        if (error == QSerialPort::ResourceError) {
            QMessageBox::critical(this, tr("Critical Error"), m_serial->errorString());
            closeSerialPort();
        }
    }
    //! [8]
    
    void MainWindow::initActionsConnections()
    {
        connect(m_ui->actionConnect, &QAction::triggered, this, &MainWindow::openSerialPort);
        connect(m_ui->actionDisconnect, &QAction::triggered, this, &MainWindow::closeSerialPort);
        connect(m_ui->actionQuit, &QAction::triggered, this, &MainWindow::close);
        connect(m_ui->actionGraph, &QAction::triggered, this, &MainWindow::closeSerialPort);
        connect(m_ui->actionGraph, &QAction::triggered, this, &MainWindow::on_actionGraph);
        connect(m_ui->actionData, &QAction::triggered, this, &MainWindow::toconsole);
        connect(m_ui->actionData, &QAction::triggered, this, &MainWindow::openSerialPort);
        connect(m_ui->actionConfigure, &QAction::triggered, m_settings, &SettingsDialog::show);
        connect(m_ui->actionClear, &QAction::triggered, m_console, &Console::clear);
        connect(m_ui->actionAbout, &QAction::triggered, this, &MainWindow::about);
        connect(m_ui->actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt);
        //connect(qApp,SIGNAL(aboutToQuit()),this,SLOT(quitMyApp()));
    }
    void MainWindow::keyPressEvent (QKeyEvent *event)
    {
        //QKeyEvent *keyEvent = static_cast<QKeyEvent *>(keyEvent);
    
        if(event->key()==Qt::Key_Plus)
        {chartView->chart()->zoomIn();}
        if(event->key()==Qt::Key_Minus)
        {chartView->chart()->zoomOut();}
        if(event->key()==Qt::Key_Left)
        {chartView->chart()->scroll(-10, 0);}
        if(event->key()==Qt::Key_Right)
        {chartView->chart()->scroll(10, 0);}
        if(event->key()==Qt::Key_Up)
        {chartView->chart()->scroll(0, 10);}
        if(event->key()==Qt::Key_Down)
        {chartView->chart()->scroll(0, -10);}
    }
    void MainWindow::showStatusMessage(const QString &message)
    {
        m_status->setText(message);
    
    }
    
    void MainWindow::on_actionGraph()
    {
    
        m_ui->actionGraph->setEnabled(false);//disable graph button
        m_ui->actionData->setEnabled(true);//able data button
        QFile fileGraph("d:/Magasin_Temp_Hygro.txt");//select text file with recorded data
        fileGraph.open(QFile::ReadOnly);//open text file with recorded data
        int line_count=0;
        qreal temp=0;
        QString date;
        qreal hygro;
        QLineSeries *temperature = new QLineSeries();
        QLineSeries *hygrometrie = new QLineSeries();
        QCategoryAxis *axisX = new QCategoryAxis;
        QCategoryAxis *axisY1 = new QCategoryAxis;
        QCategoryAxis *axisY = new QCategoryAxis;
        while( !fileGraph.atEnd())//loop until end of file
        {
            QString line=fileGraph.readLine();
    
            QString date=line.split(":")[0];
    
            bool ok = false;
            temp=line.split(":")[2].toDouble(&ok);
            hygro=line.split(":")[4].replace(";","").toDouble(&ok);
            axisX->append(date,line_count);
            axisY1->append(QString::number(temp),temp);
            axisY->append(QString::number(hygro),hygro);
            *temperature <<QPointF(line_count, temp);
            *hygrometrie <<QPointF(line_count, hygro);
            line_count++;
        }
    
        chart->addSeries(temperature);
        chart->addSeries(hygrometrie);
        temperature->attachAxis(axisX);
        temperature->attachAxis(axisY1);
        hygrometrie->attachAxis(axisY);
        axisX->setLabelsAngle(-90);
        axisX->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
        axisY1->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
        axisY1->setMin(10);
        axisY1->setMax(100);
        axisY1->setLabelsColor(temperature->pen().color());
        axisY->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
        axisY->setMin(10);
        axisY->setMax(100);
        axisY->setLabelsColor(hygrometrie->pen().color());
        chart->addAxis(axisY, Qt::AlignRight);
        chart->addAxis(axisY1, Qt::AlignLeft);
        chart->addAxis(axisX, Qt::AlignBottom);
        chart->setTitle("Revelé Température et humidité Magasin");
        chartView->setRenderHint(QPainter::Antialiasing);
        chartView->chart()->setAxisX(axisX, hygrometrie);
        chartView->chart()->setAxisY(axisY, hygrometrie);
        chartView->chart()->setAxisX(axisY1, temperature);
        setCentralWidget(chartView);
    
        fileGraph.close();
    }
    
    
    void MainWindow::toconsole()
    {
    
        m_ui->actionGraph->setEnabled(true);
        m_ui->actionData->setEnabled(false);
        m_console = new Console;
        m_console->setEnabled(true);
        setCentralWidget(m_console);
        on_actionData();
    }
    void MainWindow::on_actionData()
    {
    
        const QByteArray data= m_serial->readAll();
        readData(data);
        m_console->putData(data);
    
    }
    
    

    thank you very much for your help!


  • Qt Champions 2019

    I would guess setCentralWidget() is the problem: "Note: QMainWindow takes ownership of the widget pointer and deletes it at the appropriate time."
    Don't set a new central widget every time, use e.g. a QStackedWidget



  • @Christian-Ehrlicher Thank a lot, I'm trying to understand how stackedWidget is working but is mean not easy only to display graphic or data at need time...


  • Qt Champions 2019

    What problem do you have? Isn't the description of QStackedWidget not enough?



  • @Christian-Ehrlicher Hello, I have to confess i'm new with c++ and I don't understand how to use stackedWidget. I add stackedWidget with designer, until that it's ok, but after that I don't know, I have to take more time to read documentation.


  • Qt Champions 2019

    The detailed description I gave you the link to describes exactly what to do.

    QStackedWidget *stackedWidget = new QStackedWidget;   // or use it from ui -> ui.stackedWidget
    stackedWidget->addWidget(firstPageWidget);
    stackedWidget->addWidget(secondPageWidget);
    stackedWidget->addWidget(thirdPageWidget);
    


  • @Christian-Ehrlicher I read that yes, but I don't know what is firstPageWidget in stackedWidget->addWidget(firstPageWidget);

    I have to make multiple QWidget .h/.cpp?


  • Lifetime Qt Champion

    Hi,

    No you can put several different instances of the same class.


Log in to reply