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

qyuhtwio  于 2022-12-01  发布在  其他
关注(0)|答案(7)|浏览(253)

我是一个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();
}

由于我需要从另一个完全不相关的类访问和编辑MainWindow Widget,我认为最简单的方法是将MainWindow设为全局变量。但似乎这种方法是非常错误的。在尝试在QtDesigner中运行该项目时,我得到了一个Microsoft Visual C++运行时库错误:应用程序已请求运行时以异常方式终止它。
那么,什么是正确的方法来做我需要的?
除了主窗口之外,我还有一个新游戏的对话框(QDialog,由QtDesigner生成)。当用户输入游戏的所有参数并在对话框中单击OK时,我示例化了一个名为GameState的自定义非Qt类。该类用于操作游戏本身、绘制棋盘、提示用户等。然而,因为这个类是在QDialog中创建的,它不知道主窗口的存在,所以我不能从这个类对主窗口做任何事情。2那么,我如何从一个不相关的类修改主窗口呢?
还有,jsut setEnabled()函数是如何工作的?它似乎从来没有做过任何事情。任何我在qtDesigner中设置为禁用的小部件,然后试图通过这个函数启用,在GUI中仍然保持禁用状态。

jc3wubiy

jc3wubiy1#

首先,在创建QApplication对象之前先创建MainGame是个坏主意。如果你想让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()获取它,QApplication::topLevelWidgets()是一个静态函数,它返回一个包含所有顶级窗口小部件的列表。因为你只有一个,所以第一个就是你的MainGame。缺点是你必须强制转换它,但是使用Qtsqobject_cast<MainGame*>(...)是相当安全的,不过您必须检查结果以确保它不是NULL指针。
    1.使用singelton设计模式。您应该将全局Game指针存储在Game类本身(子类QMainWindow)的源(cpp)文件中,并且Game类应该实现一个返回该全局指针的静态公共方法。因此,如果任何其他类需要Game指针,它只需调用:
MyGame *theGame = MyGame::getInstance();

例如,可以使用其它类型的设备。
关于你的setEnabled()问题,请把相关代码发过来,如果太多的话,可以把 *.ui文件和代码一起邮寄给我。
顺祝商祺
D级

pokxtpni

pokxtpni2#

我是这样做的:

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

qzwqbdag3#

如果您的应用程序只有一个窗口,则只需使用:

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

9q78igpj4#

最简单的方法是首先在其他类的头文件中设置一个信号,表示执行一个函数来操作主类中的对象,如下所示

signals:
    void disableLoadButtton();

然后在主窗口头文件的private slots下创建一个slot,如下所示

private slots:
     void disableLoadButtton();

然后,在主窗口中将该函数创建为成员函数以操作对象

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

然后在主窗口的另一个成员函数中添加下面一行代码,即设置页面。

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

然后,要禁用loadButton(它是MainWindow中的一个对象),只需在我的另一个类searchWidget的任何成员函数中添加以下行

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

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

ars1skjm

ars1skjm5#

在过去我使用的方法描述了这个答案(发现在Qtractor项目)。
现在我使用QObject 'name'属性,并按照here所述在任何地方发现它。
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
im9ewurl

im9ewurl6#

如果你必须从另一个窗口访问你的MainWindow,你可能做错了。

mitkmikd

mitkmikd7#

没有足够的代表点来评论,但Francek的解决方案完美地回答了我的简单需求。

相关问题