Evgenii Legotckoi
3 июля 2018 г. 0:24

Qt/C++ - Урок 081. Как сделать базовый класс для виджетов использующих ui файлы форм

В некоторых случаях может потребоваться создавать классы форм виджетов, у которых будет кастомный базовый класс. То есть класс формы виджета будет наследован от вашего класса, а не напрямую от QWidget , QDialog или QMainWindow .

Естественно, что для этого ваш кастомный класс должен быть наследован от одного из этих трёх классов. Но при этом у вас будет собственный базовый класс для какого-либо специфичного функционала, не важно для какого. Не будем делать Холивар о том, насколько удобно или неудобно использовать Qt Designer или лучше писать всё вручную в коде. Знаю, что у некоторые программисты не приемлют использование Qt Designer. Но остановимся на том, что для меня он удобен, как и для части других программистов.

Создадим два класса форм FirstForm и SecondForm , которые будут наследованы от виджета BaseWidget , который в свою очередь наследован от QWidget .

Внешний вид окна приложения будет таким.


Структура проекта

Класс формы Widget в данном случае будет базовым окном приложения, в которое мы поместим виджеты FirstForm и SecondForm .

BaseWidget

В базовом классе BaseWidget определим виртуальный метод, который будем переопределять в наследованных виджетах. Это покажет нам то, что данное наследование действительно работает.

BaseWidget.h

Заголовочный файл класса.

  1. #ifndef BASEWIDGET_H
  2. #define BASEWIDGET_H
  3.  
  4. #include <QWidget>
  5.  
  6. class BaseWidget : public QWidget
  7. {
  8. Q_OBJECT
  9. public:
  10. explicit BaseWidget(QWidget *parent = nullptr);
  11.  
  12. // Виртуальный метод базового класса для проверки
  13. virtual void methodFromBaseClass() const;
  14. };
  15.  
  16. #endif // BASEWIDGET_H

BaseWidget.cpp

  1. #include "BaseWidget.h"
  2.  
  3. #include <QDebug>
  4.  
  5. BaseWidget::BaseWidget(QWidget *parent) : QWidget(parent)
  6. {
  7.  
  8. }
  9.  
  10. void BaseWidget::methodFromBaseClass() const
  11. {
  12. // Вывод сообщения из метода
  13. qDebug() << "Base Class Method";
  14. }

FirstForm

Оба класса формы необходимо будет сгенерировать с помощью визарда создания классов. При этом выберем в качестве базового класса QWidget .

После создания класса нужно будет исправить часть кода, а также исправить ui файл.

После того, как создадим новый класс, добавим кнопку на форму этого класса.

FirstForm.h

  1. #ifndef FIRSTFORM_H
  2. #define FIRSTFORM_H
  3.  
  4. // #include <QWidget> Было
  5. #include "BaseWidget.h" // Стало
  6.  
  7. namespace Ui {
  8. class FirstForm;
  9. }
  10.  
  11. class FirstForm : public BaseWidget // Изменили базовый класс
  12. {
  13. Q_OBJECT
  14.  
  15. public:
  16. explicit FirstForm(QWidget *parent = nullptr);
  17. ~FirstForm();
  18.  
  19. // Переопределили метод базового класса
  20. virtual void methodFromBaseClass() const override;
  21.  
  22. private:
  23. Ui::FirstForm *ui;
  24. };
  25.  
  26. #endif // FIRSTFORM_H

FirstForm.cpp

  1. #include "FirstForm.h"
  2. #include "ui_FirstForm.h"
  3.  
  4. #include <QDebug>
  5.  
  6. FirstForm::FirstForm(QWidget *parent) :
  7. BaseWidget(parent), // Выполним конструктор базового класса
  8. ui(new Ui::FirstForm)
  9. {
  10. ui->setupUi(this);
  11. // Подключим кнопку к виртуальному методу
  12. connect(ui->pushButton, &QPushButton::clicked, this, &FirstForm::methodFromBaseClass);
  13. }
  14.  
  15. FirstForm::~FirstForm()
  16. {
  17. delete ui;
  18. }
  19.  
  20. // Реализация переопределённого метода
  21. void FirstForm::methodFromBaseClass() const
  22. {
  23. BaseWidget::methodFromBaseClass();
  24. qDebug() << "First Form Method";
  25. }

FirstForm.ui

А вот здесь самое интересное. Чтобы заставить проект компилироваться, нужно прописать базовый класс и информацию о наследовании в UI-файле.

Во-первых прописать базовый класс в тег widget класса формы.

Было

  1. <widget class="QWidget" name="FirstForm">
  2. ...
  3. </widget>

Стало

  1. <widget class="BaseWidget" name="FirstForm">
  2. ...
  3. </widget>

Во-вторых прописать информацию о кастомных виджетах с указанием наследования и заголовочного файла.

  1. <customwidgets>
  2. <customwidget>
  3. <class>BaseWidget</class>
  4. <extends>QWidget</extends>
  5. <header>BaseWidget.h</header>
  6. <container>1</container>
  7. </customwidget>
  8. </customwidgets>

В результате получим следующий UI-файл.

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ui version="4.0">
  3. <class>FirstForm</class>
  4. <widget class="BaseWidget" name="FirstForm">
  5. <property name="geometry">
  6. <rect>
  7. <x>0</x>
  8. <y>0</y>
  9. <width>400</width>
  10. <height>300</height>
  11. </rect>
  12. </property>
  13. <property name="windowTitle">
  14. <string>Form</string>
  15. </property>
  16. <layout class="QGridLayout" name="gridLayout">
  17. <item row="0" column="0">
  18. <widget class="QPushButton" name="pushButton">
  19. <property name="text">
  20. <string>First Form Button</string>
  21. </property>
  22. </widget>
  23. </item>
  24. </layout>
  25. </widget>
  26. <customwidgets>
  27. <customwidget>
  28. <class>BaseWidget</class>
  29. <extends>QWidget</extends>
  30. <header>BaseWidget.h</header>
  31. <container>1</container>
  32. </customwidget>
  33. </customwidgets>
  34. <resources/>
  35. <connections/>
  36. </ui>

SecondForm

Здесь аналогичный программный код.

Widget

Далее нужно добавить инстансы данных классов в главное окно приложения. Для наглядности сделаем это вручную.

Widget.h

  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3.  
  4. #include <QWidget>
  5.  
  6. class FirstForm;
  7. class SecondForm;
  8.  
  9. namespace Ui {
  10. class Widget;
  11. }
  12.  
  13. class Widget : public QWidget
  14. {
  15. Q_OBJECT
  16.  
  17. public:
  18. explicit Widget(QWidget *parent = nullptr);
  19. ~Widget();
  20.  
  21. private:
  22. Ui::Widget *ui;
  23. FirstForm *m_firstForm;
  24. SecondForm *m_secondForm;
  25. };
  26.  
  27. #endif // WIDGET_H

Widget.cpp

  1. #include "Widget.h"
  2. #include "ui_Widget.h"
  3.  
  4. #include "FirstForm.h"
  5. #include "SecondForm.h"
  6.  
  7. Widget::Widget(QWidget *parent) :
  8. QWidget(parent),
  9. ui(new Ui::Widget)
  10. {
  11. ui->setupUi(this);
  12. m_firstForm = new FirstForm(this);
  13. m_secondForm = new SecondForm(this);
  14.  
  15. ui->verticalLayout->addWidget(m_firstForm);
  16. ui->verticalLayout->addWidget(m_secondForm);
  17. }
  18.  
  19. Widget::~Widget()
  20. {
  21. delete ui;
  22. }

Результат

При компилировании приложения получим окно, как было показано в начале статьи. А в консоль при нажатии кнопок получим следующий вывод.

  1. Base Class Method
  2. First Form Method
  3. Base Class Method
  4. Second Form Method

Скачать проект приложения

Вам это нравится? Поделитесь в социальных сетях!

c
  • 31 августа 2019 г. 15:13
  • (ред.)

```

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь