- 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; // Buttons with absolute positioning 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); // Create all buttons with absolute positioning 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); // Update button positions updateButtonsPosition(); } Widget::~Widget() { delete ui; } void Widget::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); // We update the button positions for each resize event of the main window updateButtonsPosition(); } void Widget::updateButtonsPosition() { // The logic of changing the absolute positions of buttons inside 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()}); }
Вывод
Таким образом, вы можете установить абсолютное позиционирование для любых других виджетов в вашей программе.
Важным моментом является то, что в качестве родителя нужно передать виджет, внутри которого должен располагаться созданный виджет. В этом случае родительский объект служит не только контроллером утечек памяти, то есть для автоматического удаления вложенных объектов, но и для индикации вложенности виджетов в графическом интерфейсе приложения.
Евгений, добрый день.
Вопрос не совсем по теме.
А почему вы объявили класс QPushButton в заголовочном файле таким образом, а не через include? Зачем include переносить в cpp?
В чём смысл?
Вопрос без "подковырки" - действительно интересно.
Добрый день, Александр.
Это Forward Declaration - Предварительное объявление. Позволяет объявить класс без подключения заголовочного файла в заголовочном файле другого класса.
Такое объявление может использоваться как для шаблонных аргментов, так и для указателей. Если переменная объявляется на стеке в заголовочном файле, то тогда да, приходится с использованием include объявлять.
По большей части Forward Declaration преследует две основные цели:
Ну и у меня уже как-то на автомате такое делается, позволяет подключать в заголовочных файлах только самое необходимое, остальное уже в cpp файлах оставлять.