Qt5开发及实例V2.0-第六章Qt图形与图片

Qt5开发及实例V2.0-第六章Qt图形与图片

  • [第6章 Qt5图形与图片](#第6章 Qt5图形与图片)
    • [6.1 Qt 5位置相关函数](#6.1 Qt 5位置相关函数)
      • [6.1.1 区别概述](#6.1.1 区别概述)
      • [6.1.2 【实例】](#6.1.2 【实例】)
    • [6.2 Qt 5基础图形的绘制](#6.2 Qt 5基础图形的绘制)
      • [6.2.1 绘图框架设计](#6.2.1 绘图框架设计)
      • [6.2.2 绘图区的实现](#6.2.2 绘图区的实现)
      • [6.2.3 主窗口的实现](#6.2.3 主窗口的实现)
    • [6.3 Qt 5双缓冲机制](#6.3 Qt 5双缓冲机制)
      • [6.3.1 原理与设计](#6.3.1 原理与设计)
      • [6.3.2 绘图区的实现](#6.3.2 绘图区的实现)
      • [6.3.3 主窗口的实现](#6.3.3 主窗口的实现)
    • [6.4 显示Qt 5 SVG格式图片](#6.4 显示Qt 5 SVG格式图片)
  • 本章相关例程源码下载
    • [1.Qt5开发及实例_CH601.rar 下载](#1.Qt5开发及实例_CH601.rar 下载)
    • [2.Qt5开发及实例_CH602.rar 下载](#2.Qt5开发及实例_CH602.rar 下载)
    • [3.Qt5开发及实例_CH603.rar 下载](#3.Qt5开发及实例_CH603.rar 下载)
    • [4.Qt5开发及实例_CH604.rar 下载](#4.Qt5开发及实例_CH604.rar 下载)

第6章 Qt5图形与图片

6.1 Qt 5位置相关函数

6.1.1 区别概述

Qt提供了很多关于获取窗体位置及显示区域大小的函数,如x()、y()和pos()、rect()、size()、geometry()等,统称为"位置相关函数"或"位置函数",如图6.1所示是几种主要的位置函数,图中清楚地标出了它们之间的区别。

其中,

 x()、y()和pos()函数的作用都是获得整个窗体左上角的坐标位置。

 frameGeometry()与geometry()相对应。frameGeometry()是获得整个窗体的左上顶点和长、宽值,而geometry()函数获得的是窗体内中央区域的左上顶点坐标及长、宽值。

 直接调用width()和height()函数获得的是中央区域的长、宽值。

 rect()、size()函数获得的结果也都是对于窗体的中央区域而言的。

6.1.2 【实例】

【例】(难度一般)(CH601),设计界面,当改变对话框的大小或移动对话框时,调用各个函数所获得的信息也相应地发生变化,从变化中可得知各函数之间的区别。

实现步骤如下。

(1)新建Qt Widgets Application(详见1.3.1节),项目名称为"Geometry",基类选择"QDialog",类名命名为"Geometry",取消"创建界面"复选框的选中状态。单击"下一步"按钮,最后单击"完成"按钮,完成该项目工程的建立。

(2)Geometry类继承自QDialog类,在头文件中声明所需的控件(主要为QLabel类)及所需要的函数。

打开"geometry.h"头文件,添加如下代码。

(3)在构造函数中完成控件的创建以及初始化工作,打开"geometry.cpp"文件,添加如下代码。

updateLabel()函数完成获得各位置函数的信息并显示功能,具体代码。

重新定义QWidget的moveEvent()函数,响应对话框的移动事件,使得窗体在被移动时能够同步更新各函数的显示结果,具体代码如下:

c 复制代码
void Geometry::moveEvent(QMoveEvent *)
{
    updateLabel();
}

重新定义QWidget的resizeEvent()函数,响应对话框的大小调整事件,使得在窗体大小发生改变时,也能够同步更新各函数的显示结果,具体代码如下:

c 复制代码
void Geometry::resizeEvent(QResizeEvent *)
{
    updateLabel();
}

(4)运行程序,效果如图6.2所示。

6.2 Qt 5基础图形的绘制

6.2.1 绘图框架设计

绘制各种基础图形使用的框架实例如图6.3所示。

此实例的具体实现包含了两个部分的内容:一个是用于画图的区域PaintArea类,另一个是主窗口MainWidget类,如图6.4所示。

实现步骤如下。

(1)新建Qt Widgets Application(详见1.3.1节),项目名称为"PaintEx",基类选择"QWidget",类名命名为"MainWidget",取消"创建界面"复选框的选中状态。单击"下一步"按钮,最后单击"完成"按钮,完成该项目工程的建立。

(2)添加该工程的提供实现绘图区的函数所在的文件,在"PaintEx"项目名上单击鼠标右键,在弹出的快捷菜单中选择"添加新文件..."菜单项,在弹出的对话框中选择"C++ Class"选项。单击"Choose..."按钮,弹出对话框,在"Base class"后面的下拉列表框中选择基类名"QWidget",在"Class name"后面的文本框中输入类的名称"PaintArea"。

(3)单击"下一步"按钮,单击"完成"按钮,添加文件"paintarea.h"和文件"paintarea.cpp"完毕。

6.2.2 绘图区的实现

打开"paintarea.h"头文件,添加如下代码。

PaintArea类的构造函数用于完成初始化工作,设置图形显示区域的背景色及最小显示尺寸,具体代码如下:

c 复制代码
#include "paintarea.h"
#include <QPainter>
PaintArea::PaintArea(QWidget *parent):QWidget(parent)
{
    setPalette(QPalette(Qt::white));
    setAutoFillBackground(true);
    setMinimumSize(400,400);
}

其中,setPalette(QPalette(Qt::white))、setAutoFillBackground(true)完成对窗体背景色的设置,与下面的代码效果一致:

c 复制代码
QPalette  p = palette();
p.setColor(QPalette::Window,Qt::white);
setPalette(p);

setShape()函数可以设置形状,setPen()函数可以设置画笔,setBrush()函数可以设置画刷,setFillRule()函数可以设置填充模式,具体代码实现。

PaintArea类的重画函数代码。

其中,

(a) QRect rect(50,100,300,200):设定一个方形区域,为画长方形、圆角方形、椭圆等做准备。

(b) static const QPoint points[4]={...}:创建一个QPoint的数组,包含四个点,为画多边形、多边线及点做准备。

© int startAngle=3016、int spanAngle =120 16:其中,参数startAngle表示起始角,为弧形的起始点与圆心之间连线与水平方向的夹角;参数spanAngle表示的是跨度角,为弧形起点、终点分别与圆心连线之间的夹角,如图6.5所示。

(d) switch(shape){...}:使用一个switch()语句,对所要画的形状做判断,调用QPainter的各个draw()函数完成图形的绘制。

(1)利用QPainter绘制图形(Shape)。

Qt为开发者提供了丰富的绘制基本图形的draw函数,如图6.6所示。

(2)利用QPainterPath绘制简单图形。

利用QPainterPath绘制简单图形,QPainterPath类为QPainter类提供了一个存储容器,里面包含了所要绘制的内容的集合及绘制的顺序,如长方形、多边形、曲线等各种任意图形。当需要绘制此预先存储在QPainterPath对象中的内容时,只需调用QPainter类的drawPath()函数即可。

QPainterPath对象的当前点自动处在上一部分图形内容的结束点上,若下一部分图形的起点不在此结束点,则需调用moveTo()函数将当前点移动到下一部分图形的起点。

cubicTo()函数绘制的是贝赛尔曲线,如图6.7所示。

利用QPainterPath类可以实现QPainter类的draw()函数能够实现的所有图形。例如,对于QPainter::drawRect()函数,除了可用上面介绍的QPainterPath::addRect()的方式实现外,还可以用如下方式实现:

c 复制代码
QPainterPath path;
path.moveTo(0,0);
path.lineTo(200,0);
path.lineTo(200,100);
path.lineTo(0,100);
path.lineTo(0,0);

这是一个更通用的方法,其他(如多边形等)图形都能够使用这种方式实现。

6.2.3 主窗口的实现

打开"mainwidget.h"头文件,添加如下代码。

MainWiget类的构造函数中创建了各参数选择控件,打开"mainwiget.cpp"文件,添加如下代码。

其中,

(a) shapeComboBox->addItem(tr("Line"),PaintArea::Line):QComboBox的addItem()函数可以仅插入文本,也可同时插入与文本相对应的具体数据,通常为枚举型数据,便于后面操作时确定选择的是哪个数据。

(b) penStyleComboBox->addItem(tr("SolidLine"),static_cast(Qt::SolidLine)):选用不同的参数,对应画笔的不同风格,如图6.8所示。

© penCapComboBox->addItem(tr("SquareCap"),Qt::SquareCap):选用不同的参数,对应画笔顶帽的不同风格,如图6.9所示。

(d) penJoinComboBox->addItem(tr("BevelJoin"),Qt::BevelJoin):选用不同的参数,对应画笔连接点的不同风格,如图6.10所示。

(e) fillRuleComboBox->addItem(tr("Odd Even"),Qt::OddEvenFill):Qt为QPainterPath类提供了两种填充规则,分别是Qt::OddEvenFill和Qt::WindingFill,如图6.11所示。

其中,Qt::OddEvenFill填充规则判断的依据是从图形中某一点画一条水平线到图形外。若这条水平线与图形边线的交点数目为奇数,则说明此点位于图形的内部;若交点数目为偶数,则此点位于图形的外部,如图6.12所示。

而Qt::WindingFill填充规则的判断依据则是从图形中某一点画一条水平线到图形外,每个交点外边线的方向可能向上,也可能向下,将这些交点数累加,方向相反的相互抵消,若最后结果不为0则说明此点在图形内,若最后结果为0则说明在图形外,如图6.13所示。

(f) spreadComboBox->addItem(tr("PadSpread"),QGradient::PadSpread):铺展效果有三种,分别为QGradient::PadSpread、QGradient::RepeatSpread和QGradient:: ReflectSpread。其中,PadSpread是默认的铺展效果,也是最常见的铺展效果,没有被渐变覆盖的区域填充单一的起始颜色或终止颜色;RepeatSpread效果与ReflectSpread效果只对线性渐变和圆形渐变起作用,如图6.14所示。

(g)brushStyleComboBox->addItem(tr("SolidPattern"),static_cast(Qt::Solid Pattern)):选用不同的参数,对应画刷的不同风格,如图6.15所示。

ShowShape()槽函数,根据当前下拉列表框中选择的选项,调用PaintArea类的setShape()函数设置PaintArea对象的形状参数,具体代码如下:

c 复制代码
void MainWidget::ShowShape(int value)
{
    PaintArea::Shape shape = PaintArea::Shape(shapeComboBox->itemData(
            value,Qt::UserRole).toInt());
    paintArea->setShape(shape);
}

在此函数中获得与画笔相关的所有属性值,包括画笔颜色、画笔线宽、画笔风格、画笔顶帽及画笔连接点,共同构成QPen对象,并调用PaintArea对象的setPen()函数设置PaintArea对象的画笔属性。其他与画笔参数相关的响应函数完成的工作与此类似,具体代码如下:

c 复制代码
void MainWidget::ShowPenColor()
{
    QColor color = QColorDialog::getColor(static_cast<int>(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));
}

ShowPenWidth()槽函数的具体实现代码如下:

c 复制代码
void MainWidget::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));
}

ShowPenStyle()槽函数的具体实现代码如下:

c 复制代码
void MainWidget::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));
}

ShowPenCap()槽函数的具体实现代码如下:

c 复制代码
void MainWidget::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));
}

ShowPenJoin()槽函数的具体实现代码如下:

c 复制代码
void MainWidget::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));
}

ShowFillRule()槽函数的具体实现代码如下:

c 复制代码
void MainWidget::ShowFillRule()
{
    Qt::FillRule rule = Qt::FillRule(fillRuleComboBox->itemData(
    fillRuleComboBox->currentIndex(),Qt::UserRole).toInt());
    paintArea->setFillRule(rule);
}

ShowSpreadStyle()槽函数的具体实现代码如下:

c 复制代码
void MainWidget::ShowSpreadStyle()
{
    spread = QGradient::Spread(spreadComboBox->itemData(
        spreadComboBox->currentIndex(),Qt::UserRole).toInt());
}

ShowBrushColor()槽函数,与设置画笔颜色函数类似,但选定颜色后并不直接调用PaintArea对象的setBrush()函数,而是调用ShowBrush()函数设置显示区的画刷属性,

实现代码如下:

c 复制代码
void MainWidget::ShowBrushColor()
{
    QColor color = QColorDialog::getColor(static_cast<int>(Qt:: blue));
    brushColorFrame->setPalette(QPalette(color));
    ShowBrush(brushStyleComboBox->currentIndex());
}

ShowBrush()槽函数的具体实现代码。

其中,

(a) Qt::BrushStyle style = Qt::BrushStyle(brushStyleComboBox->itemData (value, Qt::UserRole).toInt()):获得所选的画刷风格,若选择的是渐变或者纹理图案,则需要进行一定的处理。

(b) 主窗口的style变量值为Qt:: LinearGradientPattern时,表明选择的是线形渐变。

© 主窗口的style变量值为Qt:: RadialGradientPattern时,表明选择的是圆形渐变。

(d) 主窗口的style变量值为Qt:: ConicalGradientPattern时,表明选择的是锥形渐变。

QConicalGradient conicalGradient(startPoint,-(180*angle)/PI)创建锥形渐变类对象需要两个参数,分别是锥形的顶点位置和渐变分界线与水平方向的夹角,如图6.16所示。

打开"main.cpp"文件,添加如下代码:

c 复制代码
#include "mainwidget.h"
#include <QApplication>
#include <QFont>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QFont f("ZYSong18030",12);
    a.setFont(f);
    MainWidget w;
    w.show();
    return a.exec();
}

运行程序,程序显示效果如图6.17所示。

6.3 Qt 5双缓冲机制

6.3.1 原理与设计

【例】(难度中等)(CH603)实现一个简单的绘图工具,可以选择线型、线宽及颜色等基本要素,如图6.18所示。

QMainWindow对象作为主窗口,QToolBar对象作为工具栏,QWidget对象作为主窗口的中央窗体centralWidget,也就是绘图区,如图6.19所示。

实现步骤如下

(1)新建Qt Widgets Application (详见1.3.1节),项目名称为"DrawWidget",基类选择"QMainWindow",类名命名默认为"MainWindow",取消"创建界面"复选框的选中状态。单击"下一步"按钮,最后单击"完成"按钮,完成该项目工程的建立。

(2)添加该工程的提供实现绘图区的函数所在的文件。在"DrawWidget"项目名上单击鼠标右键,在弹出的快捷菜单中选择"添加新文件..."菜单项,在弹出的对话框中选择"C++ Class"选项。单击"Choose..."按钮,弹出对话框,在"Base class"后面的下拉列表框中选择基类名"QWidget",在"Class name"后面的文本框中输入类的名称"DrawWidget"。

(3)单击"下一步"按钮,单击"完成"按钮,添加文件"drawwidget.h"和文件"drawwidget.cpp"。

6.3.2 绘图区的实现

(1)打开"drawwidget.h"头文件,添加的代码。

(2)打开"drawwidget.cpp"文件,DrawWidget构造函数完成对窗体参数及部分功能的初始化工作,具体代码如下:

c 复制代码
#include "drawwidget.h"    
#include <QtGui>
#include <QPen>
DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent)
{
    setAutoFillBackground(true);    	//对窗体背景色的设置
    setPalette(QPalette(Qt::white));
    pix =new QPixmap(size()); 	//此QPixmap对象用来准备随时接收绘制的内容
    pix->fill(Qt::white);            	//填充背景色为白色
    setMinimumSize(600,400);      	//设置绘制区窗体的最小尺寸
}

setStyle()函数接收主窗体传来的线型风格参数,setWidth()函数接收主窗体传来的线宽参数值,setColor()函数接收主窗体传来的画笔颜色值。具体代码如下:

c 复制代码
void DrawWidget::setStyle(int s)
{
    style = s;
}
void DrawWidget::setWidth(int w)
{
    weight = w;
}
void DrawWidget::setColor(QColor c)
{
    color = c;
}

重定义鼠标按下事件mousePressEvent(),在按下鼠标时,记录当前的鼠标位置值startPos。

c 复制代码
void DrawWidget::mousePressEvent(QMouseEvent *e)
{
    startPos = e->pos();
}

QWidget的mouseTracking属性指示窗体是否追踪鼠标,默认为false(不追踪),即在至少有一个鼠标按键按下的前提下移动鼠标才触发mouseMoveEvent()事件,可以通过setMouseTracking(bool enable)方法对该属性值进行设置。如果设置为追踪,则无论是否有鼠标按键按下,只要鼠标移动,就会触发mouseMoveEvent()事件。在此事件处理函数中,完成向QPixmap对象中绘图的工作。具体代码。

下面是使用begin()和end()的一个例子:

c 复制代码
void MyWidget::paintEvent(QPaintEvent *)
{
    QPainter p;
    p.begin(this);
    p.drawLine(...); 
    p.end();
}

类似于下面的形式:

c 复制代码
void MyWidget::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    p.drawLine(...); 
}

重画函数paintEvent()完成绘制区窗体的更新工作,只需调用drawPixmap()函数将用于接收图形绘制的QPixmap对象绘制在绘制区窗体控件上即可。具体代码如下:

c 复制代码
void DrawWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.drawPixmap(QPoint(0,0),*pix);
}

调整绘制区大小函数resizeEvent(),当窗体的大小发生改变时,效果看起来虽然像是绘制区大小改变了,但实际能够进行绘制的区域仍然没有改变。因为绘图的大小并没有改变,还是原来绘制区窗口的大小,所以在窗体尺寸变化时应及时调整用于绘制的QPixmap对象的大小。具体代码如下:

c 复制代码
void DrawWidget::resizeEvent(QResizeEvent *event)
{
    if(height()>pix->height()||width()>pix->width())	//(a)
    {
        QPixmap *newPix = new QPixmap(size());	//创建一个新的QPixmap对象
        newPix->fill(Qt::white);	 //填充新QPixmap对象newPix的颜色为白色背景色
        QPainter p(newPix);
        p.drawPixmap(QPoint(0,0),*pix);	   //在newPix中绘制原pix中的内容
        pix = newPix;	  	   //将newPix赋值给pix作为新的绘制图形接收对象
    }
    QWidget::resizeEvent(event);			//完成其余的工作
}

clear()函数完成绘制区的清除工作,只需调用一个新的、干净的QPixmap对象来代替pix,并调用update()重绘即可。具体代码如下:

c 复制代码
void DrawWidget::clear()
{
    QPixmap *clearPix =new QPixmap(size());
    clearPix->fill(Qt::white);
    pix = clearPix;
    update();
}

6.3.3 主窗口的实现

(1)打开"mainwindow.h"文件,添加如下代码:

c 复制代码
//添加的头文件
#include <QToolButton>
#include <QLabel>
#include <QComboBox>
#include <QSpinBox>
#include "drawwidget.h"
class MainWindow : public QMainWindow
{    
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void createToolBar();
public slots:
    void ShowStyle();
    void ShowColor();
private:
    DrawWidget *drawWidget;
    QLabel *styleLabel;
    QComboBox *styleComboBox;
    QLabel *widthLabel;
    QSpinBox *widthSpinBox;
    QToolButton *colorBtn;
    QToolButton *clearBtn;
};

(2)打开"mainwindow.cpp"文件,MainWindow类的构造函数完成初始化工作,各个功能见注释说明,具体代码如下:

c 复制代码
#include "mainwindow.h"
#include <QToolBar>
#include <QColorDialog>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    drawWidget =new DrawWidget; 	//新建一个DrawWidget对象
    setCentralWidget(drawWidget);	//新建的DrawWidget对象作为主窗口的中央窗体
    createToolBar();               	//实现一个工具栏
    setMinimumSize(600,400);      	//设置主窗口的最小尺寸
    ShowStyle();           		//初始化线型,设置控件中的当前值作为初始值
    drawWidget->setWidth(widthSpinBox->value()); 	//初始化线宽
    drawWidget->setColor(Qt::black);             		//初始化颜色
}

createToolBar()函数完成工具栏的创建。

改变线型参数的槽函数ShowStyle(),通过调用DrawWidget类的setStyle()函数将当前线型选择控件中的线型参数传给绘制区;设置画笔颜色的槽函数ShowColor(),通过调用DrawWidget类的setColor()函数将用户在标准颜色对话框中选择的颜色值传给绘制区。这两个函数的具体代码如下:

c 复制代码
void MainWindow::ShowStyle()
{    
    drawWidget->setStyle(styleComboBox->itemData(
        styleComboBox->currentIndex(),Qt::UserRole).toInt());
}
void MainWindow::ShowColor()
{
    QColor color = QColorDialog::getColor(static_cast<int> (Qt::black), this);
	//使用标准颜色对话框QColorDialog获得一个颜色值
    if(color.isValid())
    {
	   //将新选择的颜色传给绘制区,用于改变画笔的颜色值
        drawWidget->setColor(color);	
        QPixmap p(20,20);
        p.fill(color);
        colorBtn->setIcon(QIcon(p));		//更新颜色选择按钮上的颜色显示
    }
}

(3)打开"main.cpp"文件,添加如下代码:

c 复制代码
#include <QFont>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QFont font("ZYSong18030",12);
    a.setFont(font);
    MainWindow w;
    w.show();
    return a.exec();
}

(4)运行程序,显示效果如图6.18所示。

6.4 显示Qt 5 SVG格式图片

SVG格式的特点如下。

(1)基于XML。

(2)采用文本来描述对象。

(3)具有交互性和动态性。

(4)完全支持DOM。

【例】(难度一般)(CH604)通过利用QSvgWidget类和QSvgRender类实现一个SVG图片浏览器,显示以".svg"结尾的文件以介绍SVG格式图片显示的方法,如图6.20所示。

此实例由三个层次的窗体构成,如图6.21所示。

在完成此功能的程序中使用与SVG相关的类,必须在程序中包含SVG相关的头文件:

c 复制代码
#include <QtSvg>

由于Qt默认生成的Makefile中只加入了QtGui、QtCore模块的库,所以必须在工程文件".pro"中加入一行代码:

c 复制代码
QT += svg

这样才可在编译时加入QtSvg的库。

实现步骤如下。

(1)新建Qt Widgets Application(详见1.3.1节),项目名称为"SVGTest",基类选择"QMainWindow",类名命名默认为"MainWindow",取消"创建界面"复选框的选中状态。单击"下一步"按钮,最后单击"完成"按钮,完成该项目工程的建立。

(2)下面添加该工程的提供实现一个带滚动条显示区域的函数所在的文件。在"SVGTest"项目名上单击鼠标右键,在弹出的快捷菜单中选择"添加新文件..."菜单项,在弹出的对话框中选择"C++ Class"选项。单击"Choose..."按钮,弹出对话框,在"Base class"后面的文本框中输入基类名"QScrollArea"(手工添加),在"Class name"后面的文本框中输入类的名称"SvgWindow"。

(3)单击"下一步"按钮,单击"完成"按钮,添加文件"svgwindow.h"和文件"svgwindow.cpp"。

(4)添加该工程的提供实现显示SVG图片的函数所在的文件。在"SVGTest"项目名上单击鼠标右键,在弹出的快捷菜单中选择"添加新文件..."菜单项,在弹出的对话框中选择"C++ Class"选项。单击"Choose..."按钮,弹出对话框。在"Base class"后面的文本框中输入基类名"QSvgWidget"(手工添加),在"Class name"后面的文本框中输入类的名称"SvgWidget"。

(5)单击"下一步"按钮,单击"完成"按钮,添加文件"svgwidget.h"和文件"svgwidget.cpp"。

(6)打开"svgwidget.h"头文件。SvgWidget类继承自QSvgWidget类,主要显示SVG图片。具体代码如下:

c 复制代码
#include <QtSvg>
#include <QSvgWidget>
#include <QSvgRenderer>
class SvgWidget : public QSvgWidget
{
    Q_OBJECT
public:
    SvgWidget(QWidget *parent=0);
    void wheelEvent(QWheelEvent *);
//响应鼠标的滚轮事件,使SVG图片能够通过鼠标滚轮的滚动进行缩放
private:
    QSvgRenderer *render; 	        //用于图片显示尺寸的确定
};

(7)打开"svgwidget.cpp"文件,SvgWidget构造函数,获得本窗体的QSvgRenderer对象。具体代码如下:

c 复制代码
SvgWidget::SvgWidget(QWidget *parent):QSvgWidget(parent)
{
    render =renderer();
}

以下是鼠标滚轮的响应事件,使SVG图片能够通过鼠标滚轮的滚动进行缩放。具体代码如下:

c 复制代码
void SvgWidget::wheelEvent(QWheelEvent *e)
{	
    	const double diff=0.1;				//(a)
    	QSize size =render->defaultSize();			//(b)
    	int width =size.width();
    	int height =size.height();
    	if(e->delta()>0) 					//(c)
    	{
        //对图片的长、宽值进行处理,放大一定的比例
        width =int(this->width()+this->width()*diff);
        height =int(this->height()+this->height()*diff);
    	}
    	else
    	{
	   //对图片的长、宽值进行处理,缩小一定的比例
        width =int(this->width()-this->width()*diff);
        height =int(this->height()-this->height()*diff);
    	}
    	resize(width,height);	//利用新的长、宽值对图片进行resize()操作
}

(8)SvgWindow类继承自QScrollArea类,是一个带滚动条的显示区域。在SvgWindow实现中包含SvgWidget类的头文件。使图片在放大到超过主窗口大小时,能够通过拖曳滚动条的方式进行查看。

打开"svgwindow.h"头文件,具体代码如下:

c 复制代码
#include <QScrollArea>
#include "svgwidget.h"
class SvgWindow : public QScrollArea
{
    Q_OBJECT
public:
    SvgWindow(QWidget *parent=0);
    void setFile(QString);
    void mousePressEvent(QMouseEvent *);
    void mouseMoveEvent(QMouseEvent *);
private:
    SvgWidget *svgWidget;
    QPoint mousePressPos;
    QPoint scrollBarValuesOnMousePress;
};

(9)SvgWindow类的构造函数,构造SvgWidget对象,并调用QScrollArea类的setWidget()函数设置滚动区的窗体,使svgWidget成为SvgWindow的子窗口。

打开"svgwindow.cpp"文件,具体代码如下:

c 复制代码
SvgWindow::SvgWindow(QWidget *parent):QScrollArea(parent)
{
    svgWidget =new SvgWidget;
    setWidget(svgWidget);
}

当主窗口中对文件进行了选择或修改时,将调用setFile()函数设置新的文件,具体代码如下:

c 复制代码
void SvgWindow::setFile(QString fileName)
{
    svgWidget->load(fileName);						//(a)
    QSvgRenderer *render =svgWidget->renderer();
    svgWidget->resize(render->defaultSize());		//(b)
}

鼠标键按下时,对mousePressPos和scrollBarValuesOnMousePress进行初始化,QScrollArea类的horizontalScrollBar()和verticalScrollBar()函数可以分别获得svgWindow的水平滑动条和垂直滑动条。具体代码如下:

c 复制代码
void SvgWindow::mousePressEvent(QMouseEvent *event)
{
    mousePressPos =event->pos();
    scrollBarValuesOnMousePress.rx()=horizontalScrollBar()->value();
    scrollBarValuesOnMousePress.ry()=verticalScrollBar()->value();
    event->accept();
}

当鼠标键按下并拖曳鼠标时触发mouseMoveEvent()函数,通过滑动条的位置设置实现图片拖曳的效果,具体代码如下:

c 复制代码
void SvgWindow::mouseMoveEvent(QMouseEvent *event)
{
    horizontalScrollBar()->setValue(scrollBarValuesOnMousePress.x()-                                      event->pos().x()+mousePressPos.x());		//对水平滑动条的新位置进行设置
    verticalScrollBar()->setValue(scrollBarValuesOnMousePress.y()-
event->pos().y()+mousePressPos.y());	//对垂直滑动条的新位置进行设置
    horizontalScrollBar()->update();
    verticalScrollBar()->update();
    event->accept();
}

(10)主窗口MainWindow继承自QMainWindow类,包含一个菜单栏,其中有一个"文件"菜单条,包含一个"打开"菜单项。打开"mainwindow.h"头文件,具体代码如下:

c 复制代码
#include <QMainWindow>
#include "svgwindow.h"
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void createMenu();
public slots:
    void slotOpenFile();
private:
    SvgWindow *svgWindow; 		//用于调用相关函数传递选择的文件名
};

(11)在MainWindow构造函数中,创建一个SvgWindow对象作为主窗口的中央窗体。打开"mainwindow.cpp"文件,具体代码如下:

c 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle(tr("SVG Viewer"));
    createMenu();
    svgWindow =new SvgWindow;
    setCentralWidget(svgWindow);
}

创建菜单栏,具体代码如下:

c 复制代码
void MainWindow::createMenu()
{
    QMenu *fileMenu =menuBar()->addMenu(tr("文件"));
    QAction *openAct =new QAction(tr("打开"),this);
    connect(openAct,SIGNAL(triggered()),this,SLOT(slotOpenFile()));
    fileMenu->addAction(openAct);
}

通过标准文件对话框选择SVG文件,并调用SvgWindow的setFile()函数将选择的文件名传递给svgWindow进行显示,具体代码如下:

c 复制代码
void MainWindow::slotOpenFile()
{
    QString name =QFileDialog::getOpenFileName(this,
                      "打开","/","svg files(*.svg)");
    svgWindow->setFile(name);
}

(12)运行程序,打开一张SVG图片,查看预览效果,如图6.20所示。

XML

文档对象模型(Document Object Model,DOM)是W3C开发的独立于平台和语言的接口,它可以使程序和脚本动态地存取和更新XML文档的内容、结构和风格。

DOM在内存中将XML文件表示为一棵树,用户通过API可以随意地访问树的任意节点内容。在Qt中,XML文档自身用QDomDocument表示,所有的节点类都从QDomNode继承。

SVG文件是利用XML表示的矢量图形文件,每种图形都用XML标签表示。例如,在SVG中画折线的标签如下:

c 复制代码
<polyline fill="none" stroke="#888888" stroke-width="2" points="100, 200, 100,100"/>

其中,

 polyline:表示绘制折线。

 fill:属性表示填充。

 stroke:表示画笔颜色。

 stroke-width:表示画笔宽度。

 points:表示折线的点。



本章相关例程源码下载

1.Qt5开发及实例_CH601.rar 下载

Qt5开发及实例_CH601.rar

2.Qt5开发及实例_CH602.rar 下载

Qt5开发及实例_CH602.rar

3.Qt5开发及实例_CH603.rar 下载

Qt5开发及实例_CH603.rar

4.Qt5开发及实例_CH604.rar 下载

Qt5开发及实例_CH604.rar

相关推荐
带刺的坐椅13 分钟前
老码农教你:Solon + EasyExcel 导出工具
java·excel·solon·easyexcel
迷知悟道23 分钟前
java面向对象的四大核心特征之继承---超详细(保姆级)
java
lixn24 分钟前
深入理解JVM字节码:invokedynamic
java·jvm
数据智能老司机27 分钟前
探索Java 全新的线程模型——结构化并发
java·性能优化·架构
数据智能老司机28 分钟前
探索Java 全新的线程模型——作用域值
java·性能优化·架构
数据智能老司机30 分钟前
探索Java 全新的线程模型——并发模式
java·性能优化·架构
何中应34 分钟前
分布式事务的两种解决方案
java·分布式·后端
数据智能老司机36 分钟前
探索Java 全新的线程模型——虚拟线程
java·性能优化·架构
TDengine (老段)1 小时前
TDengine IDMP 运维指南(管理策略)
大数据·数据库·物联网·ai·时序数据库·tdengine·涛思数据
byte轻骑兵1 小时前
【Linux文件系统】Linux文件系统与设备驱动
linux·运维·服务器