Реклама

Qt/C++ - Урок 014. Динамическое создание виджетов в Qt

QPushButton, Dynamic widget, Динамический виджет, Qt

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

В данном уроке описывается процесс динамического создания кнопок QPushButton, приёма сигналов от этих кнопок, а также последующее удаление этих кнопок из компоновщика Qt.

Программный код был написан в QtCreator 3.3.1 на основе Qt 5.4.1.

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

Описание структуры проекта:

  • DynamicButtons.pro - профайл;
  • mainwindow.h - заголовочный файл основного окна приложения;
  • mainwindow.cpp - исходный код окна;
  • main.cpp - основной исходный файл, с которого стартует приложение;
  • mainwindow.ui - формочка основного окна приложения;
  • qdynamicbutton.h - заголовочный файл класса обертки, который упрощает процесс работы с динамическими объектами в данном уроке;
  • qdynamicbutton.cpp - исходный файл класса обертки, который упрощает процесс работы с динамическими объектами в данном уроке.

mainwindow.ui

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

Внешний вид приложения

Непосредственная работа будет осуществляться со следующими объектами формы окна приложения:

  • addButton - кнопка для добавления динамических кнопок;
  • deleteButton - кнопка для удаления динамических кнопок;
  • verticalLayout - слой для добавления динамических кнопок с вертикальной компоновкой;
  • lineEdit - поле для отображения номеров созданных кнопок.

qdynamicbutton.h

Заголовочный файл класса обёртки, который наследуется от класса QPushButton. В Данном классе объявляется статическая переменная, которая будет общей для всех объектов класса и будет являться счетчиков всех динамических кнопок, которые будут создаваться в данном приложении. Это необходимо для адекватного присвоения номеров каждой кнопки.

#ifndef QDYNAMICBUTTON_H
#define QDYNAMICBUTTON_H

#include <QPushButton>

class QDynamicButton : public QPushButton
{
    Q_OBJECT
public:
    explicit QDynamicButton(QWidget *parent = 0);
    ~QDynamicButton();
    static int ResID;   // Статическая переменная, счетчик номеров кнопок
    int getID();        // Функция для возврата локального номера кнопки


public slots:

private:
    int buttonID = 0;   // Локальная переменная, номер кнопки
};

#endif // QDYNAMICBUTTON_H

qdynamicbutton.cpp

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

#include "qdynamicbutton.h"

QDynamicButton::QDynamicButton(QWidget *parent) :
    QPushButton(parent)
{
    ResID++;            // Увеличение счетчика на единицу
    buttonID = ResID;   /* Присвоение кнопке номера, по которому будет производиться
                         * дальнейшая работа с кнопок
                         * */

}

QDynamicButton::~QDynamicButton()
{

}

/* Метод для возврата значения номера кнопки
 * */
int QDynamicButton::getID()
{
    return buttonID;
}

/* Инициализация статической переменной класса.
 * Статическая переменная класса должна инициализироваться в обязательном порядке
 * */
int QDynamicButton::ResID = 0;

mainwindow.h

В заголовочном файле требуется добавить только СЛОТы для обработки нажатий управляющих кнопок и СЛОТ для получения номера нажатой динамической кнопки.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

/* My Includes */
#include <qdynamicbutton.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_addButton_clicked();    // СЛОТ-обработчик нажатия кнопки добавления
    void on_deleteButton_clicked(); // СЛОТ-обработчик нажатия кнопки удаления
    void slotGetNumber();           // СЛОТ для получения номера нажатой динамической кнопки

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H
mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    /* Для удобства работы слои разделены QSplitter
     * */
    ui->splitter->setStretchFactor(0,1);
    ui->splitter->setStretchFactor(1,0);
}

MainWindow::~MainWindow()
{
    delete ui;
}

/* Метод для добавления динамической кнопки
 * */
void MainWindow::on_addButton_clicked()
{
    QDynamicButton *button = new QDynamicButton(this);  // Создаем объект динамической кнопки
    /* Устанавливаем текст с номером этой кнопки
     * */
    button->setText("Кнопочка " + QString::number(button->getID()));
    /* Добавляем кнопку в слой с вертикальной компоновкой
     * */
    ui->verticalLayout->addWidget(button);
    /* Подключаем сигнал нажатия кнопки к СЛОТ получения номера кнопки
     * */
    connect(button, SIGNAL(clicked()), this, SLOT(slotGetNumber()));
}

/* Метод для удаления динамической кнопки по её номеру
 * */
void MainWindow::on_deleteButton_clicked()
{
    /* Выполняем перебор всех элементов слоя, где располагаются динамические кнопки
     * */
    for(int i = 0; i < ui->verticalLayout->count(); i++){
        /* Производим каст элемента слоя в объект динамической кнопки
         * */
        QDynamicButton *button = qobject_cast<QDynamicButton*>(ui->verticalLayout->itemAt(i)->widget());
        /* Если номер кнопки соответствует числу, которое установлено
         * в lineEdit, то производим удаление данной кнопки
         * */
        if(button->getID() == ui->lineEdit->text().toInt()){
            button->hide();
            delete button;
        }
    }
}

/* СЛОТ для получения номера кнопки.
 * */
void MainWindow::slotGetNumber()
{
    /* Определяем объект, который вызвал сигнал
     * */
    QDynamicButton *button = (QDynamicButton*) sender();
    /* После чего устанавливаем номер кнопки в lineEdit,
     * который содержится в данной динамической кнопке
     * */
    ui->lineEdit->setText(QString::number(button->getID()));
    /* То есть номер кнопки устанавливается в поле lineEdit только тогда,
     * когда мы нажимаем одну из динамических кнопок, и этот номер соответствует
     * номеру нажатой кнопки
     * */
}

Итог

В результате у Вас должно получиться приложение, которое осуществляет динамическое создание и удаление кнопок. Работа приложения показана в видео приведённом ниже.

Реклама

Комментарии

  • #
  • 26 января 2017 г. 22:13
 QDynamicButton *button = qobject_cast<QDynamicButton*>(ui->verticalLayout->itemAt(i)->widget());
Поясните пожалуйста смысл этой строки.

В Qt элементы интерфейса имеют базовый класс QWidget . QDynamycButton наследован от QPushButton , который в свою очередь наследован в конечном итоге от QWidget . Из Layout`а указатели на объекты забираются в качестве указателей на объекты класса QWidget .

Таким образом, чтобы получить доступ к методам класса QDynamicButton , объектами которого являются в данном случае объекты, которые находятся в данном Layout`е, необходимо скастовать указатель из класса QWidget в QDynamicButton

Такие возможности языка C++ достигаются за счёт парадигмы полиморфизма. Пример полиморфизма с некоторыми пояснениями дан в этой статье .

Комментарии

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

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат 50 баллов
  • Очки рейтинга -4

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат 80 баллов
  • Очки рейтинга 4

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

  • Результат 6 баллов
  • Очки рейтинга -10
Последние комментарии

QML - Урок 002. Custom Button in QML Android

Нашел http://doc.qt.io/Qt-5/qtquickcontrols2-customize.html#customizing-button

QML - Урок 002. Custom Button in QML Android

А как кастомайзить Button если использовать QtQuick.Controls 2.0 ? В этом случае пишет Cannot assign to non-existent property "style"

  • EVILEG
  • 15 ноября 2017 г. 13:56

Qt/C++ - Урок 072. Пример векторного редактора на Qt

You need add common QWidget to form, after that you need right-click on this QWidget in the form and select "Promote to..." in Context Menu. After that You will see dialog. In dialog choose Ba...

  • cordsac
  • 15 ноября 2017 г. 3:33

Qt/C++ - Урок 072. Пример векторного редактора на Qt

Sir,In this form design how did you add verectanglesettings.ui,vepolylinesettings.ui UI's to this mainwindow.ui ? have any QT tool to add so. this image shows what I meaning.

Сейчас обсуждают на форуме
  • Docent
  • 21 ноября 2017 г. 19:39

Видео на сцене QGraphicsScene, как правильно сделать?

Ситуация такая: имеется область в памяти в которую пишутся кадры с камеры. Каким наиболее оптимальным образом отобразить их на сцене. У меня это реализовано таким образом, но подозреваю что мо...

Многопоточность. Ошибки при обращении к переменной

Не будет вызываться, оно вызывается ниже по коду. Но какая разница в каком классе хранить данные, если в этой функции я только их выгружаю. Но можно ли все таки выгружать данные из ...

как отключить событие при открытии формы?

как обойти проблему: см. комментарий кода - может кто подскажет. TableView { id: table model: tableModel anchors.fill: parent focus: true Component.onComple...

  • EVILEG
  • 21 ноября 2017 г. 14:40

QGraphicsItem конструктор с параметрами

За что именно отвечают x_c , y_c ? Это положение объекта на графической сцене? Тогда лучше не в методе paint их применять, а через метод setPo...

  • EVILEG
  • 21 ноября 2017 г. 1:36

QGraphicsItem

Я так понимаю, вы каким-то образом передаёте указатель на отрисовываемый текст, то есть на QString. Но лучше добавить переменную в объявление класса, которая будет отвечать за текст, и п...