QT/C++ - 从不同的类访问 MainWindow UI

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5920527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:10:58  来源:igfitidea点击:

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

c++qt

提问by user742925

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:

我是 C++ 和 Qt 的初学者,所以这可能是微不足道的。感觉它应该很简单,但是我一直在寻找答案几个小时,但找不到解决方案。我正在制作一个简单的棋盘游戏,其中 MainWindow 的 ui(在 QtDesigner 中制作)包含游戏棋盘的画布(QGraphicsView)。现在, main.cpp 非常简单:

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.

由于我需要从另一个完全不相关的类访问和编辑 MainWindow 小部件,我认为最简单的方法是将 MainWindow 设为全局变量。不过,似乎这种方法是非常错误的。尝试在 QtDesigner 中运行项目时,我收到 Microsoft Visual C++ 运行时库错误:应用程序已请求运行时以异常方式终止它。

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?

除了 MainWindow 我有一个新游戏的对话框(QDialog,从 QtDesigner 生成),在单击 MainWindow 中的菜单项后显示。当用户输入游戏的所有参数并在对话框中单击“确定”时,我会实例化一个名为 GameState 的自定义非 Qt 类。这个类的目的是操作游戏本身,画板,提示用户等。 但是,由于这个类是在 QDialog 中创建的,它不知道 MainWindow 的存在,所以我不能对 MainWindow 做任何事情从这个班级。那么如何从不相关的类修改 MainWindow 呢?

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...

另外,请问 setEnabled() 函数是如何工作的?它似乎永远不会做任何事情。我在 QtDesigner 中设置为禁用的任何小部件然后尝试通过此功能启用仍然在 GUI 中保持禁用状态...

回答by Dariusz Scharsig

First off it's a bad idea to create MainGamebefore you create your QApplicationobject. If you want to have your MainGameobject globally available like this it should be a pointer:

首先,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;
}

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

然而,这种方法并不是最优雅的。有两个更好的选择。

  1. The QApplicationobject actually stores all top level windows like your MainGamewhich 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 Gamepointer, it simply calls:

    MyGame *theGame = MyGame::getInstance();
    

    for example.

  1. QApplication对象实际上像您一样存储所有顶级窗口MainGame,这意味着您始终可以通过QApplication::topLevelWidgets()它来获取它,这是一个静态函数,并返回一个包含所有顶级小部件的列表。由于您只有一个,因此第一个是您的MainGame. 缺点是你必须转换它,但使用 Qtsqobject_cast<MainGame*>(...)是相当安全的。您必须检查结果以确保它不是 NULL 指针。

  2. 使用单例设计模式。您应该将全局 Game 指针存储在 Game 类本身(子类QMainWindow)的源 (cpp) 文件中,并且您的 Game 类应该实现一个返回此全局指针的静态公共方法。因此,如果任何其他类需要该Game指针,它只需调用:

    MyGame *theGame = MyGame::getInstance();
    

    例如。

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.

关于你的setEnabled()问题。请贴出相关代码。如果太多,请随时通过邮件向我发送 *.ui 文件和代码段。

Best regards
D

最好的问候
D

回答by Tom

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

然后在主窗口的另一个成员函数中添加以下行,即设置页面。我的另一个班级叫做 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

然后,禁用 loadButton(它是 MainWindow 中的一个对象)所需要做的就是在我的其他类 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.

然后,这将从另一个类 searchWidget 的成员函数中操作主窗口中的对象 loadButton。

回答by Flot2011

I am doing it this way:

我是这样做的:

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

回答by Alex Reche Martinez

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

如果您的应用程序只有一个窗口,您可以简单地使用:

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

回答by Ignacius

If you have to access your MainWindow from another window, you are probably doing it wrong. Using another class to pass information with signals/slots is probably a much better approach

如果您必须从另一个窗口访问您的 MainWindow,您可能做错了。使用另一个类通过信号/插槽传递信息可能是一种更好的方法

回答by francek

In the past I used approach described in this answer (found in Qtractorproject).

过去我使用了这个答案中描述的方法(在Qtractor项目中找到)。

Now I use QObject 'name' property and discover it anywhere as described here.

现在我使用 QObject 'name' 属性并在此处描述的任何地方发现它。

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

主窗口.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

主窗口.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

cpp

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

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

c.h

ch

#ifndef C_H
#define C_H

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

#endif // C_H