[C++, Qt] Реализация двойной панели инструментов в QT
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Ссылка на исходный кодИзвините, данный ресурс не поддреживается. :( Задача и требования
- Создание двойного "тулбара" (панели инструментов), положение разделителя которого меняло бы соотношение полей сплиттераа.
Иными словами разделитель должен перетягиваться мышкой.
- Положение разделителя тулбаров так же должно зависеть от положения сплиттера.
- При наведении курсора на разделитель тулбаров должен меняться тип курсора на горизонтальный QT::SizeHorCursor
- При перетягивании разделителя курсор так же должен менять свой тип на горизонтальный
- В целом данный тулбар должен соответствовать типичному представлению пользователя о данном типе тулбаров, это сделает интерфейс простым и понятным
- Приложение должно давать возможность пользователю менять размер окна
РеализацияПервый шагСоздаем Qt Widgets application. Основы cpp и h файлов, с которыми мы работаем, сгенерируются без нашего участия.Object InspectorВыполнение задачи необходимо начать с построения структуры интерфейса.
Для корректного отображения виджета toolbar необходима хотя бы одна иконка, расположенная на нем. Иконку можете выбрать на свой вкус.Параметры виджетовУ виджетов MainWindow, centralwidget и у обоих тулбаров задаем параметр Mouse tracking, как true. Это позволит перехватывать события нажатия мыши, отпускания мыши и передвижения мыши над тулбарами. У обоих списков, что лежат в сплиттере, задаем параметр минимальной ширины. В моем случае этот параметр равен 200 пикселям. У сплиттера задаем параметр childrenCollapsible, как false. Эти действия необходимы для того, чтобы не было возможности "схлопнуть" одну из секций сплиттера или увести тулбар за пределы экрана. Ниже покажу: как это связано с реализацией cpp файла. У тулбаров нужно установить параметр movable, как false, чтобы убрать дефолтное задание размеров тулбаров пользователем.MainWindow.h
private:
Ui::MainWindow *ui;
int timerId = 0;
bool toolbar_dragged = false;
Под Ui::MainWindow *ui создаем две переменные: timerId и toolbar_dragged.
timerId необходима для хранения времени таймера, которое мы будем использовать.
toolbar_dragged определяет: тянет ли пользователь за разделитель
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_splitter_splitterMoved(int pos, int index, bool windowResized = true);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *event);
void timerEvent(QTimerEvent *event);
void resizeEvent(QResizeEvent* event);
Задаем слоты и указываем входной параметр слота on_splitter_splitterMoved windowResized, как параметр, по умолчанию заданный, как true. В resizeEvent, событии изменения размера окна, будет вызываться on_splitter_splitterMoved при помощи emit. Позиция сплиттера при изменении окна меняется, потому и должна меняться позиция разделителя тулбаров. Но в случае изменения размера окна перетягивания разделителя не происходит, toolbar_dragged == false. Потому для случая, когда окно меняет размер, необходимо данное входное условие. Подробнее об этом в cpp файле.MainWindow.cppВ файл необходимо включить две библиотеки:QMouseEvent нужна для обработки сообщений мыши
QWidget необходима для работы с виджетами приложения
#include <QMouseEvent>
#include <QWidget>
Рассмотрим конструктор главного окна:centralWidget()->layout()->setContentsMargins убирает отступы от границ окна, созданные добавлением layout-а, как центрального виджета.
setSpacing(2) нужен потому, что иконки на этом тулбаре не передают событие передвижения мыши в MainWindow, Отступ в 2 пикселя вполне достаточен, чтобы избавиться от этой проблемы.
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
centralWidget()->layout()->setContentsMargins(0, 0, 0, 0);
//this is nessesary
this->ui->toolBar_2->layout()->setSpacing(2);
}
Функция on_splitter_splitterMoved задает фиксированный размер левого тулбара. Второй тулбар автоматически подстраивается под размер первого. Данный размер можно задавать многократно, что мы и делаем. Обычными resize и move методами это сделать нельзя. В случае, если размер тулбара становится меньше, чем минимальный размер первого списка, или начинает прижимать второй список к левому краю окна так, что размер второго списка меньше минимального, изменение размера первого тулбара, а следовательно и положения разделителя между тулбарами - не происходит. Это необходимо, не смотря на то, что в QT дизайнере уже заданы минимальные параметры ширины для списков.
void MainWindow::on_splitter_splitterMoved(int pos, int /*index*/, bool windowResized)
{
if (((pos>this->ui->listWidget->minimumSize().width()) &&
(pos<(this->width() - this->ui->listWidget_2->minimumSize().width()))) || windowResized)
{
this->ui->toolBar->setMaximumSize(pos, ui->toolBar->rect().height());
this->ui->toolBar->setMinimumSize(pos, ui->toolBar->rect().height());
}
}
Функция mouseReleaseEvent вызывается, когда пользователь отпускает мышь. После этого нужно приветси курсор к типу Qt::ArrowCursor и задать соответствующую переменную toolbar_dragged, как false.
void MainWindow::mouseReleaseEvent(QMouseEvent* /*e*/)
{
if (toolbar_dragged)
{
toolbar_dragged = false;
this->setCursor(Qt::ArrowCursor);
}
}
mousePressEvent перехватывает событие нажатия мыши пользователем. При срабатывании данной функции, если мышь находится на промежутке +-20 пикселей от разделителя сплиттера, на высоте тулбаров, toolbar_dragged становится true, а тип курсора меняется на соответствующий перетягиванию.
void MainWindow::mousePressEvent(QMouseEvent *event)
{
QList<int> currentSizes = this->ui->splitter->sizes();
if ((this->ui->toolBar_2->underMouse()) &&
(event->buttons() == Qt::LeftButton) &&
(event->pos().x() < (currentSizes[0]+20)))
{
this->ui->toolBar_2->movableChanged(true);
toolbar_dragged = true;
this->setCursor(Qt::SizeHorCursor);
}
else if ((this->ui->toolBar->underMouse()) &&
(event->buttons() == Qt::LeftButton) &&
(event->pos().x() > (currentSizes[0]-20)))
{
this->ui->toolBar->movableChanged(true);
toolbar_dragged = true;
this->setCursor(Qt::SizeHorCursor);
}
}
mouseMoveEvent вызывается при перемещении мыши. Если происходит перетягивание разделителя (toolbar_dragged), то вызывает функцию on_splitter_splitterMoved для изменения размера тулбара, предварительно поменяв размеры сплиттера.В противном случае, если перетягивания не происходит, но мышь находится на промежутке -2 +5 пикселей от разделителя сплиттера, на высоте тулбаров, с отступами от горизонтальных границ в два пикселя, то тип курсора меняется на SizeHorCursor. Если эти отступы не сделать, то мышь не будет менять тип с SizeHorCursor на ArrowCursor, даже если задать Mouse tracking параметр, как true, всем другим виджетам.
void MainWindow::mouseMoveEvent(QMouseEvent* event)
{
QList<int> currentSizes = this->ui->splitter->sizes();
if (toolbar_dragged)
{
QList<int> currentSizes = this->ui->splitter->sizes();
currentSizes[0] = event->pos().x();
currentSizes[1] = this->width() - event->pos().x();
this->ui->splitter->setSizes(currentSizes);
emit on_splitter_splitterMoved(event->pos().x(), 1, false);
}
else if ((event->pos().y() > (2+this->ui->toolBar->y())) &&
(event->pos().y() < (this->ui->toolBar->height()-2+this->ui->toolBar->y())) &&
(event->pos().x() < (currentSizes[0]+5)) &&
(event->pos().x() > (currentSizes[0]-10)))
{
this->setCursor(Qt::SizeHorCursor);
}
else
{
this->setCursor(Qt::ArrowCursor);
}
}
resizeEvent - событие изменения размера окна. В этом событии нельзя вызвать on_splitter_splitterMoved, потому необходимо сделать таймер, который будет "выходить за пределы" resizeEvent, работать вне ее.
void MainWindow::resizeEvent(QResizeEvent* event)
{
if (timerId)
{
killTimer(timerId);
timerId = 0;
}
// delay beetween ends of resize and your action
timerId = startTimer(1);
QMainWindow::resizeEvent(event);
}
timerEvent меняет размеры тулбара через on_splitter_splitterMoved. При изменении размера окна, положение разделителя сплиттера определяется автоматически
void MainWindow::timerEvent(QTimerEvent *event)
{
QList<int> currentSizes = this->ui->splitter->sizes();
this->ui->toolBar_2->adjustSize();
emit on_splitter_splitterMoved(currentSizes[0], 1,true);
killTimer(event->timerId());
timerId = 0;
}
===========
Источник:
habr.com
===========
Похожие новости:
- [Информационная безопасность, Программирование, C++] С++: безопасность для новичков
- [Разработка под iOS, Разработка мобильных приложений, Разработка под Android] Кроссплатформенная мобильная разработка: история вопроса
- [Программирование] Трудности перевода
- [Интерфейсы, Usability, Графический дизайн, Дизайн] Как мы отказались от вкладок в интерфейсе и ускорили работу пользователей почти в 2,5 раза
- [C++, API, Прототипирование, 3D-принтеры, DIY или Сделай сам] Счетчик подписчиков Telegram с звуковым уведомление
- [Беспроводные технологии, Носимая электроника, DIY или Сделай сам, Электроника для начинающих] Снова о автономной Arduino-метеостанции на батарейках
- [Интерфейсы] Плохие интерфейсы, или как я ходила на башню Федерация
- [Ненормальное программирование, C++] Мемоизация в compile time вычислениях в C++
- [C++, Qt] Проверка орфографии в приложениях Qt
- [C++, Qt, Разработка под Android] Фото из Android смартфона в Qt Widgets
Теги для поиска: #_c++, #_qt, #_toolbar, #_ui, #_widget, #_customization, #_polzovatelskij_interfejs (пользовательский интерфейс), #_tulbar (тулбар), #_panel_instrumentov (панель инструментов), #_c++, #_qt
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:31
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Ссылка на исходный кодИзвините, данный ресурс не поддреживается. :( Задача и требования
Для корректного отображения виджета toolbar необходима хотя бы одна иконка, расположенная на нем. Иконку можете выбрать на свой вкус.Параметры виджетовУ виджетов MainWindow, centralwidget и у обоих тулбаров задаем параметр Mouse tracking, как true. Это позволит перехватывать события нажатия мыши, отпускания мыши и передвижения мыши над тулбарами. У обоих списков, что лежат в сплиттере, задаем параметр минимальной ширины. В моем случае этот параметр равен 200 пикселям. У сплиттера задаем параметр childrenCollapsible, как false. Эти действия необходимы для того, чтобы не было возможности "схлопнуть" одну из секций сплиттера или увести тулбар за пределы экрана. Ниже покажу: как это связано с реализацией cpp файла. У тулбаров нужно установить параметр movable, как false, чтобы убрать дефолтное задание размеров тулбаров пользователем.MainWindow.h private:
Ui::MainWindow *ui; int timerId = 0; bool toolbar_dragged = false; timerId необходима для хранения времени таймера, которое мы будем использовать. toolbar_dragged определяет: тянет ли пользователь за разделитель public:
MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void on_splitter_splitterMoved(int pos, int index, bool windowResized = true); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *event); void timerEvent(QTimerEvent *event); void resizeEvent(QResizeEvent* event); QWidget необходима для работы с виджетами приложения #include <QMouseEvent>
#include <QWidget> setSpacing(2) нужен потому, что иконки на этом тулбаре не передают событие передвижения мыши в MainWindow, Отступ в 2 пикселя вполне достаточен, чтобы избавиться от этой проблемы. MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); centralWidget()->layout()->setContentsMargins(0, 0, 0, 0); //this is nessesary this->ui->toolBar_2->layout()->setSpacing(2); } void MainWindow::on_splitter_splitterMoved(int pos, int /*index*/, bool windowResized)
{ if (((pos>this->ui->listWidget->minimumSize().width()) && (pos<(this->width() - this->ui->listWidget_2->minimumSize().width()))) || windowResized) { this->ui->toolBar->setMaximumSize(pos, ui->toolBar->rect().height()); this->ui->toolBar->setMinimumSize(pos, ui->toolBar->rect().height()); } } void MainWindow::mouseReleaseEvent(QMouseEvent* /*e*/)
{ if (toolbar_dragged) { toolbar_dragged = false; this->setCursor(Qt::ArrowCursor); } } void MainWindow::mousePressEvent(QMouseEvent *event)
{ QList<int> currentSizes = this->ui->splitter->sizes(); if ((this->ui->toolBar_2->underMouse()) && (event->buttons() == Qt::LeftButton) && (event->pos().x() < (currentSizes[0]+20))) { this->ui->toolBar_2->movableChanged(true); toolbar_dragged = true; this->setCursor(Qt::SizeHorCursor); } else if ((this->ui->toolBar->underMouse()) && (event->buttons() == Qt::LeftButton) && (event->pos().x() > (currentSizes[0]-20))) { this->ui->toolBar->movableChanged(true); toolbar_dragged = true; this->setCursor(Qt::SizeHorCursor); } } void MainWindow::mouseMoveEvent(QMouseEvent* event)
{ QList<int> currentSizes = this->ui->splitter->sizes(); if (toolbar_dragged) { QList<int> currentSizes = this->ui->splitter->sizes(); currentSizes[0] = event->pos().x(); currentSizes[1] = this->width() - event->pos().x(); this->ui->splitter->setSizes(currentSizes); emit on_splitter_splitterMoved(event->pos().x(), 1, false); } else if ((event->pos().y() > (2+this->ui->toolBar->y())) && (event->pos().y() < (this->ui->toolBar->height()-2+this->ui->toolBar->y())) && (event->pos().x() < (currentSizes[0]+5)) && (event->pos().x() > (currentSizes[0]-10))) { this->setCursor(Qt::SizeHorCursor); } else { this->setCursor(Qt::ArrowCursor); } } void MainWindow::resizeEvent(QResizeEvent* event)
{ if (timerId) { killTimer(timerId); timerId = 0; } // delay beetween ends of resize and your action timerId = startTimer(1); QMainWindow::resizeEvent(event); } void MainWindow::timerEvent(QTimerEvent *event)
{ QList<int> currentSizes = this->ui->splitter->sizes(); this->ui->toolBar_2->adjustSize(); emit on_splitter_splitterMoved(currentSizes[0], 1,true); killTimer(event->timerId()); timerId = 0; } =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:31
Часовой пояс: UTC + 5