第八章 二维图形 - QPainter

这篇博客介绍了Qt在二维图形绘制方面的强大功能,主要围绕QPainter类展开。通过学习,你可以掌握如何使用QPainter绘制几何形状、文字等元素,并了解其高级特性,如反走样、渐变填充等。Qt的图形视图框架和QOpenGL库也得到提及,为更复杂的交互和三维图形绘制提供了支持。

    前面大多学的是控件用户界面的安排学习,现在是Qt一个极其重要的方面,就是在绘制二维图形方面的强大功能,在使用得当情况下绝大部分你需要的界面和图形都能非常好看,也有很多自带的的和第三方图形库能够使用,会比手动绘制方便的多,就看你用的溜不溜了。

    Qt的二维图形引擎是基于QPainter类的。QPainter既可以绘制几何形状也可以绘制像素文字等元素。还支持一些高级特性,反走样、像素混合、渐变填充、矢量路径之类的,还有线性变换、平移旋转什么的,可谓老牛逼了。

    重新实现QWidget::painterEvent()可以用于定制窗口部件,并且相当随便的控制外观。Qt也有QGraphicsView、QGraphicsScene和QGraphicsItem类引用全新的“图形视图”体系。可以供交互、绘制、操作。QpenGL是一个绘制三维图形的标准库,也很厉害,以后详述。

一、使用QPainter绘图

    要想在绘图设备上(一般指的是窗口部件)上绘图,只需要创建一个QPainter,再将指针传到该设备中。

例如:

void MyWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
}

QPainter的drawXXX()函数可以绘制各种形状,当然前提是设置好工具的属性。

查看Qt助手对这些绘图的理解帮助会非常大。


QPainter可以这样用:

void Widget:: draw()
{
    QPainter painter( this );
    painter. setPen( QPen ( Qt :: black, 10 , Qt :: DashDotLine, Qt :: RoundCap));
    painter. setBrush( QBrush ( Qt :: green, Qt :: SolidPattern));
    painter. drawEllipse( 10 , 10 , 400 , 240 );
    painter. drawRect( QRect ( 10 , 300 , 400 , 140 ));
}
可以这样用嘞:

void Widget:: drawBezier()
{
    QPainter painter( this );
painter. setRenderHint( QPainter :: Antialiasing, true );
 
    QPainterPath path;
    path. moveTo( 10 , 320 );
path. cubicTo( 200 , 80 , 400 , 80 , 480 , 320 );
 
    painter. setPen( QPen ( Qt :: black, 2 ));
painter. drawPath( path);
 
    painter. setPen( QPen ( Qt :: red, 4 ));
    painter. drawPoint( 10 , 320 );
     painter. drawPoint( 200 , 80 );
    painter. drawPoint( 400 , 80 );
    painter. drawPoint( 480 , 320 );
}

下面做一个QPainter的实例,一个改变绘图的控制器,当然是不完善的。
#include "painterarea.h"

#ifndef PAINTAREA_H
#define PAINTAREA_H
#include <QWidget>
#include <QPen>
#include <QPaintEvent>
class PaintArea : public QWidget
{
	Q_OBJECT
public:
	enum Shape 
	{
		Line, Rectangle, RoundRect, Ellipse, Polygon, Polyline, Points, Arc, Path, Text,
		Pixmap
	};
	PaintArea(QWidget * parent = 0);
	void setShape(Shape);       //设置形状
	void setPen(QPen);          //设置画笔
	void setBrush(QBrush);      //设置画刷
	void setFillRule(Qt::FillRule);//设置填充模式
	void paintEvent(QPaintEvent *);//重画事件
private:
	Shape shape;
	QPen pen;
	QBrush brush;
	Qt::FillRule fillRule;
};
#endif // PAINTAREA_H

painterarea.cpp

#include "painterarea.h"
#include <QPainter>

PaintArea::PaintArea(QWidget *parent)
	:QWidget(parent)
{
	setPalette(QPalette(Qt::white)); //设置背景颜色
	setAutoFillBackground(true);//设置自动填充背景色
	setMinimumSize(400, 400);//设置窗口最下大小
}
void PaintArea::setShape(Shape s)   //update()更新窗口部件
{
	shape = s;
	update();
}
void PaintArea::setPen(QPen p)
{
	pen = p;
	update();
}
void PaintArea::setBrush(QBrush b)
{
	brush = b;
	update();
}
void PaintArea::setFillRule(Qt::FillRule rule)
{
	fillRule = rule;
	update();
}
//重画事件
void PaintArea::paintEvent(QPaintEvent *)
{
	QPainter p(this);
	p.setPen(pen);
	p.setBrush(brush);
	QRect rect(100, 100, 250, 200);//构造一个矩形
	static const QPoint points[4] = 
	{
		QPoint(100,100),
		QPoint(200,150),
		QPoint(300,250),
		QPoint(150,300)
	};//确定Points的四个点的坐标
	int startAngle = 60 * 16;
	int spanAngle = 180 * 16;  //为绘制曲线设置参数变量
	QPainterPath path;     //QPainterPath为Qpainter类提供了一个存储容器,里面包含了画的内容和画的顺序,
	path.moveTo(50, 150);    //当前位置移动到坐标50,150
	path.lineTo(350, 150);   //当前位置开始画直线,终点位置坐标350,150
	path.lineTo(100, 325);
	path.lineTo(200, 50);
	path.lineTo(300, 325);
	path.lineTo(50, 150);
	path.setFillRule(fillRule);  //设置填充模式
	switch (shape)
	{
	case Line:       //直线
		p.drawLine(rect.topLeft(), rect.bottomRight());  //绘制直线。起点为矩形左上点,终点为矩形右下点
		break;
	case Rectangle: //长方形
		p.drawRect(rect);
		break;
	case RoundRect:  //圆角方形
		p.drawRoundRect(rect);
		break;
	case Ellipse:   //椭圆形
		p.drawEllipse(rect);
		break;
	case Polygon:   //多边形
		p.drawPolygon(points, 4);  //绘制4个顶点多边形
		break;
	case Polyline:  //多边线
		p.drawPolyline(points, 4);
		break;
	case Points:    //点
		p.drawPoints(points, 4);
		break;
	case Arc:   //弧
		p.drawArc(rect, startAngle, spanAngle);  //后面两个参数分别为 起始角与跨度角
		break;
	case Path:  //绘制之前已经画好的路径
		p.drawPath(path);
		break;
	case Text:  //文字
		p.drawText(rect, Qt::AlignCenter, tr("Hello Qt!"));
		break;
	case Pixmap:    //图片
		p.drawPixmap(150, 150, QPixmap("1.png"));//绘制一个图像
		break;
	default:
		break;
	}
}
//前面的椭圆形、直线、长方形、圆角矩形,弧 都是利用矩形为骨架构成的,具体如何构成参照介绍中的绘制函数中的图。

void PaintArea::paintEvent(QPaintEvent *)
函数内的Point是确定的四个点当然可以根据你的需要设置成鼠标按压事件给出的坐标来

#include"mainwindow.h"

#pragma once
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <painterarea.h>
#include <QLabel>
#include <QComboBox>
#include <QSpinBox>
#include <QPushButton>
#include <QGridLayout>
class MainWindow : public QWidget
{
	Q_OBJECT
public:
	MainWindow(QWidget *parent = 0);
	~MainWindow();
private:
	PaintArea *paintArea;
	QLabel *shapelabel;//形状
	QComboBox *shapeComboBox;
	QLabel *penWidthLable;//画笔宽度
	QSpinBox *penWidthSpinBox;
	QLabel *penColorLabel;//画笔颜色
	QFrame *penColorFrame;
	QPushButton *penColorbtn;//画笔颜色按钮
	QLabel *penStyleLabel;
	QComboBox *penStyleComboBox;//画笔风格
	QLabel *penCapLabel;
	QComboBox *penCapComboBox;
	QLabel *penJoinLabel;
	QComboBox *penJoinComboBox;
	QLabel *fillLabel;
	QComboBox *fillComboBox;
	QLabel *brushStyleLabel;
	QComboBox *brushStyleComboBox;
	QLabel *brushColorlabel;
	QFrame *brushColorFrame;
	QPushButton *brushColorbtn;
	QGridLayout *settingLayout;
	protected slots:
	void ShowShape(int);
	void ShowPenWidth(int);
	void ShowPenColor();
	void ShowPenStyle(int);
	void ShowPenCap(int);
	void ShowPenJoin(int);
	void ShowFill();
	void ShowBrushColor();
	void ShowBrush(int);
};
#endif // MAINWINDOW_H


mainwindow.cpp
#include"mainwindow.h"
#include "painterarea.h"
#include<QColorDialog>
MainWindow::MainWindow(QWidget *parent)
	: QWidget(parent)
{
	paintArea = new PaintArea;
	shapelabel = new QLabel(QStringLiteral("形状:"));  //形状选择下拉列表框
	shapeComboBox = new QComboBox;
	shapeComboBox->addItem(tr("Line"), PaintArea::Line);
	shapeComboBox->addItem(tr("RoundRect"), PaintArea::RoundRect);
	shapeComboBox->addItem(tr("Ellipse"), PaintArea::Ellipse);
	shapeComboBox->addItem(tr("Polygon"), PaintArea::Polygon);
	shapeComboBox->addItem(tr("Polyline"), PaintArea::Polyline);
	shapeComboBox->addItem(tr("Points"), PaintArea::Points);
	shapeComboBox->addItem(tr("Arc"), PaintArea::Arc);
	shapeComboBox->addItem(tr("Rectangle"), PaintArea::Rectangle);
	shapeComboBox->addItem(tr("Path"), PaintArea::Path);
	shapeComboBox->addItem(tr("Text"), PaintArea::Text);
	shapeComboBox->addItem(tr("Pixmap"), PaintArea::Pixmap);
	connect(shapeComboBox, SIGNAL(activated(int)), this, SLOT(ShowShape(int)));
	penColorLabel = new QLabel(QStringLiteral("画笔颜色:")); //画笔颜色选择控件
	penColorFrame = new QFrame;
	penColorFrame->setFrameStyle(QFrame::Panel | QFrame::Sunken);//Panel - QFrame画一个平板使内容看起来凸起或者凹陷,
																 //QFrame::Sunken - 框架和内容看起来凹陷 
	penColorFrame->setAutoFillBackground(true);
	penColorFrame->setPalette(QPalette(Qt::blue));//设置默认颜色为蓝色
	penColorbtn = new QPushButton;
	connect(penColorbtn, SIGNAL(clicked()), this, SLOT(ShowPenColor()));
	penWidthLable = new QLabel(QStringLiteral("画笔宽度:"));//画笔宽度选择控件
	penWidthSpinBox = new QSpinBox;
	penWidthSpinBox->setRange(0, 20);//设置字宽滑块的取值范围
	connect(penWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ShowPenWidth(int)));
	penStyleLabel = new QLabel; //画笔风格选择下拉列表框
	penStyleComboBox = new QComboBox;
	penStyleComboBox->addItem(tr("SolidLine"), 1);
	penStyleComboBox->addItem(tr("DashLine"), 2);
	penStyleComboBox->addItem(tr("DotLine"), 3);
	penStyleComboBox->addItem(tr("DashDotLine"), 4);
	penStyleComboBox->addItem(tr("DashDotDotLine"), 5);
	penStyleComboBox->addItem(tr("CustomDashLine"), 6);//这段如果报错,可以把addItem后面的参数置换为int类的数字
	connect(penStyleComboBox, SIGNAL(activated(int)), this, SLOT(ShowPenStyle(int)));
	penCapLabel = new QLabel;  //画顶端风格选择下拉列表框
	penCapComboBox = new QComboBox;
	penCapComboBox->addItem(tr("SquareCap"), Qt::SquareCap);
	penCapComboBox->addItem(tr("FlatCap"), Qt::FlatCap);
	penCapComboBox->addItem(tr("RoundCap"), Qt::RoundCap);
	connect(penCapComboBox, SIGNAL(activated(int)), this, SLOT(ShowPenCap(int)));
	penJoinLabel = new QLabel;//画笔连接点风格选择下拉列表框
	penJoinComboBox = new QComboBox;
	penJoinComboBox->addItem(tr("BevelJoin"), Qt::BevelJoin);
	penJoinComboBox->addItem(tr("MiterJoin"), Qt::MiterJoin);
	penJoinComboBox->addItem(tr("RoundJoin"), Qt::RoundJoin);
	fillLabel = new QLabel;//填充模式选择下拉列表框
	fillComboBox = new QComboBox;
	fillComboBox->addItem(tr("Odd Even"), Qt::OddEvenFill);
	fillComboBox->addItem(tr("Winding"), Qt::WindingFill);
	connect(fillComboBox, SIGNAL(activated(int)), this, SLOT(ShowFill()));
	brushColorlabel = new QLabel;//画刷风格选择下拉列表框
	brushColorFrame = new QFrame;
	brushColorbtn = new QPushButton;
	brushColorFrame->setFrameStyle(QFrame::Panel | QFrame::Sunken);
	brushColorFrame->setAutoFillBackground(true);
	brushColorFrame->setPalette(QPalette(Qt::green));
	connect(brushColorbtn, SIGNAL(clicked()), this, SLOT(ShowBrushColor()));
	brushStyleLabel = new QLabel; //画刷风格选择下拉列表框
	brushStyleComboBox = new QComboBox;
	brushStyleComboBox->addItem(tr("SolidPattern"), 1);
	brushStyleComboBox->addItem(tr("Dense1Pattern"), 2);
	brushStyleComboBox->addItem(tr("Dense2Pattern"), 3);
	brushStyleComboBox->addItem(tr("Dense3Pattern"), 4);
	brushStyleComboBox->addItem(tr("Dense4Pattern"), 5);
	brushStyleComboBox->addItem(tr("Dense5Pattern"), 6);
	brushStyleComboBox->addItem(tr("Dense6Pattern"), 7);
	brushStyleComboBox->addItem(tr("Dense7Pattern"), 8);
	brushStyleComboBox->addItem(tr("HorPattern"), 9);
	brushStyleComboBox->addItem(tr("VerPattern"), 10);
	brushStyleComboBox->addItem(tr("CrossPattern"), 11);
	brushStyleComboBox->addItem(tr("BDiagPattern"), 12);
	brushStyleComboBox->addItem(tr("FDiagPattern"), 13);
	brushStyleComboBox->addItem(tr("DiagCrossPattern"), 14);
	brushStyleComboBox->addItem(tr("LinearGradientPattern"), 15);
	brushStyleComboBox->addItem(tr("ConicalGradientPattern"), 16);
	brushStyleComboBox->addItem(tr("RadialGradientPattern"), 17);
	brushStyleComboBox->addItem(tr("TexturePattern"), 24);
	connect(brushStyleComboBox, SIGNAL(activated(int)), this, SLOT(ShowBrush(int)));
	settingLayout = new QGridLayout;//画板布局
	settingLayout->addWidget(shapelabel, 0, 0);
	settingLayout->addWidget(shapeComboBox, 0, 1);
	settingLayout->addWidget(penColorLabel, 0, 2);
	settingLayout->addWidget(penColorFrame, 0, 3);
	settingLayout->addWidget(penColorbtn, 0, 4);
	settingLayout->addWidget(penWidthLable, 1, 0);
	settingLayout->addWidget(penWidthSpinBox, 1, 1);
	settingLayout->addWidget(penStyleLabel, 1, 2);
	settingLayout->addWidget(penStyleComboBox, 1, 3);
	settingLayout->addWidget(penCapLabel, 2, 0);
	settingLayout->addWidget(penCapComboBox, 2, 1);
	settingLayout->addWidget(penJoinLabel, 2, 2);
	settingLayout->addWidget(penJoinComboBox, 2, 3);
	settingLayout->addWidget(fillLabel, 3, 0);
	settingLayout->addWidget(fillComboBox, 3, 1);
	settingLayout->addWidget(brushColorlabel, 3, 2);
	settingLayout->addWidget(brushColorFrame, 3, 3);
	settingLayout->addWidget(brushColorbtn, 3, 4);
	settingLayout->addWidget(brushStyleLabel, 4, 0);
	settingLayout->addWidget(brushStyleComboBox, 4, 1);
	QVBoxLayout *mainLayout = new QVBoxLayout(this);
	mainLayout->addLayout(settingLayout);
	mainLayout->addWidget(paintArea);
	ShowShape(shapeComboBox->currentIndex());
}
//以下就是各种槽函数了
void MainWindow::ShowShape(int value)
{
	PaintArea::Shape shape = PaintArea::Shape(shapeComboBox->itemData(value, Qt::UserRole).toInt());
	paintArea->setShape(shape);
}
void MainWindow::ShowPenWidth(int value)//画笔宽度
{
	QColor color = penColorFrame->palette().color(QPalette::Window);
	Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(), Qt::UserRole).toInt());
	Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(), Qt::UserRole).toInt());
	Qt::PenJoinStyle join = Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(), Qt::UserRole).toInt());
	paintArea->setPen(QPen(color, value, style, cap, join));
}
void MainWindow::ShowPenColor()//画笔颜色
{
	QColor color = QColorDialog::getColor(Qt::blue);
	penColorFrame->setPalette(QPalette(color));
	int value = penWidthSpinBox->value();
	Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(), Qt::UserRole).toInt());
	Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(), Qt::UserRole).toInt());
	Qt::PenJoinStyle join = Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(), Qt::UserRole).toInt());
	paintArea->setPen(QPen(color, value, style, cap, join));
}
void MainWindow::ShowPenStyle(int styleValue)//画笔风格
{
	QColor color = penColorFrame->palette().color(QPalette::Window);
	int value = penWidthSpinBox->value();
	Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(styleValue, Qt::UserRole).toInt());
	Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(), Qt::UserRole).toInt());
	Qt::PenJoinStyle join = Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(), Qt::UserRole).toInt());
	paintArea->setPen(QPen(color, value, style, cap, join));
}
void MainWindow::ShowPenCap(int capValue)//顶端风格
{
	QColor color = penColorFrame->palette().color(QPalette::Window);
	int value = penWidthSpinBox->value();
	Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(), Qt::UserRole).toInt());
	Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(capValue, Qt::UserRole).toInt());
	Qt::PenJoinStyle join = Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(), Qt::UserRole).toInt());
	paintArea->setPen(QPen(color, value, style, cap, join));
}
void MainWindow::ShowPenJoin(int joinValue)//画笔连接点风格
{
	QColor color = penColorFrame->palette().color(QPalette::Window);
	int value = penWidthSpinBox->value();
	Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(), Qt::UserRole).toInt());
	Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(), Qt::UserRole).toInt());
	Qt::PenJoinStyle join = Qt::PenJoinStyle(penJoinComboBox->itemData(joinValue, Qt::UserRole).toInt());
	paintArea->setPen(QPen(color, value, style, cap, join));
}
void MainWindow::ShowFill()//填充模式
{
	Qt::FillRule fill = Qt::FillRule(fillComboBox->itemData(fillComboBox->currentIndex(), Qt::UserRole).toInt());
	paintArea->setFillRule(fill);
}
void MainWindow::ShowBrushColor()//画刷颜色
{
	QColor color = QColorDialog::getColor(Qt::blue);
	brushColorFrame->setPalette(QPalette(color));
	ShowBrush(brushStyleComboBox->currentIndex());
}
void MainWindow::ShowBrush(int value)//画刷风格
{
	QColor color = brushColorFrame->palette().color(QPalette::Window);//画刷当前的颜色
	Qt::BrushStyle style = Qt::BrushStyle(brushStyleComboBox->itemData(value, Qt::UserRole).toInt());//获取用户选择的画刷风格
	if (style == Qt::LinearGradientPattern)//线性渐变
	{
		QLinearGradient linearGradient(0, 0, 400, 400);//线性渐变的起止点位置
		linearGradient.setColorAt(0.0, Qt::white);//渐变比和渐变颜色
		linearGradient.setColorAt(0.2, color);
		linearGradient.setColorAt(1.0, Qt::black);
		paintArea->setBrush(linearGradient);
	}
	else if (style == Qt::RadialGradientPattern)//圆形渐变
	{
		QRadialGradient radialGradient(200, 200, 150, 150, 100);//中心点,半径,焦点
		radialGradient.setColorAt(0.0, Qt::white);
		radialGradient.setColorAt(0.2, color);
		radialGradient.setColorAt(1.0, Qt::black);
		paintArea->setBrush(radialGradient);
	}
	else if (style == Qt::ConicalGradientPattern)//锥形渐变
	{
		QConicalGradient conicalGradient(200, 200, 30);
		conicalGradient.setColorAt(0.0, Qt::white);
		conicalGradient.setColorAt(0.2, color);
		conicalGradient.setColorAt(1.0, Qt::black);
		paintArea->setBrush(conicalGradient);
	}
	else if (style == Qt::TexturePattern)
	{
		paintArea->setBrush(QBrush(QPixmap("2.png")));
	}
	else
	{
		paintArea->setBrush(QBrush(color, style));
	}
}
MainWindow::~MainWindow()
{
}

MainWindow
这个类实际上就是显示界面的辅助类,要不你怎么操控呢,怎么查看呢。。。。

main.cpp

#include "painterarea.h"
#include"mainwindow.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	MainWindow w;
	w.show();
	return a.exec();
}

参考:

http://blog.csdn.net/wushakun/article/details/49786445

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值