首页 > 代码库 > 第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(); }
//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 ¶m) { 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课 基础图形绘制(下)