Connect ComboBox signal to my class slot [SOLVED]



  • Hi all, noob here with a basic question.

    I would like to design my ui in the Creator design gui and then link the combobox currentIndexChanged signal to a slot in my PhraseChooser class. How can that be done?

    Any help would be greatly appreciated.

    Thanks


  • Lifetime Qt Champion

    Hi,

    Create the UI as usual, then do the connection in your widget's constructor.

    To have a more complete answer you should give more details like what PhraseChooser is, where is it used etc.



  • Thanks SG. This is just a something-to-do project that might be useful to my son at school. Eventually the gui will allow the user to load a file and then pass it to the class(es) which will parse the contents, do a bit of basic statistical analysis, and return the results back to the gui. With this phase I am trying to learn the mechanisms necessary to accomplish that. PhraseChanger itself should take the selected index from the combobox and return the phrase as a string to a label in the gui.

    As far as I know I'm not really creating a widget (am I?) just a sort-of background process to analyze the data. Here is phrasechooser.h:
    @#ifndef PHRASECHOOSER_H
    #define PHRASECHOOSER_H

    #include <QObject>
    #include <iostream>
    using namespace std;

    class PhraseChooser : public QObject
    {
    Q_OBJECT

    public:
    PhraseChooser();

    protected:
    const char* phrases[10];

    public slots:
    void changePhrase(int index);

    signals:
    void phraseChanged();
    };

    #endif // PHRASECHOOSER_H
    @

    and here is phrasechooser.cpp (so far)

    @#include "phrasechooser.h"

    PhraseChooser::PhraseChooser()
    {
    phrases[0] = "Now is the time for all good men to come to the aid of the party.";
    phrases[1] = "He who laughs last, laughs best.";
    phrases[2] = "No time to do it right but plenty of time to do it twice.";
    phrases[3] = "The greatest journey begins with a single step.";
    phrases[4] = "Judge not and ye shall not be judged.";
    phrases[5] = "A bird in the hand is worth two in the bush.";
    phrases[6] = "Money can't buy happiness.";
    phrases[7] = "The best things in life are free.";
    phrases[8] = "If you're not happy with what you have - you'll never be happy.";
    phrases[9] = "Be here now. Be. Here. Now.";
    }

    void PhraseChooser::changePhrase(int index)
    {
    int phraseNum = index;
    // cout << "Hello?";
    }
    @


  • Lifetime Qt Champion

    Indeed PathChooser is not a widget at all.

    @void phraseChanged(const QString& newPhrase);@

    would be more useful if you want to connect it to a QLabel setText slot.

    Some quick ideas:

    @
    phrasechooser.h

    private:
    QList<QString> _phrases; << Avoids you to have to update the array size each time you want to add/remove a phrase
    int _currentIndex;
    @

    @
    PhraseChooser::PhraseChooser()
    {
    // Even if you don't use it now, writing code with internationalization in mind is a good habit
    _phrases << tr("Now is the time for all good men to come to the aid of the party.")
    << tr("He who laughs last, laughs best.")
    << tr("No time to do it right but plenty of time to do it twice.")
    << tr("The greatest journey begins with a single step.")
    << tr("Judge not and ye shall not be judged.")
    << tr("A bird in the hand is worth two in the bush.")
    << tr("Money can't buy happiness.")
    << tr("The best things in life are free.")
    << tr("If you're not happy with what you have - you'll never be happy.")
    << tr("Be here now. Be. Here. Now.");
    }

    void PhraseChooser::changePhrase(int index)
    {
    if (_currentIndex != index) {
    _currentIndex = index;
    emit phraseChanged(_phrases.at(i));
    }
    }@



  • Ok. I will study this and be probably be back later (or sooner) with more examples of my obvious confusion. :-)



  • I'll try again - I just did another post and it disappeared when I hit 'Post reply'. Hope this doesn't turn into a double post.

    So - next question. I'm trying to do the 'connect' - here's the code from main.cpp:
    @#include "app_1_mainwindow.h"
    #include "phrasechooser.h"
    #include <QApplication>

    // recieves a signal containing the current index of the combo box
    // returns a string to the label corresponding to the index

    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    app_1_MainWindow main_w;

    PhraseChooser chooser;
    
    connect(app1cB01,SIGNAL(currentIndexChanged(int)), chooser, SLOT(changePhase(QString)));
    
    main_w.show();
    
    return app.exec();
    

    }
    @
    Then Qt says:
    @15: error: 'app1cB01' was not declared in this scope
    connect(app1cB01,SIGNAL(currentIndexChanged(int)), chooser, SLOT(changePhase(QString)));
    @
    and:
    @15: error: 'connect' was not declared in this scope
    connect(app1cB01,SIGNAL(currentIndexChanged(int)), chooser, SLOT(changePhase(QString)));
    @
    I've been trying to figure this out now for weeks but I keep banging my head on this part. So, where is the 'connect' line supposed to go - main.cpp? - phrasechooser.cpp? - mainwindow.cpp? - a header file? - a method somewhere? the phrasechooser constructor?

    And how do I resolve the 'call' to app1cB01 (the name I gave the comboBox in designer)? I'm getting really confused about when and where to use or not use 'new' and where and when to use or not use . or -> or ::.

    TIA


  • Lifetime Qt Champion

    connect is a static (except for one overload) method of QObject so you either call it like you already do when in a QObject derived class or use QObject::connect(etc.)

    PathChooser should rather be a member variable of app_1_MainWindow, you would then connect it in the constructor of app_1_MainWindow using something like:

    @connect(ui->app1cB01, etc.@

    Note that what you are trying to do is wrong (or at least the signature is wrong) your can't connect a signal with an integer parameter to a slot with a QString parameter.



  • This board ate my reply again, so here it is again.

    Thanks - appreciate the help but I'm confused. Are you saying that PhraseChooser can't be a 'stand alone' class but must be declared and defined as a member of the app_1_MainWindow class?

    (I see the mismatched signature.)


  • Lifetime Qt Champion

    No I'm not saying that.

    Based on your current main implementation it seems that PathChooser won't do anything (in the sense that there's nothing connected to it's phraseChanged signal), so I'm guessing that you want to do something with in MainWindow, aren't you ?



  • I'm not sure myself. I used the designer in creator to make a gui that contains only the comboBox and a label mainly to get to understand how to connect the gui widgets to c++ logic and then once I get that, to develop a slightly less trivial app where I use the designer to create the gui and c++ to handle the (simple) logic.

    Trying to go one step at a time I thought I would connect the comboBox to phraseChanged and then use something like qdebug or cout from inside phraseChanged to see where I was. When satisfied that that was working then I would return the new phrase to the label, expecting to use the changePhrase signal of PhraseChanger.

    In main I thought I would need to instantiate an instance of PhraseChanger so that the connection would be made and the logic handling methods would be available when I can figure out how to use them.

    I don't know if that is a good idea and, if so, whether a PhraseChanger object should be created under main or app_1_mainwindow. So I guess that brings up the question: Should PhraseChooser be instantiated in main or in MainWindow (if at all) and (if you have time) why?

    Thanks.



  • Here's what I have now:

    app_1_mainwindow.h
    @#ifndef APP_1_MAINWINDOW_H
    #define APP_1_MAINWINDOW_H

    #include <QMainWindow>

    namespace Ui
    {
    class app_1_MainWindow;
    }

    class app_1_MainWindow : public QMainWindow
    {

    Q_OBJECT

    public:

    explicit app_1_MainWindow(QWidget *parent = 0);
    ~app_1_MainWindow();

    private:

    Ui::app_1_MainWindow *ui;

    };

    #endif // APP_1_MAINWINDOW_H
    @
    app_1_mainwindow.cpp
    @#include "app_1_mainwindow.h"
    #include "ui_app_1_mainwindow.h"

    app_1_MainWindow::app_1_MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::app_1_MainWindow)
    {

    ui->setupUi(this);

    }

    app_1_MainWindow::~app_1_MainWindow()
    {

    delete ui;

    }
    @
    phrasechooser.h
    @#ifndef PHRASECHOOSER_H
    #define PHRASECHOOSER_H

    #include <QObject>
    #include <iostream>

    using namespace std;

    class PhraseChooser : public QObject
    {
    Q_OBJECT

    public:

    PhraseChooser();

    protected:

    QList<QString> _phrases;
    int _currentIndex;

    public slots:

    void changePhrase(int index);

    signals:

    void phraseChanged(const QString& newPhrase);

    };

    #endif // PHRASECHOOSER_H
    @
    phrasechooser.cpp
    @#include "phrasechooser.h"

    PhraseChooser::PhraseChooser()
    {

    _phrases
    <<tr("Now is the time for all good men to come to the aid of the party.")
    <<tr("He who laughs last, laughs best.")
    <<tr("No time to do it right but plenty of time to do it twice.")
    <<tr("The greatest journey begins with a single step.")
    <<tr("Judge not and ye shall not be judged.")
    <<tr("A bird in the hand is worth two in the bush.")
    <<tr("Money can't buy happiness.")
    <<tr("The best things in life are free.")
    <<tr("If you're not happy with what you have - you'll never be happy.")
    <<tr("Be here now. Be. Here. Now.");

    connect(ui->cb01,SIGNAL(currentIndexChanged(int)), this, SLOT(changePhase(int)));

    }

    void PhraseChooser::changePhrase(int index)
    {

    if(_currentIndex != index)
    {
    _currentIndex = index;
    emit phraseChanged(_phrases.at(index));
    }

    // cout << "Hello?";

    }
    @
    and main.cpp
    @#include "app_1_mainwindow.h"
    #include "phrasechooser.h"
    #include <QApplication>

    // recieves a signal containing the current index of the combo box
    // returns a string to the label corresponding to the index

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

    QApplication app(argc, argv);
    app_1_MainWindow main_w;

    main_w.show();

    return app.exec();

    }
    @
    and the error
    @/home/phil/projects/qt/various/app_1/app_1/phrasechooser.cpp:18: error: 'ui' was not declared in this scope
    connect(ui->cb01,SIGNAL(currentIndexChanged(int)), this, SLOT(changePhase(int)));
    @
    I've tried all sorts of locations for the connect code and headers but I keep getting the same error. Anybody have any idea why this is happening?

    Thanks.



  • "ui" is a member of "class app_1_MainWindow".
    "ui" is NOT a member of "class PhraseChooser".
    Hence it is undefined in the connect statement.



  • OK. Iv'e tried variations on this theme (in phrasechooser.cpp):

    @
    // #include "app_1_mainwindow.h"
    // class ; - forward declaration?
    @

    and these (in various combinations with above):

    @
    connect(app_1_mainwindow->ui->cb01...
    connect(app_1_mainwindow::ui->cb01...
    @

    etc... and I still keep getting errors.

    So how the heck do I resolve 'ui' in this context?

    I'm old, my hair's starting to fall out, I can't afford to pull any more of it out!!


  • Lifetime Qt Champion

    ui is a private member of app_1_mainwindow.

    You're doing it from the wrong end. PathChooser should not know anything about app_1_mainwindow or try to connect to it. It's what we could call a helper class.

    On the other hand, app_1_mainwindow will use PathChooser, so it's its responsibility to do the connections and use what PathChooser provides. So make it a member variable of app_1_mainwindow and you should be good to go.



  • Thanks again SG.

    As you can see I'm no expert at either end of this - Qt or c++ - so when you say 'member variable' all that pops into my head is ints or strings or stuff like that. I'm stuck on thinking I've made a class - PhraseChooser - and that classes aren't members of other classes (other than through inheritance) so I don't understand when you say 'make it a member variable'. I'm not disputing, I'm sure you know more about this than I ever will - I just don't understand.



  • It works!

    I figured "member variable" meant something like this:

    @#ifndef APP_1_MAINWINDOW_H
    #define APP_1_MAINWINDOW_H

    #include <QMainWindow>
    #include "phrasechooser.h"

    namespace Ui
    {
    class app_1_MainWindow;
    }

    class app_1_MainWindow : public QMainWindow
    {

    Q_OBJECT

    public:

    explicit app_1_MainWindow(QWidget *parent = 0);
    ~app_1_MainWindow();

    private:

    Ui::app_1_MainWindow *ui;
    PhraseChooser chooser;

    };

    #endif // APP_1_MAINWINDOW_H
    @
    and then this in the cpp:
    @connect(ui->cb01,SIGNAL(currentIndexChanged(int)), &chooser, SLOT(changePhrase(int)));
    connect(&chooser, SIGNAL(phraseChanged(QString)), ui->lbl01,SLOT(setText(QString)));
    @
    ...and it worked!

    Thanks again. Now I can sleep tonight.


  • Lifetime Qt Champion

    "C++":http://www.cplusplus.com can help you getting started better. Don't try to run before you walk with C++, it's the quickest way to shoot yourself in the foot.



  • Thanks again. I did some college level programming courses in the 70's and 80's but never used it and forgot most of it. Started with Waterloo MicroBASIC, TurboPASCAL, straight into C++ (not realizing I should probably have learned C first) and even a full semester course on C++ pointers. I'm hoping some of it will come back to me as I attempt to use it again and with the help of people like you and your cohorts.

    I'm sure I'll be back again with more lost-in-the-fog-where-am-I questions soon.


  • Lifetime Qt Champion

    Don't worry a bit of patience and a good book will do marvels ;)


Log in to reply
 

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