- 1. Вступ
- 1. widget.h
- 2. Widget.cpp
- 2. Висновок
З огляду на кількість питань на форумі, що відносяться до того, як додати кнопки всередині QGraphicsView, вирішив написати невеликий туторіал на цю тему. Причому варіації питання бувають різні. Це може бути звичайна кнопка, або навіть міні-карта, якщо основний QGraphicsView виступає в якості великої карти. В цілому, що саме являє собою подібний віджет не важливо. Суть одна, є основною QWidget, всередині якого розташовуються інші QWidget об'єкти, які мають абсолютне позиціонування всередині даного віджету.
Виглядати це буде таким чином.
Вступ
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 додатки.
Евгений, добрый день.
Вопрос не совсем по теме.
А почему вы объявили класс QPushButton в заголовочном файле таким образом, а не через include? Зачем include переносить в cpp?
В чём смысл?
Вопрос без "подковырки" - действительно интересно.
Добрый день, Александр.
Это Forward Declaration - Предварительное объявление. Позволяет объявить класс без подключения заголовочного файла в заголовочном файле другого класса.
Такое объявление может использоваться как для шаблонных аргментов, так и для указателей. Если переменная объявляется на стеке в заголовочном файле, то тогда да, приходится с использованием include объявлять.
По большей части Forward Declaration преследует две основные цели:
Ну и у меня уже как-то на автомате такое делается, позволяет подключать в заголовочных файлах только самое необходимое, остальное уже в cpp файлах оставлять.