Search code examples
qtsignals-slotsqproperty

using Q_PROPERTY with a NOTIFY item for a QString


I have a widget-based class. It has two private QString members. I would like to be able to use signals to notify when the values are changed. So for both variables I have a setter and a getter. I also have a signal.

  • Question: Can they both use the same signal? Or do I have to define two independent signals?

Then - I would like to bind that signal to a slot in the same class (I know I could just call the slot instead of emiting signal - but I'd like to use signal).

  • How do I connect them? I tried:

    connect( &invoiceFilterDirectionPart, SIGNAL(valueChanged(QString)), this, SLOT(invoiceFilterDirectionPart_valueChanged(QString)) );
    

But it doesn't compile - as invoiceFilterDirectionPart is a QString, whereas connect expects first argument to be QObject*

I could use this in the connect statement - but as far as single signal is concerned - i guess that both slots would trigger? Is only option two independent signals and then using this in the connect statement - or am I missing something?

  • Last question: do I need a Q_PROPERTY to make all this work? When i first used it i thoud it is some kind of a magic macro - that when I used it, like this:

    Q_PROPERTY(QString invoiceFilterContractorPart 
        READ getInvoiceFilterContractorPart
        WRITE setInvoiceFilterContractorPart
        NOTIFY valueChanged
    )
    

I thought it will auto-magically generate the variable, setter, getter and the notifier signal. Sadly - that didn't happen ;). It just screamed that none of mentioned items exists. Is that all it does? Can't really find a good use case for it...


Solution

  • As far as I can see, you do not necessarily need to set Q_PROPERTY but since invoiceFilterContractorPart seems to be a property of your object, it is correctly used. Leave it.

    Having a valueChanged signal indicates a wrong way of thinking of the property. Assume invoiceFilterContractorPart is a property of some class Foo:

    class Foo : public QObject
    {
        // ...
    
        Q_PROPERTY(QString invoiceFilterContractorPart 
            READ getInvoiceFilterContractorPart
            WRITE setInvoiceFilterContractorPart
            NOTIFY valueChanged
        )
    }
    

    Then what an external object gets notified about is:

    Object foo1 of type Foo says: 'valueChanged'

    and not

    invoiceFilterContractorPart says: 'valueChanged'

    Thus you need to change your signal, such that it is clear which property has changed, e.g. rename it to invoiceFilterContractorPartChanged():

    class Foo : public QObject
    {
        // ...
    
        Q_PROPERTY(QString invoiceFilterContractorPart 
            READ getInvoiceFilterContractorPart
            WRITE setInvoiceFilterContractorPart
            NOTIFY invoiceFilterContractorPartChanged
        )
    }
    

    Now what an external object gets notified about is:

    Object foo1 of type Foo says: 'invoiceFilterContractorPartChanged'

    which enabled you to ask for the new value like foo1.getInvoiceFilterContractorPart().

    Thus, you do not connect the property but the object owning that property:

    connect(this, SIGNAL(invoiceFilterDirectionPartChanged(QString)),
            someotherobject, SLOT(onFooDidInvoiceFilterDirectionPartChanged(QString)));
    

    or inside of some other class Bar:

    connect(&foo1, SIGNAL(invoiceFilterDirectionPartChanged(QString)),
            this, SLOT(onFooDidInvoiceFilterDirectionPartChanged(QString)));