QT 利用QPainter绘制常规图形

    利用QPainter绘制常规图形,可以实现绘制矩形、线段、三角形、圆形、菱形、切换画笔样式等。
    我们通过重写paintEvent()这个处理函数,帮助我们在画面上进行想要的绘画效果。如果我们想要实现拖动鼠标来进行绘制就需要再重写mouseReleaseEvent()、mouseMoveEvent()、mousePressEvent(),分别为鼠标释放、鼠标移动、鼠标按下这三个鼠标事件处理函数,这样就可以实现鼠标按下拖动到合适的位置再松开完成画图的功能。

  

将切换绘制图形的功能绑定在鼠标右键的菜单上,并使用connect来连接我们自己的槽函数实现选中效果的展示和对应功能。利用setContextMenuPolicy(Qt::CustomContextMenu) 

switch (drawFlag) {
    case 0:
        foreach (auto &action, painter_menu->actions()) {
            if(action == action1)
                action->setChecked(true);
            else
                action->setChecked(false);
        }
        break;
    case 1:
        ......
        break;
    case 2:
        ......
        break;
    case 3:
        ......
        break;
    case 4:
        ......
        break;
    default:
        foreach (auto &action, painter_menu->actions()){
            action->setChecked(false);
        }
        break;
    }
    painter_menu->exec(QCursor::pos());
}

        觉得这个颜色、宽度、样式都不符合我们的预期,我们就可以使用画笔工具去进行自定义,设置完成会在页面上实时进行更新。

       但有一点需要注意的是,如果我们使用QPainter中的drawLine()函数去绘制线段的话,我们是无法进行实时的绘制的,而在这里我们使用drawPolygon()函数去进行绘制线段,我们把线段定义成一个QPolygon类对象,这样就可以实现在拖动的过程中实时绘制了。而对QPolygon类对象的描述可以看看这篇博客QPolygon-CSDN博客,我们绘制的三角形、菱形也是QPolygon类对象。


widget.cpp

#include "widget.h"
#include "ui_widget.h"

QPen pen;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //用于设置Widget的背景
    //this->setAutoFillBackground(true);
    //QPalette palette;
    //QT5 QPalette::Background;QT6 QPalette::Window
    //palette.setColor(QPalette::Background, QColor(0x00,0xff,0x00,0x00));//背景透明,QColor(0x00,0xff,0x00,0x00);黑色:Qt::black
    //this->setPalette(palette);
//初始化自定义右键菜单
    painter_menu = new QMenu(this);
    action1 = new QAction("矩    形");
    action2 = new QAction("线    段");
    action3 = new QAction("圆    形");
    action4 = new QAction("三角形");
    action5 = new QAction("棱    形");

    action1->setIcon(QIcon(":/img/rect.png"));
    action2->setIcon(QIcon(":/img/line.png"));
    action3->setIcon(QIcon(":/img/circle.png"));
    action4->setIcon(QIcon(":/img/traingle.png"));
    action5->setIcon(QIcon(":/img/lengx.png"));
    action1->setCheckable(true);
    action2->setCheckable(true);
    action3->setCheckable(true);
    action4->setCheckable(true);
    action5->setCheckable(true);

    painter_menu->addAction(action1);
    painter_menu->addAction(action2);
    painter_menu->addAction(action3);
    painter_menu->addAction(action4);
    painter_menu->addAction(action5);
    painter_menu->addSeparator();
    clear = new QAction("清空");
    clear->setIcon(QIcon(":/img/clear_all.png"));
    painter_menu->addAction(clear);
    confirm = new QAction("确认区域");
    confirm->setIcon(QIcon(":/img/confirm.png"));
    painter_menu->addAction(confirm);
    painter_menu->addSeparator();
    change_Pen = new QAction("画笔设置");
    change_Pen->setIcon(QIcon(":/img/pen.png"));
    painter_menu->addAction(change_Pen);

    painter_menu_click(action2);
    this->setContextMenuPolicy(Qt::CustomContextMenu);//设置自定义菜单,否则会右键创建菜单失败

    connect(this,&QWidget::customContextMenuRequested,this,&Widget::painter_customContextMenuRequested);
    connect(painter_menu,SIGNAL(triggered(QAction*)),this,SLOT(painter_menu_click(QAction*)));
    connect(clear,&QAction::triggered,this,[=](){
        clear_all();
        list_point.clear();
    });
    connect(confirm,&QAction::triggered,this,[=](){
        list_point = confirm_Region();
        qDebug() << list_point;
    });
    connect(change_Pen,&QAction::triggered,this,[=](){
        changepen->show();
    });

    QColor color(0xff,0,0);
    pen.setColor(color);
    pen.setWidth(2);
    pen.setCapStyle(Qt::RoundCap);
    pen.setJoinStyle(Qt::BevelJoin);
    pen.setStyle(Qt::DotLine);
    //setDashPattern会与style发生冲突,通常根据调用位置来生效其中一个,特殊情况Style设置为Qt::CustomDashLine
    //pen.setDashPattern(QVector<qreal>() << 5 << 15 );//实线与虚线比例5:15,5表示5个像素
    changepen = new changePen();
    connect(changepen,&changePen::need_update,this,&Widget::goto_update);
}

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

void Widget::painter_menu_click(QAction *ac){
    if(ac == action1){
        lastflag = drawFlag = 0;
    }else if(ac == action2){
        lastflag = drawFlag = 1;
    }else if(ac == action3){
        lastflag = drawFlag = 2;
    }else if(ac == action4){
        lastflag = drawFlag = 3;
    }else if(ac == action5){
        lastflag = drawFlag = 4;
    }else if(ac == clear){
        drawFlag = 999;
    }
    if(lastflag == 0)
        this->setWindowTitle("正在绘制:" + action1->text());
    if(lastflag == 1)
        this->setWindowTitle("正在绘制:" + action2->text());
    if(lastflag == 2)
        this->setWindowTitle("正在绘制:" + action3->text());
    if(lastflag == 3)
        this->setWindowTitle("正在绘制:" + action4->text());
    if(lastflag == 4)
        this->setWindowTitle("正在绘制:" + action5->text());
    this->update();
}

void Widget::painter_customContextMenuRequested()
{//设置右键菜单样式选中
    switch (drawFlag) {
    case 0:
        foreach (auto &action, painter_menu->actions()) {
            if(action == action1)
                action->setChecked(true);
            else
                action->setChecked(false);
        }
        break;
    case 1:
        foreach (auto &action, painter_menu->actions()){
            if(action == action2)
                action->setChecked(true);
            else
                action->setChecked(false);
        }
        break;
    case 2:
        foreach (auto &action, painter_menu->actions()){
            if(action == action3)
                action->setChecked(true);
            else
                action->setChecked(false);
        }
        break;
    case 3:
        foreach (auto &action, painter_menu->actions()){
            if(action == action4)
                action->setChecked(true);
            else
                action->setChecked(false);
        }
        break;
    case 4:
        foreach (auto &action, painter_menu->actions()){
            if(action == action5)
                action->setChecked(true);
            else
                action->setChecked(false);
        }
        break;
    default:
        foreach (auto &action, painter_menu->actions()){
            action->setChecked(false);
        }
        break;
    }
    painter_menu->exec(QCursor::pos());
}

void Widget::paintEvent(QPaintEvent *event)
{
    // 创建画笔对象
    QPainter painter(this);
    painter.setPen(pen);
    // 设置绘制对象抗锯齿
    painter.setRenderHint(QPainter::Antialiasing);
    // 绘制当前rect对象
    switch (drawFlag) {
        case 0:
            painter.drawRect(m_tmpRect);
            break;
        case 1:
            foreach (const auto &line, m_listLines) {
                painter.drawPolygon(line);
            }
            painter.drawPolygon(m_tmpLine);
            break;
        case 2:
            painter.drawEllipse(m_tmpCircle);
            break;
        case 3:
            painter.drawPolygon(m_tmpTrgl);
            break;
        case 4:
            painter.drawPolygon(m_tmpleng);
            break;
        case 999:
            painter.eraseRect(this->rect());
            drawFlag = lastflag;
            break;
        default:
            break;
    }
    if(event)
        return;
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    if(!leftbtn_click)
        return;
    int width = 0,height = 0;
    switch (drawFlag) {
        case 0:
            m_tmpRect = QRect(m_startPos, event->pos());
            break;
        case 1:
            if(m_linePoint.count() >= 6)
                return;
            m_tmpLine.clear();
            if(m_linePoint.count() > 1)
                m_tmpLine << m_endPos << event->pos();
            else
                m_tmpLine << m_startPos << event->pos();
            break;
        case 2:
            m_tmpCircle = QRect(m_startPos, event->pos());
            break;
        case 3:
            m_tmpTrgl.clear();
            m_tmpTrgl << m_startPos << QPoint(event->pos().x(),m_startPos.y()) << event->pos();
            break;
        case 4:
            width = abs(m_startPos.x() - event->pos().x());
            height = abs(m_startPos.y() - event->pos().y());
            m_tmpleng.clear();
            if((m_startPos.x() > event->pos().x()) && (m_startPos.y() > event->pos().y())){
                m_tmpleng << QPoint(m_startPos.x()-width/2,m_startPos.y()) << QPoint(m_startPos.x(),m_startPos.y()-height/2)
                          << QPoint(event->pos().x()+width/2,event->pos().y()) << QPoint(event->pos().x(),event->pos().y()+height/2);
            }else if((m_startPos.x() > event->pos().x()) && (m_startPos.y() < event->pos().y())){
                m_tmpleng << QPoint(m_startPos.x()-width/2,m_startPos.y()) << QPoint(m_startPos.x(),m_startPos.y()+height/2)
                          << QPoint(event->pos().x()+width/2,event->pos().y()) << QPoint(event->pos().x(),event->pos().y()-height/2);
            }else if((m_startPos.x() < event->pos().x()) && (m_startPos.y() > event->pos().y())){
                m_tmpleng << QPoint(m_startPos.x()+width/2,m_startPos.y()) << QPoint(m_startPos.x(),m_startPos.y()-height/2)
                          << QPoint(event->pos().x()-width/2,event->pos().y()) << QPoint(event->pos().x(),event->pos().y()+height/2);
            }else if((m_startPos.x() < event->pos().x()) && (m_startPos.y() < event->pos().y())){
                m_tmpleng << QPoint(m_startPos.x()+width/2,m_startPos.y()) << QPoint(m_startPos.x(),m_startPos.y()+height/2)
                          << QPoint(event->pos().x()-width/2,event->pos().y()) << QPoint(event->pos().x(),event->pos().y()-height/2);
            }
            break;
        default:
            break;
    }
    // 更新界面
    this->update(this->rect());
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    if(!leftbtn_click)
        return;
    m_endPos = event->pos();

    switch (drawFlag) {
        case 0:
            transPoint();
            break;
        case 1:
            if(m_linePoint.count() >= 6)
                return;
            m_linePoint << m_endPos;
            m_listLines << m_tmpLine;
            m_tmpLine.clear();
            if(m_linePoint.count() == 6){
                m_tmpLine << m_linePoint[m_linePoint.count()-1] << m_linePoint[0];
                m_listLines << m_tmpLine;
                m_tmpLine.clear();
                //qDebug() << m_linePoint;
                //qDebug() << m_listLines;
            }
            break;
        default:
            break;
    }
    // 重绘界面
    this->repaint(this->rect());
}

void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() != Qt::LeftButton){
        leftbtn_click = 0;
        return;
    }else{
        leftbtn_click = 1;
        m_startPos = event->pos();
        if(drawFlag == 1){
            if(m_linePoint.count() >= 6)
                return;
            m_linePoint << m_startPos;
        }
    }
}

void Widget::clear_all(){
    point_rect.left_down = QPoint();
    point_rect.left_up = QPoint();
    point_rect.right_down = QPoint();
    point_rect.right_up = QPoint();
    m_startPos = QPoint();
    m_endPos = QPoint();
    m_tmpRect = QRect();
    m_tmpCircle = QRect();
    m_tmpTrgl.clear();
    m_tmpleng.clear();
    m_tmpLine.clear();
    m_listLines.clear();
    m_linePoint.clear();
    list_point.clear();
}

void Widget::transPoint(){
    int x1 = 0,x2 = 0,y1 = 0,y2 = 0;
    if(m_startPos == m_endPos)
        return;
    x1 = m_startPos.x();
    y1 = m_startPos.y();
    x2 = m_endPos.x();
    y2 = m_endPos.y();
    //qDebug() << x1 << x2 << y1 << y2;
    if(x1 > this->width())
        x1 = this->width();
    if(x2 > this->width())
        x2 = this->width();
    if(y1 > this->height())
        y1 = this->height();
    if(y2 > this->height())
        y2 = this->height();
    if(x1 < 0)
        x1 = 0;
    if(x2 < 0)
        x2 = 0;
    if(y1 < 0)
        y1 = 0;
    if(y2 < 0)
        y2 = 0;
    if(x1 > x2){
        x2 += x1;
        x1 = x2 - x1;
        x2 = x2 - x1;
    }
    if(y1 > y2){
        y2 += y1;
        y1 = y2 - y1;
        y2 = y2 - y1;
    }
    //qDebug() << x1 << x2 << y1 << y2;
    point_rect.left_down = QPoint(x1,y2);
    point_rect.left_up = QPoint(x1,y1);
    point_rect.right_down = QPoint(x2,y2);
    point_rect.right_up = QPoint(x2,y1);
    //qDebug()<< point_rect.left_up  << point_rect.right_up << point_rect.left_down << point_rect.right_down;
}

void Widget::goto_update(){
    this->update();
}

QList<QPoint> Widget::confirm_Region(){
    QList<QPoint> polygon;
    switch (drawFlag) {
    case 0:
        polygon << point_rect.left_up  << point_rect.right_up << point_rect.left_down << point_rect.right_down;
        break;
    case 1:
        if(m_linePoint.count() < 6){
            QMessageBox::critical(this,tr("警告"),tr("所画线段过少\n无法组成一个四边形\n请补充完整再提交。"),QMessageBox::Ok);
        }else{
            polygon << m_listLines[0].point(0) << m_listLines[1].point(0) << m_listLines[2].point(0) << m_listLines[3].point(0);
        }
        break;
    case 3:
        polygon << m_tmpTrgl.point(0) << m_tmpTrgl.point(1) << m_tmpTrgl.point(2);
        break;
    case 4:
        polygon << m_tmpleng.point(0) << m_tmpleng.point(1) << m_tmpleng.point(2) << m_tmpleng.point(3);
        break;
    default:
        break;
    }

    return polygon;
}

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值