Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    SetProperty : Cannot send events to objects owned by a different thread

    General and Desktop
    3
    11
    14338
    Loading More Posts
    • 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.
    • D
      dvdk last edited by

      I set some dynamic properties on QObjects from different threads using QObject->setProperty()
      I was under the impression this is executed by posting a QDynamicPropertyChangeEvent so I didn't have to worry about what thread it was sent from.

      This seemed to work on linux, but on windows I get the following assert :

      @ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread.@

      What would be the best approach to set Dynamic properties in a multi threaded application?

      1 Reply Last reply Reply Quote 0
      • A
        andre last edited by

        AFAIK, the event is there to enable you to act on the change, but they are not used to make the actual change. An inspection of the sources can tell you the details.

        I guess I'd create a slot on the class as a thin wrapper for setProperty. That would enable you to use the cross-thread signal/slot mechanism (either via a signal or by using QMetaObject) to set the properties.

        1 Reply Last reply Reply Quote 0
        • D
          dvdk last edited by

          I suppose you are right about the event. Thanks for clearing that up :)
          Are you suggesting to create a wrapper for every QObject derived class I want to use to set a dynamic property? Since I use a lot of the QWidgets, this seems like an impossible job to maintain.

          Any idea why this behaviour only manifests on windows and not on linux?

          1 Reply Last reply Reply Quote 0
          • D
            dbzhang800 last edited by

            Hi dvdk,

            Though all functions in class QObject are reentrant, but only connect() and disconnect() are thread-safe. And you should not use not-thread-safe method in this way.

            You can using signals and slots between threads(with auto connection or queued connection), which is easy and safe.

            Regards,

            Debao

            1 Reply Last reply Reply Quote 0
            • D
              dvdk last edited by

              I understand I should use cross-thread signaling, but I fail to see how I can achieve this in a simple way.

              Say I want to do a setProperty on a QLabel object, how can I achieve this with signals without writing a wrapper round QLabel (and every other qwidget I like to use)? setProperty is not a slot.

              1 Reply Last reply Reply Quote 0
              • D
                dbzhang800 last edited by

                You did not say that the QObject you mentioned is QWidget before.

                [quote author="dvdk" date="1333131332"]
                Say I want to do a setProperty on a QLabel object, how can I achieve this with signals without writing a wrapper round QLabel (and every other qwidget I like to use)? setProperty is not a slot.[/quote]

                In fact, You cannot! The manual says:

                bq. Although QObject is reentrant, the GUI classes, notably QWidget and all its subclasses, are not reentrant. They can only be used from the main thread.

                By the way, if you want to call slots or signals or invoked methods, you can use
                @
                QMetaObject::invokeMethod()
                @

                1 Reply Last reply Reply Quote 0
                • A
                  andre last edited by

                  Well, that's an issue, indeed.

                  If your issue is to set properties from different threads to your GUI thread (you're talking about widgets, after all), then I think I'd create a QObject derived class, of which you create an instance in your main tread. You can use that class as a proxy to your widget. Simply pass the pointer to the widget, as well as the property name and the QVariant value to that class via the threaded signal/slot mechanism, and let that class then do the actual property setting.

                  1 Reply Last reply Reply Quote 0
                  • D
                    dvdk last edited by

                    Thanks Andre, your solutions looks very clean. I will implement the proxy class.

                    1+1=2 :
                    Just out of curiosity I wanted to try your hint about InvokeMethod(), but I can't figure out how to use it properly.

                    I tried the following

                    @QMetaObject::invokeMethod(pObj, "setProperty", Qt::AutoConnection,
                    Q_ARG(const char*, "somevar"), Q_ARG(const QVariant, "somevalue"));@

                    It compiles fine, but on execution I get :

                    @QMetaObject::invokeMethod: No such method QLabel::setProperty(const char*,const QVariant)@

                    Any idea what I did wrong? Documentation on Q_ARG is a bit thin, I probably misinterpreted something.

                    1 Reply Last reply Reply Quote 0
                    • A
                      andre last edited by

                      What you are doing wrong, is that on QLabel, setProperty is not declared as a a slot, or at least as Q_INVOKABLE. This functionality is basically a 'raw' way of using the signal/slot mechanism, and it relies on the same mechanisms.

                      1 Reply Last reply Reply Quote 0
                      • D
                        dvdk last edited by

                        Thanks for the answer. So the QMetaObject::invokeMethod cannot be used in this case.

                        1 Reply Last reply Reply Quote 0
                        • A
                          andre last edited by

                          well, it can be used through the proxy object that I suggested. You can use QMetaObject::invokeMethod on the slot you define there. That slot can then use a normal method invocation on the object you pass for the actual property setting. The invokeMethod should use the Qt::QueuedConnection connection type.

                          The proxy object could be quite simple, I guess something like this would suffice:

                          @
                          class PropertySetProxy: public QObject
                          {
                          Q_OBJECT

                          public:
                          PropertySetProxy(QObject* parent = 0): QObject(parent) {}

                          setProperty(const QObject* target, const char* property, QVariant value);
                          

                          };

                          //implementation
                          PropertySetProxy::setProperty(const QObject* target, const char* property, QVariant value)
                          {
                          //check if target object lives in the same thread as we do
                          if (thread() != target->thread()) {
                          qWarning() << "Can't set property of object living in different thread!";
                          return;
                          }

                          target->setProperty(property, value);
                          }
                          @

                          Note: brain to forum editor, code is not tested and to be understood as an example only.

                          1 Reply Last reply Reply Quote 0
                          • First post
                            Last post