Qt实现可移动、可改变大小矩形框

在做图形裁剪的时候,需要一个可以改变大小和位置的矩形框,用于指定裁剪区域大小

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

enum MOUSE_STATE{
    LEFT = 0,
    RIGHT,
    BOTTOM,
    TOP,
    TOP_LEFT,
    TOP_RIGHT,
    BOTTOM_LEFT,
    BOTTOM_RIGHT,
    IN,
    OUT
};



class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    QTransform mat;
    QRect rect;

    bool m_left_down;
    QPoint m_pt_begin;
    QPoint m_pt_rc;

    MOUSE_STATE fsm_state;
    MOUSE_STATE mouse_state;
    MOUSE_STATE get_mouse_state(QPoint pt);

protected:
    void paintEvent(QPaintEvent *event);

    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QKeyEvent>
#include <qDebug>

#define CORNER_WIDTH    30  //四个角的大小

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    , m_left_down(false)
    , fsm_state(OUT)
    , mouse_state(OUT)
{
    ui->setupUi(this);

    rect = QRect(100,100,800,600);

    this->setMouseTracking(true);
}

Widget::~Widget()
{
    delete ui;
}


MOUSE_STATE Widget::get_mouse_state(QPoint pt){
    QRect rcMax(rect),rcMin(rect);
    QRect rcCorner(0,0,CORNER_WIDTH,CORNER_WIDTH);
    rcMax += QMargins(CORNER_WIDTH/2,CORNER_WIDTH/2,CORNER_WIDTH/2,CORNER_WIDTH/2);
    rcMin -= QMargins(CORNER_WIDTH/2,CORNER_WIDTH/2,CORNER_WIDTH/2,CORNER_WIDTH/2);

    if(!rcMax.contains(pt))
        return OUT;
    else{
        if(rcMin.contains(pt))
            return IN;
        else{
            rcCorner.moveCenter(rect.topLeft());
            if(rcCorner.contains(pt))
                return TOP_LEFT;

            rcCorner.moveCenter(rect.topRight());
            if(rcCorner.contains(pt))
                return TOP_RIGHT;

            rcCorner.moveCenter(rect.bottomLeft());
            if(rcCorner.contains(pt))
                return BOTTOM_LEFT;

            rcCorner.moveCenter(rect.bottomRight());
            if(rcCorner.contains(pt))
                return BOTTOM_RIGHT;

            if(fabs(pt.x() - rect.left()) < CORNER_WIDTH/2)
                return LEFT;
            else if(fabs(pt.x() - rect.right()) < CORNER_WIDTH/2)
                return RIGHT;

            if(fabs(pt.y() - rect.top()) < CORNER_WIDTH/2)
                return TOP;
            else if(fabs(pt.y() - rect.bottom()) < CORNER_WIDTH/2)
                return BOTTOM;
        }
    }
    return OUT;
}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    QColor line_color(Qt::lightGray);
    QColor line_color_sel(Qt::darkBlue);
    QColor corner_color(Qt::lightGray);
    QColor corner_color_sel(Qt::darkBlue);

    painter.translate(rect.topLeft());
    painter.setPen(QPen(mouse_state == TOP?line_color_sel:line_color,2, Qt::SolidLine));
    painter.drawLine(QPoint{0,0},QPoint{rect.width()-CORNER_WIDTH/2, 0});
    painter.setPen(QPen(mouse_state == TOP_LEFT?corner_color_sel:corner_color,6, Qt::SolidLine));
    painter.drawLine(QPoint{0,CORNER_WIDTH/2},QPoint{0, 0});
    painter.drawLine(QPoint{0,0},QPoint{CORNER_WIDTH/2, 0});

    painter.resetTransform();
    painter.translate(rect.topRight());
    painter.rotate(90);
    painter.setPen(QPen(mouse_state == RIGHT?line_color_sel:line_color,2, Qt::SolidLine));
    painter.drawLine(QPoint{0,0},QPoint{rect.height()-CORNER_WIDTH/2, 0});
    painter.setPen(QPen(mouse_state == TOP_RIGHT?corner_color_sel:corner_color,6, Qt::SolidLine));
    painter.drawLine(QPoint{0,CORNER_WIDTH/2},QPoint{0, 0});
    painter.drawLine(QPoint{0,0},QPoint{CORNER_WIDTH/2, 0});

    painter.resetTransform();
    painter.translate(rect.bottomRight());
    painter.rotate(180);
    painter.setPen(QPen(mouse_state == BOTTOM?line_color_sel:line_color,2, Qt::SolidLine));
    painter.drawLine(QPoint{0,0},QPoint{rect.width()-CORNER_WIDTH/2, 0});
    painter.setPen(QPen(mouse_state == BOTTOM_RIGHT?corner_color_sel:corner_color,6, Qt::SolidLine));
    painter.drawLine(QPoint{0,CORNER_WIDTH/2},QPoint{0, 0});
    painter.drawLine(QPoint{0,0},QPoint{CORNER_WIDTH/2, 0});

    painter.resetTransform();
    painter.translate(rect.bottomLeft());
    painter.rotate(270);
    painter.setPen(QPen(mouse_state == LEFT?line_color_sel:line_color,2, Qt::SolidLine));
    painter.drawLine(QPoint{0,0},QPoint{rect.height()-CORNER_WIDTH/2, 0});
    painter.setPen(QPen(mouse_state == BOTTOM_LEFT?corner_color_sel:corner_color,6, Qt::SolidLine));
    painter.drawLine(QPoint{0,CORNER_WIDTH/2},QPoint{0, 0});
    painter.drawLine(QPoint{0,0},QPoint{CORNER_WIDTH/2, 0});

}

void Widget::mousePressEvent(QMouseEvent *event)
{
    m_left_down = true;
    m_pt_begin = event->pos();
    m_pt_rc = rect.center();

    fsm_state = get_mouse_state(event->pos());

    update();
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    m_left_down = false;
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    auto state  = get_mouse_state(event->pos());
    if(mouse_state != state){
        mouse_state = state;
        switch(mouse_state){
        case LEFT:setCursor(Qt::SizeHorCursor); break;
        case RIGHT:setCursor(Qt::SizeHorCursor);break;
        case BOTTOM:setCursor(Qt::SizeVerCursor);break;
        case TOP:setCursor(Qt::SizeVerCursor);break;
        case TOP_LEFT:setCursor(Qt::SizeFDiagCursor);break;
        case TOP_RIGHT:setCursor(Qt::SizeBDiagCursor);break;
        case BOTTOM_LEFT:setCursor(Qt::SizeBDiagCursor);break;
        case BOTTOM_RIGHT:setCursor(Qt::SizeFDiagCursor);break;
        case IN:setCursor(Qt::SizeAllCursor);break;
        case OUT:setCursor(Qt::ArrowCursor);break;
            break;
        }
    }

    if(m_left_down){
        auto pt = event->pos();
        switch(fsm_state){
        case LEFT:
            if(pt.x() < rect.right() - CORNER_WIDTH/2)
                rect.setLeft(pt.x());
            break;
        case RIGHT:
            if(pt.x() > rect.left() + CORNER_WIDTH/2)
                rect.setRight(pt.x());
            break;
        case BOTTOM:
            if(pt.y() > rect.top() + CORNER_WIDTH/2)
                rect.setBottom(pt.y());
            break;
        case TOP:
            if(pt.y() < rect.bottom() - CORNER_WIDTH/2)
                rect.setTop(pt.y());
            break;
        case TOP_LEFT:
            if(pt.x() < rect.right() - CORNER_WIDTH/2 && pt.y() < rect.bottom() - CORNER_WIDTH/2)
                rect.setTopLeft(pt);
            break;
        case TOP_RIGHT:
            if(pt.x() > rect.left() + CORNER_WIDTH/2 && pt.y() < rect.bottom() - CORNER_WIDTH/2)
                rect.setTopRight(pt);
            break;
        case BOTTOM_LEFT:
            if(pt.x() < rect.right() - CORNER_WIDTH/2 && pt.y() > rect.top() + CORNER_WIDTH/2)
                rect.setBottomLeft(pt);
            break;
        case BOTTOM_RIGHT:
            if(pt.x() > rect.left() + CORNER_WIDTH/2 && pt.y() > rect.top() + CORNER_WIDTH/2)
                rect.setBottomRight(pt);
            break;
        case IN:
            rect.moveCenter(m_pt_rc + pt - m_pt_begin);
            break;
        case OUT:break;
            break;
        }
    }

    update();
    return QWidget::mouseMoveEvent(event);
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值