Qt/C++ - Урок 089. Кнопки с абсолютным позиционированием внутри QGraphicsView

QGraphicsView, QPushButton, QWidget, Qt

Учитывая количество вопросов на форуме, относящихся к тому, как добавить кнопки внутри QGraphicsView, решил написать небольшой туториал на эту тему. Причём вариации вопроса бывают различные. Это может быть обычная кнопка, или даже мини-карта, если основной QGraphicsView выступает в качестве большой карты. В целом, что именно представляет из себя подобный виджет не важно. Суть одна, есть основной QWidget, внутри которого располагаются остальные QWidget объекты, которые имеют абсолютное позиционирование внутри данного виджета.

Выглядеть это будет таким образом.

QGraphicsView, внутри которого располагаются кнопки QPushButton с абсолютным позиционированием.

Введение

QGraphicsView будет располагаться в виджете главного окна и будет добавлено через Qt Designer.

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

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

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class QPushButton;

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

    virtual void resizeEvent(QResizeEvent *event) override;

private:
    void updateButtonsPosition();

    Ui::Widget *ui;

    // Кнопки с абсолютным позиционированием
    QPushButton* m_topLeftButton;
    QPushButton* m_topRightButton;
    QPushButton* m_bottomLeftButton;
    QPushButton* m_bottomRightButton;
};

#endif // WIDGET_H

Widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    // Создадим все кнопки с абсолютным позиционированием
    m_topLeftButton = new QPushButton("Top Left", ui->graphicsView);
    m_topRightButton = new QPushButton("Top Right", ui->graphicsView);
    m_bottomLeftButton = new QPushButton("Bottom Left", ui->graphicsView);
    m_bottomRightButton = new QPushButton("Bottom Right", ui->graphicsView);
    // Обновим позиции кнопок
    updateButtonsPosition();
}

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

void Widget::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event);
    // Обновляем позиции кнопок при каждом событии изменения размера главного окна
    updateButtonsPosition();
}

void Widget::updateButtonsPosition()
{
    // Логика изменения абсолютных позиций кнопок внутри QGraphicsView
    QRect graphicsViewGeometry = ui->graphicsView->geometry();
    m_topLeftButton->setGeometry({25,
                                  25,
                                  m_topLeftButton->geometry().width(),
                                  m_topLeftButton->geometry().height()});
    m_topRightButton->setGeometry({graphicsViewGeometry.width() - m_topRightButton->geometry().width() - 25,
                                   25,
                                   m_topRightButton->geometry().width(),
                                   m_topRightButton->geometry().height()});
    m_bottomLeftButton->setGeometry({25,
                                     graphicsViewGeometry.height() - m_bottomLeftButton->geometry().height() - 25,
                                     m_bottomLeftButton->geometry().width(),
                                     m_bottomLeftButton->geometry().height()});
    m_bottomRightButton->setGeometry({graphicsViewGeometry.width() - m_bottomRightButton->geometry().width() - 25,
                                      graphicsViewGeometry.height() - m_bottomRightButton->geometry().height() - 25,
                                      m_bottomRightButton->geometry().width(),
                                      m_bottomRightButton->geometry().height()});
}

Заключение

Таким образом можно установить абсолютное позиционирование для каких-либо других виджетов в вашей программе.

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

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

Евгений, добрый день.
Вопрос не совсем по теме.
А почему вы объявили класс QPushButton в заголовочном файле таким образом, а не через include? Зачем include переносить в cpp?
В чём смысл?
Вопрос без "подковырки" - действительно интересно.

Добрый день, Александр.
Это Forward Declaration - Предварительное объявление. Позволяет объявить класс без подключения заголовочного файла в заголовочном файле другого класса.
Такое объявление может использоваться как для шаблонных аргментов, так и для указателей. Если переменная объявляется на стеке в заголовочном файле, то тогда да, приходится с использованием include объявлять.

По большей части Forward Declaration преследует две основные цели:

  • Оптимизация подключения заголовочных файлов при компиляции (ну тут всё понятно)
  • Разрешение циклических зависимостей, когда один класс имеет объявленные указатели на другой класс, а второй класс в свою очередь имеет указатели на первый класс. Если в обоих классах подключать заголовочный файлы через include в заголовочных файлах, то ничего не скомпилируется. А вот подключение заголовочных файлов в cpp и с Forward Declaration позволяют разрулить такую ситуацию.

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

Комментарии

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

Здравствуйте, уважаемые пользователи EVILEG !!!

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

Вы можете сделать это следующими способами:

Спасибо, Евгений Легоцкой

ЛП
12 ноября 2019 г. 8:22
Лев Пархимович

C++ - Тест 006. Перечисления

  • Результат:50баллов,
  • Очки рейтинга-4
ЛП
12 ноября 2019 г. 7:35
Лев Пархимович

C++ - Тест 005. Структуры и Классы

  • Результат:66баллов,
  • Очки рейтинга-1
ЛП
12 ноября 2019 г. 7:26
Лев Пархимович

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

  • Результат:50баллов,
  • Очки рейтинга-4
Последние комментарии
b
9 ноября 2019 г. 8:28
bastonc

спасибо ещё раз. огромное, за уделённое время
b
9 ноября 2019 г. 8:24
bastonc

Спасибо Вам большое. Буду изучать.
9 ноября 2019 г. 5:58
Евгений Легоцкой

Добрый день. По первым двум вопросам вы найдёте ответ в этой статье - PyQt5 - Урок 008. Работа с QTableWidget (Обновление урока 006) Что касается последнего вопроса, то я вам…
9 ноября 2019 г. 2:50
Евгений Легоцкой

Как и обещал, вы можете посмотреть новую статью QML - Урок 037. Кастомизация кнопок в QML (Обновление урока 002) . Там же найдёте ссылку на Git репозиторий. Не забудьте поставить звёз…
b
8 ноября 2019 г. 7:40
bastonc

Приветствую. Подскажите пожалуйста пару моментов. 1. Как сделать столбец не редактируемый, а остальные ячейки остаются редактируемыми 2. Как оталвливать события двойного клика для реда…
Сейчас обсуждают на форуме
14 ноября 2019 г. 4:23
Ruslan Polupan

Я уже понял это, ковыряюсь сижу....
14 ноября 2019 г. 3:56
Евгений Легоцкой

Добрый день. Я уже очень давно не создавал инсталляторы, но на данный момент поведение Maintenance Tool выглядит так, что он имеет свой собственный пакет в репозитории. Но честно, я могу с…
14 ноября 2019 г. 2:16
Ruslan Polupan

посмотрите тут http://www.prog.org.ru/topic_6637_15.html И гдето на Гитхабе я видел исходни класса который это реализует
13 ноября 2019 г. 9:33
Pavel.K

Приложение трэкинг задач. Есть вложения. Добавляем вложение и отправляем его на сервер. Для синхронного вызова методов в синхронизации, используем QEventLoop при отправке вложений. В момент син…
13 ноября 2019 г. 3:13
Евгений Легоцкой

Добрый день. Думаю, что да. Выбранный стиль можно подгружать при запуске программы. Во всяком случае, есть такой пример на C++ - Controls Gallery . И там есть такой код #incl…
EVILEG
О нас
Услуги
© EVILEG 2015-2019
Рекомендует хостинг TIMEWEB