Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QT/C++ - Accessing MainWindow UI from a different class

Tags:

c++

qt

I'm a beginner to both C++ and Qt, so perhaps this is trivial. It certainly feels like it should be simple, but I've been searching for an answer for a few hours now and can't find the solution. I'm making a simple board game where the MainWindow's ui (made in QtDesigner) contains a canvas for the game board (a QGraphicsView). Now, the main.cpp is as simple as can be:

MainWindow Game;

int main(int argc, char *argv[])
{
 QApplication a(argc, argv);

 Game.show();

return a.exec();
}

Since I need to access and edit the MainWindow Widgets from another totally unrelated class, I thought the easiest way would be to just make MainWindow a global variable. It seems that this approach was very wrong, though. Upon trying to run the project in QtDesigner I get a Microsoft Visual C++ runtime library error: the application has requested runtime to terminate it in an unusual way.

So what is the correct way to do what I need?

Aside from the MainWindow I have a dialog for a new game (QDialog, generated from QtDesigner) that is displayed after clicking a menu item in MainWindow. When the user inputs all parameters for the game and clicks OK in the dialog, I instantiate a custom non-Qt class called GameState. This class is meant to operate the game itself, draw the board, prompt the user, etc. However, as this class is created in the QDialog, it does not know of the existence of a MainWindow and so I cannot do anything with the MainWindow from this class. How can I modify the MainWindow from an unrelated class, then?

Also, jsut how does the setEnabled() function work? It never seems to do anything. Any widget I set as disabled in the QtDesigner and then try to enable through this function still stays disabled in the GUI...

like image 410
user742925 Avatar asked May 07 '11 10:05

user742925


4 Answers

First off it's a bad idea to create MainGame before you create your QApplication object. If you want to have your MainGame object globally available like this it should be a pointer:

MainWindow *Game;
int main (int argc, char **argv)
{
  QApplication a (argc, argv);

  Game = new MainWindow();
  Game->show();

  int result = a.exec();

  delete Game;
  Game = NULL;

  return result;
}

This approach is however not the most elegant. There are two much better choices.

  1. The QApplication object actually stores all top level windows like your MainGame which means you can allways aquire it through QApplication::topLevelWidgets() which is a static function and returns a list with all top level widgets. Since you only have one, the first one is your MainGame. The drawback is you'll have to cast it, but using Qts qobject_cast<MainGame*>(...) is fairly safe. You'll have to check the result though to make sure it isn't a NULL pointer.

  2. Use the singelton design pattern. You should store the global Game pointer in the source (cpp) file of the Game class itself (subclass QMainWindow) and your Game class should implement a static public method which returns this global pointer. So if any other class needs the Game pointer, it simply calls:

    MyGame *theGame = MyGame::getInstance();
    

    for example.

Regarding your setEnabled() problem. Please post the relevant code. If it's too much feel free to send me the *.ui file and the piece of code via mail.

Best regards
D

like image 133
Dariusz Scharsig Avatar answered Nov 15 '22 03:11

Dariusz Scharsig


The easiest way to do this is to first set up a signal in the header file of your other class to say perform a function to manipulate an object in the main class like this

signals:
    void disableLoadButtton();

Then create a slot under private slots in the header file of the main window like this

private slots:
     void disableLoadButtton();

Then create the function as a members function in the main window to manipulate the object

void MainWindow::disableLoadButton()
{
     ui->loadButton->setenabled(false);
}

Then add the following line in another member function of the main window which say sets up the page. My other class is called searchWidget

void MainWindow::setUpPage()
{
    connect(searchWidget, SIGNAL(disableLoadButton()), this, SLOT(disableLoadButton()));
}

Then all you have to do to disable the loadButton (which is a object in MainWindow) is to add the following line in any members function of my other class searchWidget

void searchWidget::performSomething()
{
      emit disableLoadButton();
}

This will then manipulate the object loadButton in the mainwindow from within a member function of the other class searchWidget.

like image 44
Tom Avatar answered Nov 15 '22 03:11

Tom


I am doing it this way:

QMainWindow* getMainWindow()
{
    foreach (QWidget *w, qApp->topLevelWidgets())
        if (QMainWindow* mainWin = qobject_cast<QMainWindow*>(w))
            return mainWin;
    return nullptr;
}
like image 9
Flot2011 Avatar answered Nov 15 '22 03:11

Flot2011


If your application has only one window you can simply use:

MainWindow * win = (MainWindow *) qApp::activeWindow();
like image 7
Alex Reche Martinez Avatar answered Nov 15 '22 02:11

Alex Reche Martinez