首页 > 代码库 > 第68课 基础图形绘制(下)

第68课 基础图形绘制(下)

1. 简易绘图程序

技术分享 

(1)功能需求

  ①自由图形绘制

  ②基本图形绘制(直线、矩形和椭圆)

  ③能够选择图形绘制颜色

(2)界面解决方案

  ①以QWidget为基类创建绘图主窗口

  ②使用QGroupBox创建图形设置区域

  ③使用单选按钮QRadioBox实现目标图形的选择

  ④使用组合框QCombox实现绘图颜色的选择

2. 自由绘图的实现

(1)自由绘图的本质跟踪鼠标的移动轨迹;因此,必须考虑什么时候开始?什么时候结束?以及如何记录鼠标移动?

(2)从绘图参数的角度,可以将己经绘制结束的图形正在绘制的图形分开处理

(3)自由绘图必须记录鼠标移动时经过的所有点坐标。因此,绘图参数必须有能力保存多个坐标值。

(4)解决方案

  ①mousePressEvent:以鼠标按下为开始,记录开始坐标

  ②mouseMoveEvent: 记录鼠标移动时经过的像素坐标

  ③mouseReleaseEvent:以鼠标释放为结束,记录结束坐标

  ④paintEvent:按照记录顺序在俩俩坐标之间绘制直线

3. 基础图形的动态绘制

(1)分析:基础图形的目标是固定的,但是开始点与结束点不同会导致最终形状的差异;因此鼠标移动时根据当前坐标实时绘制鼠标松开时确定最终图形

(2)基本图形绘制需要在鼠标按下并移动时进行动态绘制图;但是,无论何时都只需要记录两个坐标值

(3)解决方案

  ①mousePressEvent:以鼠标按下为开始,记录开始坐标

  ②mouseMoveEvent: 将鼠标移动时经过的每个坐标作为临时结束坐标

  ③mouseReleaseEvent:以鼠标释放为结束,确定最终结束坐标

  ④paintEvent:在开始坐标与结束坐标之间绘制目标图形

【编程实验】简易绘图程序

//main.cpp

技术分享
#include "Widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}
View Code

//Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QRadioButton>
#include <QComboBox>
#include <QGroupBox>
#include <QList>
#include <QPoint>

class Widget : public QWidget
{
    Q_OBJECT

    //图形类型
    enum DrawType
    {
        NONE,
        FREE,
        LINE,
        RECT,
        ELLIPSE
    };

    //绘图参数
    struct DrawParam
    {
        DrawType type;    //图形类型
        Qt::GlobalColor color; //图形颜色
        QList<QPoint> points;  //绘制图形所需的点
    };

    QGroupBox m_group;
    QRadioButton m_freeBtn;
    QRadioButton m_lineBtn;
    QRadioButton m_rectBtn;
    QRadioButton m_ellipseBtn;
    QComboBox m_colorBox;

    //所有己经绘制的图形
    QList<DrawParam> m_drawList;
    DrawParam m_current;  //正在绘制的图形

    DrawType drawType(); //获取当前选择的图形类型
    Qt::GlobalColor drawColor();//获取当前选择的颜色

    //绘制一个图形
    void draw(QPainter& painter, DrawParam& param);
    //将点加入DrawParam中
    void append(QPoint p);

protected:
    void mousePressEvent(QMouseEvent* evt);
    void mouseMoveEvent(QMouseEvent* evt);
    void mouseReleaseEvent(QMouseEvent* evt);
    void paintEvent(QPaintEvent *);

public:
    Widget(QWidget *parent = 0);
    ~Widget();
};

#endif // WIDGET_H

//Widget.cpp

#include "Widget.h"
#include <QMouseEvent>
#include <QPainter>
#include <QPen>
#include <QBrush>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    m_group.setParent(this);
    m_group.setTitle("Setting");
    m_group.resize(600, 65);
    m_group.move(20, 20);

    m_freeBtn.setParent(&m_group);
    m_freeBtn.setText("Free");
    m_freeBtn.resize(70, 30);
    m_freeBtn.move(35, 20);
    m_freeBtn.setChecked(true);

    m_lineBtn.setParent(&m_group);
    m_lineBtn.setText("Line");
    m_lineBtn.resize(70, 30);
    m_lineBtn.move(140, 20);

    m_rectBtn.setParent(&m_group);
    m_rectBtn.setText("Rect");
    m_rectBtn.resize(70, 30);
    m_rectBtn.move(245, 20);

    m_ellipseBtn.setParent(&m_group);
    m_ellipseBtn.setText("Ellipse");
    m_ellipseBtn.resize(70, 30);
    m_ellipseBtn.move(350, 20);

    m_colorBox.setParent(&m_group);
    m_colorBox.resize(80, 25);
    m_colorBox.move(480, 23);
    m_colorBox.addItem("Black");
    m_colorBox.addItem("Blue");
    m_colorBox.addItem("Green");
    m_colorBox.addItem("Red");
    m_colorBox.addItem("Yellow");

    setFixedSize(width(), 400);

    m_current.type = NONE;
    m_current.color = Qt::white;
    m_current.points.clear();
}


Widget::DrawType Widget::drawType()
{
    DrawType ret = NONE;

    if( m_freeBtn.isChecked() )    ret = FREE;
    if( m_lineBtn.isChecked() )    ret = LINE;
    if( m_rectBtn.isChecked() )    ret = RECT;
    if( m_ellipseBtn.isChecked() ) ret = ELLIPSE;

    return ret;
}

Qt::GlobalColor Widget::drawColor()
{
    Qt::GlobalColor ret = Qt::black;

    if( m_colorBox.currentText() == "Black")    ret = Qt::black;
    if( m_colorBox.currentText() == "Blue")     ret = Qt::blue;
    if( m_colorBox.currentText() == "Green")    ret = Qt::green;
    if( m_colorBox.currentText() == "Red")      ret = Qt::red;
    if( m_colorBox.currentText() == "Yellow")   ret = Qt::yellow;

    return ret;
}

void Widget::draw(QPainter &painter, Widget::DrawParam &param)
{
    if ( (param.type != NONE) && (param.points.count() >=2) )
    {
        int x = (param.points[0].x() < param.points[1].x()) ? param.points[0].x() : param.points[1].x();
        int y = (param.points[0].y() < param.points[1].y()) ? param.points[0].y() : param.points[1].y();
        int w = qAbs(param.points[0].x() - param.points[1].x());
        int h = qAbs(param.points[0].y() - param.points[1].y());

        painter.setPen(QPen(param.color));
        painter.setBrush(QBrush(param.color));

        switch(param.type)
        {
        case FREE:
            for(int i=0; i<param.points.count()-1; i++)
            {
                painter.drawLine(param.points[i], param.points[i+1]);
            }
            break;
        case LINE:
            painter.drawLine(param.points[0], param.points[1]);
            break;
        case RECT:
            painter.drawRect(x, y, w, h);
            break;
        case ELLIPSE:
            painter.drawEllipse(x, y, w, h);
            break;
        default:
            break;
        }
    }
}

//将点加入当前正在绘制的图形中
void Widget::append(QPoint p)
{
    if( m_current.type != NONE )
    {
        //自由图形,则每个点都必须加入
        if( m_current.type == FREE)
        {
            m_current.points.append(p);
        }
        //基本图形,只需保存起点和终点
        else
        {
            if(m_current.points.count() == 2)
            {
                //更新终点位置
                m_current.points.removeLast(); //删除最后一个点
            }

            m_current.points.append(p);
        }
    }
}

void Widget::mousePressEvent(QMouseEvent *evt)
{
    m_current.type = drawType();
    m_current.color = drawColor();
    m_current.points.append(evt->pos());
}

void Widget::mouseMoveEvent(QMouseEvent *evt)
{
    append(evt->pos()); //记录鼠标经过点的位置

    update();
}

void Widget::mouseReleaseEvent(QMouseEvent *evt)
{
    append(evt->pos()); //记束结束点位置
    m_drawList.append(m_current); //保存正在绘制的图形

    m_current.type = NONE;
    m_current.color = Qt::white;
    m_current.points.clear();

    //update();
}

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    //绘制己经结束的图形
    for(int i=0; i<m_drawList.count(); i++)
    {
        draw(painter, m_drawList[i]);
    }

    //绘制正在绘制的图形
    draw(painter, m_current);
}

Widget::~Widget()
{

}

4. 小结

(1)绘图程序需要重写鼠标事件处理函数

(2)模型视图的思想适用于绘图程序

(3)所有图形的绘制由paintEvent函数完成

(4)工程中需要避免在绘制时进行浮点运算。

第68课 基础图形绘制(下)