- 1. Структура проекта
- 2. BaseWidget
- 3. FirstForm
- 1. FirstForm.h
- 2. FirstForm.cpp
- 3. FirstForm.ui
- 4. SecondForm
- 5. Widget
- 1. Widget.h
- 2. Widget.cpp
- 6. Результат
В некоторых случаях может потребоваться создавать классы форм виджетов, у которых будет кастомный базовый класс. То есть класс формы виджета будет наследован от вашего класса, а не напрямую от QWidget , QDialog или QMainWindow .
Естественно, что для этого ваш кастомный класс должен быть наследован от одного из этих трёх классов. Но при этом у вас будет собственный базовый класс для какого-либо специфичного функционала, не важно для какого. Не будем делать Холивар о том, насколько удобно или неудобно использовать Qt Designer или лучше писать всё вручную в коде. Знаю, что у некоторые программисты не приемлют использование Qt Designer. Но остановимся на том, что для меня он удобен, как и для части других программистов.
Создадим два класса форм FirstForm и SecondForm , которые будут наследованы от виджета BaseWidget , который в свою очередь наследован от QWidget .
Внешний вид окна приложения будет таким.
Структура проекта
Класс формы Widget в данном случае будет базовым окном приложения, в которое мы поместим виджеты FirstForm и SecondForm .
BaseWidget
В базовом классе BaseWidget определим виртуальный метод, который будем переопределять в наследованных виджетах. Это покажет нам то, что данное наследование действительно работает.
BaseWidget.h
Заголовочный файл класса.
- #ifndef BASEWIDGET_H
- #define BASEWIDGET_H
- #include <QWidget>
- class BaseWidget : public QWidget
- {
- Q_OBJECT
- public:
- explicit BaseWidget(QWidget *parent = nullptr);
- // Виртуальный метод базового класса для проверки
- virtual void methodFromBaseClass() const;
- };
- #endif // BASEWIDGET_H
BaseWidget.cpp
- #include "BaseWidget.h"
- #include <QDebug>
- BaseWidget::BaseWidget(QWidget *parent) : QWidget(parent)
- {
- }
- void BaseWidget::methodFromBaseClass() const
- {
- // Вывод сообщения из метода
- qDebug() << "Base Class Method";
- }
FirstForm
Оба класса формы необходимо будет сгенерировать с помощью визарда создания классов. При этом выберем в качестве базового класса QWidget .
После создания класса нужно будет исправить часть кода, а также исправить ui файл.
После того, как создадим новый класс, добавим кнопку на форму этого класса.
FirstForm.h
- #ifndef FIRSTFORM_H
- #define FIRSTFORM_H
- // #include <QWidget> Было
- #include "BaseWidget.h" // Стало
- namespace Ui {
- class FirstForm;
- }
- class FirstForm : public BaseWidget // Изменили базовый класс
- {
- Q_OBJECT
- public:
- explicit FirstForm(QWidget *parent = nullptr);
- ~FirstForm();
- // Переопределили метод базового класса
- virtual void methodFromBaseClass() const override;
- private:
- Ui::FirstForm *ui;
- };
- #endif // FIRSTFORM_H
FirstForm.cpp
- #include "FirstForm.h"
- #include "ui_FirstForm.h"
- #include <QDebug>
- FirstForm::FirstForm(QWidget *parent) :
- BaseWidget(parent), // Выполним конструктор базового класса
- ui(new Ui::FirstForm)
- {
- ui->setupUi(this);
- // Подключим кнопку к виртуальному методу
- connect(ui->pushButton, &QPushButton::clicked, this, &FirstForm::methodFromBaseClass);
- }
- FirstForm::~FirstForm()
- {
- delete ui;
- }
- // Реализация переопределённого метода
- void FirstForm::methodFromBaseClass() const
- {
- BaseWidget::methodFromBaseClass();
- qDebug() << "First Form Method";
- }
FirstForm.ui
А вот здесь самое интересное. Чтобы заставить проект компилироваться, нужно прописать базовый класс и информацию о наследовании в UI-файле.
Во-первых прописать базовый класс в тег widget класса формы.
Было
- <widget class="QWidget" name="FirstForm">
- ...
- </widget>
Стало
- <widget class="BaseWidget" name="FirstForm">
- ...
- </widget>
Во-вторых прописать информацию о кастомных виджетах с указанием наследования и заголовочного файла.
- <customwidgets>
- <customwidget>
- <class>BaseWidget</class>
- <extends>QWidget</extends>
- <header>BaseWidget.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
В результате получим следующий UI-файл.
- <?xml version="1.0" encoding="UTF-8"?>
- <ui version="4.0">
- <class>FirstForm</class>
- <widget class="BaseWidget" name="FirstForm">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>300</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Form</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QPushButton" name="pushButton">
- <property name="text">
- <string>First Form Button</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- <customwidgets>
- <customwidget>
- <class>BaseWidget</class>
- <extends>QWidget</extends>
- <header>BaseWidget.h</header>
- <container>1</container>
- </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
- </ui>
SecondForm
Здесь аналогичный программный код.
Widget
Далее нужно добавить инстансы данных классов в главное окно приложения. Для наглядности сделаем это вручную.
Widget.h
- #ifndef WIDGET_H
- #define WIDGET_H
- #include <QWidget>
- class FirstForm;
- class SecondForm;
- namespace Ui {
- class Widget;
- }
- class Widget : public QWidget
- {
- Q_OBJECT
- public:
- explicit Widget(QWidget *parent = nullptr);
- ~Widget();
- private:
- Ui::Widget *ui;
- FirstForm *m_firstForm;
- SecondForm *m_secondForm;
- };
- #endif // WIDGET_H
Widget.cpp
- #include "Widget.h"
- #include "ui_Widget.h"
- #include "FirstForm.h"
- #include "SecondForm.h"
- Widget::Widget(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::Widget)
- {
- ui->setupUi(this);
- m_firstForm = new FirstForm(this);
- m_secondForm = new SecondForm(this);
- ui->verticalLayout->addWidget(m_firstForm);
- ui->verticalLayout->addWidget(m_secondForm);
- }
- Widget::~Widget()
- {
- delete ui;
- }
Результат
При компилировании приложения получим окно, как было показано в начале статьи. А в консоль при нажатии кнопок получим следующий вывод.
- Base Class Method
- First Form Method
- Base Class Method
- Second Form Method
```