Евгений Легоцкой2 июля 2018 г. 14:24

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

В некоторых случаях может потребоваться создавать классы форм виджетов, у которых будет кастомный базовый класс. То есть класс формы виджета будет наследован от вашего класса, а не напрямую от 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

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

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Поддержать автора Donate
c

```

Комментарии

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

Позвольте мне порекомендовать вам отличный хостинг, на котором расположен EVILEG.

В течение многих лет Timeweb доказывает свою стабильность.

Для проектов на Django рекомендую VDS хостинг

Посмотреть Хостинг
VD

C++ - Тест 001. Первая программа и типы данных

  • Результат:73баллов,
  • Очки рейтинга1
Ds

C++ - Тест 003. Условия и циклы

  • Результат:64баллов,
  • Очки рейтинга-1
o

C++ - Тест 001. Первая программа и типы данных

  • Результат:86баллов,
  • Очки рейтинга6
Последние комментарии
RK
РГ

QML - Урок 016. База данных SQLite и работа с ней в QML Qt

Добрый день! можно как то обойтись без метода updateModel()? После вызова этого метода происходит перерисовка страницы(если я правильно понимаю), и все элементы, например, CheckBox перерисовываю…
D:

QML - Урок 016. База данных SQLite и работа с ней в QML Qt

Добрый день, пытаюсь разобраться и подргнать пример под себя. Есть бд с огромным количеством полей. В приложении на виджетах при использовании QTableView все работает и путем простого sql запрос…

Django - Урок 039. Добавление личных сообщений и чатов на сайте - Часть 2 (Счётчик диалогов и чатов с непрочитанными сообщениями)

Добавляйте поле файла в модель сообщения. И в форме сообщения указывайте, что поле с файлом.
Сейчас обсуждают на форуме
ДК

Уйти от gtk

ошибка: Gtk-Message: 15:56:06.190: Failed to load module "atk-bridge" Привет. Начало истории здесь Кратко: на АЛЬТ линукс при запуске в консоли приложения по…
ДК

применяется некорректное разрешение для стилей под обычным пользователем

Привет. Такая проблема на ALT Linux: если запускать приложение от руута, то со стилями и размером шрифта всё в полном порядке. Если же мы запускаем приложение под обычным пользователем, то …

Наследование QWidget

Это утверждение ничего не значит. Наличие методов и т.д. не делает обязательным наследование в том виде, в котором вы его изначально попытались сделать. Тем более, если у вас будет два видж…
  • BlinCT
  • 7 августа 2020 г. 9:05

Динамическое заполнение StackLayout в qml

Всем привет. Пытаюсь решить такую задачку, есть TabBar и его кнопки. StackLayout{ currentIndex: tabBar.currentIndex A {id: tabA} B {id: tabB} C {id: tabC} D {id: ta…
М

QML: изменение стиля при наведении и при нажатии на кнопку

enabled = false перестанет быть активной и не будет ни на что реагировать) Хм.. по-моему пробовал такое. Проверю ещё раз после работы. Ура, спасибо большо…
О нас
Услуги
© EVILEG 2015-2020
Рекомендует хостинг TIMEWEB