Віджети (Widgets)

Віджети (Widgets) – це візуальні елементи, з яких складається традиційний графічний інтерфейс для стільниць.

Прикладами віджетів є:

  • Кнопка (клас QPushButton)

  • Мітка (клас QLabel)

  • Поле вводу (клас QLineEdit)

  • Числове поле-лічильник (клас QSpinBox)

  • Стрічка прокручування (клас QScrollBar)

У Qt є близько 50 готових класів графічних елементів доступних для використання. Батьківським класом для усіх віджетів є клас QWidget. Від нього успадковуються всі основні властивості візуальних елементів, які ми розглянемо у цьому розділі. Дослідження способів розробки програм з графічним інтерфейсом почнемо з прикладу.

Структура віконного проекту

Створимо пустий файл проекту. Запустимо майстра проектів та виберемо у розділі Projects пункт Other Projects. Далі виберемо тип проекту Empty Qt Project. До файлу проекту додамо вміст:

TEMPLATE = app

# Модулі Qt які ми будемо використовувати
QT += widgets # Додаємо модуль widgets
              # необхідний для роботи з віджетами.
TARGET = widget # Назва виконуваного файлу
SOURCES += \
    main.cpp

Тепер створимо просту програму з вікном, у якому будемо виводити надпис. Задамо розмір вікна та текст його заголовку, а також задамо шрифт для надпису. Для цього створимо файл main.cpp з наступним вмістом:

#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[])
{
    // Створюємо об'єкт QApplication, який ініціалізує та налаштовує віконну
    // програму, керує її викоаннням з допомогою цикла обробки подій
    QApplication application(argc, argv);
    QLabel label;                          // Сворюємо віджет QLabel - мітку
    label.setText("I am Widget!");         // Задаємо текст для мітки
    label.setGeometry(200, 200, 300, 150); // Задаємо розміри - позицію (x, y)
                                           // ширину та висоту
    // Задаємо вирівнювання тексту
    label.setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    // Клас QFont використовують для налаштування параметрів
    // шрифту. Вибираємо сімейсво шрифтів Arial Black та розмір 12.
    QFont lBlackFont("Courier New", 14);
    lBlackFont.setBold(true);
    lLabel.setFont(lBlackFont);             // Задаємо шрифт для мітки
    lLabel.show();                          // Викликаємо метод show(), щоб
                                            // показати мітку на екрані.
    lLabel.setWindowTitle("First GUI Project"); // Задаємо текст заголовку вікна
    return lApplication.exec(); // Запускаємо програму на виконання
                                // exec() виконує цикл обробки подій
                                // Програма очікує на дії користувача
                                // та виконує їх обробку.

Малюнок 3.10 Перший віконний проект.

Розмір та позиція віджета

Як бачимо, елементи, з яких складаються інтерфейси користувача у Qt, мають власні позицію та розмір — так звану “геометрію” — та, таким чином, займають відповідну прямокутну ділянку на екрані. Також кожен з елементів має налаштування, які визначають його поведінку та вигляд.

Батьківські віджети

Для створення структури, віджети організовують у ієрархії за принципом “частина — ціле”. Кожен з віджетів може містити інші віджети. Такий візуальний елемент стає “батьком” або батьківським віджетом для елементів, які він містить. Наголошуємо, що таке відношення не слід плутати з успадкуванням у C++ та відношенням між класами. Відношення між віджетами є відношенням між об'єктами. Як ми побачимо далі, таке відношення має кілька наслідків:

  • батьківський елемент буде відповідати за видалення дочірнього елемента: якщо об'єкт, який є батьківським віджетом видалять — то він автоматично видалить і всі дочірні елементи;

  • батьківській віджет розміщує дочірні віджети всередині себе, частини дочірніх віджетів, які виходять за межі батька є невидимі;

  • стан батьківського віджета передається дочірнім — це стосується деяких властивостей (видимість, активність) та стилів, які накладаються на візуальний елемент (детальніше про стилі — у наступних розділах);

Віджети які не мають батька, мають вигляд окремих вікон у програмі. Розглянемо приклад.

Приклад вікна з кількома віджетами

Назвемо новий проект ParentExample. Файл проекту буде містити звичайні для GUI проекту налаштування:

TEMPLATE = app
TARGET = ParentExample
QT += widgets

Для віджета, який ми будемо використовувати у ролі головного вікна створимо новий клас. Для цього у категорії Files and Classes оберемо розділ С++ та виберемо С++ Class.

Малюнок 3.11 Майстер створення нового класу.

Введемо ім'я для класу (ParentWidget) оберемо базовий клас для нього (QWidget). Після створення майстер додасть .cpp та .h файл до проекту та відкриє їх.

Наступним кроком буде створення кількох елементів на вікні. Для цього відкриємо файл parentwidget.cpp та змінимо код конструктора класу. Для відображення елементів достатньо створити їх у конструкторі класу та задати ParentWidget як батька для них. Код parentwidget.cpp має такий вигляд:

#include "parentwidget.h"

#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
ParentWidget::ParentWidget(QWidget *parent) :
    QWidget(parent)
{
    // Створюємо мітку
    QLabel *lLabel = new QLabel(this);   // Задаємо батьківський віджет – this,
                                         // тобто екземпляр класу ParentWidget.
    lLabel->setGeometry(50, 0, 100, 30); // Позиція відносно лівого верхнього 
                                         // кута батьківського віджета.
    lLabel->setText("Text Label");       // Текст на мітці.
    // Створюємо кнопку, задаємо "батька", геометрію та текст
    QPushButton *lPushButton = new QPushButton(this);
    lPushButton->setGeometry(50, 50, 100, 30);
    lPushButton->setText("PushButton");
    // Створюємо поле вводу, задаємо "батька", геометрію та текст
    QLineEdit *lLineEdit = new QLineEdit(this);
    lLineEdit->setGeometry(50, 100, 100, 30);
    lLineEdit->setText("LineEdit");
    lLineEdit->selectAll(); // Виділяємо текст у полі вводу(просто для прикладу)
    // Врешті решт змінюємо розміри батьківського віджета
    setGeometry(x(), y(), 300, 150);
    // та встановлюємо текст заголовку вікна
    setWindowTitle("Parent Widget Example");
}

Оскільки батьківським елементом є ParentWidget, то мітка, кнопка та текстове поле знаходяться у його межах. Позицію дочірніх віджетів задають відносно лівого верхнього кута батька. Зверніть увагу на те як ми створювали елементи користувацького інтерфейсу у динамічній пам'яті використовуючи оператор new. Це гарантує, що елементи не будуть видалені після завершення роботи конструктора ParentWidget.

Далі додамо до проекту файл main.cpp. Наш клас успадковує від класу QWidget — базового класу для всіх візуальних елементів користувацького інтерфейсу, а отже буде володіти всіма його особливостями. Створимо екземпляр нашого класу та викличемо метод show() для того, щоб показати його. Головний файл програми тепер має вигляд:

#include <QApplication>

// Підключаємо .h файл з визначенням
// нашого класу ParentWidget
#include "parentwidget.h"
int main(int lArgc, char *lArgv[])
{
    QApplication lApplication(lArgc, lArgv);
    // Створюємо та показуємо вікно програми
    ParentWidget lParentWidget;
    lParentWidget.show();
    return lApplication.exec();
}

Після компіляції та запуску програми, ми побачимо вікно та розміщені на ньому віджети як на малюнку. Координати віджетів розташованих на вікні (батьківському віджеті) розраховуються відносно його лівого верхнього краю. У цьому легко переконатися змінивши позицію вікна нашої програми.

Малюнок 3.12 Приклад створення дочірніх віджетів.

Якщо ми тепер спробуємо змінити розміри вікна, то побачимо, що віджети розташовані на ньому є нерухомі і відмальовуються лише в межах вікна. Звичайно, така поведінка далеко не завжди є зручною. Частіше за все під час зміни розміру вікна, ми очікуємо, що розташовані в ньому віджети будуть відповідним чином реагувати (розтягуватись, розміщуватись заповнюючи вільний простір, тощо). У той же час задавати позицію та розмір для кожного віджета у програмі не зручно. Щоб подолати ці проблеми зазвичай використовують компонування — засоби Qt які дають змогу автоматично розмістити віджети всередині батьківського.

Last updated