[Solved] Accessing UI components from another file



  • Hi,
    I'm new to the forum and new to qt as well. My problem may seem simple to you but i can't find solution.
    I have a .ui form (mainform), I added a separate class (functions.cpp and .h) in which I will put all the functions (calculation) needed in my work. The problem is that results of these calculations have to be displayed in the mainform (lineEdit for example).
    So how can I write in functions.cpp to access components of the mainform.ui
    What I have tried is:
    @#include "mainform.h"
    void myFunc()
    {
    MainForm::ui->text1->setText(...)

    @

    but it does not work.
    I tried also to include the ui_mainform.h and use the class Ui::Mainform but no success.
    So would someone please give me some hints.
    Thank you in advance.


  • Moderators

    welcome to devnet

    If you like to have access to the values of your form, you may pass a reference or a pointer to the form to your functions for access.

    Are you experienced with OOP and C++?



  • Hi koahnig,
    Thanx for the reply and the welcome. I have some experience but not so advanced.
    I have already tested what you said but it says Ui::MainForm* MainForm::ui is private.

    @#include "functions.h"
    #include "mainform.h"
    #include "ui_mainform.h"

    MainForm *form=new MainForm();

    functions::functions(QObject *parent) :
    QObject(parent)
    {

    }

    void setCont()
    {
    form->ui->lineEdit->setText("some text");
    }@

    Where did I make mistake?


  • Moderators

    You should write some access functions for MainForm.

    E.g.

    @
    class MainForm : public QWidget
    {
    Q_OBJECT

    public:
    MainForm(QWidget *parent = 0);
    ~MainForm();

    QString getName () const;
    void setName ( const QString & name );
    

    private:
    Ui::MainForm ui;
    };

    QString MainForm :: getName () const
    {
    return ui->lineEdit->text();
    }

    void MainForm :: setName ( const QString & name )
    {
    ui->lineEdit->setText ( name );
    }
    @

    NOTE: this is brain to keyboard just providing an example.

    However, i would also recommend you to have a look at some C++ tutorials. One needs a bit of experience with C++ to work with Qt.



  • Thanx for your reply.
    You really make me scared with your example :)
    It's only an example but my application can contain like 20 text edits, tables,.... And the actions to do on these components can be just everything: set text, change caption, insert rows,... so I think it's no way to wirte functions for each of these stuff.
    I am sure the right way is to pass a pointer to the form but I can not yet find my way.
    Any other suggestions are highly appreciated.



  • In your header you should declare all of your widgets:
    @
    private:
    QTextEdit *text1;
    QTextEdit *text2;
    QLabel *label1;
    // and so on....
    @



  • Hi,
    I changed Ui::MainForm ui to be public in the MainForm and it compiles without problem but nothing happens when I press the button. I send here my codes.

    mainwindow.h:
    @
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>

    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

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

    public:
    Ui::MainWindow *ui;
    private slots:
    void on_pushButton_clicked();
    };

    #endif // MAINWINDOW_H
    @

    mainwindow.cpp:

    @#include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "functions.h"

    functions f;

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    }

    MainWindow::~MainWindow()
    {
    delete ui;
    }

    void MainWindow::on_pushButton_clicked()
    {
    f.setCont();
    }
    @

    functions.h:

    @#ifndef FUNCTIONS_H
    #define FUNCTIONS_H

    class functions
    {
    public:
    functions();
    void setCont();
    };

    #endif // FUNCTIONS_H@

    functions.cpp:

    @#include "functions.h"
    #include "mainwindow.h"
    #include "ui_mainwindow.h"

    functions::functions()
    {
    }

    void functions::setCont()
    {
    MainWindow m;
    m.ui->lineEdit->setText("my text");
    }
    @

    and main.cpp:

    @#include <QtGui/QApplication>
    #include "mainwindow.h"

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec&#40;&#41;;
    

    }
    @

    Need your help please.
    Thanks a lot in advance.



  • Declaring things public is not the way to solve these issues. You're breaking encapsulation, and that will come back to haunt you. It means that you are producing dependencies between components of your application that should be independent, ultimately leading to spaghetti code.

    Why does another class need direct access to the UI components of the mainwindow?



  • Thank you Andre for your reply.
    I do this for simplicity reasons. As I am a beginner in qt (I come from c++builder), I learn from this "simple" example. In my application, I will have one main window and at least three different forms with some widgets in them. One form has to access another forms components: pass / read value to/from Ui components. I have read tons of threads in many forums but still cant find my way.
    Thanks in advance for any help.



  • How come no one is recommending "signals and slots":http://developer.qt.nokia.com/doc/qt-4.8/signalsandslots.html? :)

    Use signals and slots instead of breaking your encapsulation, just add slots for the functionality you want accessible through your main window, and connect those to the signals of the classes that need to use that functionality. This way your forms don't have to know and be exposed naked to each other, just the slot interface of your mainwindow.



  • [quote author="ddriver" date="1330360312"]How come no one is recommending "signals and slots":http://developer.qt.nokia.com/doc/qt-4.8/signalsandslots.html? :) .[/quote]
    Because it is important to first understand the actual problem, before suggesting a suggestion. As the problem is not clear yet, it is a bit early to suggest that signals & slots can be a fix for it.



  • [quote author="andry_gasy" date="1330360010"]Thank you Andre for your reply.
    I do this for simplicity reasons. As I am a beginner in qt (I come from c++builder), I learn from this "simple" example. In my application, I will have one main window and at least three different forms with some widgets in them. One form has to access another forms components: pass / read value to/from Ui components. I have read tons of threads in many forums but still cant find my way.
    Thanks in advance for any help.[/quote]

    Well, the point is, exposing the inner workings of a class to other classes does not make your applications simpler. It will make them more complicated in the end. Think of C++ classes as relatively independent parts of a complex organization. They provide a service to other classes. It is very, very important to be clear about what service that is exactly, but not to bother the users of the class with details on how it performs that service. That is: you have to design an API for each of your classes that gives a clear image of what the class can do, but that not exposes how it does that.

    What you are suggesting to do, is to expose the guts of your mainwindow class to everyone. That goes directly against the idea above. Instead, try to think of what service your mainwindow class should provide to the rest of your application, and create and use that. That will make sure that if you later on decide to reorganize your mainwindow, the rest of your code will still work as long as you keep the API on the surface of your mainwindow class constant.

    BTW: this is basic OOP stuff, nothing Qt specific.



  • Thank you all for your reply.
    I went through the link ddriver was suggesting and was thinking about all Andre's lecture :)
    Well, for a C++builder user like me, it seems quite complicated. I totally agree with Andre but for me gui classes must be some kind of "public" classes for other classes in the project. All other classes must have access to ui components because they have to "show" their results to the user. For small project (few visual components), signals and slots are still ok, but for many forms with many widgets in them, it gets messy.
    As i said, I will have many forms with many widgets. I put all the calculation stuff in separate files. According to results of these calculations, tasks as following will be done on the gui: changing contents of text/line edits, labels, adding rows to tables, updating tables/combo boxes contents,... So again I think to allow these calculation files to have direct access to ui components would be the easiest way.
    My question is then still the same: is there a way to make thing like
    @form->ui->lineEdit->setText("some text");
    @

    from a file outside the form?
    Thanks a lot for trying to help. I really appreciate.



  • Last attempt by me: I would really, really not allow direct access to the widgets by classes that don't own them. Your calculator classes should not need to know how their results are used. Instead, they could just announce their results via a signal, and you can connect those signals to the relevant slots to set the values on the widgets. Perhaps you can even make that connection to the widgets directly, if the mainWindow has access to the calculator instances.

    GUI classes do not form the exception for having to provide a good, clear API.



  • Really sorry for the very late reply as I was completely absorbed by the job.
    Thanks again for all your help. I totally agree with Andre for "his" approach. I've had time to learn about signal and slot. I will do it the "right" way when time allows me but for the moment, I just used the "dirty" way: setting the Ui::Mainwindow as public and it's working well for my small project.
    All the best!



  • Sorry for replying the very old thread, just adding the information missing for Qt newbies like me was some time ago, who came down here in hunting for "proper" fast access to form elements.

    The cannonical form for "fast, just clean" access to Qt form elements "out of box" can be:
    (It took looong time to me to elaborate this "simple" line of code. IMHO it should be printed ready somewhere up in the Qt intro examples.)

    w.findChild<QTextBrowser*>("FormElement")->setText("TEST");
    

    where

    • w is the MainWindow object
    • QTextBrowser is type of the element you want to access
    • "FormElement" is the name of the element you want to access
      (You can omitt it from parameter list if there is only one element of the given type. findChild will return it by default.)
    • setText is the method you want to call.

Log in to reply
 

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