Enums not working or be referenced correctly in QML



  • Background: I am trying to make a remote control for a car controlled with Raspberry Pi. I'm using REST API from WebIOPI to do it." More info":http://nayarweb.com/blog/2014/control-raspberry-pis-gpio-with-rest-qt-webiopi/ (optional)

    Problem: I have a class CarController (stripped version)
    @class CarController : public QObject
    {
    Q_OBJECT
    Q_ENUMS(ACCELERATE_DIRECTION)

    public:

    enum ACCELERATE_DIRECTION {
        FORWARD,
        BACKWARD
    };
    
    explicit CarController(QObject *parent = 0);
    Q_INVOKABLE void accelerate(ACCELERATE_DIRECTION direction, double power = 1);
    void setGPIO(int no, int value);
    

    };

    #endif // CARCONTROLLER_H
    @

    @
    void CarController::accelerate(CarController::ACCELERATE_DIRECTION direction, double power)
    {
    qDebug() << "direction" << direction;
    if((direction == CarController::FORWARD) && (power > 0)){
    qDebug() << "Forward";
    setGPIO(forward_GPIO(),1);
    setGPIO(backward_GPIO(),0);
    }
    else if ((direction == CarController::BACKWARD) && (power > 0)){
    qDebug() << "Backward";
    setGPIO(forward_GPIO(),0);
    setGPIO(backward_GPIO(),1);
    }
    else{
    setGPIO(forward_GPIO(),0);
    setGPIO(backward_GPIO(),0);
    }
    }
    @

    I have the following QML
    @
    Button {
    id: button1
    x: 268
    y: 158
    width: 155
    height: 73
    text: qsTr("Forward")
    onClicked: {
    car.accelerate(car.FORWARD,1);
    }
    }

    Button {
        id: button4
        x: 268
        y: 308
        width: 155
        height: 23
        text: qsTr("Reverse")
        onClicked: {
            car.accelerate(car.BACKWARD,1);
        }
    }
    

    @

    The first button works fine. But the "reverse" button is doing the same job as the "forward". The direction is always being integer 0 in CarController::accelerate().

    If i replace
    @car.accelerate(car.BACKWARD,1)@
    by
    @car.accelerate(1,1); @

    in the QML, it works fine then. Any guesses what is going wrong by calling car.BACKWARD?





  • That's what i did tubbias. Qt Creator shows the enums in autocomplete too. It just isn't working



  • Hi, what is "car" in your QML code? I guess that is an object of your CarController, but enum values are not properties of your object, but only your class (don't always trust auto completion)!
    So you need to use your class instead of the object to access enum values from QML:
    @
    car.accelerate(CarController.FORWARD,1);
    @
    or whatever name you used to register the CarController class to QML.



  • You're awesome man (y)

    Indeed "car" was an object of CarController. Used the class name and it worked :D

    But wasn't the object supposed to have the enum too? I'm kinda new to C++ and Qt. I'm just trusting my instinct and autocompletion.

    Thanks a lot :)



  • Well I think it is better this way and more clear. In c++ you can access all static members of the class form the objects, but that is still considered bad design (in my opinion at least haha).
    Some other languages don't have that feature, and you have to use the class name instead of the object to avoid confusion. So if you use it like you should be, it works in all programming languages I know like this. :D

    c++ example
    @
    QString num = QString::number(123); // static access with ::
    QString num = QString().number(123); // object access
    @
    both should work the same, maybe this example is a little stupid but in the 2nd example the QString() could be any existing object of QString and using QString::number makes it more clear that the number method is actually a static function and not a member function.

    Similar with enum values, one reason you should prefer c++11 enum class over plain enum because they are scoped and the "old" enum values are always in the parent scope
    @
    class EnumTest {
    enum class Foo { One, Two, Three }; // new with c++11
    enum Bar{ One, Two, Three };
    };
    // you access the c++11 enum like it is scoped and not directly
    EnumTest::Foo::One
    // with the old style all enum values are accessible in the parent scope
    Enum::One
    // which is bad if you have multiple enums or other values with the same name
    @
    look at the Qt namespace which has defined many values like colors or positions etc it is not only chaos but unclear where some values come from
    @
    Qt::horizontal // what enum is that from?
    // from qt definition
    enum Orientation {
    Horizontal = 0x1,
    Vertical = 0x2
    };
    //I think this would be better to read
    Qt::Orientation::horizontal
    @
    sorry for the long text ^^



  • Yeah. Agreed it is bad practice.

    But in future, Qt gonna either make the enums available to the objects too or prevent it from compiling. Right now, it can be counted as a "bug"

    I come from a Java, Python, PHP background. We usually take such things as granted. Moreover, QML is not a strict typed language.



  • QML ist mostly "just" JavaScript, and JS has dynamic objects. so the code is valid if you try something like this:
    @
    var obj = {} // empty object
    console.log(obj.foo)
    @
    obj.foo is valid code, it will just be undefined and that is why your code shows no warnings or error, you just try accessing a property that is not there and Qt will convert "undefined" to 0 if the target type in c++ is an int :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.