Implementing a Dual Toolbar in QT

Link to source code





Challenge and requirements

  • Creation of a double "toolbar" (toolbar), the position of the separator of which would change the ratio of the fields of the splitter.

    In other words, the separator must be dragged with the mouse.





  • The position of the toolbar divider should also depend on the position of the splitter.





  • When hovering over the toolbar separator, the cursor type should change to horizontal QT :: SizeHorCursor





  • When dragging the separator, the cursor must also change its type to horizontal





  • ,









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 - window resize event. On_splitter_splitterMoved cannot be called in this event, therefore it is necessary to make the timer, which will "go beyond" the resizeEvent, to work outside of it.





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 resizes the toolbar via on_splitter_splitterMoved. When the window is resized, the position of the splitter splitter is determined automatically





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;
}
      
      






All Articles