Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Exposing abstract/interface objects with Q_PROPERTYs, abstract slots, etc, to QML?



  • I'd like to define in one place an abstract interface like this, that is used by QML. And then be able to have many implementations of that interface.

    The app would be using a list of IDeviceLink.

    Here's what I was hoping to do:

    //Abstract interface for all subclasses
    class IDeviceLink
    {
        Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
        Q_PROPERTY(QString deviceName READ deviceName NOTIFY deviceNameChanged)
        Q_PROPERTY(uint uptime READ uptime NOTIFY uptimeChanged);
    
    public:
    	Q_INVOKABLE virtual void connect() = 0;
    	Q_INVOKABLE virtual void doPoll() = 0;
    
    signals:
        void connected();
        void connectionLost();
        void pollCompleted();
    };
    
    //Concrete implementation example
    class SimDeviceLink: public QObject, public IDeviceLink
    {
    public:
    	explicit SimDeviceLink(QObject* parent = nullptr): QObject(parent) {} 
    
    	Q_INVOKABLE virtual void connect() { emit connected(); }
    	Q_INVOKABLE virtual void doPoll() { emit pollCompleted(); }
    
        virtual bool connected() const { return true; }
        virtual QString deviceName() const { return "sim"; };
        virtual uint uptime() const { return 123; }
    };
    
    //Another concrete implementation
    class LinuxLink: public QObject, public IDeviceLink {
    	...
    }
    class WindowsLink: public QObject, public IDeviceLink {
    	...
    }
    
    

    The compiler says "Class declaration lacks Q_OBJECT macro" for IDeviceLink. OK, so I added it. Then, need to add inheriting QObject. Then, the dual inheritance in SimDeviceLink stops working, so OK, I switch to single inheritance of IDeviceLink (thankfully only need to implement one class). Update both constructors.

    Then naturally, it complains about the missing properties in IDeviceLink. I don't want it to implement properties, but OK. I implement them and move them to protected. Finally, it builds, but the QML code fails at runtime by saying "TypeError: Property 'deviceName' of object SimDeviceLink(0x5619681f9cf0) is not a function". Calling one of the invokables returns undefined.

    The updated example code after all my changes is here: https://github.com/jerkstorecaller/abstractqml

    It's already way messier than I had hoped, and still doesn't work. How am I meant I achieve a basic clean abstract/interface + concrete implementation approach here? What is the Recommended Approach (tm)?


Log in to reply