Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED] Access function in the mainwindow class from another class
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] Access function in the mainwindow class from another class

Scheduled Pinned Locked Moved General and Desktop
17 Posts 3 Posters 11.2k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    gaijinpunch
    wrote on 20 Sept 2014, 18:21 last edited by
    #4

    What does your main.cpp look like?

    Generally if you initialize both objects in the same scope, you can easily access either of them: this goes for getting and setting variables (assuming the methods/members are public), and of course, using QObject::connect() to do the signal() and slot() method.

    1 Reply Last reply
    0
    • Q Offline
      Q Offline
      Qub1
      wrote on 20 Sept 2014, 18:23 last edited by
      #5

      My main.cpp is pretty much still left as it was when I created my project. So you're saying I should move all my initialization code from the constructor in my mainwindow class to the main class?

      This is my main.cpp:
      @#include "mainwindow.h"
      #include <QApplication>

      // TODO: Allow users to use arguments to start the program
      int main(int argc, char *argv[]) {
      QApplication a(argc, argv);
      MainWindow w;
      w.show();
      return a.exec();
      }
      @

      1 Reply Last reply
      0
      • G Offline
        G Offline
        gaijinpunch
        wrote on 20 Sept 2014, 18:31 last edited by
        #6

        Actually, I didn't need that. :)

        @void MainWindow::on_pushButton_Games_Library_AddGame_clicked() {
        AddGameWizard wizard(this);
        // wizard.setSettings( settings );
        wizard.exec()@

        See where I added a comment in the function above. You will need to add a function to your AddGameWizard class. It must go under public, but you could probably figure that out. It would look something like:

        void AddGameWizard::setSettings( Settings s ) { settings = s; }

        If you're going to be passing around your Settings file to lots of other objects, you should look into passing a pointer, for a few reasons. Not sure how new you are to C++, but they are a key part of the language. They of course, open up some headaches though. :)

        1 Reply Last reply
        0
        • Q Offline
          Q Offline
          Qub1
          wrote on 20 Sept 2014, 18:34 last edited by
          #7

          Alright, thanks! Now I look at it, this seems to be the best way indeed :)

          And yeah I've been fiddling around with pointers for the last few days so I'm going to use those.

          Thanks for the help!

          1 Reply Last reply
          0
          • G Offline
            G Offline
            gaijinpunch
            wrote on 20 Sept 2014, 18:42 last edited by
            #8

            No prob -- Enjoy!

            1 Reply Last reply
            0
            • Q Offline
              Q Offline
              Qub1
              wrote on 20 Sept 2014, 18:42 last edited by
              #9

              Actually, I'm getting a new error now.

              It's when the settings variable is set in the addgamewizard class.

              This is the error:
              C:\Qt\5.3\mingw482_32\include\QtCore\qsettings.h:192: error: 'QSettings::QSettings(const QSettings&)' is private
              Q_DISABLE_COPY(QSettings)
              ^

              It seems I'm still copying the variable instead of passing a pointer.

              This is my setSettings function:
              @void AddGameWizard::setSettings(Settings &arg1) {
              settings = arg1;
              }@

              And the settings variable in the header file:
              @private:
              Settings *settings;@

              This should work right? Or am I missing something?

              1 Reply Last reply
              0
              • G Offline
                G Offline
                gaijinpunch
                wrote on 20 Sept 2014, 19:15 last edited by
                #10

                The Q_DISABLE_COPY() part means you can't copy it around. I forgot how this is set in Qt (there are a number of ways to do this in C++, usually by making operator=() private. Qt probably uses some macro though ).

                Do something like this:
                in AddGameWizard you should have a place for a pointer to settings (Settings*)

                @class AddGameWizard : public QWizard {
                Q_OBJECT

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

                /* Right here. :) /
                void setSettings( Settings
                s ) { settings = s; }

                private:
                Ui::AddGameWizard *ui;

                /* This is now a pointer /
                Settings
                settings;
                void accept();
                };@

                Don't forget though it's best practice to make sure the default value of any member of a class which is a pointer to NULL. So, make sure your AddGameWizard constructor looks like this:

                AddGameWizard::AddGameWizard(QWidget *parent) : QWizard(parent), ui(new Ui::AddGameWizard), settings( NULL )
                {
                ui->setupUi(this);
                }

                If you don't, the default value of a pointer is garbage, and accessing it will lead to undefined behavior (most likely a coredump).

                Be warned here... any changes you make to settings within AddGameWizard are changed within MainWindow. Can't say for certain but this is usually the way a "settings" should work... at least that I can think of.

                Protip: within AddGameWizard, any time you access settings, check it for NULL.

                if ( !settings ) {
                // BOO... can't access it.
                }

                To get it out of your MainWindow, you need something like this:

                @Settings* MainWindow::getSettings() { return &settings; }@

                See how that works.

                1 Reply Last reply
                0
                • Q Offline
                  Q Offline
                  Qub1
                  wrote on 20 Sept 2014, 19:20 last edited by
                  #11

                  Alright, so that's working now, and again another new error. It seems I get a loop with includes. Because I need to use my mainwindow class from my settings class, however my mainwindow class also includes my settings class.

                  The headers:
                  mainwindow.h:
                  @#ifndef MAINWINDOW_H
                  #define MAINWINDOW_H

                  #include "settings.h"

                  namespace Ui {
                  class MainWindow;
                  }

                  class MainWindow : public QMainWindow {
                  Q_OBJECT

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

                  private:
                  Ui::MainWindow *ui;
                  Settings *settings;
                  };

                  #endif // MAINWINDOW_H
                  @

                  settings.h:
                  @#ifndef SETTINGS_H
                  #define SETTINGS_H

                  #include "mainwindow.h"

                  class Settings : public QSettings {
                  public:
                  Settings(MainWindow *arg1);
                  void addGame(const QString &gameName, const QString &gameExecutablePath, const bool &enableModManager, const QString &gameIconPath = "");

                  private:
                  MainWindow *window;
                  };

                  #endif // SETTINGS_H
                  @

                  I think I need forward declarations but I have no idea how they work. I've looked it up and tried it but it failed to compile. Because I need actual functions from each class, I would essentially have to define all functions in both header files right? I think that would make everything a lot harder to change later on. Could you maybe give an example? And I really appreciate the help!

                  1 Reply Last reply
                  0
                  • G Offline
                    G Offline
                    gaijinpunch
                    wrote on 20 Sept 2014, 19:25 last edited by
                    #12

                    I replied (a rather long one) but I can't post for some reason.

                    This can be frustrating and it killed me a few times.

                    In any header file where you only have a pointer to an object, do not include it's header. Instead, simply declare it with:

                    class ClassName;

                    The source file (.cpp) requires the header included.

                    However, I don't think your Settings class needs (or should have) a MainWindow* object. This is a design question and probably beyond the scope of this thread.

                    Just in case, here's my reply that wouldn't go through...

                    The Q_DISABLE_COPY() part means you can't copy it around. I forgot how this is set in Qt (there are a number of ways to do this in C++, usually by making operator=() private. Qt probably uses some macro though ).

                    Do something like this:
                    in AddGameWizard you should have a place for a pointer to settings (Settings*)

                    @class AddGameWizard : public QWizard {
                    Q_OBJECT

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

                    /* Right here. :) /
                    void setSettings( Settings
                    s ) { settings = s; }

                    private:
                    Ui::AddGameWizard *ui;

                    /* This is now a pointer /
                    Settings
                    settings;
                    void accept();
                    };@

                    Don't forget though it's best practice to make sure the default value of any member of a class which is a pointer to NULL. So, make sure your AddGameWizard constructor looks like this:

                    AddGameWizard::AddGameWizard(QWidget *parent) : QWizard(parent), ui(new Ui::AddGameWizard), settings( NULL )
                    {
                    ui->setupUi(this);
                    }

                    If you don't, the default value of a pointer is garbage, and accessing it will lead to undefined behavior (most likely a coredump).

                    Be warned here... any changes you make to settings within AddGameWizard are changed within MainWindow. Can't say for certain but this is usually the way a "settings" should work... at least that I can think of.

                    Protip: within AddGameWizard, any time you access settings, check it for NULL.

                    if ( !settings ) {
                    // BOO... can't access it.
                    }

                    To get it out of your MainWindow, you need something like this:

                    @Settings* MainWindow::getSettings() { return &settings; }@

                    See how that works.

                    1 Reply Last reply
                    0
                    • Q Offline
                      Q Offline
                      Qub1
                      wrote on 20 Sept 2014, 19:29 last edited by
                      #13

                      Alright thanks I'll do that then. However, just for reference since I'm still learning, how would you recommend I access the setStatus function in my MainWindow class then? Because I would need the actual mainwindow class to access its functions right? Or is there another way?
                      Sorry for all the questions :P

                      1 Reply Last reply
                      0
                      • G Offline
                        G Offline
                        gaijinpunch
                        wrote on 20 Sept 2014, 19:57 last edited by
                        #14

                        No problem on the questions... I ask a lot too, and I know it's frustrating.

                        Generally the design I would do is that in your MainWindow, you have your Settings. It can be a pointer, just make sure you initialize it (with new Settings() ) before anyone accesses it. In the constructor could be okay. As such, MainWindow doesn't need a setStatus() function. Only other objects (which need the Settings) will have a SetStatus() function.

                        From this point, I would access the pointer and pass it to any other object that needs it with the following public methods:

                        @// Assuming it's not a pointer in MainWindow
                        Settings* MainWindow::getSetings() { return &settings; }@

                        @// Assuming it is a pointer
                        Settings* MainWindow::getSettings() { return settings; }@

                        Just about anything should be accessible from your MainWindow at some point. So when you create your AddGameWizard, which you're doing within a member function of MainWindow, do something like:

                        @AddGameWizard wizard( this );
                        myWizard.setSettings( this->getSettings() ); // "this->" isn't required, but easy to read.
                        wizard.exec()@

                        Your AddGameWizard should have a pointer to it. If your wizard makes a change to the Settings, your main window will know.

                        Make sense?

                        1 Reply Last reply
                        0
                        • S Offline
                          S Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on 20 Sept 2014, 19:59 last edited by
                          #15

                          Hi and welcome to devnet,

                          For your last include problem, it's called circular dependencies and the only solution is indeed forward declaration.

                          However, if your Settings object inherits from QSettings, then there's no need to pass it around. QSettings allows to access settings of your application anywhere. You just create a QSettings object, use it and done.

                          You should really take the time of going through Qt's tutorials, examples and demos. Get a feeling of signals and slots and how to avoid unnecessary dependencies

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          1 Reply Last reply
                          0
                          • Q Offline
                            Q Offline
                            Qub1
                            wrote on 20 Sept 2014, 21:48 last edited by
                            #16

                            EDIT: Never mind, fixed it! I added #include "mainwindow.h" to my settings.cpp class and now it works.

                            Alright I've read a lot of posts and searched a lot but I can't get this to work and it is really frustrating. Basically what I'm trying to do is have the main class use functions from the settings class and vice versa. I can't use emit since I need to get a return value and emit signals happen asynchronously.

                            Here is all the relevant code (I've removed irrelevant functions and includes):
                            mainwindow.h:
                            @#ifndef MAINWINDOW_H
                            #define MAINWINDOW_H

                            #include "settings.h"

                            namespace Ui {
                            class MainWindow;
                            }

                            class MainWindow : public QMainWindow {
                            Q_OBJECT

                            public:
                            explicit MainWindow(QWidget parent = 0);
                            ~MainWindow();
                            QTreeWidgetItem
                            setStatus(const QString &message, const QString &type, QTreeWidgetItem *parent = 0);

                            private:
                            Ui::MainWindow *ui;
                            Settings settings;
                            };

                            #endif // MAINWINDOW_H@

                            mainwindow.cpp:
                            @#include "mainwindow.h"
                            #include "ui_mainwindow.h"

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

                            QTreeWidgetItem* status;

                            // Actually load the settings
                            status = setStatus("Loading settings", "Status");
                            QHash<int, QHash<QString, QVariant> > games = settings.getGames();
                            for(int i = 0; i < games.size(); i++) {
                            QTreeWidgetItem *item = new QTreeWidgetItem;
                            item->setText(0, games.value(i).value("Name").toString());
                            ui->treeWidget_Games_Library->addTopLevelItem(item);
                            }
                            ui->frame_Console->setVisible(settings.getConsoleOpen());
                            ui->pushButton_Console->setVisible(settings.getShowConsole());
                            if(settings.getStartMaximized()) {
                            setWindowState(Qt::WindowMaximized);
                            }
                            Theme::loadTheme(settings.getTheme());
                            setStatus("Done loading settings", "Status", status);

                            // Make the widgets reflect the settings
                            status = setStatus("Initializing interface", "Status");
                            ui->comboBox_Theme->setCurrentIndex(ui->comboBox_Theme->findText(settings.getTheme()));
                            ui->checkBox_ShowConsole->setChecked(settings.getShowConsole());
                            ui->checkBox_ShowExperimental->setChecked(settings.getShowExperimental());
                            ui->checkBox_StartMaximized->setChecked(settings.getStartMaximized());
                            setStatus("Done initializing interface", "Status", status);
                            }

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

                            QTreeWidgetItem* MainWindow::setStatus(const QString &message, const QString &type, QTreeWidgetItem *parent) {
                            ui->label_Status->setText(message);
                            QTreeWidgetItem *item = new QTreeWidgetItem();
                            item->setText(0, QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz"));
                            item->setText(1, type.toUpper());
                            item->setText(2, message);
                            if(parent == 0) {
                            ui->treeWidget_Console->addTopLevelItem(item);
                            } else {
                            parent->addChild(item);
                            }
                            ui->treeWidget_Console->expandAll();
                            return item;
                            }@

                            settings.h:
                            @#ifndef SETTINGS_H
                            #define SETTINGS_H

                            #include "mainwindow.h"

                            class Settings : public QSettings {
                            public:
                            Settings(MainWindow arg1);
                            void setDefaultValues();
                            void addGame(const QString &gameName, const QString &gameExecutablePath, const bool &enableModManager, const QString &gameIconPath = "");
                            QHash<int, QHash<QString, QVariant> > getGames();
                            bool getConsoleOpen();
                            void setConsoleOpen(const bool &open);
                            bool getShowConsole();
                            void setShowConsole(const bool &showConsole);
                            bool getShowExperimental();
                            void setShowExperimental(const bool &showExperimental);
                            bool getStartMaximized();
                            void setStartMaximized(const bool &startMaximized);
                            QString getTheme();
                            void setTheme(const QString &theme);

                            private:
                            MainWindow window;
                            };

                            #endif // SETTINGS_H
                            @

                            settings.cpp:
                            @#include "settings.h"

                            Settings::Settings(MainWindow arg1) : QSettings(qApp->applicationDirPath() + "/settings.ini", QSettings::IniFormat), window(arg1) {
                            }

                            void Settings::setDefaultValues() {
                            // This function just sets the default settings
                            }

                            void Settings::addGame(const QString &gameName, const QString &gameExecutablePath, const bool &enableModManager, const QString &gameIconPath) {
                            QTreeWidgetItem* status = window->setStatus("Adding game "" + gameName + """, "Status");
                            setDefaultValues();
                            int size = value("Games/size").toInt();
                            beginWriteArray("Games");
                            setArrayIndex(size);
                            setValue("Name", gameName);
                            setValue("ExecutablePath", gameExecutablePath);
                            setValue("IconPath", gameIconPath);
                            setValue("EnableModManager", enableModManager);
                            endArray();
                            window->setStatus("Game added", "Status", status);
                            }

                            QHash<int, QHash<QString, QVariant> > Settings::getGames() {
                            QHash<int, QHash<QString, QVariant> > result;
                            int size = beginReadArray("Games");
                            for (int i = 0; i < size; ++i) {
                            setArrayIndex(i);
                            result[i]["Name"] = value("Name");
                            result[i]["ExecutablePath"] = value("ExecutablePath");
                            result[i]["IconPath"] = value("IconPath");
                            result[i]["EnableModManager"] = value("EnableModManager");
                            }
                            endArray();
                            return result;
                            }

                            bool Settings::getConsoleOpen() {
                            setDefaultValues();
                            return value("State/ConsoleOpen").toBool();
                            }

                            void Settings::setConsoleOpen(const bool &open) {
                            setValue("State/ConsoleOpen", open);
                            }

                            // The other functions are like the two above
                            @

                            And this doesn't work. I know why it doesn't work, because each header includes the other so you get an infinite loop. I have no idea how I would apply forward declarations to this, since I've never used them before and when I try to do it I get a lot of errors about incomplete classes.

                            If anyone could please provide an example of how to do what I'm trying to do relevant to the code posted above I would be very, very grateful.

                            Thanks in advance

                            1 Reply Last reply
                            0
                            • G Offline
                              G Offline
                              gaijinpunch
                              wrote on 20 Sept 2014, 22:15 last edited by
                              #17

                              Okay, so you're all sorted now?

                              EDIT: Ah, marked solved. Would seem so.
                              Welcome to C++ & Qt.

                              While it's easier to learn Qt after C++, I did both at the same time (more or less). I had a brief head start on C++, so it's definitely doable.

                              1 Reply Last reply
                              0

                              13/17

                              20 Sept 2014, 19:29

                              • Login

                              • Login or register to search.
                              13 out of 17
                              • First post
                                13/17
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • Users
                              • Groups
                              • Search
                              • Get Qt Extensions
                              • Unsolved