- 1. Project structure
- 2. BaseWidget
- 3. FirstForm
- 1. FirstForm.h
- 2. FirstForm.cpp
- 3. FirstForm.ui
- 4. SecondForm
- 5. Widget
- 1. Widget.h
- 2. Widget.cpp
- 6. Result
In some cases, you might need to create widget form classes that have a custom base class. That is, the form class of the widget will be inherited from your class, and not directly from QWidget , QDialog , or QMainWindow .
Naturally, for this, your custom class must be inherited from one of these three classes. But at the same time you will have your own base class for any specific functionality, no matter what. Do not make Holivar about how convenient or uncomfortable it is to use Qt Designer or it's better to write everything manually in the code. I know that some programmers do not accept the use of Qt Designer. But let us dwell on the fact that for me it is convenient, as for some other programmers.
Let's create two classes of FirstForm and SecondForm forms that will be inherited from the BaseWidget widget, which in turn is inherited from QWidget .
The appearance of the application window will be as follows.
Project structure
The Widget form class in this case is the application's base window, into which we will put the FirstForm and SecondForm widgets.
BaseWidget
In the BaseWidget base class, we define a virtual method that we will redefine in the inherited widgets. This will show us that this inheritance does work.
BaseWidget.h
Header file of the class.
#ifndef BASEWIDGET_H #define BASEWIDGET_H #include <QWidget> class BaseWidget : public QWidget { Q_OBJECT public: explicit BaseWidget(QWidget *parent = nullptr); // Virtual base class method for validation virtual void methodFromBaseClass() const; }; #endif // BASEWIDGET_H
BaseWidget.cpp
#include "BaseWidget.h" #include <QDebug> BaseWidget::BaseWidget(QWidget *parent) : QWidget(parent) { } void BaseWidget::methodFromBaseClass() const { // Outputting a message from a method qDebug() << "Base Class Method"; }
FirstForm
Both form classes will need to be generated using the class creation wizard. In this case, we choose QWidget as the base class.
After creating the class, you will need to fix some of the code, as well as fix the ui file.
After we create a new class, add a button to the form of this class.
FirstForm.h
#ifndef FIRSTFORM_H #define FIRSTFORM_H // #include <QWidget> It was #include "BaseWidget.h" // Became namespace Ui { class FirstForm; } class FirstForm : public BaseWidget // Changed the base class { Q_OBJECT public: explicit FirstForm(QWidget *parent = nullptr); ~FirstForm(); // Overrided base class method 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), // Perform the constructor of the base class ui(new Ui::FirstForm) { ui->setupUi(this); // Connect the button to the virtual method connect(ui->pushButton, &QPushButton::clicked, this, &FirstForm::methodFromBaseClass); } FirstForm::~FirstForm() { delete ui; } // Implementing the Override Method void FirstForm::methodFromBaseClass() const { BaseWidget::methodFromBaseClass(); qDebug() << "First Form Method"; }
FirstForm.ui
And here is the most interesting. To force the project to compile, you need to write a base class and information about inheritance in the UI file.
First, write the base class into the widget of the form class.
It was
<widget class="QWidget" name="FirstForm"> ... </widget>
Became
<widget class="BaseWidget" name="FirstForm"> ... </widget>
Secondly, write information about custom widgets with an indication of inheritance and the header file.
<customwidgets> <customwidget> <class>BaseWidget</class> <extends>QWidget</extends> <header>BaseWidget.h</header> <container>1</container> </customwidget> </customwidgets>
The result is the following UI file.
<?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
Here is a similar program code.
Widget
Next, you need to add instances of these classes to the main application window. For clarity, we'll do it manually.
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; }
Result
When compiling the application, we get a window, as shown at the beginning of the article. And in the console when you press the buttons, we get the following output.
Base Class Method First Form Method Base Class Method Second Form Method
```