1

我的问题是我找到了一种切换 UI 的方法。但是当它切换 UI 时,不会加载 UI 的 .cpp。

主菜单.cpp

#include "mainmenu.h"
#include "ui_mainmenu.h"

MainMenu::MainMenu(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainMenu),
    newgame(new Ui::PlayerMenu),
    optionmenu(new Ui::OptionMenu)
{
    ui->setupUi(this);
    QPixmap background("../../res/Testbg.png");
    background = background.scaled(this->size(), Qt::IgnoreAspectRatio);
    QPalette palette;
    palette.setBrush(QPalette::Background, background);
    this->setPalette(palette);
}

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

void MainMenu::on_pushButtonNewGame_clicked()
{
   changeAppearance(1);
}

void MainMenu::on_pushButtonOption_clicked()
{
   changeAppearance(2);
}

void MainMenu::changeAppearance(int id)
{

    if(id == 0)
    {
        ui->setupUi(this);
    }
    else if(id == 1)
    {
        newgame->setupUi(this);
    }
    else if(id ==2)
        optionmenu->setupUi(this);
}

主菜单.h

#ifndef MAINMENU_H
#define MAINMENU_H

#include <QMainWindow>
#include "playermenu.h"
#include "optionmenu.h"

namespace Ui {
class MainMenu;
}

class MainMenu : public QMainWindow
{
    Q_OBJECT

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


private slots:
    void on_pushButtonNewGame_clicked();

    void on_pushButtonOption_clicked();

private:
    void changeAppearance(int id);


    Ui::MainMenu *ui;
    Ui::PlayerMenu *newgame;
    Ui::OptionMenu *optionmenu;
};

#endif // MAINMENU_H

播放器菜单.cpp

 #include "playermenu.h"
 #include "ui_playermenu.h"

PlayerMenu::PlayerMenu(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::PlayerMenu),
    levelmenu(new Ui::LevelMenu)
{
    ui->setupUi(this);
    QPixmap background("../../res/Testbg.png");
       background = background.scaled(this->size(),Qt::IgnoreAspectRatio);
       QPalette palette;
       palette.setBrush(QPalette::Background, background);
       this->setPalette(palette);
}
...

播放器菜单.h

#ifndef PLAYERMENU_H
#define PLAYERMENU_H

#include <QMainWindow>
#include <ui_playermenu.h>
#include "levelmenu.h"

namespace Ui {
class PlayerMenu;
}

class PlayerMenu : public QMainWindow, Ui::PlayerMenu
{
    Q_OBJECT

public:
    explicit PlayerMenu(QWidget *parent = 0);
    ~PlayerMenu();
...
private:
    Ui::PlayerMenu *ui;
    Ui::LevelMenu *levelmenu;
};

#endif // PLAYERMENU_H

我是 QT 的新手,所以我真的不知道这是否是正确的方法。有没有人知道问题出在哪里或者是否有解决方法?

4

2 回答 2

0

听起来你想要一个在不同状态之间切换的窗口。我不建议使用多个 .ui 文件来执行此操作.. 一些更好的方法可能是:

  1. 使用QStackedWidget - 您可以在 UI 设计器中添加它,将其视为您以编程方式选择的一组页面。使用它并让您的按钮将其更改为适当的页面。

  2. 为您的不同视图提供多个不同的类,并在需要时将主窗口的中央小部件设置为不同的小部件。

就个人而言,我会选择选项1。

于 2017-02-23T15:25:15.367 回答
0

命名空间中的类Ui由没有布局的空小部件生成uic并且旨在构建小部件层次结构。通过尝试交换,您正在滥用该代码来做它从未想过的事情。

为了使您的方法有效,您必须首先摆脱上一次setupUi调用安装的所有对象。这是可行的,但有问题——因为没有简单的方法来枚举ui结构本身中的所有对象,你必须诉诸于迭代你的小部件的布局子——然后没有一般的方法可以知道这些孩子是否来自您的其他代码,或从生成的代码。

此外,所有用户界面都必须设计在QMainWindow. 换出基于另一种小部件类型的界面是行不通的,因为基本小部件是一个QMainWindow需要centralWidget. 这是一个黑客,但它有效:

// https://github.com/KubaO/stackoverflown/tree/master/questions/ui-swap-42416275
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif

// mock uic output
namespace Ui {
struct MainMenu { void setupUi(QMainWindow*) {} };
struct PlayerMenu { void setupUi(QMainWindow*) {} };
struct OptionMenu { void setupUi(QMainWindow*) {} };
}

class MainMenuHack : public QMainWindow {
   Q_OBJECT
   enum class UiKind { MainMenu, PlayerMenu, OptionMenu };
   Ui::MainMenu uiMainMenu;
   Ui::PlayerMenu uiPlayerMenu;
   Ui::OptionMenu uiOptionMenu;
   void clearLayout(QLayout * layout) {
      if (!layout) return;
      while (layout->count()) {
         QScopedPointer<QLayoutItem> item{layout->takeAt(0)};
         if (!item)
            continue;
         delete item->widget();
         clearLayout(item->layout());
      }
   }
public:
   MainMenuHack(QWidget * parent = {}, Qt::WindowFlags flags = {}) :
      QMainWindow{parent, flags}
   {
      setAppearance(UiKind::MainMenu);
   }
   void setAppearance(UiKind kind) {
      clearLayout(layout());
      switch (kind) {
      case UiKind::MainMenu: return uiMainMenu.setupUi(this);
      case UiKind::PlayerMenu: return uiPlayerMenu.setupUi(this);
      case UiKind::OptionMenu: return uiOptionMenu.setupUi(this);
      }
   }
};

注意: 1.ui按值保存对象,而不是按指针。额外的间接是无用的。2. 使用强类型枚举而不是魔术常量来表示选择。

唉,我们不需要求助于黑客。我们可以QStackedWidget用来交换可见窗格。

首先,让我们创建一个UiWidget包装给定Ui::类型及其相应小部件的类。它会自动在小部件上设置子级,将自身添加到堆叠的小部件父级中,并有一个帮助器将其设置为堆栈中的当前小部件。

template <typename Ui>
struct ui_traits : ui_traits<decltype(&Ui::setupUi)> {};
template <typename Ui, typename Widget>
struct ui_traits<void(Ui::*)(Widget*)> {
   using widget_type = Widget;
};
template <typename Ui, typename Widget = typename ui_traits<Ui>::widget_type>
struct UiWidget : Widget, Ui {
   UiWidget(QWidget * parent = {}) : Widget{parent} { this->setupUi(this); }
   UiWidget(QStackedWidget * parent) : UiWidget{static_cast<QWidget*>(parent)} {
      parent->addWidget(this);
   }
   void setCurrent() {
      auto stack = qobject_cast<QStackedWidget*>(this->parent());
      if (stack) stack->setCurrentWidget(this);
   }
};

现在,每个Ui类都可以基于不同的小部件类型,例如Ui::MainMenu可以基于QMainWindow但例如Ui::OptionMenu可以基于QDialog.

现在MainMenu可以简单地是一个QStackedWidget包含具有它们的 ui 结构的子小部件:

class MainMenu : public QStackedWidget {
   Q_OBJECT
   enum class UiKind { MainMenu, PlayerMenu, OptionMenu };
   UiWidget<Ui::MainMenu> uiMainMenu{this};
   UiWidget<Ui::PlayerMenu> uiPlayerMenu{this};
   UiWidget<Ui::OptionMenu> uiOptionMenu{this};
public:
   MainMenu(QWidget * parent = {}, Qt::WindowFlags flags = {}) :
      QStackedWidget{parent}
   {
      setWindowFlags(flags);
      setAppearance(UiKind::MainMenu);
   }
   void setAppearance(UiKind kind) {
      switch (kind) {
      case UiKind::MainMenu: return uiMainMenu.setCurrent();
      case UiKind::PlayerMenu: return uiPlayerMenu.setCurrent();
      case UiKind::OptionMenu: return uiOptionMenu.setCurrent();
      }
   }
};

MainMenuandMainMenuHack中,uiFoo成员是-a 他们各自的Ui::Class,例如uiMainMenuis-a Ui::MainMenu

此时,如果setAppearance可以将 设为非公共方法,则不需要任何间接,可以uiFoo直接对成员进行操作:将 any 替换setAppearance(UiKind::Foo)uiFoo.setCurrent()

class MainMenu : public QStackedWidget {
   Q_OBJECT
   UiWidget<Ui::MainMenu> uiMainMenu{this};
   UiWidget<Ui::PlayerMenu> uiPlayerMenu{this};
   UiWidget<Ui::OptionMenu> uiOptionMenu{this};
public:
   MainMenu(QWidget * parent = {}, Qt::WindowFlags flags = {}) :
      QStackedWidget{parent}
   {
      setWindowFlags(flags);
      uiMainMenu.setCurrent();
   }
};

该代码适用于 Qt 5 和 Qt 4。

于 2017-02-23T15:28:31.040 回答