QT / C ++ - Доступ к интерфейсу MainWindow из другого класса - PullRequest
15 голосов
/ 07 мая 2011

Я новичок в C ++ и Qt, так что, возможно, это тривиально. Конечно, кажется, что все должно быть просто, но я уже несколько часов ищу ответ и не могу найти решение. Я делаю простую настольную игру, в которой пользовательский интерфейс MainWindow (сделанный в QtDesigner) содержит холст для игровой доски (QGraphicsView). Теперь main.cpp настолько прост, насколько это возможно:

MainWindow Game;

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

 Game.show();

return a.exec();
}

Поскольку мне нужно получить доступ и редактировать виджеты MainWindow из другого совершенно не связанного класса, я подумал, что самый простой способ - просто сделать MainWindow глобальной переменной. Кажется, однако, что этот подход был очень неправильным. При попытке запустить проект в QtDesigner я получаю ошибку библиотеки времени выполнения Microsoft Visual C ++: приложение запросило среду выполнения, чтобы завершить его необычным способом.

Так, как правильно делать то, что мне нужно?

Помимо MainWindow, у меня есть диалог для новой игры (QDialog, сгенерированный из QtDesigner), который отображается после щелчка по пункту меню в MainWindow. Когда пользователь вводит все параметры для игры и нажимает кнопку ОК в диалоговом окне, я создаю экземпляр пользовательского класса, не являющегося Qt, с именем GameState. Этот класс предназначен для управления самой игрой, рисования доски, приглашения пользователя и т. Д. Однако, поскольку этот класс создан в QDialog, он не знает о существовании MainWindow, и поэтому я ничего не могу сделать с MainWindow. из этого класса. Как я могу изменить MainWindow из несвязанного класса, тогда?

Кроме того, jsut, как работает функция setEnabled ()? Кажется, он никогда ничего не делает. Любой виджет, который я установил как отключенный в QtDesigner и затем пытающийся включить его с помощью этой функции, все еще остается отключенным в графическом интерфейсе ...

Ответы [ 6 ]

12 голосов
/ 07 мая 2011

Во-первых, создание MainGame перед созданием объекта QApplication - плохая идея. Если вы хотите, чтобы ваш объект MainGame был доступен глобально, это должен быть указатель:

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

Этот подход, однако, не самый элегантный. Есть два гораздо лучших варианта.

  1. Объект QApplication на самом деле хранит все окна верхнего уровня, такие как MainGame, что означает, что вы всегда можете вызвать его через QApplication::topLevelWidgets(), который является статической функцией, и возвращает список со всеми виджетами верхнего уровня. Поскольку у вас есть только один, первым будет ваш MainGame. Недостаток в том, что вам придется разыграть его, но использование Qts qobject_cast<MainGame*>(...) довольно безопасно. Вам нужно будет проверить результат, чтобы убедиться, что он не равен NULL.

  2. Используйте шаблон проектирования Singelton. Вы должны сохранить глобальный указатель Game в исходном (cpp) файле самого класса Game (подкласс QMainWindow), а ваш класс Game должен реализовать статический открытый метод, который возвращает этот глобальный указатель. Так что если любому другому классу нужен указатель Game, он просто вызывает:

    MyGame *theGame = MyGame::getInstance();
    

    например.

Относительно вашей setEnabled() проблемы. Пожалуйста, отправьте соответствующий код. Если это слишком много, не стесняйтесь присылать мне файл * .ui и фрагмент кода по почте.

С уважением
D

7 голосов
/ 21 ноября 2014

Самый простой способ сделать это - сначала установить сигнал в заголовочном файле вашего другого класса, чтобы он сказал, что выполняет функцию для управления объектом в основном классе, как это

signals:
    void disableLoadButtton();

Затем создайте слот под частными слотами в заголовочном файле главного окна, как это

private slots:
     void disableLoadButtton();

Затем создайте функцию в качестве функции-члена в главном окне для управления объектом

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

Затем добавьте следующую строку в другую функцию-член главного окна, которая говорит, что устанавливает страницу. Мой другой класс называется searchWidget

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

Тогда все, что вам нужно сделать для отключения loadButton (который является объектом в MainWindow), это добавить следующую строку в любую функцию-член моего другого класса searchWidget

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

Затем он будет манипулировать объектом loadButton в главном окне из функции-члена другого класса searchWidget.

5 голосов
/ 07 мая 2011

Если ваше приложение имеет только одно окно, вы можете просто использовать:

MainWindow * win = (MainWindow *) qApp::activeWindow();
4 голосов
/ 27 сентября 2017

Я делаю это так:

QMainWindow* getMainWindow()
{
    foreach (QWidget *w, qApp->topLevelWidgets())
        if (QMainWindow* mainWin = qobject_cast<QMainWindow*>(w))
            return mainWin;
    return nullptr;
}
3 голосов
/ 07 мая 2011

Если вам нужно получить доступ к вашему главному окну из другого окна, вы, вероятно, делаете это неправильно. Использование другого класса для передачи информации с помощью сигналов / слотов, вероятно, гораздо лучший подход

0 голосов
/ 07 мая 2018

Я использую этот подход, найденный в Qtractor project:

main.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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...