Qt 绘图机制

QPainter提供绘图机制,可以在QPainterDevice上进行绘制,QPainterEngine提供不同设备的绘图接口,供以上内部使用,一般情况下用不到。

一般情况下通过重写QWidget中的
void QWidget::paintEvent(QPaintEvent *event)方法来实现绘图

  • QPen用于控制线条颜色,宽度,线型等
  • QBrush设置一块区域的填充特性,颜色,填充方式,渐变类型
  • QFont绘制文字,样式,大小,属性
  • 其他还有旋转,缩放等功能。
    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing); //反锯齿
    p.setRenderHint(QPainter::TextAntialiasing); //文字反锯齿

    int W = this->width();
    int H = this->height();
    QPen pen ;
    QBrush brush;
    QFont font ;

    pen.setWidth(2); //宽度
    pen.setColor(Qt::black); //颜色
    pen.setStyle(Qt::PenStyle::SolidLine); //线的样式,实线,虚线等
    pen.setCapStyle(Qt::PenCapStyle::FlatCap); //端点的样式
    pen.setJoinStyle(Qt::PenJoinStyle::BevelJoin);//连接点的样式

    brush.setColor(Qt::white); //画刷颜色
    brush.setStyle(Qt::BrushStyle::SolidPattern); //画刷填充样式

    p.setPen(pen);
    p.setBrush(brush);
    //p.drawEllipse(150,150,80,80);
    QRect topRect(150,150,80,80); // 绘图区域
    p.drawArc(topRect,16*0,16*180);
    QRect underRect(150,150,80,110);

    p.drawArc(underRect,16*180,180*16);
    QRect leftEarRect(140,190,20,15);
    QRect RightEarRect(220,190,20,15);
    p.drawArc(leftEarRect,90*16,180*16);
    p.drawArc(RightEarRect,270*16,180*16);

    QRect browRect(160,170,30,30);
    p.drawArc(browRect,45*16,120*16);
    QRect rightbrowRect(190,170,30,30);
    p.drawArc(rightbrowRect,25*16,120*16);

    QRect eyeAreaRect(162,176,25,20);
    p.drawArc(eyeAreaRect,0*16,360*16);

    QRect eye2AreaRect(192,176,25,20);
    p.drawArc(eye2AreaRect,0*16,360*16);

    p.drawLine(190,200,180,220);
    p.drawLine(180,220,190,220);

    QRect mouth(175,210,30,30);
    p.drawArc(mouth,210*16,120*16);
    QPen pen2;
    pen2.setColor(Qt::black);
    p.setPen(pen2);

渐变填充

  • QLinearGradient线性渐变
  • QRadialGradient 辐射渐变和扩展辐射渐变
  • QConicalGradient 圆锥形渐变

以上均继承自QGradent,可通过setSpread(QGradient::Spread method)
* PadSpread模式是用结束点的颜色填充外部区域,这是缺省的方式
* RepeatSpread重复使用渐变方式填充外部区域

  • RelfectSpread反射式重复使用渐变方式填充外部区域
    对圆锥型渐变不起作用
QRadialGradient radialGrad(W/2,H/2/*中心点*/,qMax(W/8,H/8)/*辐射填充区半径*/,W/2,H/2/*焦点坐标*/);
    radialGrad.setColorAt(0,Qt::red); //0表示起点
   // radialGrad.setColorAt(0.5,Qt::green);
    radialGrad.setColorAt(1,Qt::yellow); //1表示终点
    radialGrad.setSpread(QGradient::RepeatSpread);
    p.setBrush(radialGrad);


当QGradient::QGradient时

使用线性渐变

QLinearGradient linearGradient(rect().topLeft(),rect().bottomRight());
    linearGradient.setSpread(QGradient::RepeatSpread);
    linearGradient.setColorAt(0,Qt::blue);
    linearGradient.setColorAt(0.5,Qt::red);
    linearGradient.setColorAt(1,Qt::green);
    p.setBrush(linearGradient);

锥型渐变

 QConicalGradient conicalGradient(W/2,H/2,45);
    conicalGradient.setColorAt(0,Qt::blue);
    conicalGradient.setColorAt(1,Qt::green);
    p.setBrush(conicalGradient);

  • 叠加模式–详情看文档

QPainterPath

可用于绘制一系列操作并保存,便于重复使用

QString rocketNames[3] = {"长江一号","长江二号","长江三号"}; //火箭数组

    QPen pen ;
    pen.setColor(Qt::blue);
    pen.setWidth(3);

    const QPoint rockets[8] = { //自制🚀的所有坐标点
        QPoint(100,100),
        QPoint(50,150),
        QPoint(50,300),
        QPoint(30,330),
        QPoint(100,300),
        QPoint(180,330),
        QPoint(150,300),
        QPoint(150,150)
    };

    QPainterPath path;
    path.moveTo(rockets[0]);
    for(int i = 0; i<8;i++){
        path.lineTo(rockets[i]);
    }

    path.closeSubpath();

    brush.setColor(Qt::red);
    brush.setStyle(Qt::SolidPattern);
    p.setBrush(brush);
   // p.drawPath(path);

    QFont serifFont("Times", 30, QFont::Bold);

    {
        qreal sxy  = 0.6;
        for(int i = 0, offset=0;i < 3;i++,offset+=300,sxy+=0.2){
            p.resetTransform();
            QPainterPath path2 = path;
            path2.addText(rockets[0]+QPoint(-55,-15),serifFont,rocketNames[i]);
            p.translate(QPointF(offset,0));
            p.scale(sxy,sxy);
            p.drawPath(path2);
        }
    }

Graphics View

QPainter适用于绘制一些简单的图形。不能实现图件的选择、编辑、拖放、修改等功能。
Graphics View是基于图形项的模型(model)视图(view)模式,类似于数据显示的model/view架构,由场景(QGraphicsScene),视图(QGraphicsView),图形项(QGraphicsItem)构成。
1. QGraphicsScene
不可见的一个管理图形项的容器,可以向场景中加入(获取)图形项,主要功能:
* 提供管理图形项的快速接口
* 将事件传播到每个图形项
* 管理每个图形项的状态
* 管理未经变换的渲染功能,主要用于打印
2. QGraphicsView
用于显示场景中的内容,可为一个场景设置几个视图,用于对同一个数据集提供不同的视口
视图接受鼠标键盘事件转化为场景事件,并进行坐标转换后传送给可视场景
3. QGraphicsItem
基本的图形元件,QGraphicsItem为图形项的基类,Qt提供了一些基本图形项,如QGraphicEllipseItem、QGraphicRectItem等。QGraphicsItem主要操作:
* 鼠标事件响应
* 键盘事件
* 拖放操作
* 支持组合,父子项关系组合或通过QGraphicsItemGroup类进行组合

 若编写信号和槽,还能实现各种编辑功能

QGraphicsView 坐标系统

  • 图形项坐标
    1. 使用自己的局部坐标,以其中心(0,0),鼠标事件是以局部坐标来表示创建自定义图形项,只需考虑局部坐标,Scene于View会进行自动转换
    2. 图形项的位置是其中心坐标,在父坐标中的坐标,如果没有父图形,父对象就是场景,位置就是场景中的坐标
    3. 父图形项坐标变换子图形进行相同的坐标变换
  • 视图坐标
    窗口的物理坐标,坐标只与widget或视口有关,与观察场景无关,QGraphicsView左上角总是(0,0)
    所有的事件首先通过视图坐标定义,然后将这些坐标映射为场景坐标,便于与图形项交互。

  • 场景坐标
    所有图形项的基础坐标,描述了每个顶层Item的位置。
    每个图形项在场景中都有一个位置坐标(QGraphicsView::scenePos());图形项边界矩形(QGraphicsView::sceneBoundingRect();场景发生变化会发出QGraphicsView::change信号

    Demo

    #include "GraphicsDemo.h"

#include <QLabel>

#include <QGraphicsItem>

#include <QGraphicsRectItem>

#include <QGraphicsEllipseItem>

GraphicsDemo::GraphicsDemo(QWidget *parent)

       : QMainWindow(parent)

{
       ui->setupUi(this);
       init();
}
GraphicsDemo::~GraphicsDemo() {}
void GraphicsDemo::init() {
       sceneLabel = new QLabel("Scene coord:");
       viewLabel = new QLabel("view coord:");
       itemLabel = new QLabel("item coord:");

       sceneLabel->setMinimumWidth(150);
       viewLabel->setMinimumWidth(150);
       itemLabel->setMinimumWidth(150);

       statusBar()->addWidget(viewLabel);
       statusBar()->addWidget(sceneLabel);
       statusBar()->addWidget(itemLabel);
       ui->graphicsView->setCursor(Qt::CrossCursor);
       ui->graphicsView->setMouseTracking(true); 
       ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);

       QObject::connect(ui->graphicsView, &MyGraphicsView::mouseMovePoint, this, 
&GraphicsDemo::on_mouseMovePoint);
       QObject::connect(ui->graphicsView, SIGNAL(mousePressPoint(QPoint)), this, 
SLOT(on_mousePressPoint(QPoint)));
       initGriphicsItems();

}

void GraphicsDemo::on_mousePressPoint(QPoint point) {

       QPointF scenePoint = ui->graphicsView->mapToScene(point);//映射场景坐标
       QGraphicsItem *item = scene->itemAt(scenePoint, 
ui->graphicsView->transform());
       if (item != NULL) {
              QPointF pointItem = item->mapFromScene(scenePoint); //图形象局部坐标

              itemLabel->setText( QString::asprintf("item Coord:%.0f,%.0f", 
pointItem.x(), pointItem.y()));

       }

}

void GraphicsDemo::on_mouseMovePoint(QPoint point) {

       viewLabel->setText(QString::asprintf("View Coord:%d,%d", point.x(), 
point.y()));

       QPointF scenePoint = ui->graphicsView->mapToScene(point); //映射场景坐标

       sceneLabel->setText(QString::asprintf("Scene Coord:%.0f,%.0f", 
scenePoint.x(), scenePoint.y()));

} 



void GraphicsDemo::initGriphicsItems() {

       QRectF rect(-200, -100, 400, 200); //左上角坐标,宽度,高度
       scene = new QGraphicsScene(rect);
       ui->graphicsView->setScene(scene);//设置场景
       QGraphicsRectItem* item = new QGraphicsRectItem(rect);
       item->setFlags(QGraphicsItem::ItemIsSelectable | 
              QGraphicsItem::ItemIsFocusable);
       QPen pen;
       pen.setWidth(2);
       item->setPen(pen);
       scene->addItem(item);
       QGraphicsEllipseItem* item2 = new QGraphicsEllipseItem(-100, -50, 200, 
100);
       item2->setPos(0, 0);
       item2->setBrush(QBrush(Qt::blue));
       item2->setFlags(QGraphicsItem::ItemIsMovable
              | QGraphicsItem::ItemIsSelectable
              | QGraphicsItem::ItemIsFocusable);//可移动
       scene->addItem(item2);

       QGraphicsEllipseItem* item3 = new QGraphicsEllipseItem(-50, -50, 100, 100);
       item3->setPos(rect.right(), rect.bottom());
       item3->setBrush(Qt::green);
       item3->setFlags(QGraphicsItem::ItemIsSelectable | //可选择
              QGraphicsItem::ItemIsFocusable | //可获取焦点
              QGraphicsItem::ItemIsMovable); //可移动
       scene->addItem(item3);
       scene->clearSelection();
}

void GraphicsDemo::resizeEvent(QResizeEvent* event)
{ //窗口变化大小时的事件
       Q_UNUSED(event);
       ui->label->setText(QString::asprintf("Graphics View coord,top left conner 
always(0,0),width=%d,height=%d",
              ui->graphicsView->width(), ui->graphicsView->height()));
       QRectF  rectF = ui->graphicsView->sceneRect(); //Scene的矩形区

       ui->label_2->setText(QString::asprintf("QGraphicsView::sceneRect=(Left,Top,Width,Height)=%.0f,%.0f,%.0f,%.0f",
              rectF.left(), rectF.top(), rectF.width(), rectF.height()));
}


(window原生界面是真丑啊)
view:setScene;Scene addItem
view 通过mapToScene将坐标转换为Scene,Scene通过mapFromScene将坐标转换到item

Qt 绘图机制

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动到顶部