- 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
```