Search code examples
c++multithreadingqtuser-interfaceworker

updating qt gui when running a method


i know how to use qt threads, but it is possible to use a thread to update gui without subclassing qthread or qobject? for example:

class Foo {
    public void heavyWork();
}

Foo::heavyWork() {
    doSomething();
}

and using a thread (just an option)

void ThreadSubClass::run() {
    myFoo.heavyWork();
    updateGui(); //i know, heavyWork will run before updateGui()
}

i don't want to subclass qobject or qthread to implement my "foo" class because this class could be (or should be) use independently of gui library (or even in console), i'm using Qt, but i plan to try anything else


Solution

  • So, I presume that Foo's methods execute in a worker thread, and you wish to offer a mechanism to pass some data from Foo to a GUI thread.

    The typical way of doing it is to provide a mechanism of executing a callback within Foo's thread - the callback's implementation then is specific to the particular GUI toolkit that's in use.

    The callback can be a simple function pointer, or an interface (observer pattern). For example:

    class FooObserver {
      friend class Foo;
    protected:
      virtual void update(Foo *) = 0;
    };
    
    class Foo {
      int m_data;
      std::list<std::shared_ptr<FooObserver>> m_observers;
    public:
      void heavyWork();
      int data() const;
      void addObserver(std::shared_ptr<FooObserver> observer);
    }
    
    void Foo::addObserver(std::shared_ptr<FooObserver> observer)
    {
      m_observers.push_back(observer);
    }
    
    void Foo::heavyWork()
    {
      ...
      for (auto observer: m_observers) observer->update(this);
    }
    

    Then, for Qt, you could have:

    class QtFooObserver : public FooObserver {
      Q_OBJECT
      void update(Foo * foo) override { emit newData(foo->data()); }
    public:
      QtFooObserver() {}
      Q_SIGNAL void newData(int);
    };
    

    This is perfectly thread-safe, since the determination of signal's thread happens upon signal emission. The QtFooObserver object can reside in any thread, including a thread different from Foo's thread. Thus if Foo is in thread A, and a slot connected to QtFooObserver is on an object in thread B, Qt will automatically use a thread-safe cross-thread signal delivery method.

    For more inspiration, see this answer and the Leap Motion C++ SDK.