web-dev-qa-db-fra.com

QT/C++ - Accès à l'interface utilisateur MainWindow à partir d'une classe différente

Je suis un débutant à la fois en C++ et en Qt, alors c'est peut-être trivial. Cela doit certainement être simple, mais je cherche une réponse depuis quelques heures et je ne trouve pas la solution. Je fais un jeu de plateau simple où l'interface utilisateur de MainWindow (faite dans QtDesigner) contient un canevas pour le plateau de jeu (un QGraphicsView). Maintenant, le fichier main.cpp est aussi simple que possible:

MainWindow Game;

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

 Game.show();

return a.exec();
}

Étant donné que je dois accéder et modifier les widgets MainWindow à partir d’une autre classe totalement indépendante, j’ai pensé que le moyen le plus simple consisterait simplement à faire de MainWindow une variable globale. Il semble que cette approche était très fausse, cependant. Lorsque j'essaie d'exécuter le projet dans QtDesigner, une erreur de bibliothèque d'exécution Microsoft Visual C++ se produit: l'application a demandé à l'exécution de le terminer de manière inhabituelle.

Alors, quelle est la bonne façon de faire ce dont j'ai besoin?

Outre MainWindow, j'ai une boîte de dialogue pour un nouveau jeu (QDialog, généré à partir de QtDesigner) qui s'affiche après avoir cliqué sur un élément de menu dans MainWindow. Lorsque l'utilisateur entre tous les paramètres du jeu et clique sur OK dans la boîte de dialogue, j'instancie une classe personnalisée non-Qt appelée GameState. Cette classe est destinée à faire fonctionner le jeu lui-même, à dessiner le tableau, à inviter l'utilisateur, etc. Cependant, cette classe étant créée dans QDialog, elle ne connaît pas l'existence d'une MainWindow et je ne peux donc rien faire avec MainWindow de cette classe. Comment puis-je modifier le MainWindow à partir d'une classe non liée, alors?

Aussi, comment fonctionne la fonction setEnabled ()? Il semble ne jamais rien faire. Tous les widgets que j'ai définis comme étant désactivés dans QtDesigner, puis que vous essayez d'activer via cette fonction restent toujours désactivés dans l'interface graphique ...

15
user742925

Tout d’abord, c’est une mauvaise idée de créer MainGame avant de créer votre objet QApplication. Si vous souhaitez que votre objet MainGame soit globalement disponible comme ceci, il doit s'agir d'un pointeur:

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;
}

Cette approche n'est cependant pas la plus élégante. Il y a deux choix bien meilleurs.

  1. L’objet QApplication stocke en fait toutes les fenêtres de niveau supérieur, comme votre MainGame, ce qui signifie que vous pouvez toujours l’acquérir via QApplication::topLevelWidgets(), une fonction statique, et renvoie une liste avec tous les widgets de niveau supérieur. Puisque vous n’en avez qu’un, le premier est votre MainGame. L'inconvénient est que vous devrez le lancer, mais utiliser Qts qobject_cast<MainGame*>(...) est relativement sûr. Vous devrez toutefois vérifier le résultat pour vous assurer qu'il ne s'agit pas d'un pointeur NULL.

  2. Utilisez le modèle de conception singelton. Vous devez stocker le pointeur de jeu global dans le fichier source (cpp) de la classe Game elle-même (sous-classe QMainWindow) et votre classe Game doit implémenter une méthode publique statique qui renvoie ce pointeur global. Donc, si une autre classe a besoin du pointeur Game, elle appelle simplement:

    MyGame *theGame = MyGame::getInstance();
    

    par exemple.

Concernant votre problème setEnabled(). Merci de poster le code correspondant. Si c'est trop, n'hésitez pas à m'envoyer le fichier * .ui et le morceau de code par courrier.

Meilleures salutations

11

Pour ce faire, le plus simple consiste à configurer d'abord un signal dans le fichier d'en-tête de votre autre classe, afin d'exécuter une fonction permettant de manipuler un objet de la classe principale comme celui-ci.

signals:
    void disableLoadButtton();

Créez ensuite un emplacement sous les emplacements privés dans le fichier d'en-tête de la fenêtre principale, comme ceci:

private slots:
     void disableLoadButtton();

Créez ensuite la fonction en tant que membre dans la fenêtre principale pour manipuler l'objet.

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

Ajoutez ensuite la ligne suivante dans une autre fonction membre de la fenêtre principale qui dit met en place la page. Mon autre classe s'appelle searchWidget

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

Ensuite, tout ce que vous avez à faire pour désactiver le loadButton (qui est un objet dans MainWindow) est d’ajouter la ligne suivante à n’importe quelle fonction de membre de mon autre classe searchWidget

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

Cela manipulera ensuite l'objet loadButton dans la fenêtre principale à partir d'une fonction membre de l'autre classe searchWidget.

7
Tom

Si votre application n'a qu'une seule fenêtre, vous pouvez simplement utiliser:

MainWindow * win = (MainWindow *) qApp::activeWindow();
5

Je le fais de cette façon:

QMainWindow* getMainWindow()
{
    foreach (QWidget *w, qApp->topLevelWidgets())
        if (QMainWindow* mainWin = qobject_cast<QMainWindow*>(w))
            return mainWin;
    return nullptr;
}
3
Flot2011

Si vous devez accéder à votre fenêtre principale à partir d’une autre fenêtre, vous le faites probablement mal. Utiliser une autre classe pour transmettre des informations avec des signaux/slots est probablement une bien meilleure approche

3
Ignacius

J'utilise cette approche trouvée dans Qtractor project:

principal c

#include "mainwindow.h"
#include <QApplication>

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

    return a.exec();
}

mainwindow.cpp

#include <QString>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "c.h"

MainWindow * MainWindow::pMainWindow = nullptr;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    pMainWindow = this;
    setCentralWidget(&m_pb);
    connect(&m_pb, SIGNAL(clicked()), this, SLOT(on_pb_clicked()));
}

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

// kind of singleton reference.
MainWindow *MainWindow::getMainWinPtr()
{
    return pMainWindow;
}

void MainWindow::pbSetText()
{
    m_pb.setText(QString{"Call from c."});
}

void MainWindow::on_pb_clicked()
{
    c C;  // call of MainWindow from class c ctor
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QString>
#include <QPushButton>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    static MainWindow * getMainWinPtr();
    void pbSetText();

public slots:
    void on_pb_clicked();

private:
    static MainWindow * pMainWindow;

    Ui::MainWindow *ui;
    QPushButton m_pb{QString{"Press me."}, this};
};

#endif // MAINWINDOW_H

c.cpp

#include "c.h"
#include "mainwindow.h"

c::c()
{
    MainWindow * mw = MainWindow::getMainWinPtr();
    mw->pbSetText();
}

c.h

#ifndef C_H
#define C_H

class c
{
public:
    explicit c();
};

#endif // C_H
0
francek