QT — Проблемы с переключением .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, так что я действительно не знаю, является ли это правильным способом сделать это.
У кого-нибудь есть подсказка, где проблема или есть обходной путь?

1

Решение

Похоже, вы хотите иметь одно окно, которое переключается между различными состояниями. Я бы не рекомендовал использовать для этого несколько файлов .ui. Возможно, есть несколько способов:

  1. Использовать QStackedWidget — Вы можете добавить это в дизайнере пользовательского интерфейса, думая об этом как о наборе страниц, которые вы выбираете программно. Используйте это, и ваши кнопки поменяют его на соответствующую страницу.

  2. Иметь несколько разных классов для ваших разных взглядов, и установить центральный виджет главного окна для разных виджетов, когда это необходимо.

Лично я бы пошел на вариант 1.

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 который содержит подвиджеты с их структурами пользовательского интерфейса:

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 может быть закрытым методом, вам не нужно никакого косвенного обращения и вы можете оперировать uiFoo Участники напрямую: заменить любой 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.

0

По вопросам рекламы [email protected]