QPainter绘图系统

QPainter 和 QPaintDevice

Qt 的绘图系统使用户可以在屏幕或打印设备上用相同的 API 绘图,绘图系统基于 QPainter、QPaintDevice 和 QPaintEngine 类。QPainter 是用来进行绘图操作的类,QPaintDevice 是一个可以使用 QPainter 进行绘图的抽象的二维界面,QPaintEngine 给 QPainter 提供在不同设备上绘图的接口。QPaintENgine 类由 QPainter 和 QPaintDevice 内部使用,应用程序一般无需和 QPaintEngine 打交道,除非要创建自己的设备类型。一般的绘图设备包括 QWidget、QPixmap、QImage 等,这些绘图设备为 QPainter 提供一个“画布”。

paintEvent 事件和绘图区

QWidget 类及其子类时最常用的绘图设备,从 QWidget 类继承的类都有 paintEvent() 事件,要在设备上绘图,只需要重定义此事件并编写响应代码。创建一个 QPainter 对象获取绘图设备的接口,然后就可以在绘图设备的“画布”上绘图了。
paintEvent() 事件里绘图的基本程序结构是:

void widget::paintEvent(QPaintEvent* event)
{
    QPainter painter(this); // 创建与绘图设备关联的QPainter对象
    // painter 在设备的窗口上绘图
}

image.png

QPainter 绘图的主要属性

用 QPainter 在绘图设备上绘图,主要是绘制一些基本的图形元素,包括点、直线、圆形、矩形、曲线、文字等,控制这些绘图元素特性的主要是 QPainter 的 3 个属性,分别如下:

  • pen 属性:是一个 QPen 对象,用于控制线条的颜色、宽度、线型等,上图的矩形边框的线条的特性就是由 pen 属性决定的。
  • brush 属性:是一个 QBrush 对象,用于设置一个区域的填充特性,可以设置填充颜色、填充方式、渐变特性等,还可以采用图片做材质填充。
  • font 属性:是一个 QFont 对象,用于绘制文字时,设置文字的字体样式、大小等属性。

使用这三个属性基本就控制了绘图的基本特点,当然还有一些其他的功能结合使用,比如叠加模式、旋转和缩放等功能。

创建实例

为了演示 QPainter 绘图的基本功能,创建一个 Qt Widget Application 项目,并选择窗口基类为 QWidget,自动创建窗体。创建后的项目有一个 Widget 类,为了简化代码功能,Widget 窗口里不放置任何其他组件,只用来绘图。
下面是 Widget 类的完整定义。只是重新定义了 paintEvent() 事件,在此事件里编写绘图代码。Q_DECL_OVERRIDE 宏表示这个函数时用父类虚函数的重载。

class Widget : public QWidget
{
    Q_OBJECT

protected:
    void    paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;

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

private:
    Ui::Widget *ui;
};

下面是 Widget 类构造函数和 paintEvent() 函数的代码,在界面上绘制如上图所示的一个填充矩形,演示了 QPainter 绘图的基本过程。

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    setPalette(QPalette(Qt::white));//设置窗口为白色背景
    setAutoFillBackground(true);
}

void Widget::paintEvent(QPaintEvent* event)
{
    QPainter    painter(this);//创建QPainter对象
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::TextAntialiasing);

    int W=this->width(); //绘图区宽度
    int H=this->height(); //绘图区高度

    //设置画笔
    QPen    pen;
    pen.setWidth(3); //线宽
    pen.setColor(Qt::black); //划线颜色

    //Qt::NoPen,Qt::SolidLine, Qt::DashLine, Qt::DotLine,Qt::DashDotLine,Qt::DashDotDotLine,Qt::CustomDashLine
    pen.setStyle(Qt::SolidLine);//线的类型,实线、虚线等

    //Qt::FlatCap, Qt::SquareCap,Qt::RoundCap
    pen.setCapStyle(Qt::FlatCap);//线端点样式

    //Qt::MiterJoin,Qt::BevelJoin,Qt::RoundJoin,Qt::SvgMiterJoin
    pen.setJoinStyle(Qt::BevelJoin);//线的连接点样式
    painter.setPen(pen);

    QBrush brush;
    brush.setColor(Qt::yellow);
    brush.setStyle(Qt::SolidPattern);
    painter.setBrush(brush);

    painter.drawRect(rect);
}

paintEvent() 函数中,首先创建与 Widget 关联的 QPainter 对象 painter,这样就可以用这个 painter 在 Widget 上绘图了。

QPen 的主要功能

QPen 用于绘图时对线条进行设置,主要包括线宽、颜色、线型等,主要接口如下:

| 函数原型 | 功能 |
| —————————————— | ——————————— |
| void setColor (QColor& color) | 设置画笔颜色、即线条颜色 |
| void setWidth (int width) | 设置线条宽度 |
| void setStyle (Qt::PenStyle style) | 设置线条样式,参数为 Qt::PenStyle 枚举类型 |
| void setCapStyle (Qt::PenCapStyle style) | 设置线条端点样式,参数为 Qt::PenCapStyle 枚举类型 |
| void setJoinStyle (Qt::PenJoinStyle style) | 设置连接样式,参数为 Qt::PenJoinStyle 枚举类型 |

线条样式

image.png

除了几种基本的线条样式,用户还可以自定义线条样式,自定义线条样式时需要用到 setDashOffet()setDashPattern() 函数。

线条端点样式

image.png

线条连接样式

image.png

QBrush 主要功能

QBrush 定义了 QPainter 绘图时的填充特性,包括填充颜色、填充样式、材质填充时的材质图片等,主要函数如下:

| 函数原型 | 功能 |
| ———————————— | ———————— |
| void setColor (QColor& color) | 设置画刷颜色,实体填充时即为填充颜色 |
| void setStyle (Qt::BrushStyle style) | 设置画刷样式 |
| void setTexture (QPixmap& pixmap) | 设置一个 QPixmap 类型的图片作为画刷图片 |
| void setTextureImage (QImage& image) | 设置一个 QImage 类型图片为画刷 |

Qt::BrushStyle

image.png

下面是使用资源文件里的一个图片进行材质填充的示例程序,用材质图片填充一个矩形。

void Widget::paintEvent(QPaintEvent* event) {
    QPainter painter(this);
    int w = this->width();
    int h = this->height();
    QRect rect(w/4, h/4, w/2, h/2);
    QPen pen;
    pen.setWidth(3);
    pen.setColor(Qt::read);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);
    QPixmap texturePixmap(":/image/texture.jpg");
    QBrush brush;
    brush.setStyle(Qt::TexturePattern);
    brush.setTexture(texturePattern);
    painter.setBrush(brush);
    painter.drawRect(rect);
}