Access the UI, from multiple windows.



  • I have 3 windows, and i need to access the UI.

    Ther is MainWindow, Window1, and Settings_Window.

    In mainwindow.h i have a declaration of object, so it's

    Settings_Window S_Window;
    

    In MainWindow i have one button to show S_Window.

     void MainWindow::on_Show_Window_Button()
    
    S_Window.activateWindow;
    S_Window.show;
    

    And this is the problem, because this is the settings window, and window1 need to read some data from ther.

    If i create a new object in window1 so:

            Window1.cpp file:
    
    Settings_Window* C = new Settings_Window;
    

    And then activate it and show the window from MainWindow, if i check some options in S_Window , they dont affect Window1, they just affect MainWindow, it's probably because ther i create it, and i can use it directly.

    I create a function, to send from Window1 the object of Settings_Window, and make it equal to S_Window, because ther i am gonna change the options,but when i check some CheckBox it still affecting only MainWindow.

    I need help to make Settings_Window C created in Window1, equal to S_Window created and show from MainWindow.

    I try this code:

    void MainWindow :: GetWindowData(Settings_Window* S_Window_Temp)   //<< Here i send Object from Settings_Window created in Window1
    {  
    
    
     S_Window_Temp =  & S_Window; 
    
     //  So i expect C (Object form Window1)  should be equal to S_Window (Object form MainWindow ), but it's not.
    
    }
    

    Then:

    This is Window1:

    I include mainwindow.h and make friend class and:

    MainWindow MW;
    
    Settings_Window* C = new Settings_Window;   // (This is the copy created in Window1)
    
    MW.SendWindowData(& C);    // Here i call MainWindow object, call the function, send the copy of window, and trying to get the data below:
    
    
    if(C.ui->CheckerBox->isChecked())
    {
    
       //Do something
    
    }
    

    I think, when i am changing the options for window1, they are changing but in another copy

    Any help? I am not gonna tell you how mutch time i loss, just trying to fix that stuff, i check a lot of topic's, forums, but nothing work for me, need help here.

    I dont have time to watch another tutorials, because i almost end my tools, setting window is the last thing what i need to do, and i finish some simple but very usefull tools for me.


  • Qt Champions 2016

    Hi
    The most common way is to provide data access functions to get the data from the
    widgets without letting rest of program know the exact type. ( as in direct access to UI object)

    so for your sample
    MainWindow MW;

    Settings_Window* C = new Settings_Window; // (This is the copy created in Window1)
    MW.SendWindowData(& C); // Here i call MainWindow object, call the function, send the copy of window,

    if( MW.getCheckerBoxStatus() )
    {
    //Do something
    }

    So getCheckerBoxStatus() returns the ui->CheckerBox status. The rest of the program do not know
    its in a checkbox and that is better design as if you later read it from a file, you need only to change
    getCheckerBoxStatus to return status from the data and rest of program do not need to change at all.
    Still works the same.



  • @mrjj But ther is no way to just simply send the widnows object as reference ? Becuse ye, 75% of that setting window is just CheckerBoxe's, but some of stuff is different.
    It can help me, but i would like to find 100% solution

    I would like to have the same flexibility like in MainWindow.


  • Qt Champions 2016

    @Loc888
    Well u can move the UI object to public section of the class and its accessible from outside but
    it leads to spaghetti code and really not recommended.
    External users of a class should not know the inner details and hence providing access functions beats
    letting everybody know what widgets a window has.



  • @mrjj No, i dont like it, even if it helps, i mean make it public. Friend class should help, ye?

    And i am not talking about the class, i am talking about object, because like i said, i can access the class from Window1, but i need to access object S_Window from Setting_Window class, and that object is created in MainWindow, that's the problem.


  • Qt Champions 2016

    @Loc888
    Ok, and its not possible to use signals and hook object up
    in mainwindow ?
    There is nothing stopping you from giving other class a pointer to some widget.
    like in mainwindow
    Local *local = new Local()
    Other *other= new Other()
    UseClass *useclass= new UseClass (this, local, other);



  • @mrjj I create it with pointer already, i mean the object.
    I dont know how to use signal and slots in this example, what and wher should i type to pass the object??
    I use it with timers, but not with Windows objects.


  • Qt Champions 2016

    Hi
    With signals and slots your would pass the data not the objects.
    Normally you hook things up in mainwindow as it knows most other class.
    But really depends on where its created etc.



  • @mrjj Sorry, but i rly dont understand... I can pass the object here

    void MainWindow :: GetWindowData(Settings_Window* S_Window_Temp)   
     {
    
         S_Window_Temp =  & S_Window;
    
    }
    

    So why i cant make a reference to it from another window, if i have the access to pass it??


  • Qt Champions 2016

    @Loc888
    Hi
    Im not sure what part is causing your problems.
    Maybe we talk about different things.

    Yes, you can make a reference to a window.
    or give a pointer / ref to a window to another window.

    Like create settings_win in main.cpp
    give it to mainwindow.
    Mainwindow create a new Window and give settings_win to that also.



  • @mrjj Yes, and that's the problem. Maybe i name this topic title a little bit bad, but i dont have any problem with access, because i can access them all.

    The problem is, when i pass the window with that function, it's seems like another copy, not reference, so when i change something, nothing happens because it change the copy variables, and i dont know why it happend.

    If i pass ther the window object, UI stuff should be ther??


  • Moderators

    @Loc888 Let's clean up your code.

    // You need to declare S_Window_Temp as reference to pointer, else you cannot change it inside GetWindowData!
    void MainWindow :: GetWindowData(Settings_Window* &S_Window_Temp)   //<< Here i send Object from Settings_Window created in Window1
    {  
     S_Window_Temp =  &S_Window; 
    
     //  So i expect C (Object form Window1)  should be equal to S_Window (Object form MainWindow ), but it's not.
    }
    

    Actually you should simply return the pointer from GetWindowData as your current API design is bad (it isn't a good idea to change method parameters from inside the method):

    Settings_Window* void MainWindow :: GetWindowData()
    {  
        return &S_Window; 
    }


  • @jsulm If i just copy and paste, your code, it gives me an error.

    The best solution I found is just create the definition of the object in mainwindow.cpp under include, i test it with my own class, and it works exacly how i wanted it.

    Unfortunately when i do the same thing with the Window, it crash the application and gives a message:

    "QWidget: Must construct a QApplication before a QWidget"

    Any way to fix it?


  • Lifetime Qt Champion

    Hi,

    The usual fix to this one is: don't create static QWidget based objects.



  • @SGaist I dont know what you mean.


  • Qt Champions 2016

    @Loc888
    Hi
    You cannot have global Widgets as they are NOT
    allow to be constructed before QApplication in main.
    They must be pointers and you can first new them After application is created.


  • Lifetime Qt Champion

    If you have anything that looks like static MyClass thingy where MyClass is derived from QWidget, then remove it.



  • @mrjj I tried by reference, and this happend:

    Error: 'QWidget& QWidget::operator=(const QWidget&)' is private
    Class &operator=(const Class &) Q_DECL_EQ_DELETE;
    ^

    mingw48_32\include\QtWidgets\qwidget.h:728: in expansion of macro 'Q_DISABLE_COPY'
    Q_DISABLE_COPY(QWidget)
    ^

    It happend in this line Class &operator=(const Class &) Q_DECL_EQ_DELETE;

    I try later with pointers, and will see what happend.


  • Lifetime Qt Champion

    For more information why, read this.



  • @SGaist

    Now i tried with pointers, error :

    error: invalid operands of types 'Settings_Window*' and 'Settings_Window*' to binary 'operator*'
    A* &Settings_Widget;
    ^

    void MainWindow::Get_Window_Data(Settings_Window* A)
    {

    A* &Settings_Widget;
    

    }

    What i did wrong?


  • Qt Champions 2016

    @Loc888
    Hi
    Why not just
    Settings_Window* MainWindow::Get_Window_Data()
    {
    return Settings_Widget; // Settings_Widget is * (pointer) ?
    }



  • @mrjj

    It run at least, but is not working. If i check something, then press the button with this code, nothing happened. Probably is another copy.
    I am tired, tomorrow i try something else.

    Is this the way how i should use it?

    MainWindow B;
    
    
    if(B.Get_Window_Data()->ui->Checker_Box_01->isChecked())
    {
    
        //Do something
    
    }

  • Qt Champions 2016

    Hi
    Yes but im old school and always check pointers
    so i would do

    MainWindow B; // this should not be a second instance but the one you (might) create in main.cpp

    Settings_Window * win=B.Get_Window_Data();

    if (!win) {
    qDebug() << "NULL ptr from Get_Window_Data";
    return;
    }
    if(win->ui->Checker_Box_01->isChecked())
    {
        //Do something
    }
    if(win->ui->Checker_Box_XX->isChecked())
    {
        //Do something
    }
    
    

    However, the UI variable is private so unless the using class is friend, its not allowed.
    So you make make UI public ( bad design )
    or provide access functions for the widgets.


  • Moderators

    @Loc888 said in Access the UI, from multiple windows.:

    B.Get_Window_Data()->ui->Checker_Box_01->isChecked()

    From software design point of view this is so bad!
    You should not expose internal details of your MainWindow like that.
    Add public methods to MainWindow which return needed invormation without exposing internal implementation details.
    Example:

    class MainWindow...
    {
    public:
        bool isSomethingActivated()
        {
            return ui->Checker_Box_01->isChecked();
        }
    }
    
    MainWindow B;
    if(B.isSomethingActivated())
    {
        //Do something
    }
    

    Now, the user of MainWindow does not have to know anything about how the MainWindow is designed (what UI elements it has for example) - it just calls a public interface method to get the information. Usn't this much nicer? One more advantage of this approach: if you later change your MainWindow UI the caller of the MainWindow will not be affected.
    Example:

    class MainWindow...
    {
    public:
        bool isSomethingActivated()
        {
            // You decided that the condition should be different
            return ui->Checker_Box_01->isChecked() && ui->Checker_Box_02->isChecked();
        }
    }
    
    // No need to change the caller of MainWindow
    MainWindow B;
    if(B.isSomethingActivated())
    {
        //Do something
    }
    

  • Qt Champions 2016

    @jsulm
    And we come full circle \o/
    I told OP that 4 days ago, but he seems unwilling to
    create access functions :)
    Maybe seeing your good example, OP will feel the joy of good design
    and do it the right way.



  • @mrjj

    It makes me a little bit mad, why everything need's to be complicated.
    So, in main window can i use something like that:

      B.Get_Window_Data()->ui->Checker_Box_01->isChecked()
    

    But in other window, i need to do it in other way?


  • Moderators

    @Loc888 You should no access internal implementation details of one window (class) from another. It is not related to Qt, this are simply software design basics...
    And what is complicated about it? Is my example really complicated? What you're trying to do is much more complicated and error prone. Why do you want to know in window A how window B is constructed? Why not simply define simple APIs to communicate between windows? To be honest code like what you're trying to write would not pass code reviews in the company where I'm working.



  • @mrjj Listen, i show you my code, cuz i am getting a little bit crazy, i can't create it in main.cpp, becasuse then how can i show it?

    In MainWindow.h i have

        Settings_Window* Get_Window_Data();
    
         Settings_Window* Settings_Widget = new Settings_Window;
    

    MainWindow.cpp

    Settings_Window* MainWindow::Get_Window_Data()
    {
    
        return Settings_Widget;
    
    }
    

    Window1

    MainWindow B;
    
    Settings_Window S;
    
    
    if(B.Get_Window_Data()->ui->Checker_01->isChecked())
    {
    
      
    }


  • @jsulm I never gonna work for anybody from software design. I am doing it more like hobby.



  • @mrjj This method is not working

    Settings_Window* MainWindow::Get_Window_Data()
    {
    
    return Settings_Widget;
    
    }
    

    If i press the checkerbox, it should be setted to true

    void Settings_Window::on_CheckerBox_clicked()
    {
    
        B->Get_Window_Data()->ui->CheckerBox->setChecked(true);
    
    }
    

    Then when i go to window one, and press the button

    void Window1::on_Button001_clicked()
    {
    
    MainWindow* B = new MainWindow;
    
    
    if(B->Get_Window_Data()->ui->Auto_Reset_Data_Timer->isChecked())
    {
    
        //do something
    
      }
    
    }
    

    I don't understand all your methods, so if anyone can, please correct this stuff, cuz i have enough.


  • Qt Champions 2016

    In what way not working ?
    it just returns the pointer to your
    Settings_Widget so only way it can fail is to return null.

    I wonder here
    void Window1::on_Button001_clicked()
    {

    MainWindow* B = new MainWindow; << you create new one. ?

    so you dont have one already ?
    Or is that on purpose ?
    So each time you click you make a new window ?



  • @mrjj I have another button to activate and show that window.

    MainWindow* B = new MainWindow;
    

    No,i have already one window.
    I just use this to get MainWindow method, and try to set checkerBox as true but from ther.

    If i copy the same code from that button, and paste it to Window1, it's working, but is not the way how it should work, i dont want to set it ther....

    I mean:

    MainWindow* B = new MainWindow;
    
    B->Get_Window_Data()->ui->CheckerBox->setChecked(true);
    
    
    if(B->Get_Window_Data()->ui->Auto_Reset_Data_Timer->isChecked())
    {
    
        //do something
    
      }
    

    When i say "Is not working", i mean when i click the button, checkBox should return true, and when i compare it in another window, checkBox returns false, i think because i set it to another copy... How,i don't know. It should return Settings_Widget in window1.


  • Qt Champions 2016

    Hi
    Im sorry if we frustrated you. We just know from experience
    what works bad over time so that is why we seem so keen to do it the right way.
    Lets start over.
    ok, so you have a normal main.cpp

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

    so w is mainwindow
    and it has the true Settings_Window embedded.

    So we need Window1 to have access to MainWins Settings_Window and not a new copy.
    So Window1 should NOT new one it self but get the one from Mainwin.

    I assume Mainwindow also creates and show Window1
    You can change its constructor to take a Settings_Window * and it can then store it for accessing.

    Like

    #include "Settings_Window.h"  // so it knows the TYPE ( make to use right name if not that)
    
    class Window1 : public QMainWindow
    {
        Q_OBJECT
    Settings_Window *GivenToMe;
    public:
        explicit Window1 (QWidget *parent = 0, Settings_Window *TheTrueOne) {
    GivenToMe = TheTrueOne; // store the pointer for later
    }
        ~Window1 ();
    ....
    };
    
    // then in MainWin where you show the Window1
    void MainWindow::ShowSettings() {
    Window1 * Win1= new Window1(this,   & S_Window ); // the & to make it pointer
    Win1->show();
    }
    

    now inside
    void Window1::SomeButtonClick() {
    // you now have GivenToMe that is the Settings_Widget from MainWindow
    now you can call public functions in it
    if ( GivenToMe -> SomeFunc() ) ...

    }

    If you do not want to create public access functions but go directly via UI you have to make it public
    so in Settings_Window.h

    private:
    Ui::Settings_Windowui;
    must be
    public:
    Ui::Settings_Window
    ui;

    to allow
    if ( GivenToMe -> ui->CheckerBox->isChecked() ) ...

    --

    What we tried to make you do was to add public access function in mainwindow
    so you would say
    if ( GivenToMe ->GetSettingForX() ) ( and it just returns the ui->Checker_01->isChecked() )

    but if you really not want that, then you can make ui public and the syntax you want is then possible
    even if its not best practice/bad idea/design.

    Hope this helps. :)



  • @mrjj Thank you, i like exemples rly :)

    Because this is the only thing can help at least when you rly dont know what to do. Tomorrow i will try in this way.



  • @mrjj

    I have few errors:

    default argument missing for parameter 2 of 'Window1::Window1(QWidget*, Settings_Window*)'
    explicit Window1(QWidget *parent = 0, Settings_Window *TheTrueOne)
    ^

    redefinition of 'Window1::Window1(QWidget*, Settings_Window*)'
    Window1::Window1(QWidget *parent, Settings_Window *TheTrueOne = 0) :
    ^

    'Window1::Window1(QWidget*, Settings_Window*)' previously defined here
    explicit Window1(QWidget *parent = 0, Settings_Window *TheTrueOne)
    ^

    Can you correct it? Because i tried what i could, but doesn't help.

    Window1.h

    #ifndef WINDOW1_H
    #define WINDOW1_H
    
    #include <QWidget>
    #include "Settings_Window.h"
    
    namespace Ui {
    class Window1;
    }
    
    class Window1 : public QWidget
    {
        Q_OBJECT
    
        Settings_Window *GivenToMe;
    
    public:
        explicit Window1(QWidget *parent = 0, Settings_Window *TheTrueOne)
    {
    
        GivenToMe = TheTrueOne; // store the pointer for later
    
    }
    
    
    ~Window1();
    
    private:
    Ui::Window1 *ui;
    };
    
    #endif // WINDOW1_H
    

    And this is Window1.cpp

    #include "window1.h"
    #include "ui_window1.h"
    #include "settings_window.h"
    
    Window1::Window1(QWidget *parent, Settings_Window *TheTrueOne = 0) :
        QWidget(parent),
        ui(new Ui::Window1)
    {
        ui->setupUi(this);
    }
    
    Window1::~Window1()
    {
        delete ui;
    }

  • Lifetime Qt Champion

    Hi,

    Default arguments can only be set in the function declaration. So move all = 0 to the header.

    As a matter of good practice, the parent parameter should always be last. Question of coherency with the Qt library and what other developers expects.



  • @SGaist Ok, i try that.



  • @SGaist I still have some errors the:

    Error: redefinition of 'Window1::Window1(Settings_Window*, QWidget*)'
    Window1::Window1(Settings_Window *TheTrueOne,QWidget *parent) : QWidget(parent),
    ^


  • Lifetime Qt Champion

    Do you have matching declaration and implementation ?



  • @SGaist

    Header :

        explicit Window1(Settings_Window *TheTrueOne = 0, QWidget *parent = 0)
        {
    
            GivenToMe = TheTrueOne;
    
        }
    

    Source:

    Window1::Window1(Settings_Window *TheTrueOne,QWidget *parent) :         
    QWidget(parent),ui(new Ui::Window1)
    {
    ui->setupUi(this);
    }
    

    error: redefinition of 'Window1::Window1(Settings_Window*, QWidget*)'
    Window1::Window1(Settings_Window *TheTrueOne,QWidget *parent) : QWidget(parent),ui(new Ui::Window1)
    ^

    I i remove ther Settings_Window, then i have no type specified error.


Log in to reply
 

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