QT - 切换问题.ui

时间:2017-02-23 12:51:08

标签: c++ qt user-interface load parents

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

mainmenu.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);
}

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

playermenu.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);
}
...

playermenu.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的新手,所以我真的不知道这是否是正确的方法。 有没有人知道问题出在哪里或是否有解决方法?

2 个答案:

答案 0 :(得分:0)

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

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

  2. 为您的不同视图提供多个不同的类,并在需要时为不同的小部件提供主窗口的set the central widget

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

答案 1 :(得分:0)

Ui命名空间中的类由uic生成,用于在没有布局的空窗口小部件上构建窗口小部件层次结构。通过尝试进行交换,您会滥用该代码来执行它从未想要的操作。

要使您的方法有效,您必须首先清除之前setupUi调用所安装的所有对象。这是可行的,但有问题 - 因为没有简单的方法来枚举ui结构本身中的所有对象,你必须求助于迭代窗口小部件的布局子项 - 然后在那里&# 39;不知道这些孩子是来自你的其他代码,还是来自生成的代码。

此外,所有用户界面必须设计在QMainWindow之上。替换基于其他窗口小部件类型的界面不会起作用,因为基本窗口小部件是需要QMainWindow的{​​{1}}。它是一个黑客,但它的工作原理:

centralWidget

注意: 1.按值保留// 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); } } }; 个对象,而不是按指针。额外的间接是没用的。 2.使用强类型枚举而不是魔术常量来表示选择。

唉,我们不需要诉诸黑客。我们可以使用ui来交换可见窗格。

首先,让我们创建一个包含给定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,其中包含带有ui结构的子窗口小部件:

QStackedWidget

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(); } } }; MainMenu中,MainMenuHack成员是他们各自的uiFoo,例如Ui::Class是一个uiMainMenu

此时,如果Ui::MainMenu可以成为非公开方法,则您不需要任何间接,并且可以直接对setAppearance成员进行操作:替换任何uiFoosetAppearance(UiKind::Foo)

uiFoo.setCurrent()

该代码在Qt 5和Qt 4下工作。