Изменение размера окна с помощью мышки

142
06 февраля 2021, 20:40

Создал окно без рамки. Сейчас написал код который работает только при увеличении размеров окна, если пытаться уменьшить то получается белиберда или окно вовсе крашится. Возможно неправильно просчитываю...

bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
    //События для resize окна
    if(acceptDrag)
    {
        if(event->type() == QEvent::MouseButtonPress && Border != null)
        {
            QMouseEvent* mouse_event = dynamic_cast<QMouseEvent*>(event);
            if (mouse_event->button() & Qt::LeftButton)
            {
                dragStartPosition = mouse_event->pos();
                dragStartGeometry = geometry();
                StartResize = true;
                return false;
            }
        }
        else if(event->type() == QEvent::MouseMove)
        {
            QMouseEvent* mouse_event = dynamic_cast<QMouseEvent*>(event);
            if(!(mouse_event->button() & Qt::LeftButton))
            {
                if(mouse_event->x() <= 3 && mouse_event->y() <= 3)
                {
                    setCursor(Qt::SizeFDiagCursor);
                    Border = topleft;
                }
                else if(mouse_event->x() >= width() - 3 && mouse_event->y() <= 3)
                {
                    setCursor(Qt::SizeBDiagCursor);
                    Border = topright;
                }
                else if(mouse_event->x() <= 3 && mouse_event->y() >= height() - 3)
                {
                    setCursor(Qt::SizeBDiagCursor);
                    Border = bottomleft;
                }
                else if(mouse_event->x() >= width() - 3 && mouse_event->y() >= height() - 3)
                {
                    setCursor(Qt::SizeFDiagCursor);
                    Border = bottomright;
                }
                else if(mouse_event->x() <= 3)
                {
                    setCursor(Qt::SizeHorCursor);
                    Border = left;
                }
                else if(mouse_event->x() >= width() - 3)
                {
                    setCursor(Qt::SizeHorCursor);
                    Border = right;
                }
                else if(mouse_event->y() <= 3)
                {
                    setCursor(Qt::SizeVerCursor);
                    Border = top;
                }
                else if(mouse_event->y() >= height() - 3 && mouse_event->x() <= width())
                {
                    setCursor(Qt::SizeVerCursor);
                    Border = bottom;
                }
                else {
                    unsetCursor();
                    Border = null;
                }
            }
            if(StartResize)
            {
                switch(Border)
                {
                case topleft:
                    setGeometry(dragStartGeometry.left() - (dragStartPosition.x() - mouse_event->x()),
                                dragStartGeometry.top() - (dragStartPosition.y() - mouse_event->y()),
                                dragStartGeometry.width() + (dragStartPosition.x() - mouse_event->x()),
                                height() + (dragStartPosition.y() - mouse_event->y()));
                    dragStartGeometry = geometry();
                    break;
                case bottomleft:
                    setGeometry(dragStartGeometry.left() - (dragStartPosition.x() - mouse_event->x()),
                                dragStartGeometry.top(),
                                dragStartGeometry.width() + (dragStartPosition.x() - mouse_event->x()),
                                mouse_event->y());
                    dragStartGeometry = geometry();
                    break;
                case topright:
                    setGeometry(dragStartGeometry.left(),
                                dragStartGeometry.top() - (dragStartPosition.y() - mouse_event->y()),
                                mouse_event->x(),
                                height() + (dragStartPosition.y() - mouse_event->y()));
                    dragStartGeometry = geometry();
                    break;
                case bottomright:
                    setGeometry(dragStartGeometry.left(),
                                dragStartGeometry.top(),
                                mouse_event->x(),
                                mouse_event->y());
                    break;
                case left:
                    setGeometry(dragStartGeometry.left() - (dragStartPosition.x() - mouse_event->x()),
                                dragStartGeometry.top(),
                                dragStartGeometry.width() + (dragStartPosition.x() - mouse_event->x()),
                                height());
                    dragStartGeometry = geometry();
                    break;
                case right:
                    setGeometry(dragStartGeometry.left(),
                                dragStartGeometry.top(),
                                mouse_event->x(),
                                height());
                    break;
                case top:
                    setGeometry(dragStartGeometry.left(),
                                dragStartGeometry.top() - (dragStartPosition.y() - mouse_event->y()),
                                dragStartGeometry.width(),
                                height() + (dragStartPosition.y() - mouse_event->y()));
                    dragStartGeometry = geometry();
                    break;
                case bottom:
                    setGeometry(dragStartGeometry.left(),
                                dragStartGeometry.top(),
                                width(),
                                mouse_event->y());
                    break;
                case null:
                    break;
                }
            }
            return false;
        }
    }
    if(event->type() == QEvent::MouseButtonRelease)
        StartResize = false;
    return false;
}

В заголовке MainWindow описаны:

bool eventFilter(QObject *object, QEvent *event);
enum sBorder{topleft, left, bottomleft, bottom,
             bottomright, right, topright, top, null} Border = null;
bool StartResize = false;
QPoint dragStartPosition;
QRect dragStartGeometry;

В конструкторе MainWindow:

setMouseTracking(true);
installEventFilter(this);

Заранее спасибо! Готов выслушать любые идеи)

Answer 1

Создадим пустой ui диалога. В качестве границ диалога будем использовать QLabel'лы. Для каждой стороны и угла соотвественно Top, Left, Bottom, Rigth, TopLeft, TopRight, BottomLeft, BottomRight. Минимальный размер угловых лэйблов установим 4х4, остальных 2x2. По центру создать QWidget с именем central. Скомпоновать их следующим образом.

Всем компоновкам выставить margin и spacing в 0. В основной компоновке свойству соотношения размеров виджетов внутри компоновки layoutStretch выставить 1,1000,1

Далее объявим класс, реализующий нашу ui.

#include "ui_DialogResizeBase.h"
class ResizeDialogBase : public QDialog, public Ui::DialogResizeBase
{
    Q_OBJECT
    //отображает курсор в соответствии с QLabel
    void setSideCursor(int);  
    //Вычисляет новый размер
    void changeSize(int, QMouseEvent*);
public:
    ResizeDialogBase(QWidget* parent = Q_NULLPTR);
    bool eventFilter(QObject *watched, QEvent *event);
};

Конструктор

    enum {
        TOP,
        BOTTOM,
        RIGHT,
        LEFT,
        TOP_LEFT,
        BOTTOM_RIGHT,
        TOP_RIGHT,
        BOTTOM_LEFT
    };
ResizeDialogBase::
ResizeDialogBase(QWidget *parent):
    QDialog (parent)
{
    setupUi(this);
    setAttribute(Qt::WA_DeleteOnClose);
    setWindowFlag(Qt::FramelessWindowHint);
    //устанавливаем фильтр событий для каждого QLabel
    Top->installEventFilter(this);
    Bottom->installEventFilter(this);
    Right->installEventFilter(this);
    Left->installEventFilter(this);
    LefTop->installEventFilter(this);
    RightBottom->installEventFilter(this);
    RightTop->installEventFilter(this);
    LeftBottom->installEventFilter(this);
    //Определяем свойство side для идентификации стороны
    //можно сделать в дизайнере
    Top->setProperty("side", TOP);
    Bottom->setProperty("side", BOTTOM);
    Right->setProperty("side", RIGHT);
    Left->setProperty("side", LEFT);
    LefTop->setProperty("side", TOP_LEFT);
    RightBottom->setProperty("side", BOTTOM_RIGHT);
    RightTop->setProperty("side", TOP_RIGHT);
    LeftBottom->setProperty("side", BOTTOM_LEFT);
    //Нажата ли левая кнопка мыши
    setProperty("pressed", false);
    //Обрамление диалога
    setStyleSheet("QDialog {\n  border: 1px solid red;\n}");
}

Фильтр событий

bool
ResizeDialogBase::
eventFilter(QObject *watched, QEvent *event)
{
    switch (event->type()) {
        case QEvent::Enter: setSideCursor(watched->property("side").toInt()); break;
        case QEvent::Leave: setCursor(Qt::ArrowCursor); break;
        case QEvent::MouseButtonPress:
            if( static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
                setProperty("pressed", true); break;
        case QEvent::MouseButtonRelease:
            if( static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton)
                setProperty("pressed", false); break;
        case QEvent::MouseMove: changeSize(watched->property("side").toInt(), static_cast<QMouseEvent*>(event)); break;
        default: break;
    }
    return false;
}

Установка курсора

void
ResizeDialogBase::
setSideCursor(int side)
{
    switch (side) {
        case TOP:      case BOTTOM:       setCursor(Qt::SizeVerCursor);   break;
        case RIGHT:    case LEFT:         setCursor(Qt::SizeHorCursor);   break;
        case TOP_LEFT: case BOTTOM_RIGHT: setCursor(Qt::SizeFDiagCursor); break;
        case TOP_RIGHT:case BOTTOM_LEFT:  setCursor(Qt::SizeBDiagCursor); break;
    }
}

Изменение размеров диалога

void
ResizeDialogBase::
changeSize(int side, QMouseEvent* event)
{
    if(property("pressed").toBool()) {
        auto geom = geometry();
        auto x = event->globalX();
        auto y = event->globalY();
        static auto minW = minimumWidth();
        static auto minH = minimumHeight();
        switch (side) {
            case TOP: {
                geom.setY(minH < geom.height() ? y : geom.y());
                geom.setHeight(geom.height() + (geom.y()-y));
                setGeometry(geom);
                break;
            }
            case BOTTOM:
                geom.setHeight(geom.height() + event->y());
                setGeometry(geom);
                break;
            case RIGHT:
                geom.setWidth(geom.width()+event->x());
                setGeometry(geom);
                break;
            case LEFT: {
                geom.setX(minW < geom.width() ? x : geom.x());
                geom.setWidth(geom.width()+(geom.x()-x));
                setGeometry(geom);
                break;
            }
            case TOP_LEFT: {
                geom.setX(minW < geom.width() ? x : geom.x());
                geom.setY(minH < geom.height() ? y : geom.y());
                geom.setWidth(geom.width()+(geom.x()-x));
                geom.setHeight(geom.height() + (geom.y()-y));
                setGeometry(geom);
                break;
            }
            case BOTTOM_RIGHT:
                geom.setWidth(geom.width()+event->x());
                geom.setHeight(geom.height() + event->y());
                setGeometry(geom);
                break;
            case TOP_RIGHT: {
                geom.setY(minH < geom.height() ? y : geom.y());
                geom.setWidth(geom.width()+event->x());
                geom.setHeight(geom.height() + (geom.y()-y));
                setGeometry(geom);
                break;
            }
            case BOTTOM_LEFT: {
                geom.setX(minW < geom.width() ? x : geom.x());
                geom.setWidth(geom.width()+(geom.x()-x));
                geom.setHeight(geom.height() + event->y());
                setGeometry(geom);
                break;
            }
        }
    }
}

Можно использовать как базовый класс для кастомных диалогов, требующих изменения размеров.

READ ALSO
не могу получить значение ячейки в QTableWidget

не могу получить значение ячейки в QTableWidget

имеется таблица,необходимо было сделать ввод в ячейки только double:

128
Как написать for_each parallel для std::map?

Как написать for_each parallel для std::map?

мне необходимо многопоточно обработать элементы std::mapc++ 17 для это есть for_each parallel, но я работаю на C++ 14

90
Сортировка столбцов матрицы

Сортировка столбцов матрицы

Задание звучит так:

92
Выравнивание дивов

Выравнивание дивов

На странице нужно поместить два дива рядом в один контейнерКаждый див имеет фиксированную ширину, но правый див может скрываться и нужно,...

109