Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to access Widgets from an include-file containing functions



  • Re: Some problem to learn Qt :(
    Hello, community, hello, mrjj,
    sorry to bring back this issue, some of you might be bored about this by now. But for some reason I'm unable to grasp this. Maybe I don't see the forest for the trees ?
    Here is what I want to do:
    main. cpp: untouched

    // mainwindow.cpp:
    #include "mainwindow.h"
    
    #include "functions.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::on_pushButton_1_clicked()
    {
    
        void set_10();
    }
    
    void MainWindow::on_pushButton_2_clicked()
    {
        void set_100();
    }
    
    void MainWindow::on_pushButton_3_clicked()
    {
        close();
    }
    

    mainwindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include "ui_mainwindow.h"
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private slots:
        void on_pushButton_1_clicked();
    
        void on_pushButton_2_clicked();
    
        void on_pushButton_3_clicked();
    
    private:
        Ui::MainWindow *ui;
    
    
    };
    
    #endif // MAINWINDOW_H
    

    functions.h:

    #ifndef FUNCTIONS_H
    #define FUNCTIONS_H
    
    #include "mainwindow.h"
    
    void set_10(){
    
        ui->  lcdNumber->display(10);
        return;
    }
    
    void set_100(){
    
        ui->  lcdNumber->display(100);
        return;
    }
    
    #endif // FUNCTIONS_H
    

    How can I access the Widgets from inside my functions included from functions.h ?
    As far as I understand, using signals and slots is the preferred method to use. I've fooled around with this quite a lot but was unable to find a solution. Is there a way to implement this directly without going through a dialog as suggested by mrjj ?
    To put the Widget-manipulating code into the respective slot is not an option, in the slots I only want to have function-calls for better readability in larger projects.
    Thanks a lot in advance. Every help is highly appreciated.



  • @KlausF
    It's difficult to give you the right answer (way to do things) if we don't know what your functions module is all about.

    As it stands, you would need to pass ui, or the individual widget ui->lcdNumber, as a parameter to your functions defined in functions.

    However, this is probably not the best way to do things. In C++ you are not intended to go about writing lots of global functions. If the functions basically access objects living in MainWindow they probably belong inside the MainWindow class, together with the one-source-file rule that implies in C++.

    Meanwhile, your existing

    void MainWindow::on_pushButton_2_clicked()
    {
        void set_100();
    }
    

    does not call set_100() like I expect you intend it to. You need to remove that void to make it call the function. (At present, it declares that there exists some function with signature void set_100(), but does not call/execute it.) This is going to keep happening in code you write till you grasp that distinction.



  • Hello, community, hello, JonB,
    thanks for looking into this and thanks for pointing out the issue with the function call ( void needs to be removed ).
    O.k., in my first post I've tried to avoid too much of blah-blah and just to ask the question I have.
    I'm working on a gui-implementation of the Monty Hall Problem which is described at https://en.wikipedia.org/wiki/Monty_Hall_problem, calculating the winning chances for playing the game with staying and and playing the game with switching.
    I've got my code all strung together and it works just as desired with all the widgets being updated and calculating the correct results. That is when i put all of my somewhat lengthy code into the slot of the Start-Button of my application. That makes it hard to read.
    Since the Monty Hall Problem basically consists of two ( independent ) aspects, these two aspects can be coded as functions. ( f1() = play the game with staying / f2() = play the game with switching ). Therefore I could have ( and I want to have ) just two function calls in my Start-Button slot ( makes it easy to read ). The functions implementation should be "exported" in functions.h. Anyone reading the code in the slot and being interested in what these functions do can go to functions.h, and examine the code not being distracted by other stuff.
    That's the reason for "exporting" the code to functions.h. Therefore I need to access the widgets created by the Designer from inside my "exported" functions.
    My question is: how can I access the widgets from inside my "exported" functions ? As far as I understand, using signals and slots is the preferred method to use. I've fooled around with this quite a lot but was unable to find a solution. Is there a way to implement this directly without going through a dialog as suggested by mrjj ?
    Another reason for that design is that once this is working I'll try to call these two functions in the Start-Button slot in a way so that they get threaded.
    Again, Thanks a lot in advance. Every help is highly appreciated.



  • @KlausF said in How to access Widgets from an include-file containing functions:

    My question is: how can I access the widgets from inside my "exported" functions ?

    Wrong, there is no reason for this functions to interact with the interface, your functions must calculate something and return the result, that's all.
    Have a look at the MVC design pattern, it should be of interest.

    Let state some basic principals in programming:
    Each object/method must do only one thing and receive just enough information to do the job.
    Each object/method must be independent as much as possible to prevent hard coupling.

    You must think a program as a hierarchical object structure of responsabilities. There is a central object, the boss, the master of ceremony (usely the main window) and the only one who gives orders.

    There are two kind of orders:
    Synchronus order: do something and give me the result.
    result = doSomething WithData(data ...)

    Asynchronus order: do something and tell me when is done.
    Usely it means there's a thread underneath.

    I'll try to call these two functions in the Start-Button slot in a way so that they get threaded.

    Definitively the way to go, you have to create a worker thread for each of your functions and update the interface when this worker threads tell you the work is done (through signals and slots)



  • @KlausF

    I think the amount of GUI related stuff you'll need for your Monty-Hall problem simulation is not that high, that it distracts the reader from your actual game logic.
    You can work with Signals & Slots to control your simuation and put your calculation functions below or above GUI related slots or you send out a signal to your functions class from your GUI. You just need to connect your slots in functions.h to your GUI events (Buttons etc.).

    MainWindow.h

    #include montyhall.h // your functions
    
    // [...]
    
    private:
            MontyHall *m_montyHall;
         
    

    MainWindow.cpp

    MainWindow::MainWindow(QWidget *parent):
        QMainWindow(parent),
        ui(new Ui::MainWindow),
        m_montyHall(new MontyHall())
    {
       ui->setupUi(this);
    
        connect(ui->btn_startSim, &QPushButton::clicked, m_montyHall, &MontyHall::runSimulation);
        
       // If you want to pass the number of (random) cases, your connection could look like this:
            // connect(ui->btn_startSim, &QPushButton::clicked, this, &MainWindow::initSim);
       // Add "initSim"-slot to mainWindow to read the amount of cases and send it to "runSimulation"
            // connect(this, &MainWindow::startSim, m_montyHall, &MontyHall::runSimulation);
    }
    

    MontyHall.h

    // [...] Constructor and stuff
    public slots:
           void runSimulation(/*int gameCases*/);
    

    MontyHall.cpp

    void MontyHall::runSimulation(/*int gameCases*/) // you could pass an Int from your GUI to set a number of iterations 
    {
       // You actual game / simulation logic and other function calls here
    }
    

    (MontyHall equals your function-class)

    @KlausF said in How to access Widgets from an include-file containing functions:

    Another reason for that design is that once this is working I'll try to call these two functions in the Start-Button slot in a way so that they get threaded.

    A slot function is not executed in a new thread, if you dont use additional threading classes or workers.

    For your thread-approach you can have a look at this:
    https://doc.qt.io/qt-5/thread-basics.html
    https://stackoverflow.com/questions/26996036/worker-class-for-multithreading-in-qt

    One or more worker thread(s) which will run the simulation. This wont freeze / lock your GUI, so you could go for.. idk... thousands of simulation steps or more, which may take some time.

    But at first, I would try to make it run in general (without any threading)



  • Thank you, mpergand and pi45m4 , for your input.
    Now I've got to ponder this...


Log in to reply