Access UI elements from another class



  • Hello, I am trying to figure out how to use UI elements in another class... Spent hours and did not find solution...

    Headers
    mainwindow.h
    controls.h

    Sources
    mainwindow.cpp
    controls.cpp
    main.cpp

    Forms
    mainwindow.ui

    I would like to add all functions of controls (buttons) in class controls...
    Example: When user clicks button, it should execute code in controls.cpp

    I tried all possible combinations, connections and just can't get it work...
    So could someone please explain me, how to access UI elements from class controls...

    Example of function in controls class... But it does not work...
    @
    void controls::buttonClicked()
    {
    ui->btn->setText("Test");
    }@



  • 1.
    Move Ui::MainWindow *ui; from private to public in MainWindow class declaration.

    before:

    @public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    private:
    Ui::MainWindow *ui;@

    after

    @public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    Ui::MainWindow *ui;

    private:@

    2.
    Define friend class:

    @friend class controls;

    public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    private:
    Ui::MainWindow *ui;@

    Better solution:

    Add #include "ui_mainwindow.h" to controls.h and Ui::MainWindow *ui; to controls class.

    @#include <QObject>
    #include "ui_mainwindow.h"

    class controls: public QObject
    {
    Q_OBJECT
    public:
    controls(QObject *parent = 0);
    Ui::MainWindow *ui;

    public slots:
    void buttonClicked();
    };@



  • Hey, better solution does not work... It compile but does not execute buttonClicked()...

    controls.h
    @#ifndef CONTROLS_H
    #define CONTROLS_H
    #include "ui_mainwindow.h"
    class controls:public QObject
    {
    Q_OBJECT
    public:
    controls();
    Ui::MainWindow *ui;

    public slots:
    void buttonClicked();
    };

    #endif // CONTROLS_H
    @

    controls.cpp
    @#include "controls.h"

    controls::controls()
    {
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(buttonClicked()));
    }

    void controls::buttonClicked()
    {
    ui->pushButton->setText("Test");
    }
    @



  • ui->pushButton must be a valid object, and in your case is NULL because ui is not created (or assigned) ... so one solution would be to do the connections after you have just created the application ui:

    i.e.

    @MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    connect(ui->pushButton, SIGNAL(clicked()), &controls, SLOT(buttonClicked()));//controls is member in MainWindow
    ...
    @

    imho I think is a bad idea to move widget's event handlers from view class(class which has created them), and against MVC policy: a view class must be very light, creation code and handlers, and handlers should call heavy operation methods from other classes



  • My two cent:

    1. If you need to access GUI widgets that are in class A from another class B, you should probably rethink your design! You should probably use "Signals and Slots":http://qt-project.org/doc/qt-4.8/signalsandslots.html here! So when something important in class B happens, class B can simply emit a Signal. Now, if class A needs to react on things that happen in class B, simply add a suitable Slot to class A, where it would update the GUI as needed. You can also pass parameters in the Signal.

    @//Class B - Signal
    ClassB::doSomeCalculation(void)
    {
    /Some calculation here..../
    int theResult = someImportantCalculation();

    /*Now emit the result*/
    emit resultAvailable(theResult);
    

    }

    //------------------

    //Class A - Slot
    ClassA::handleResult(int x)
    {
    /Update GUI according to result/
    ui->myLabel->SetText(tr("Result is %1").arg(QString::number(x)));
    }

    //------------------

    //Main Function - Connection Setup
    main()
    {
    /* [...] */

    connect(objectB, SIGNAL(resultAvailable(int)), objectA, SLOT(handleResult(int)));
    
    /* [...] */
    

    } @
    _

    1. If you really need to access GUI widgets of class A from a class B in a direct way, which I think is bad design, please do NOT make them public! Instead you can do it as follows: Simply pass a pointer to the required GUI widgets (in class A) into the constructor of class B. Then B can store those pointers in a member variable and use them to access the GUI widgets when needed...

    @//constructor
    ClassB::ClassB(QLabel *theLabel)
    {
    m_theLabel = theLabel;
    }

    //some function
    ClassB::doCalculation(void)
    {
    /Some calculation here..../
    int x = someImportantCalculation();

    /*Now update the GUI*/
    m_theLabel->SetText(tr("Result is %1").arg(QString::number(x)));
    

    }

    //------------------

    ClassA::useClassB(void)
    {
    ClassB *b = new ClassB(ui->myLabel);
    b. doCalculation();
    }@



  • Thank you...



  • You are welcome.

    BTW: Added some example code above.



  • Yea, I saw...


Log in to reply
 

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