[SOLVED] Read checkbox checked state?



  • Hi all, I'm a little shaky with the QML, and a bit of a newbie to anything but embedded C for microcontrollers, so bear with me.. I'm trying to read the state of a number of checkboxes. Basically, when a box is checked, I'd like for a subroutine that is called from a button click, to read the neighboring checkbox, and perform it's task based on the state of the check box.

    I've seen several examples in other threads on this forum, but I'm not sure I understand it. Also, a lot of posts make reference to linked pages which no longer exist, or lead to somewhere new. At this point, I've constructed the object, but I'm not sure what to do with it from here to read if the box is checked, and not sure how to specify which checkbox to read. So far:

    @ QQuickView view;
    view.setSource(QUrl::fromLocalFile("main.qml"));
    view.show();
    QObject *cbox = view.rootObject();@

    This was from an example of something slightly different, and the suggestion was to use QQuickView. in my qml file, I have 5 or so checkboxes set up as such:

    @ CheckBox {
    id: left
    x: 86
    y: 3
    text: "Left"
    }

            CheckBox {
                id: right
                x: 172
                y: 3
                text: "Right"
            }@
    

    How would I individually read the state of each checkbox from this point?

    Another method I explored (but it wouldn't compile) was this (using the same qml code):

    @QSettings settings;

    QCheckBox* left->Left;                                     
    QCheckBox* right->Right;
    
    Left->setChecked(settings.value("checkstate").toBool());
    Right->setChecked(settings.value("checkstate").toBool());@
    

    And as far as I can tell, this should save the state of the checkbox to a boo called left (and right). It doesn't compile, and I'm a little lost. If someone could show me the error of my ways, slightly dumbed down, that would be appreciated. Thanks!



  • First of all you are using C/C++ code in QML (which is a different language) so that won't work :).

    QML works with properties. If you want to react to a change of the checked property you do the following:

    @
    CheckBox {
    id: left
    x: 86
    y: 3
    text: "Left"
    onCheckedChanged: /your code/
    }@

    You can find more documentation here:

    http://qt-project.org/doc/qt-5.1/qtdoc/qmlfirststeps.html



  • Thanks t3685, but all that code was in my C/C++ file, except for the button code which I specified was in my qml file. I guess I'll have to edit and label it to avoid further confusion. I've read the link you posted, but that didn't help answer my question. I want to know how to read the state of a checkbox (is it checked or not) from my C/C++ code. I'm told for the last 1000 pages I've read that it can be done, but every example shown was of how to change the state of a checkbox, not read it.

    In your example, you added "onCheckedChanged:" - this would mean that I have to connect the signal to a slot that would define an action to be called when the checkbox is changed. I'm just looking to read its state from the C/C++ side.



  • ah I misunderstood your question

    http://qt-project.org/doc/qt-5.0/qtcore/qobject.html#property
    http://qt-project.org/doc/qt-5.0/qtqml/qtqml-cppintegration-interactqmlfromcpp.html

    I hope these links helped. I should add though that it's better design you have your gui invoke c++ methods than to read the state from the ui from c++. that way if you ever modify your ui you don't need to change your c++ code. of course you may have your reasons :-)



  • Well, up until this morning, there was only supposed to be one gui program, now I'm being told I'm needed to make a few more... I can't win. But those links helped, thanks!! So I guess I'll be doing it your way after all. I have a few buttons that are set up that way as well, as shown below:

    QML:

    @Rectangle {
    id: main
    width: 800
    height: 600
    color: "#abcfe9"
    border.width: 4
    border.color: "#000000"

    signal buttonClicked_enable()
    
            Button {
            id: enable
            x: 0
            y: 25
            text: "Enable"
            onClicked:buttonClicked_enable()
        }
    

    }@

    And on the C++ side I have:

    @class TLA_Funcs : public QObject
    {
    Q_OBJECT
    public slots:
    void sys_enable(void);
    ....
    protected
    ....
    }

    int main (int argc, char*argv[]) {

    QGuiApplication app(argc, argv);
    
    QQuickView *view = new QQuickView(QUrl("main.qml"));                   
    view->show();                                                           
    QQuickItem *button = view->rootObject();                               
    TLA_Funcs *funcs = new TLA_Funcs();                                     
    
    // connect signals to slots:
    QObject::connect(button, SIGNAL(buttonClicked_enable()), funcs, SLOT(sys_enable()));
    

    ....
    }@

    but when I compile, I get an error message that only says "required from here" for the code that connects my signal to my "sys_enable()" slot. The function is not fully defined, but it does have a cout<< statement in it to give it something to do... What would cause that error? I could use a little insight on that before I start creating signals and slots for my checkboxes...



  • You'll probably want to read this then:

    http://qt-project.org/doc/qt-5.0/qtqml/qtqml-cppintegration-topic.html

    As for your problem,

    @onClicked@

    is already the slot so you don't need to make any connections anymore.
    So when a user clicks on the button the signal "clicked" is emitted, the "on<Signal>" syntax allows you to define what should happen when that button is clicked.



  • I'm not sure I follow what you're saying...

    @signal buttonClicked_enable()@ doesn't need to be there?

    @onClicked@ needs to be in the button code to direct the signal to the proper slot, right? and on the C++ side, you need to connect the signal name to the slot right? I've done it this way because I have many buttons to address...


  • Moderators

    Signals and slots between QML and C++
    As far as the C++ side can tell, your QQuickItem is a black box. Your C++ code cannot see what's inside your QQuickItem -- it cannot see your buttons or checkboxes.

    The purpose of adding signal buttonClicked_enable() to your top-level QML item was to create an interface between your QML code and C++ code. C++ cannot see the signals that are emitted by your "inner" buttons/checkboxes, but it can see the signals emitted by your top-level item. So, in order for your QML Button's signal to reach C++ land, you relay it through the top-level signal.

    A note about clicked() and onClicked(): When you click the Button, it emits the clicked() signal. It is just like any other signal -- you can connect to any slot(s) of your choice (assuming that the signal can reach that slot, of course). onClicked() is a special slot (called a "signal handler") that is built into the Button. It is auto-connected to the clicked() signal, so you don't need to explicitly make the connection yourself.

    So, in your code...
    @
    Rectangle {
    id: main
    signal buttonClicked_enable()

    Button {
        id: enable
        onClicked:buttonClicked_enable()
    }
    

    }
    @
    ...when you click your Button, this sequence occurs:

    The Button emits the clicked() signal.

    This signal calls the Button's onClicked() slot.

    In your code, the onClicked() slot does one thing only: emit the top-level Rectangle's buttonClicked_enable() signal.

    (Assuming that you made the C++ connection) The buttonClicked_enable() passes into C++ land, and activates your sys_enable() slot.

    Passing data from QML into C++
    There are 2 ways to pass data from QML out into C++:

    Signals with parameters can be used to pass data to slots that accept these parameters

    QML makes extensive use of "dynamic properties":http://qt-project.org/doc/qt-5/properties.html#reading-and-writing-properties-with-the-meta-object-system (this article was written for C++. Ignore the long section about Q_PROPERTY, go straight to "Reading and WritingProperties")

    @
    // QML
    Rectangle {
    id: main
    signal signalWithParam(bool myParam)
    property bool myBooleanProperty: false

    //...
    

    }
    @

    @
    // C++
    QQuickView *view = new QQuickView(QUrl("main.qml"));
    QQuickItem *qmlItem = view->rootObject();
    TLA_Funcs *funcs = new TLA_Funcs();

    // Connect signals to slots
    QObject::connect(qmlItem, SIGNAL(signalWithParam(bool)), funcs, SLOT(slotThatAcceptsParam(bool)));

    // Read property
    bool valueFromQml = qmlItem->property("myBooleanProperty").toBool();
    @

    How to use your checkbox to emit the signal or set the property in QML is left as an exercise :)



  • Thanks JKSH, good info - and I pretty much understand that info already. But a refresh was good!! I was trying to understand the other guy's information, because it was a little vague:

    [quote author="t3685" date="1392293795"]

    As for your problem,

    @onClicked@

    is already the slot so you don't need to make any connections anymore.
    So when a user clicks on the button the signal "clicked" is emitted, the "on<Signal>" syntax allows you to define what should happen when that button is clicked.
    [/quote]

    Connecting the checkboxes to the c++ was practically the same as when you explained the buttons in the other thread, but instead of onClicked() I used onCheckedChenged() and my slot function handles it. Now the only issue I'm working through is in the c++ side, where the line:

    @QObject::connect(stuff, SIGNAL(buttonClicked_enable()), funcs, SLOT(sys_enable()));@

    is rejected by the compiler with the following errors:

    "X:\Lambda UDP Test Program\Lambda_UDP_Test_GUI\TLA_UDP.cpp:122: note: candidate expects 3 arguments, 4 provided QObject::connect(stuff, SIGNAL(buttonClicked_inhibit()), funcs, SLOT(sys_enable()));"

    and

    "C:\Qt\Qt5.2.1MinGw\5.2.1\mingw48_32\include\QtCore\qobject.h:-1: In substitution of 'template<class Func1, class Func2> static typename QtPrivate::QEnableIf<(QtPrivate::FunctionPointer<Func2>::ArgumentCount == (-1)), QMetaObject::Connection>::Type QObject::connect(const typename QtPrivate::FunctionPointer<Func>::Object*, Func1, const QObject*, Func2, Qt::ConnectionType) [with Func1 = const char*; Func2 = const char*]': X:\Lambda UDP Test Program\Lambda_UDP_Test_GUI\TLA_UDP.cpp:122: required from here"

    I'm still trying to hunt down the reason. I've been on the QObject resurce page looking at QObject::Connect() condition, and even in their examples, they are showing 4 arguments structured the same as what I have. So I'm a little puzzled as to what's holding that back... and I put this in this thread because it pertains to the way I set up the checkboxes.



  • What I meant was that onClicked is already a slot, and it seems weird to throw another signal from there.


  • Moderators

    [quote author="jediengineer" date="1392309698"]
    @QObject::connect(stuff, SIGNAL(buttonClicked_enable()), funcs, SLOT(sys_enable()));@

    is rejected by the compiler with the following errors:

    "X:\Lambda UDP Test Program\Lambda_UDP_Test_GUI\TLA_UDP.cpp:122: note: candidate expects 3 arguments, 4 provided QObject::connect(stuff, SIGNAL(buttonClicked_inhibit()), funcs, SLOT(sys_enable()));"
    [/quote]Erase the line and re-type it. I suspect a typo.

    [quote author="t3685" date="1392319949"]What I meant was that onClicked is already a slot, and it seems weird to throw another signal from there.[/quote]Why is it weird?

    • It's perfectly valid to chain multiple signals together.
    • This design can be used to enforce modularity/encapsulation.
    • You can emit a signal with parameters in response to a click.


  • the clicked signal is no more or less encapsulated than the custom signal you defined in your button. it is just as accessible to everyone else. since you are not using it with any parameters or I must have looked over out it felt a little redundant to me :-). any case good luck!



  • Ok, retyping didn't help. T3685, in my case, I have about 23 buttons I'm assigning to slots. How would you differentiate them all, based on what you said?



  • Ok, here's a screenshot of the error:

    !http://tinypic.com/r/2vsoups/8()!

    Sorry, it's the first place I found to host the picture...


  • Moderators

    [quote author="jediengineer" date="1392386177"]Ok, here's a screenshot of the error:

    !http://tinypic.com/r/2vsoups/8()!

    Sorry, it's the first place I found to host the picture... [/quote]Your compiler doesn't know what a QQuickItem is, and doesn't realize that it can take part in signal-slot connections. To inform your compiler,
    @#include <QQuickItem>@

    By the way, the "is required here" message is only an extra note that comes after the actual error message. The real error message (which is the message you'd use to find the root of the problem) is at the 1st red exclamation mark.

    [quote author="t3685" date="1392361043"]the clicked signal is no more or less encapsulated than the custom signal you defined in your button. it is just as accessible to everyone else. since you are not using it with any parameters or I must have looked over out it felt a little redundant to me :-). any case good luck! [/quote]I meant encapsulating the buttons/checkboxes away from C++ code. :) The OP's slot is a C++ function.

    Granted, it's not very "hidden" at the moment because the signal name is "buttonClicked_enable()", but that's a different matter.

    [quote author="jediengineer" date="1392378240"]T3685, in my case, I have about 23 buttons I'm assigning to slots. How would you differentiate them all, based on what you said?[/quote]t3685 meant that you can call your C++ slots directly from QML, without adding the extra "buttonClicked_enable()" signal. It's the "shorter method" that I hinted at in http://qt-project.org/forums/viewthread/37907/

    If you're eager to investigate it, that method involves inserting your C++ object into QML as a "context property":http://qt-project.org/doc/qt-5/qtqml-cppintegration-contextproperties.html. However, I still recommend that you leave context properties for later, and focus on mastering the signal-slot method first. The latter is much more useful for Qt programming overall.



  • Holy Crap, JKSH, I can't believe it was as simple as a header file... I'm not sure how I didn't catch that, maybe it's because QQuickView highlighted itself in green, so I assumed it was recognized... Well, I feel dumb. But thanks for pointing that out...

    I won't bother with the context property for now unless this runs at a snail's pace, which I suspect it won't. Thanks again, you've given me an insight to how some of this stuff works, and I appreciate it! Now I've got a little reading to do on checkbox signals... Thanks a million!!



  • Ok, one last question about this - I think I've got a destructor issue... now I'm not too sure of myself with destructors, but I've tried a few different ways to fix this. Everything compiles fine except the class - I get a "undefined reference to 'vtable for TLA_Funcs' " message when I compile. I know this has something to do with the destructor, and I'm trying to figure it out, and I've even tried several recommended methods for fixing it, posted on stackoverflow... but nothing seems to help. Any ideas? Again, here's my class, and it's in my custom header file...

    @class TLA_Funcs : public QObject {

    Q_OBJECT
    

    public slots:
    void sys_enable(){return;} // enable left, right, or both inverters
    void sys_inhibit(){return;} // inhibit left, right, or both inverters
    void sys_hard_inhibit(){return;} // inhibit system via main inhibit line
    void sys_disable(){return;} // disable entire system
    void sys_autoupdate(){return;} // enables or disables autoupdate
    void sys_reset(){return;} // resets analog inverter controller
    void sys_observe(){return;} // forces observation mode
    void sys_dac_test(){return;} // performs DAC self test
    void sys_reset_dac(){return;} // resets the DAC
    void sys_read_adc(){return;} // reads ADC inputs
    void sys_read_mux(){return;} // reads MUX inputs
    void sys_poll(){return;} // Quick ADC and MUX poll
    void sys_set_voltage(){return;} // sets output voltage percent
    void sys_set_current(){return;} // sets output current percent
    void sys_set_power(){return;} // sets output power percent
    void sys_set_all(){return;} // sets all output controls simultaneously by percent
    void sys_save_dac_settings(){return;} // save all dac settings
    void sys_delete_dac_settings(){return;} // delete saved dac settings
    void sys_restore_dac_settings(){return;} // restores saved settings from memory
    void sys_cpu_reset(){return;} // resets CPU
    void sys_cpu_halt(){return;} // halts cpu
    void sys_self_check(){return;} // performs full system check.
    void sys_adc_test(){return;} // ADC test

    void sys_left_inv(){left_inv = !left_inv;}
    void sys_right_inv(){right_inv = !right_inv;}
    void sys_step(){step = !step;}
    void sys_fine_step(){fine = !fine;}
    void sys_step_up(){up = !up;}
    void sys_spec_mux(){specific_mux = !specific_mux;}
    void sys_spec_adc(){specific_adc = !specific_adc;}
    

    protected:
    bool left_inv;
    bool right_inv;
    bool step;
    bool fine;
    bool up;
    bool specific_mux;
    bool specific_adc;
    };@

    I've tried a bunch of different methods of constructing and destructing, but nothing seems to work. Any ideas?


  • Moderators

    [quote]I get a “undefined reference to ‘vtable for TLA_Funcs’ “[/quote]No destructors involved here.

    This error can be cause by a few different things. In your case, you just have an outdated Makefile. You need to generate a new one if you add "Q_OBJECT" to any class:

    Build -> Clean Project _____ (not strictly necessary, but I do it just in case)

    Build -> Run qmake

    Build -> Build Project _____



  • err... Nope, that wasn't it. Same error as before. Still pointing to my class with the "undefined reference to 'vtable for TLA' " error message.

    I'm fiddling with it, trying to understand this. This is quite a change from what I'm used to doing with embedded DSP processors...


  • Moderators

    [quote author="jediengineer" date="1392503915"]err... Nope, that wasn't it. Same error as before. Still pointing to my class with the "undefined reference to 'vtable for TLA' " error message.

    I'm fiddling with it, trying to understand this. This is quite a change from what I'm used to doing with embedded DSP processors...[/quote]Another cause of this error is if you declared TLA_Funcs in a .cpp file.

    Qt uses a "code generator":http://qt-project.org/doc/qt-5/why-moc.html to support signals+slots and many other features. The code generator (called 'moc', for "Meta-Object Compiler") requires all QObject declarations to be put in an header files.

    Solution: Move your TLA_Funcs declaration to a .h file (Remember to run qmake afterwards)

    P.S. Add a constructor to your class to initialize all its variables to a default value. If you don't do this, they will contain random garbage values.
    @
    public:
    TLA_Funcs(QObject *parent = 0) : QObject(parent)
    {
    // Initialize all your member variables here
    }
    @
    P.P.S. Use "private", not "protected". "Protected" is for subclassing.



  • JKSH - thanks, I had already tried that but it didn't work.. :-(

    HOWEVER, I did the following, which I hadn't before: I went to File->New File or Project->C++->C++ Class to create a new class, versus just making a class in my header file. Once completed, I transferred my class to the new file and lo and behold, it compiled. I tried to do a test run, and it gave me a connection error, which I'm still currently working on...

    QObject::connect: Cannot connect (null)::buttonClicked_enable() to TLA_Funcs::sys_enable()



  • Just to be clear, my code is now this:

    header file:

    @class TLA_Funcs : public QObject
    {
    Q_OBJECT
    public:
    explicit TLA_Funcs(QObject *parent = 0);
    signals:

    public slots:
    Q_INVOKABLE void sys_enable(){return;}

    . . .
    };@

    .cpp file:

    @#include " ... "

    TLA_Funcs::TLA_Funcs(QObject *parent) :
    QObject(parent)
    {
    }

    int main (int argc, char*argv[]) {

    QGuiApplication app(argc, argv);
    
    QQuickView *view = new QQuickView(QUrl("main.qml"));                   
    view->show(); 
    
    QQuickItem *item = view->rootObject();                               
    
    TLA_Funcs *funcs = new TLA_Funcs();      
                              
    // connect button signals to their slots:
    QObject::connect(item, SIGNAL(buttonClicked_enable()), funcs, SLOT(sys_enable()));
    

    return 0;
    }@

    QML:

    @Rectangle {
    id: main
    width: 800
    height: 600
    color: "#abcfe9"
    border.width: 4
    border.color: "#000000"

    signal buttonClicked_enable
    
    Button {
        id: autoupdate
        x: 628
        y: 55
        text: "AutoUpdate"
        onClicked:buttonClicked_enable()
    

    }@

    It builds fine, but when I run it, I get the error:

    "QObject::connect: Cannot connect (null)::buttonClicked_enable() to TLA_Funcs::sys_enable()"

    I tried using @onClicked:main.buttonClicked_enable()@
    to connect... I also tried using your method from the previous post you suggested:

    @onClicked:{
    buttonClicked_enable()
    TLA_Funcs.sys_enable()
    }@

    but it still gives me the same error. Did I miss something? Do I need to list my signals under "signals" in the class? if so, would they be posted the same way as in the QML code?

    @
    signals:
    buttonClicked_enable()@

    Please advise, this is tormenting me because I'm getting the feeling that it is one of those things that's staring me in the face... only this time it's laughing at me...



  • Cancel that last request. Problem solved. There was an issue with the .pro file. I have since created a new project, copied my code into it, and it works correctly!!! Thanks all, especially JKSH, for all the help with affording me an opportunity to learn!!!


Log in to reply
 

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