【问题标题】:QT/C++ - Accessing MainWindow UI from a different classQT/C++ - 从不同的类访问 MainWindow UI
【发布时间】:2011-05-07 10:41:04
【问题描述】:

我是 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 小部件,我认为最简单的方法是将 MainWindow 设为全局变量。不过,这种方法似乎是非常错误的。尝试在 QtDesigner 中运行项目时,我收到 Microsoft Visual C++ 运行时库错误:应用程序已请求运行时以不寻常的方式终止它。

那么做我需要的正确方法是什么?

除了主窗口之外,我还有一个新游戏对话框(QDialog,由 QtDesigner 生成),在单击主窗口中的菜单项后会显示该对话框。当用户输入游戏的所有参数并在对话框中单击“确定”时,我会实例化一个名为 GameState 的自定义非 Qt 类。该类用于操作游戏本身,绘制棋盘,提示用户等。但是,由于该类是在 QDialog 中创建的,它不知道 MainWindow 的存在,因此我无法对 MainWindow 做任何事情从这堂课。那么,如何从不相关的类中修改 MainWindow?

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

【问题讨论】:

标签: c++ qt


【解决方案1】:

首先,在创建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() 获取它,这是一个静态函数并返回一个包含所有顶级小部件的列表。由于您只有一个,所以第一个是您的MainGame。缺点是你必须强制转换它,但使用 Qts qobject_cast<MainGame*>(...) 是相当安全的。您必须检查结果以确保它不是 NULL 指针。

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

    MyGame *theGame = MyGame::getInstance();
    

    例如。

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

最好的问候
D

【讨论】:

    【解决方案2】:

    最简单的方法是首先在你的其他类的头文件中设置一个信号,说执行一个函数来像这样操作主类中的一个对象

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

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

    【讨论】:

      【解决方案3】:

      我是这样做的:

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

        • 不要在 C++ 中使用 C 风格的强制转换。请改用qobject_caststatic_cast
        • static_cast&lt;MainWindow*&gt;(parent())-&gt;theMethodYouWantToCall();
        • 此外,如果 MainWindow 没有键盘焦点 = 如果它不活动,则此方法将不起作用。
        • 供参考,现在在Qt5中,这是QApplication::activeWindow()
        • 这种方法在很多情况下都失败了,所以不应该使用它。如果主窗口没有键盘焦点(例如通过单击任务栏被调出后),则qApp::activeWindow() 返回 nullptr。
        【解决方案5】:

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

        【讨论】:

        • 如果我们需要观察者设计模式,我们需要将视图(MainWindow)传递给控制器​​类,以便 cotoller 可以访问它的方法。
        • 啊,是的。 不可避免的“你做错了!”不回答。直接访问单例主窗口有完全正当的理由。父母摇摆手指很少是有用的反应。这也不例外。我们都是负责任的成年人。
        【解决方案6】:

        过去我使用此答案中描述的方法(在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();
        }
        

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-08-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多