QPainter描述
1、QPainter 类在小部件和其他绘制设备上执行低级绘制。
2、QPainter 提供了高度优化的功能来完成大多数图形GUI程序所需的工作。它可以画从简单的线条到复杂的形状。它还可以绘制对齐的文本和像素图。QPainter 可以对继承 QPaintDevice 类的任何对象进行操作。
3、QPainter 与 QPaintDevice 和 QPaintEngine 类一起构成了Qt绘制系统的基础:
QPainter 是用于执行绘图操作的类。
QPaintDevice 表示可以使用 QPainter 在其上绘制的设备。
QPaintEngine 提供了一个接口,QPainter 可以使用这个接口来绘制不同类型的设备。
项目示例
在右边可以选择绘图样式,左边显示对应的样式效果
绘图区
新建类PaintArea,基类QWidget,作为绘制图形区域。其成员有:
private:
Shape m_shape;
QPen m_pen;
QBrush m_brush;
Qt::FillRule m_fillrule;
m_shape用于记录绘图样式,例如绘制线或者绘制矩形;m_pen用于记录画笔样式;m_brush用于记录画刷样式,m_fillrule用于记录填充规则。
当左端控制区发生样式改变时,将对应的样式属性传递给PaintArea类对应的成员,然后调用update( )方法重绘窗体来实现绘图区样式的改变。这就需要我们重写printEvent( )方法,来实现绘制自己需要的图形。
PaintArea类构造函数中,设置背景颜色为白色,以及固定大小
PaintArea::PaintArea(QWidget *parent) : QWidget(parent)
{
setPalette(QPalette(Qt::white));
setAutoFillBackground(true);
setFixedSize( 400,400);
}
控制区样式改变时,将对应的样式属性传递给PaintArea类的对应成员
void PaintArea::setShape(PaintArea::Shape shape) {
m_shape=shape;
update();
}
void PaintArea::setPen(QPen pen) {
m_pen=pen;
update();
}
void PaintArea::setBrush(QBrush brush) {
m_brush=brush;
update();
}
void PaintArea::setFillRule(Qt::FillRule rule) {
m_fillrule=rule;
update();
}
重写paintEvent( )方法,在函数中根据m_shape图片类型调用对应的绘图函数。
void PaintArea::paintEvent(QPaintEvent *event) {
//画矩形和线的坐标
QRect rect(50,100,300,200);
//画点的坐标
const QPoint points[4] = {
QPoint(150,100),
QPoint(300,150),
QPoint(350,250),
QPoint(100,300)
};
//画弧的角度
int startAngle = 30*16;
int spanAngle = 120*16;
//画路径
QPainterPath path;
path.addRect(150,150,100,100);//左上角坐标,宽,高
path.moveTo(100,200);
//bic曲线
path.cubicTo(300,100,200,200,300,300);//三个坐标
path.cubicTo(100,300,200,200,100,100);
path.setFillRule(m_fillrule);
//画家类
QPainter painter(this);
painter.setPen(m_pen);//设置画笔样式
painter.setBrush(m_brush);//设置画刷样式
switch (m_shape) {
case Line://画线
painter.drawLine(rect.topLeft(),rect.bottomRight());
break;
case Rectangle://画矩形
painter.drawRect(rect);
break;
case RoundRect://圆角矩形
painter.drawRoundRect(rect);
break;
case Ellipse://椭圆
painter.drawEllipse(rect);
break;
case Polygon:
painter.drawPolygon(points,4);
break;
case Polyline:
painter.drawPolyline(points,4);
break;
case Points:
painter.drawPoints(points,4);
break;
case Arc:
painter.drawArc(rect,startAngle,spanAngle);
break;
case Path:
painter.drawPath(path);
break;
case Text://文本
painter.drawText(rect,Qt::AlignCenter,"北极熊猫");
break;
case Pixmap://图片
painter.drawPixmap(50,100,QPixmap("fly.png"));
break;
default:
break;
}
}
控制区
控制区就是我们的主窗口类,类名为MainWidget,基类QWidget。将上面我们自定义的PaintArea类作为主窗口类的成员,成员名为m_paintArea。
画笔颜色
当点击"更改"按钮时弹出一个颜色对话框,将用户选择的颜色显示在中间QFrame部件中,同时更改绘图区边框颜色
在初始化函数中初始化QFrame的颜色,以及按钮的槽方法连接。tr可以使该显示的文本能够被翻译。
void MainWidget::initWidgets(){
//画笔颜色
m_penColorLabel = new QLabel(tr("画笔颜色"));
m_penColorFrame = new QFrame;
m_penColorFrame->setFrameStyle(QFrame::Panel|QFrame::Sunken);
m_penColorFrame->setAutoFillBackground(true);//设置填充背景
m_penColorFrame->setPalette(QPalette(Qt::black));//初始化颜色
m_penColorBtn = new QPushButton("更改");
connect(m_penColorBtn,SIGNAL(clicked()),this,SLOT(ShowPenColor()));
}
ShowPenColor( )槽方法
在该槽方法中,我们首先获得QFrame部件的颜色,作为打开颜色对话框时的初始颜色,接着从其他样式选项框中获取和画笔样式有关的值。调用PaintArea类的setPen( ) 方法设置画笔样式。
获得部件颜色:QColor color = 部件名称->palette( ).color(QPalette : :Window);参数QPalette::Window表示获得该部件的窗体颜色
获得组合框选中的值:首先调用组合框的currentIndex( )方法获得组合框当前选中值的索引,再调用组合框的itemData(int index).toInt( ),传入索引,并且将返回值转换成int类型,再强转成对应的样式枚举值。
void MainWidget::ShowPenColor(){
//笔颜色
QColor penCurrenColor = m_penColorFrame->palette().color(QPalette::Window);//获取当前颜色
QColor penColor = QColorDialog::getColor(penCurrenColor,this,"画笔颜色");
m_penColorFrame->setPalette(QPalette(penColor));
//笔宽
int penWidth = m_penWidthSpinBox->value();
//画笔样式
int penStyleIndex = m_penStyleCombo->currentIndex();
Qt::PenStyle penStyle = Qt::PenStyle(m_penStyleCombo->itemData(penStyleIndex).toInt());
//笔帽样式
int penCapIndex = m_penCapCombox->currentIndex();
Qt::PenCapStyle penCapStyle = Qt::PenCapStyle(m_penCapCombox->itemData(penCapIndex).toInt());
//连接点样式
int penJoinIndex = m_penJoinCombox->currentIndex();
Qt::PenJoinStyle penJoinStyle = Qt::PenJoinStyle(m_penJoinCombox->itemData(penJoinIndex).toInt());
//设置画笔
m_paintArea->setPen(QPen(penColor,penWidth,penStyle,penCapStyle,penJoinStyle));
}
绘制形状
形状选取是一个组合框部件,在初始换函数中将可选取的值添加到组合框中.
在初始化函数中,向组合框添加形状条目,这里我们又将能绘制的形状单独在PaintArea类中用枚举类型声明了一下
void MainWidget::initWidgets(){
m_paintArea = new PaintArea;
//形状
m_shapeLabel = new QLabel(tr("形状"));//tr表示可用于翻译
m_shapeCombox = new QComboBox;
m_shapeCombox->addItem(tr("Line"),PaintArea::Line);
m_shapeCombox->addItem(tr("Rectangle"),PaintArea::Rectangle);
m_shapeCombox->addItem(tr("RoundedRect"),PaintArea::RoundRect);
m_shapeCombox->addItem(tr("Ellipse"),PaintArea::Ellipse);
m_shapeCombox->addItem(tr("Polygon"),PaintArea::Polygon);
m_shapeCombox->addItem(tr("Polyline"),PaintArea::Polyline);
m_shapeCombox->addItem(tr("Points"),PaintArea::Points);
m_shapeCombox->addItem(tr("Arc"),PaintArea::Arc);
m_shapeCombox->addItem(tr("Path"),PaintArea::Path);
m_shapeCombox->addItem(tr("Text"),PaintArea::Text);
m_shapeCombox->addItem(tr("Pixmap"),PaintArea::Pixmap);
connect(m_shapeCombox,SIGNAL(activated(int)),this,SLOT(ShowShape(int)));
}
ShowShape(int)槽方法
在该槽方法中,我们获取形状组合框选取的值,再调用PaintArea类的setShape( )方法设置形状.
void MainWidget::ShowShape(int value){
//获得索引在组合框中对应的值,转成int类型,再转成枚举值
PaintArea::Shape shape = PaintArea::Shape(m_shapeCombox->itemData(value).toInt());
m_paintArea->setShape(shape);
}
线宽
设置线宽我们采用一个QSpinBox部件来实现,设置取值范围为1到20。
初始化函数
void MainWidget::initWidgets(){
m_penWidthLabel = new QLabel(tr("画线宽度"));
m_penWidthSpinBox = new QSpinBox;
m_penWidthSpinBox->setRange(1,20);//设置取值范围
connect(m_penWidthSpinBox,SIGNAL(valueChanged(int)),this,SLOT(ShowPenWidth(int)));//值改变信号
}
ShowPenWidth( int)槽方法
槽方法可以直接获取到更改的笔宽值
void MainWidget::ShowPenWidth(int value){
//笔颜色
QColor penColor = m_penColorFrame->palette().color(QPalette::Window);//指定获取这个部件的窗体颜色
//笔宽
int penWidth = value;
//画笔样式
int penStyleIndex = m_penStyleCombo->currentIndex();
Qt::PenStyle penStyle = Qt::PenStyle(m_penStyleCombo->itemData(penStyleIndex).toInt());
//笔帽样式
int penCapIndex = m_penCapCombox->currentIndex();
Qt::PenCapStyle penCapStyle = Qt::PenCapStyle(m_penCapCombox->itemData(penCapIndex).toInt());
//连接点样式
int penJoinIndex = m_penJoinCombox->currentIndex();
Qt::PenJoinStyle penJoinStyle = Qt::PenJoinStyle(m_penJoinCombox->itemData(penJoinIndex).toInt());
m_paintArea->setPen(QPen(penColor,penWidth,penStyle,penCapStyle,penJoinStyle));
}
画笔风格
画笔风格的选择是一个组合框,我们可以选择不同的风格,例如实线(SolidLine)、点线(DotLine)或者其他样式,也可以选择自定义的DashLine。
不同的画笔风格对应的效果大致如下
画笔风格的实现代码与画笔颜色大致相同:首先在初始化函数中向组合框添加可选项,再将组合框的信号与槽方法连接。在槽方法中需要注意的是需要设置自定义的DashLine的样式。
初始化函数
void MainWidget::initWidgets(){
//画笔风格
m_penStyleLabel = new QLabel(tr("画笔风格"));
m_penStyleCombo = new QComboBox;
m_penStyleCombo->addItem(tr("SolidLing"),static_cast<int>(Qt::SolidLine));//适用QT的枚举值,转int类型
m_penStyleCombo->addItem(tr("DorLine"),static_cast<int>(Qt::DotLine));
m_penStyleCombo->addItem(tr("DashDotLine"),static_cast<int>(Qt::DashDotLine));
m_penStyleCombo->addItem(tr("DashDotDotLine"),static_cast<int>(Qt::DashDotDotLine));
m_penStyleCombo->addItem(tr("CustomDashLine"),static_cast<int>(Qt::CustomDashLine));
connect(m_penStyleCombo,SIGNAL(activated(int)),this,SLOT(ShowPenStyle(int)));
}
ShowPenStyle(int)槽方法
在槽方法中需要设置自定义的DashLine样式
void MainWidget::ShowPenStyle(int value){
//笔颜色
QColor penColor = m_penColorFrame->palette().color(QPalette::Window);//指定获取这个部件的窗体颜色
//笔宽
int penWidth = m_penWidthSpinBox->value();
//画笔样式
Qt::PenStyle penStyle = Qt::PenStyle(m_penStyleCombo->itemData(value).toInt());
//笔帽样式
int penCapIndex = m_penCapCombox->currentIndex();
Qt::PenCapStyle penCapStyle = Qt::PenCapStyle(m_penCapCombox->itemData(penCapIndex).toInt());
//连接点样式
int penJoinIndex = m_penJoinCombox->currentIndex();
Qt::PenJoinStyle penJoinStyle = Qt::PenJoinStyle(m_penJoinCombox->itemData(penJoinIndex).toInt());
QPen paintPen(penColor,penWidth,penStyle,penCapStyle,penJoinStyle);
//设置自定义DashLine
if(penStyle == Qt::CustomDashLine){
QVector<qreal>dashes;
qreal space=4;//空格
dashes << 1 << space << 2 << space << 3 << space << 4 << space;
paintPen.setDashPattern(dashes);
}
m_paintArea->setPen(paintPen);
}
笔帽风格
不同的笔帽风格对应的样式如下
释义:
Qt::SquareCap 方形线端,不覆盖线的端点
Qt::FlatCap 方形线端,覆盖线的端点,并以线框一半向外延伸
Qt::RoundCap 圆线端
初始化函数
void MainWidget::initWidgets(){
//笔帽风格
m_penCapLabel = new QLabel(tr("画笔笔帽"));
m_penCapCombox =new QComboBox;
m_penCapCombox->addItem(tr("SquareCap"),Qt::SquareCap);
m_penCapCombox->addItem(tr("FlatCap"),Qt::FlatCap);
m_penCapCombox->addItem(tr("RoundCap"),Qt::RoundCap);
connect(m_penCapCombox,SIGNAL(activated(int)),this,SLOT(ShowPenCap(int)));
}
ShowPenStyle(int)槽方法
void MainWidget::ShowPenCap(int value){
//笔颜色
QColor penColor = m_penColorFrame->palette().color(QPalette::Window);//指定获取这个部件的窗体颜色
//笔宽
int penWidth = m_penWidthSpinBox->value();
//画笔样式
int penStyleIndex = m_penStyleCombo->currentIndex();
Qt::PenStyle penStyle = Qt::PenStyle(m_penStyleCombo->itemData(penStyleIndex).toInt());
//笔帽样式
Qt::PenCapStyle penCapStyle = Qt::PenCapStyle(m_penCapCombox->itemData(value).toInt());
//连接点样式
int penJoinIndex = m_penJoinCombox->currentIndex();
Qt::PenJoinStyle penJoinStyle = Qt::PenJoinStyle(m_penJoinCombox->itemData(penJoinIndex).toInt());
m_paintArea->setPen(QPen(penColor,penWidth,penStyle,penCapStyle,penJoinStyle));
}
连接点样式
不同的连接点样式对应的效果如下
释义:
Qt::BevelJoin 两条线相汇形成方形连接
Qt::MiterJoin 两条线相汇形成尖角连接
Qt::RoundJoin两条线相汇形成圆角连接
初始化函数
void MainWidget::initWidgets(){
//画笔连接点
m_penJoinLabel = new QLabel("画笔连接点");
m_penJoinCombox = new QComboBox;
m_penJoinCombox->addItem(tr("BevelJoin"),Qt::BevelJoin);
m_penJoinCombox->addItem(tr("MiterJoin"),Qt::MiterJoin);
m_penJoinCombox->addItem(tr("RoundJoin"),Qt::RoundJoin);
connect(m_penJoinCombox,SIGNAL(activated(int)),this,SLOT(ShowPenJoin(int)));
}
ShowPenJoin(int)槽方法
void MainWidget::ShowPenJoin(int value){
//笔颜色
QColor penColor = m_penColorFrame->palette().color(QPalette::Window);//指定获取这个部件的窗体颜色
//笔宽
int penWidth = m_penWidthSpinBox->value();
//画笔样式
int penStyleIndex = m_penStyleCombo->currentIndex();
Qt::PenStyle penStyle = Qt::PenStyle(m_penStyleCombo->itemData(penStyleIndex).toInt());
//笔帽样式
int penCapIndex = m_penCapCombox->currentIndex();
Qt::PenCapStyle penCapStyle = Qt::PenCapStyle(m_penCapCombox->itemData(penCapIndex).toInt());
//连接点样式
Qt::PenJoinStyle penJoinStyle = Qt::PenJoinStyle(m_penJoinCombox->itemData(value).toInt());
m_paintArea->setPen(QPen(penColor,penWidth,penStyle,penCapStyle,penJoinStyle));
}
填充模式
不同的填充模式对应的效果如下
Qt::OddEvenFill填充规则:从图形中某一点画一条水平线到图形外,若这条线与图形边线的交点为奇数则说明此点位于图形的内部;若交点为偶数,则此点在图形的外部。
Qt::WindingFill填充规则:从图形总某一点画一条水平线到图形外,每个交点外边线方向可能向上、向下、方向相反的相互抵消,若结果不为0表此点在图形内,若为0则在图形外。其中边线的方向是由QPainterPath创建时根据描述的顺序决定的,如果采用addRect()或addPolygon()等函数加入的图形默认为顺时针方向。
初始化函数
void MainWidget::initWidgets(){
//填充模式
m_fillRuleLabel =new QLabel(tr("填充模式"));
m_fillRuleCombox = new QComboBox;
m_fillRuleCombox->addItem(tr("Odd Even"),Qt::OddEvenFill);
m_fillRuleCombox->addItem(tr("Winding"),Qt::WindingFill);
connect(m_fillRuleCombox,SIGNAL(activated(int)),this,SLOT(ShowFillRule(int)));
}
ShowFileRule(int)槽方法
void MainWidget::ShowFillRule(int value){
int fillRuleIndex = m_fillRuleCombox.currentIndex();
Qt::FillRule fillrule = Qt::FillRule(m_fullRuleCombox->itemDate(fillRuleIndex).toInt());
m_paintArea->setFillRule(fillrule);
}
铺展效果
不同的铺展样式效果如下
初始化函数
void MainWidget::initWidgets(){
m_spreadLabel = new QLabel(tr("铺展效果"));
m_spreadCombox = new QComboBox;
m_spreadCombox->addItem(tr("PadSpread"),QGradient::PadSpread);
m_spreadCombox->addItem(tr("RepeadSpread"),QGradient::RepeatSpread);
m_spreadCombox->addItem(tr("ReflectSpread"),QGradient::ReflectSpread);
connect(m_spreadCombox,SIGNAL(activated(int)),this,SLOT(ShowSpread(int)));
}
ShowSpread(int)槽方法
m_brushSpread是一个QGradient : :Spread类型,用来记录选择的铺展效果。之后调用ShowBrushStyle( int )槽方法来改变样式效果
void MainWidget::ShowSpread(int value){
m_brushSpread = QGradient::Spread(m_spreadCombox->itemData(value).toInt());
ShowBrushStyle(m_brushStyleCombox->currentIndex());
}
画刷风格
不同的画刷风格效果如下
初始化函数
void MainWidget::initWidgets(){
//画刷风格
m_brushStyleLabel = new QLabel(tr("画刷风格"));
m_brushStyleCombox = new QComboBox;
m_brushStyleCombox->addItem(tr("SolidPattern"),static_cast<int>(Qt::SolidPattern));
m_brushStyleCombox->addItem(tr("Dense1Pattern"),static_cast<int>(Qt::Dense1Pattern));
m_brushStyleCombox->addItem(tr("Dense2Pattern"),static_cast<int>(Qt::Dense2Pattern));
m_brushStyleCombox->addItem(tr("Dense3Pattern"),static_cast<int>(Qt::Dense3Pattern));
m_brushStyleCombox->addItem(tr("Dense4Pattern"),static_cast<int>(Qt::Dense4Pattern));
m_brushStyleCombox->addItem(tr("Dense5Pattern"),static_cast<int>(Qt::Dense5Pattern));
m_brushStyleCombox->addItem(tr("Dense6Pattern"),static_cast<int>(Qt::Dense6Pattern));
m_brushStyleCombox->addItem(tr("Dense7Pattern"),static_cast<int>(Qt::Dense7Pattern));
m_brushStyleCombox->addItem(tr("HorPattern"),static_cast<int>(Qt::HorPattern));
m_brushStyleCombox->addItem(tr("VerPattern"),static_cast<int>(Qt::VerPattern));
m_brushStyleCombox->addItem(tr("CrossPattern"),static_cast<int>(Qt::CrossPattern));
m_brushStyleCombox->addItem(tr("BDiagPattern"),static_cast<int>(Qt::BDiagPattern));
m_brushStyleCombox->addItem(tr("FDiagPattern"),static_cast<int>(Qt::FDiagPattern));
m_brushStyleCombox->addItem(tr("DiagCrossPattern"),static_cast<int>(Qt::DiagCrossPattern));
m_brushStyleCombox->addItem(tr("LinearGradientPattern"),static_cast<int>(Qt::LinearGradientPattern));
m_brushStyleCombox->addItem(tr("ConicalGradientPattern"),static_cast<int>(Qt::ConicalGradientPattern));
m_brushStyleCombox->addItem(tr("RadialGradientPattern"),static_cast<int>(Qt::RadialGradientPattern));
m_brushStyleCombox->addItem(tr("TexturePattern"),static_cast<int>(Qt::TexturePattern));
connect(m_brushStyleCombox,SIGNAL(activated(int)),this,SLOT(ShowBrushStyle(int)));
}
ShowBrushStyle(int)槽方法
画刷风格中有几种样式需要特别设置参数,例如QLineGradient就需要设置渐变区域和渐变色
void MainWidget::ShowBrushStyle(int value){
//获取设置的画刷颜色
QColor brushColor = m_brushColorFrame->palette().color(QPalette::Window);
//画刷风格
Qt::BrushStyle brushStyle = Qt::BrushStyle(m_brushStyleCombox->itemData(value).toInt());
//判断画刷风格类型
//线性渐变
if(brushStyle==Qt::LinearGradientPattern){
//指定线性渐变的区域
QLinearGradient lineGradient(0,0,400,400);//起始点和终止点
//指定某个位置的渐变色,pos取值范围0~1
lineGradient.setColorAt(0.0,Qt::white);//0表示起始位置
lineGradient.setColorAt(0.2,brushColor);
lineGradient.setColorAt(1.0,Qt::black); //1表示终止位置
lineGradient.setSpread(m_brushSpread); //铺展效果
m_paintArea->setBrush(lineGradient);
}
//环形渲染
else if(brushStyle == Qt::RadialGradientPattern){
//(中心坐标,半径长度,焦点坐标)
//如果需要对称则中心坐标和焦点坐标保持一致
QRadialGradient radialGrdient(200,200,150,150,100);
//设置位置渐变色
radialGrdient.setColorAt(0.0,Qt::white);
radialGrdient.setColorAt(0.2,brushColor);
radialGrdient.setColorAt(1.0,Qt::black);
m_paintArea->setBrush(radialGrdient);
}
//弧形渲染(锥形渲染)
else if(brushStyle == Qt::ConicalGradientPattern){
QConicalGradient conicalGradient(200,200,30);//指定中心坐标和角度
//设置位置渐变色
conicalGradient.setColorAt(0.0,Qt::white);
conicalGradient.setColorAt(0.2,brushColor);
conicalGradient.setColorAt(1.0,Qt::black);
m_paintArea->setBrush(conicalGradient);
}
else if(brushStyle == Qt::TexturePattern){
m_paintArea->setBrush(QBrush(QPixmap("fly.png")));
}
else{
m_paintArea->setBrush(QBrush(brushColor,brushStyle));
}
}
追风赶月莫停留,平芜尽处是春山!