1、基础图形绘制
综合实例开发:简易绘图程序
-功能需求:
★ 自由图形绘制
★ 基本图形绘制(直线,矩形,椭圆)
★ 能够选择图形绘制颜色
简易绘图程序运行截图
界面解决方案
1. 以QWdget为基类创建绘图主窗口
2. 使用QGroupBox创建图形设置区域
3. 使用单选按钮QRadioBox实现目标图形的选择
4. 使用组合框Combox实现绘图颜色的选择
2、问题
如何实现自由绘图?
分析
自由绘图的本质是跟踪鼠标的移动轨迹;因此,必须考
虑什么时候开始?什么时候结束?如何记录鼠标移动?
两个提示
★ 从绘图参数的角度,可以将已经绘制结
束的图形与正在绘制的图形分开处理。
★ 自由绘图必须记录鼠标移动时经过的所有点坐标;
因此,绘图参数必须有能力保存多个坐标值。
自由绘图解决方案
1. 以鼠标按下为开始,记录开始坐标
• mousePressEvent
2. 记录鼠标移动时经过的像素坐标
• mouseMoveEvent
3. 以鼠标释放为结束,记录结束坐标
• mouseReleaseEvent
4 . 按照记录顺序在俩俩坐标之间绘制直线
• paintEvent
3、问题
如何实现基础图形动态绘制?
分析
基础图形的目标是固定的,但是开始点与结束点的不同
会导致最终形状的差异;因此,鼠标移动时根据当前坐
标实时绘图,鼠标松开时确定最终图形。
提示
★ 基本图形绘制需要在鼠标按下并移动时进行动态绘
图;但是,无论何时都只需要记录两个坐标值。
基础图形绘制解决方案
1. 以鼠标按下为开始,记录开始坐标
• mousePressEvent
2. 将鼠标移动时经过的每个坐标作为临时结束坐标
• mouseMoveEvent
3. 以鼠标释放为结束,确定最终结束坐标
• mouseReleaseEvent
4 在开始坐标和结束坐标之间绘制目标图形
• paintEvent
4、编程实验
基础图形绘制 68-1.pro
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/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);
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(), 600);
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::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::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::paintEvent(QPaintEvent *)
{
QPainter painter(this);
for(int i=0; i<m_drawList.count(); i++)
{
draw(painter, m_drawList[i]); //绘制已经完成的图形
}
draw(painter, m_current); //正在绘制的图形
}
void Widget::draw(QPainter& painter, 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()) + 1;
int h = qAbs(param.points[0].y() - param.points[1].y()) + 1;
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;
}
}
}
Widget::~Widget()
{
}
5、小结
绘图程序需要重写鼠标事件处理函数
模型视图的思想适用于绘图程序
所有图形的绘制由paintEvent函数完成
工程中需要避免在绘制时进行浮点运算