Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Trouble of using QBrush in different threads
Forum Updated to NodeBB v4.3 + New Features

Trouble of using QBrush in different threads

Scheduled Pinned Locked Moved General and Desktop
6 Posts 3 Posters 1.6k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    march
    wrote on last edited by
    #1

    Hello!
    I have problem. I want to make some color animation in my app. In my case I want to use a separate thread that performs some calculations and defines a brush that transmitted to main thread and then sets to the widgets palette. That is code (main.cpp)
    @
    #include <QPalette>
    #include <QThread>
    #include <QEvent>
    #include <QQueue>
    #include <QWidget>
    #include <QApplication>
    #include <QLabel>
    #include <QMetaProperty>
    #include <QDebug>

    int g_animevent = QEvent::registerEventType();
    bool g_blink = false;

    struct str
    {
    str(QWidget* widget, const QBrush& brush) :
    widget(widget), value(brush) {}

    str(const str& other)
    {
        this->widget    = other.widget;
        this->value     = other.value;
    }
    
    QWidget*            widget;
    QBrush              value;
    

    };

    class PalEvent : public QEvent
    {
    public:
    PalEvent(QQueue<str>* q) : QEvent((QEvent::Type)g_animevent), queue(q) {}
    QQueue<str>* queue;
    };

    class PalThread : public QThread
    {
    public:
    PalThread(QWidget* m, const QList<QWidget*>& lw) : main(m), widgets(lw) {}

    protected:
    void run()
    {
    QQueue<str>* queue = new QQueue<str>();
    bool flag;
    for(;;)
    {
    flag = g_blink;
    foreach(QWidget* widget, widgets)
    {
    QPalette pal(widget->palette());
    QBrush b(Qt::red);
    if (flag)
    b.setColor(Qt::blue);
    else
    b.setColor(Qt::yellow);

                const QBrush& bb = pal.brush(QPalette::WindowText);
                if (bb != b)
                {
                    str s(widget, b);
                    queue->enqueue(s);
                }
    
            }
            if (!queue->isEmpty())
            {
                QCoreApplication::postEvent(main, new PalEvent(queue), Qt::HighEventPriority);
                queue = new QQueue<str>();
            }
    
            QThread::msleep(10);
        }
    }
    

    private:
    QList<QWidget*> widgets;
    QWidget* main;
    };

    class Main : public QWidget
    {
    public:
    Main()
    {
    for (int i = 0; i < 1000; ++i)
    {
    QLabel* lbl = new QLabel("L" + QString::number(i + 1), this);
    lbl->move((i % 25) * 40, (i / 25) * 16);
    widgets.append(lbl);
    }
    PalThread* pt = new PalThread(this, widgets);
    pt->start();
    startTimer(500);
    }

    bool event(QEvent *e)
    {
        if (e->type() == g_animevent)
        {
            QQueue<str> *qp = ((PalEvent*)e)->queue;
            while (!qp->isEmpty())
            {
                str pd = qp->dequeue();
                QPalette pal = pd.widget->palette();
                pal.setBrush(QPalette::WindowText, pd.value);
                pd.widget->setPalette(pal);
            }
    
            delete qp;
            return true;
        }
        else if (e->type() == QEvent::Timer)
        {
            g_blink = !g_blink;
            /*
            bool flag = g_blink;
            QQueue<str>* queue = new QQueue<str>();
            foreach(QWidget* widget, widgets)
            {
                QPalette pal(widget->palette());
                QBrush b(Qt::red);
                if (flag)
                    b.setColor(Qt::blue);
                else
                    b.setColor(Qt::yellow);
    
                const QBrush& bb = pal.brush(QPalette::WindowText);
                if (bb != b)
                {
                    str s(widget, b);
                    queue->enqueue(s);
                }
            }
            if (queue->isEmpty())
                delete queue;
            else
                QCoreApplication::postEvent(this, new PalEvent(queue), Qt::HighEventPriority);
            */
        }
        return QWidget::event(e);
    }
    

    private:
    QList<QWidget*> widgets;
    };

    int main(int argc, char** argv)
    {
    QApplication a(argc, argv);
    Main m;
    m.show();
    return a.exec();
    }
    @
    But after little time since start execution of application it crashes at 'memory access error'. I can't understand what is the reason of trouble at present time and I hope someone can help me.
    Besides, I defined that in case of using single thread app all executing normal (as you can see in commented block of code).

    1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by
      #2

      You should consider creating smaller examples. It's hard to read through all this. It's also my impression that you needlessly complicated this. For example why so many dynamic allocations? One thread allocates queue with new, packs it into another dynamic event and it is expected that another thread will successful get that, unpack and delete queue... this is scetchy at best.

      But anyway...
      I don't see any thread synchronization done in your code? You access g_blink in both threads but there's no mutex guarding it. Consider a QMutex or QAtomicInt there.
      Another thing is that you access widget->palette() from the worker thread. Widgets should only be accessed from the main thread and even if they weren't you're again not guarding it with any synchronization primitives.

      1 Reply Last reply
      0
      • JKSHJ Offline
        JKSHJ Offline
        JKSH
        Moderators
        wrote on last edited by
        #3

        Hi,

        A QWidget must only be accessed from the thread that instantiates QApplication.

        Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

        1 Reply Last reply
        0
        • M Offline
          M Offline
          march
          wrote on last edited by
          #4

          Chris Kawa, It's, of course, simplified version of real application that desribes my problem and using QMutex-access g_blink is not critical in my case.
          I understand that I can't write Widget properties in other threads.
          But do not I even read Widget's state in other thread?
          Or in this case I must use some synchronization?

          1 Reply Last reply
          0
          • Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by
            #5

            You can't assume anything about access to the widgets in other threads. It might be platform dependent. It might be system settings dependent, it might be Qt version dependent, it might be specific member function dependent etc.

            If any widget member function is thread safe it is marked so in the docs. Most are not.
            The rule of thumb is: don't try it.

            If you need to access some widget data in another thread retrieve it in the ui thread and pass it via synchronized data.

            1 Reply Last reply
            0
            • M Offline
              M Offline
              march
              wrote on last edited by
              #6

              Thanks for help. I'll try.

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved