ASSERT failure in QCoreApplication::sendEvent



  • I've spent a good deal trying to figure out why this isn't working, so I'm hoping someone can point out what I'm doing wrong.
    I'm including the relevant part of the source since it's multiple files.

    I keep receiving this -

    Starting U:\HVACPi\build-HVACPi-Desktop_Qt_5_8_0_MSVC2015_64bit-Debug\debug\HVACPi.exe...
    app QThread(0x1a2646230f0)
    main QThread(0x1a2646230f0)
    mainwindow QThread(0x1a2646230f0)
    m_pThread MainWindowVisual(0x1a269561a90)
    ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 1a269561a90. Receiver 'MainWindow' (of type 'MainWindow') was created in thread 1a2646230f0", file kernel\qcoreapplication.cpp, line 541
    QObject::~QObject: Timers cannot be stopped from another thread
    U:\HVACPi\build-HVACPi-Desktop_Qt_5_8_0_MSVC2015_64bit-Debug\debug\HVACPi.exe exited with code 3
    

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    #include <QMutex>
    #include <QTime>
    #include <QTimer>
    #include <QThread>
    #include <QUuid>
    
    namespace Ui {
        class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
    
        bool m_bInitdVisual;
        QTimer *m_timerVisual;
    
    protected:
        void showEvent(QShowEvent *event);
    };
    
    /*****************************************************************************/
    
    namespace Ui {
        class MainWindowVisual;
    }
    
    const QString VIS_BG_COLOR = "666666";
    const QUuid VIS_BG_IMAGE = QUuid("00000000-0000-0000-0000-000000000000");
    
    class MainWindowVisual : public QThread
    {
        Q_OBJECT
    
    public:
        static MainWindowVisual *instance();
        static bool updateVisual(const int &visual);
    
        enum Constants {
           VIS_BG = 1,
           VIS_DISABLED_INTERVAL = -1,
           VIS_THREAD_REFRESH_INTERVAL = 100,
           VIS_BG_ROTATION_INTERVAL = 1000 * 60 * 30,
        };
    
    public slots:
        static void setWindow(MainWindow *window);
    
    private:
        MainWindowVisual();
        virtual ~MainWindowVisual();
    
        Q_DISABLE_COPY(MainWindowVisual)
    
        bool m_bReady;
        bool m_bInitd;
        QTime m_timeElapsed;
        QHash< QString, int > m_visualInterval;
        QHash< QString, int > m_visualElapsed;
    
    protected:
        void run();
    
        static MainWindowVisual *m_pInstance;
        static MainWindow *m_pWindow;
        static QMutex *m_pMutex;
    
    signals:
        void updatePaint();
    };
    
    #endif // MAINWINDOW_H
    

    mainwindow.c

    #include "main.h"
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include "settings.h"
    
    #include <QColor>
    #include <QImage>
    #include <QPainter>
    #include <QPalette>
    #include <QThread>
    
    #include <QDebug>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow),
        m_bInitdVisual(false)
    {
        ui->setupUi(this);
        qDebug() << "mainwindow" << QThread::currentThread();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::showEvent(QShowEvent *event)
    {
        QWidget::showEvent(event);
    
        if (!m_bInitdVisual) {
            connect(MainWindowVisual::instance(), &MainWindowVisual::updatePaint, [=](){ this->update(); });
            MainWindowVisual::instance()->setWindow(this);
    
            m_timerVisual = new QTimer();
            m_timerVisual->setInterval(MainWindowVisual::VIS_THREAD_REFRESH_INTERVAL);
            connect(m_timerVisual, &QTimer::timeout, [=](){ MainWindowVisual::instance()->start(); });
            m_timerVisual->start();
    
            m_bInitdVisual = true;
        }
    }
    
    /*****************************************************************************/
    
    MainWindowVisual *MainWindowVisual::instance()
    {
        if (!m_pInstance)
        {
            m_pMutex->lock();
            m_pInstance = new MainWindowVisual();
            m_pMutex->unlock();
        }
    
        return m_pInstance;
    }
    
    MainWindowVisual::MainWindowVisual()
    {
        m_bReady = false;
        m_bInitd = false;
    
        if ((Settings::instance()->isNull("visual", "bgmode") ? 0 : Settings::instance()->getValue("visual", "bgmode").toInt()) == 2)
        {
            int iInterval = Settings::instance()->isNull("visual", "bgimagetimer") ? VIS_BG_ROTATION_INTERVAL : Settings::instance()->getValue("visual", "bgimagetimer").toInt();
            m_visualInterval.insert("bgimagetimer", iInterval);
            m_visualElapsed.insert("bgimagetimer", iInterval);
        } else {
            m_visualInterval.insert("bgimagetimer", VIS_DISABLED_INTERVAL);
            m_visualElapsed.insert("bgimagetimer", VIS_DISABLED_INTERVAL);
        }
    }
    
    MainWindowVisual::~MainWindowVisual()
    {
        wait();
    }
    
    void MainWindowVisual::run()
    {
        qDebug() << "m_pThread" << QThread::currentThread();
        if (!MainWindowVisual::instance()->m_bReady)
            return;
    
        if ((MainWindowVisual::instance()->m_visualInterval.value("bgimagetimer", VIS_BG_ROTATION_INTERVAL) != VIS_DISABLED_INTERVAL && MainWindowVisual::instance()->m_timeElapsed.elapsed() >= MainWindowVisual::instance()->m_visualElapsed.value("bgimagetimer")) ||
                MainWindowVisual::instance()->m_bInitd == false)
        {
            updateVisual(VIS_BG);
    
            int iNextInterval = MainWindowVisual::instance()->m_visualInterval.value("bgimagetimer", VIS_BG_ROTATION_INTERVAL) +
                    MainWindowVisual::instance()->m_timeElapsed.elapsed();
            MainWindowVisual::instance()->m_visualElapsed.insert("bgimagetimer", iNextInterval);
        }
    
        if (!MainWindowVisual::instance()->m_bInitd)
            MainWindowVisual::instance()->m_bInitd = true;
    }
    
    void MainWindowVisual::setWindow(MainWindow *window)
    {
        m_pMutex->lock();
        m_pWindow = window;
        MainWindowVisual::instance()->m_bReady = true;
        m_pMutex->unlock();
    
        MainWindowVisual::instance()->m_timeElapsed.start();
    }
    
    bool MainWindowVisual::updateVisual(const int &visual)
    {
        if (!MainWindowVisual::instance()->m_bReady)
            return false;
    
        switch (visual)
        {
            case VIS_BG:
                m_pMutex->lock();
                int iBGMode = Settings::instance()->getValue("visual", "bgmode").toInt();
                QString sColor = Settings::instance()->isNull("visual", "bgcolor") ? VIS_BG_COLOR : Settings::instance()->getValue("visual", "bgcolor").toString();
                QColor colorBackground("#" + sColor);
                QPalette paletteBackground;
                m_pMutex->unlock();
    
                switch (iBGMode)
                {
                    case 1:
                    {
                        m_pMutex->lock();
                        QUuid uuidBGImage = Settings::instance()->isNull("visual", "bgimage") ? VIS_BG_IMAGE : Settings::instance()->getValue("visual", "bgimage").toUuid();
                        File fileBGImage = Utilities::instance()->getFile(uuidBGImage);
    
                        if (!fileBGImage.data.isEmpty())
                        {
                            Settings::instance()->setValue("visual", "bgimage", uuidBGImage.toString());
    
                            QImage imageBGImage;
                            imageBGImage.loadFromData(fileBGImage.data);
                            imageBGImage = imageBGImage.scaled(m_pWindow->size(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
    
                            paletteBackground.setBrush(QPalette::Background, imageBGImage);
                            m_pWindow->setPalette(paletteBackground);
                            m_pMutex->unlock();
    
                            return true;
                        }
    
                        m_pMutex->unlock();
                    }
    
                    case 2:
                    {
                        m_pMutex->lock();
                        QUuid uuidPreviousBGImage = Settings::instance()->isNull("visual", "bgimage") ? VIS_BG_IMAGE : Settings::instance()->getValue("visual", "bgimage").toUuid();
                        File filePreviousBGImage = Utilities::instance()->getRandomFile("visual-bg", uuidPreviousBGImage);
                        File fileBGImage = Utilities::instance()->getRandomFile("visual-bg", uuidPreviousBGImage);
    
                        if (!filePreviousBGImage.data.isEmpty() && !fileBGImage.data.isEmpty())
                        {
                            Settings::instance()->setValue("visual", "bgimage", fileBGImage.uuid.toString());
    
                            QImage imagePreviousBGImage;
                            imagePreviousBGImage.loadFromData(filePreviousBGImage.data);
                            imagePreviousBGImage = imagePreviousBGImage.scaled(m_pWindow->size(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
    
                            QImage imageBGImage;
                            imageBGImage.loadFromData(fileBGImage.data);
                            imageBGImage = imageBGImage.scaled(m_pWindow->size(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
    
                            QImage imageBGCombo = QImage(m_pWindow->size(), QImage::Format_RGB32);
                            m_pMutex->unlock();
    
                            for (double fOpacity = 0; fOpacity < 1.05; fOpacity += 0.05)
                            {
                                m_pMutex->lock();
                                QPainter painter(&imageBGCombo);
                                painter.drawImage(QPoint(0,0), imagePreviousBGImage);
                                painter.setOpacity(fOpacity);
                                painter.drawImage(QPoint(0,0), imageBGImage);
                                painter.end();
    
                                paletteBackground.setBrush(QPalette::Background, imageBGCombo);
                                m_pWindow->setPalette(paletteBackground);
                                m_pMutex->unlock();
    
                                emit MainWindowVisual::instance()->updatePaint();
    
                                QThread::msleep(100);
                            }
    
                            return true;
                        }
    
                        m_pMutex->unlock();
                    }
    
                    case 0:
                    default:
                        m_pMutex->lock();
                        paletteBackground.setColor(QPalette::Window, colorBackground);
                        m_pWindow->setPalette(paletteBackground);
                        m_pMutex->unlock();
    
                        return true;
                }
        }
    
        return false;
    }
    
    MainWindowVisual *MainWindowVisual::m_pInstance = NULL;
    MainWindow *MainWindowVisual::m_pWindow = NULL;
    QMutex *MainWindowVisual::m_pMutex = new QMutex();
    

    This is a rewrite of a previous version of my code, and I'm trying to utilize singletons and attempting to make everything thread safe.
    But it seems to be m_pWindow->setPalette(paletteBackground); that is where the issue is... I just don't know what I'm doing wrong.

    Let me know if I need to include other portions of my code.


  • Qt Champions 2016

    @Artistan said in ASSERT failure in QCoreApplication::sendEvent:

    I'm trying to utilize singletons

    For what reason exactly do you think this is a good idea? Read this.

    attempting to make everything thread safe.

    You can't. The GUI classes - widgets, painters and so on are not thread safe and are not even reentrant. The message you get is quite explanatory, you have race conditions. Fix your code - use GUI related stuff only in the GUI thread!


Log in to reply