66 2D绘图(绘制文字、路径、图像、模式)

绘制文字

除了绘制图形以外,还可以使用QPainter::darwText()函数来绘制文字,也可以使用QPainter::setFont()设置文字所使用的字体,使用QPainter::fontInfo()函数可以获取字体的信息,它返回QFontInfo类对象。在绘制文字时会默认使用抗锯齿。

    QPainter painter(this);
    painter.setPen(Qt::blue);
    painter.setFont(QFont("Arial", 30));
    painter.drawText(rect(), Qt::AlignCenter, "Qt");

绘制文本函数的一种重载形式

QPainter::drawText ( const QRectF & rectangle, int flags, const QString & text, QRectF * boundingRect = 0 )
  • 第一个参数指定了绘制文字所在的矩形;
  • 第二个参数指定了文字在矩形中的对齐方式,它由Qt::AlignmentFlag枚举变量进行定义,不同对齐方式也可以使用“|”操作符同时使用,这里还可以使用Qt::TextFlag定义的其他一些标志,比如自动换行等;
  • 第三个参数就是所要绘制的文字,这里可以使用“\n”来实现换行;
  • 第四个参数一般不用设置。

如果绘制的文字和它的布局不用经常改动,那么也可以使用drawStaticText()函数,它更高效。

实例:

    QPainter painter(this);
    QRectF rect(10.0, 10.0, 380.0, 280.0);
    painter.setPen(Qt::red);
    painter.drawRect(rect);
    painter.setPen(Qt::blue);
    painter.drawText(rect, Qt::AlignHCenter, tr("AlignHCenter"));
    painter.drawText(rect, Qt::AlignLeft, tr("AlignLeft"));
    painter.drawText(rect, Qt::AlignRight, tr("AlignRight"));
    painter.drawText(rect, Qt::AlignVCenter, tr("AlignVCenter"));
    painter.drawText(rect, Qt::AlignBottom, tr("AlignBottom"));
    painter.drawText(rect, Qt::AlignCenter, tr("AlignCenter"));
    painter.drawText(rect, Qt::AlignBottom | Qt::AlignRight,
                     tr("AlignBottom\nAlignRight"));

运行结果:

66 2D绘图(绘制文字、路径、图像、模式)_第1张图片

实例:

QFont font("宋体", 15, QFont::Bold, true);
//设置下划线
font.setUnderline(true);
//设置上划线
font.setOverline(true);
//设置字母大小写
font.setCapitalization(QFont::SmallCaps);
//设置字符间的间距
font.setLetterSpacing(QFont::AbsoluteSpacing, 10);
//使用字体
painter.setFont(font);
painter.setPen(Qt::green);
painter.drawText(120, 80, tr("yafeilinux"));
painter.translate(100, 100);
painter.rotate(90);
painter.drawText(0, 0, tr("helloqt"));

运行结果:

66 2D绘图(绘制文字、路径、图像、模式)_第2张图片

绘制路径

如果要绘制一个复杂的图形,尤其是要重复绘制这样的图形,那么可以使用QPainterPath类对象,然后使用QPainter::drawPath()来进行绘制。QPainterPath类为绘制操作提供了一个容器,可以用来创建图形并且进行重复使用。

一个绘图路径就是由多个矩形、椭圆、线条或者曲线等组成的对象,一个路径可以是封闭的,例如矩形和椭圆;也可以是非封闭的,例如线条和曲线。

实例:

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPainterPath path;
    // 移动当前点到点(50, 250)
    path.moveTo(50, 250);
    // 从当前点即(50, 250)绘制一条直线到点(50, 230),完成后当前点更改为(50, 230)
    path.lineTo(50, 230);
    // 从当前点和点(120, 60)之间绘制一条三次贝塞尔曲线
    path.cubicTo(QPointF(105, 40), QPointF(115, 80), QPointF(120, 60));
    path.lineTo(130, 130);
    // 向路径中添加一个椭圆
    path.addEllipse(QPoint(130, 130), 30, 30);
    painter.setPen(Qt::darkYellow);
    // 绘制路径
    painter.drawPath(path);
    // 平移坐标系统后重新绘制路径
    path.translate(200,0);
    painter.setPen(Qt::darkBlue);
    painter.drawPath(path);
}

运行结果:

66 2D绘图(绘制文字、路径、图像、模式)_第3张图片

当创建一个QPainterPath对象后就会以坐标原点为当前点进行绘制,可以随时使用moveTo()函数改变当前点,比如程序中移动到了点(50, 250),那么下次就会从该点开始进行绘制;可以使用lineTo()、arcTo()、cubicTo()和quadTo()等函数将直线或者曲线添加到路径中。

QPainterPath::cubicTo ( const QPointF & c1, const QPointF & c2, const QPointF & endPoint )函数可以在当前点和endPoint点之间添加一个三次贝塞尔曲线,其中的c1和c2是控制点。quadTo()函数可以绘制一个二次贝塞尔曲线。

可以使用addEllipse()、addPath()、addRect()、addRegion()、addText()和addPolygon()来向路径中添加一些图形或者文字,它们都从当前点开始进行绘制,绘制完成后以结束点作为新的当前点,这些图形都是由一组直线或者曲线组成的。例如矩形就是顺时针添加的一组直线,绘制完成后当前点在矩形的左上角;而椭圆由一组顺时针曲线组成,开始点和结束点都在0度处(3点钟的位置)。另外还可以使用addPath()来添加其他的路径,这样会从本路径的当前点和要添加路径的第一个组件间添加一条直线。

可以使用currentPosition()函数获取当前点,使用moveTo()函数改变当前点;当组建好路径后可以使用drawPath()函数来绘制路径,这里使用translate()函数将路径平移后又重新绘制了路径,可以看到这样就可以重复绘制复杂的图形了,这也是QPainterPath的主要作用。

66 2D绘图(绘制文字、路径、图像、模式)_第4张图片

填充规则

填充路径时也要使用填充规则,这里一共有两个填充规则:Qt::OddEvenFill和Qt::WindingFill。其中Qt::OddEvenFill使用的是奇偶填充规则,具体来说就是:如果要判断一个点是否在图形中,那么可以从该点向图形外引一条水平线,如果该水平线与图形的交点的个数为奇数,那么该点就在图形中。这个规则是默认值;而Qt::WindingFill使用的是非零弯曲规则,具体来说就是:如果要判断一个点是否在图形中,那么可以从该点向图形外引一条水平线,那么如果该水平线与图形的边线相交,这个边线是顺时针绘制的,就记为1,是逆时针绘制的就记为-1,然后将所有数值相加,如果结果不为0,那么该点就在图形中。

下图是这两种规则的示意图,对于Qt::OddEvenFill规则,第一个交点记为1,第二个交点记为2;对于Qt::WindingFill规则,因为椭圆和矩形都是以顺时针进行绘制的,所以各个交点对应的边都使用1来代表。

66 2D绘图(绘制文字、路径、图像、模式)_第5张图片

实例:

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPainterPath path;
    path.addEllipse(10,50,100,100);
    path.addRect(50,100,100,100);
    painter.setBrush(Qt::cyan);
    painter.drawPath(path);
    painter.translate(180,0);
    path.setFillRule(Qt::WindingFill);
    painter.drawPath(path);
}

运行结果:

66 2D绘图(绘制文字、路径、图像、模式)_第6张图片

绘制图像

Qt提供了四个类来处理图像数据:QImage、QPixmap、QBitmap和QPicture,它们也都是常用的绘图设备。

  • QImage主要用来进行I/O处理,它对I/O处理操作进行了优化,而且也可以用来直接访问和操作像素;
  • QPixmap主要用来在屏幕上显示图像,它对在屏幕上显示图像进行了优化;
  • QBitmap是QPixmap的子类,它是一个便捷类,用来处理颜色深度为1的图像,即只能显示黑白两种颜色;
  • QPicture用来记录并重演QPainter命令。

QImage

QImage类提供了一个与硬件无关的图像表示方法,可以直接访问像素数据,也可以作为绘图设备。

因为QImage是QPaintDevice的子类,所以QPainter可以直接在QImage对象上进行绘制。当在QImage上使用QPainter时,绘制操作会在当前GUI线程以外的其他线程中执行。

QImage支持的图像格式包含了单色、8位、32位和alpha混合格式图像。QImage提供了获取图像各种信息的相关函数,还提供了一些转换图像的函数。

QImage使用了隐式数据共享,所以可以进行值传递,QImage对象还可以使用数据流或者进行比较。

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QImage image;
    // 加载一张图片
    image.load("image.png");
    // 输出图片的一些信息
    qDebug() << image.size() << image.format() << image.depth();
    // 在界面上绘制图片
    painter.drawImage(QPoint(10, 10), image);
    // 获取镜像图片
    QImage mirror = image.mirrored();
    // 将图片进行扭曲
    QTransform transform;
    transform.shear(0.2, 0);
    QImage image2 = mirror.transformed(transform);
    painter.drawImage(QPoint(10, 160), image2);
    // 将镜像图片保存到文件
    image2.save("../myDrawing3/mirror.png");
}

运行结果:

66 2D绘图(绘制文字、路径、图像、模式)_第7张图片

QPixmap

QPixmap可以作为一个绘图设备将图像显示在屏幕上。QPixmap中的像素在内部由底层的窗口系统来进行管理。因为QPixmap是QPaintDevice的子类,所以QPainter也可以直接在它上面进行绘制。要想访问像素,只能使用QPainter的相应函数,或者将QPixmap转换为QImage。而与QImage不同,QPixmap中的fill()函数可以使用指定的颜色初始化整个pixmap图像。

可以使用toImage()和fromImage()函数在QImage和QPixmap之间进行转换。通常情况下,QImage类用来加载一个图像文件,随意操纵图像数据,然后将QImage对象转换为QPixmap类型再显示到屏幕上。当然,如果不需要对图像进行操作,那么也可以直接使用QPixmap来加载图像文件。与QImage不同,QPixmap依赖于具体的硬件。QPixmap类也是使用隐式数据共享,可以作为值进行传递。

QPixmap可以很容易的使用QLabel或QAbstractButton的子类(比如QPushButton)来显示在屏幕上。QLabel拥有一个pixmap属性,而QAbstractButton拥有一个icon属性。我们还可以使用grabWidget()和grabWindow()等静态函数来实现截屏功能,使用mask()等函数实现遮罩效果。

实例:

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPixmap pix;
    pix.load("iamge.png");
    painter.drawPixmap(0, 0, pix.width(), pix.height(), pix);
    painter.setBrush(QColor(255, 255, 255, 100));
    painter.drawRect(0, 0, pix.width(), pix.height());
    painter.drawPixmap(100, 0, pix.width(), pix.height(), pix);
    painter.setBrush(QColor(0, 0, 255, 100));
    painter.drawRect(100, 0, pix.width(), pix.height());
}

运行结果:

66 2D绘图(绘制文字、路径、图像、模式)_第8张图片

QPicture

 QPicture是一个可以记录和重演QPainter命令的绘图设备。QPicture可以使用一个平台无关的格式(.pic格式)将绘图命令序列化到IO设备中,所有可以绘制在QWidget部件或者QPixmap上的内容,都可以保存在QPicture中。QPicture与分辨率无关,在不同设备上的显示效果都是一样的。要记录QPainter命令,可以像如下代码这样进行:

QPicture picture;
QPainter painter;
painter.begin(&picture);
painter.drawEllipse(10,20, 80,70);
painter.end();
picture.save("drawing.pic");

要重演QPainter命令,可以像如下代码这样进行:

QPicture picture;
picture.load("drawing.pic");
QPainter painter;
painter.begin(&myImage);
painter.drawPicture(0, 0, picture);
painter.end();

复合模式

QPainter提供了复合模式(Composition Modes)来定义如何完成数字图像的复合,即如何将源图像的像素和目标图像的像素进行合并。

66 2D绘图(绘制文字、路径、图像、模式)_第9张图片

实例:

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter;
    QImage image(400, 300, QImage::Format_ARGB32_Premultiplied);
    painter.begin(&image);
    painter.setBrush(Qt::green);
    painter.drawRect(100, 50, 200, 200);
    painter.setBrush(QColor(0, 0, 255, 150));
    painter.drawRect(50, 0, 100, 100);
    painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
    painter.drawRect(250, 0, 100, 100);
    painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
    painter.drawRect(50, 200, 100, 100);
    painter.setCompositionMode(QPainter::CompositionMode_Xor);
    painter.drawRect(250, 200, 100, 100);
    painter.end();
    painter.begin(this);
    painter.drawImage(0, 0, image);
}

运行结果:

66 2D绘图(绘制文字、路径、图像、模式)_第10张图片

 

 

 

 

 

 

 

 

你可能感兴趣的:(QT学习)