- 1. Структура проекту
- 2. BaseWidget
- 3. FirstForm
- 1. FirstForm.h
- 2. FirstForm.cpp
- 3. FirstForm.ui
- 4. Друга форма
- 5. Віджет
- 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>
Друга форма
Тут є аналогічний програмний код.
Віджет
Далі потрібно додати інстанси даних класів у головне вікно програми. Для наочності зробимо це вручну.
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
```