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

news2024/11/25 1:34:38

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

  • 第6章 Qt5图形与图片
    • 6.1 Qt 5位置相关函数
      • 6.1.1 区别概述
      • 6.1.2 【实例】
    • 6.2 Qt 5基础图形的绘制
      • 6.2.1 绘图框架设计
      • 6.2.2 绘图区的实现
      • 6.2.3 主窗口的实现
    • 6.3 Qt 5双缓冲机制
      • 6.3.1 原理与设计
      • 6.3.2 绘图区的实现
      • 6.3.3 主窗口的实现
    • 6.4 显示Qt 5 SVG格式图片
  • 本章相关例程源码下载
    • 1.Qt5开发及实例_CH601.rar 下载
    • 2.Qt5开发及实例_CH602.rar 下载
    • 3.Qt5开发及实例_CH603.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()函数,响应对话框的移动事件,使得窗体在被移动时能够同步更新各函数的显示结果,具体代码如下:

void Geometry::moveEvent(QMoveEvent *)
{
    updateLabel();
}

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

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

#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)完成对窗体背景色的设置,与下面的代码效果一致:

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 =12016:其中,参数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()的方式实现外,还可以用如下方式实现:

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对象的形状参数,具体代码如下:

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

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

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()槽函数的具体实现代码如下:

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()槽函数的具体实现代码如下:

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()槽函数的具体实现代码如下:

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()槽函数的具体实现代码如下:

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()槽函数的具体实现代码如下:

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

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

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

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

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”文件,添加如下代码:

#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构造函数完成对窗体参数及部分功能的初始化工作,具体代码如下:

#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()函数接收主窗体传来的画笔颜色值。具体代码如下:

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

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

void DrawWidget::mousePressEvent(QMouseEvent *e)
{
    startPos = e->pos();
}

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

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

void MyWidget::paintEvent(QPaintEvent *)
{
    QPainter p;
    p.begin(this);
    p.drawLine(...); 
    p.end();
}

类似于下面的形式:

void MyWidget::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    p.drawLine(...); 
}

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

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

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

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()重绘即可。具体代码如下:

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

6.3.3 主窗口的实现

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

//添加的头文件
#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类的构造函数完成初始化工作,各个功能见注释说明,具体代码如下:

#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()函数将用户在标准颜色对话框中选择的颜色值传给绘制区。这两个函数的具体代码如下:

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”文件,添加如下代码:

#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相关的头文件:

#include <QtSvg>

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

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图片。具体代码如下:

#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对象。具体代码如下:

SvgWidget::SvgWidget(QWidget *parent):QSvgWidget(parent)
{
    render =renderer();
}

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

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”头文件,具体代码如下:

#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”文件,具体代码如下:

SvgWindow::SvgWindow(QWidget *parent):QScrollArea(parent)
{
    svgWidget =new SvgWidget;
    setWidget(svgWidget);
}

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

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

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

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

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

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”头文件,具体代码如下:

#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”文件,具体代码如下:

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

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

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进行显示,具体代码如下:

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中画折线的标签如下:

<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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1024264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker搭建DNS服务器--use

前言 DNS服务器是(Domain Name System或者Domain Name Service)域名系统或者域名服务,域名系统为Internet上的主机分配域名地址和IP地址。 安装 2.1 实验环境 IP 系统版本 角色 192.168.40.121 Ubuntu 22.10 DNS服务器 192.168.40.122 Ubuntu 22.10 测试机器 2.2 …

使用正确的命令重启WSL子系统

问题&#xff1a; 大家都知道一般Linux系统重启非常简单&#xff0c;但是在WSL子系统中执行以下两个重启命令是完全无效的。 $ reboot $ shutdown -r # 执行命令后提示如下&#xff1a; System has not been booted with systemd as init system (PID 1). Cant operate. Fail…

C# OpenCvSharp 图片模糊检测(拉普拉斯算子)

效果 项目 代码 using OpenCvSharp; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Windows.Forms.VisualStyl…

电脑屏幕实时监控软件有哪些(监控电脑操作的软件叫什么?)

随着科技的不断发展&#xff0c;人们对于电脑使用的需求也越来越高。无论是工作还是娱乐&#xff0c;我们都希望能够更加高效地利用电脑。为了满足这一需求&#xff0c;实时监控电脑屏幕软件应运而生。本文将为大家介绍几款实用的实时监控电脑屏幕软件&#xff0c;帮助大家更好…

架构问题:技术选型

1. 几款数据库特性及如何选型 1.MySQL&#xff1a;一种常用的开源关系型数据库管理系统&#xff0c;可以快速访问大量数据&#xff0c;并支持多用户同时访问。其最大的优点在于成本低&#xff0c;易于安装和配置&#xff0c;因此被广泛应用于各种中小型企业和网站。支持读写分离…

React 全栈体系(九)

第五章 React 路由 一、相关理解 1. SPA 的理解 单页 Web 应用&#xff08;single page web application&#xff0c;SPA&#xff09;。整个应用只有一个完整的页面。点击页面中的链接不会刷新页面&#xff0c;只会做页面的局部更新。数据都需要通过 ajax 请求获取, 并在前端…

软考 -- 计算机学习(2)

文章目录 一、安全性知识1.1 信息安全和信息系统安全1.2 信息安全技术1.3 网络安全技术 二、多媒体技术三、软件工程基础知识3.1 信息系统生命周期3.2 软件过程模型3.3 信息系统开发方法3.4 系统分析和设计概述3.5 结构化开发方法3.6 系统运行与维护 四、项目管理4.1 进度管理4…

(避开网上复制操作)最详细的树莓派刷机配置(含IP固定、更改国内源的避坑操作、SSH网络登录、VNC远程桌面登录)

一、准备工作 SD卡格式化 二、 树莓派系统环境搭建&#xff08;官方&#xff09; 官方镜像 1.1、 必备的配件 读卡器&#xff0c; 内存卡&#xff08;强烈推荐 32GB 内存卡&#xff0c; #lite 命令行界面版本至少需要 8G&#xff0c; 图形化带桌面版镜像需要 16GB&#xf…

Java之异常的详细解析

1. 异常 1.1 异常概念 异常&#xff0c;就是不正常的意思。在生活中:医生说,你的身体某个部位有异常,该部位和正常相比有点不同,该部位的功能将受影响.在程序中的意思就是&#xff1a; 异常 &#xff1a;指的是程序在执行过程中&#xff0c;出现的非正常的情况&#xff0c;最…

web自动化jenkins+git+allure

jenkins -- 持续集成平台 -- 持续集成的场景 -- 【持续】【集成】自动执行你的任务 --- 定时任务 -- 结果通知 -- 报告展示安装jenkins --- http://testingpai.com/article/16092251322041、工作空间 - jenkins的工作空间job任务的工作空间 -- 给任务存放数据/资料 -- 生成的…

闭着眼睛安装Neoj4版本(5.12.0 Community windows)

1.安装 Java SE 17.0.5 &#xff08;及以上&#xff0c;建议和我一样&#xff09;&#xff0c;安装完配置环境变量&#xff0c;成功标志&#xff08;cmd输出java -version的内容&#xff09; 1.上Neo4j Download Center - Graph Database & Analytics 3. 4.进入cmd &#…

tcpdump常用命令

需要安装 tcpdump wireshark ifconfig找到网卡名称 eth0, ens192... tcpdump需要root权限 网卡eth0 经过221.231.92.240:80的流量写入到http.cap tcpdump -i eth0 host 221.231.92.240 and port 80 -vvv -w http.cap ssh登录到主机查看排除ssh 22端口的报文 tcpdump -i …

Java拓展——常见数据结构(数组,栈,链表,树,图)

Java基础11——数据结构 文章目录 Java基础11——数据结构数据结构常见的数据结构数组栈栈简介如何创建一个类实现栈的功能?**栈使用场景**队列队列简介如何实现?**队列分类**链表**单链表****循环链表****双向链表****双向循环链表****链表使用场景****数组** **vs** **链表…

听GPT 讲Istio源代码--cni

在 Istio 项目中&#xff0c; cni: CNI 目录包含了 Istio CNI 插件的相关代码和配置文件。CNI&#xff08;Container Network Interface&#xff09;是一个用于配置容器网络的接口规范。Istio CNI 插件用于将 Istio 的网络功能集成到容器运行时环境中&#xff0c;以便实现对微服…

Nvidia计算卡扫盲

title: Nvidia计算卡扫盲 sidebarDepth: 4 layout: AtmLayout GPU 大的方面来讲&#xff0c; 由显存计算单元组成&#xff1b; 显存 GPU板卡上的DRAM容量大&#xff0c;速度慢&#xff0c;CPU和GPU都可以访问 计算单元 Streaming Multiprocessor,执行计算&#xff0c; 每个…

【FAQ】安防监控系统/视频云存储/监控平台EasyCVR服务器解释器出现变更该如何修改?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

开发高性能知识付费平台:关键技术策略

引言 在构建知识付费平台时&#xff0c;高性能是确保用户满意度和平台成功的关键因素之一。本文将探讨一些关键的技术策略&#xff0c;帮助开发者打造高性能的知识付费平台。 1. 前端性能优化 使用CDN加速资源加载 使用内容分发网络&#xff08;CDN&#xff09;来托管和加…

解决Office Word另存为PDF卡死的问题

今天突然间遇到这个问题&#xff0c;在网上找了好久都没有想要的答案。后来一步一步摸索终于找到了问题所在&#xff0c;希望这篇文章能帮助有同样问题的各位&#xff01; 1.问题 当word文件点击另存为PDF格式时&#xff0c;下一刻光标变为加载状态&#xff0c;并且一直在转圈…

数据结构----链式栈

目录 前言 链式栈 操作方式 1.存储结构 2.初始化 3.创建节点 4.判断是否满栈 5.判断是否空栈 6.入栈 7.出栈 8.获取栈顶元素 9.遍历栈 10.清空栈 完整代码 前言 前面我们学习过了数组栈的相关方法&#xff0c;&#xff08;链接&#xff1a;线性表-----栈&#xff08;栈…

【初阶数据结构】——堆的引入和实现二叉树

目录 前言 一、二叉树的顺序结构及实现 1.1二叉树的顺序结构 1.2堆的结构 二、堆的实现 2.1堆向上调整算法&#xff08;堆的插入&#xff09; 2.2堆向下调整算法&#xff08;堆的删除&#xff09; 2.3建堆的时间复杂度 2.4堆的创建 2.5堆的初始化和空间的销毁 2.6堆…