Qt学习:图形视图框架的使用

文章目录

  • 前言
  • 一、场景、视图和图形项的介绍
  • 二、图形视图框架的坐标系统
  • 三、图形视图框架的事件处理
  • 四、示例完整代码
  • 五、QtCreator官方示例
  • 总结


前言

近期重温了一下Qt中的图形视图框架,这里将所学习的内容进行记录总结。这个框架提供了一个基于图形项的模型视图编程方法,主要有场景、视图和图形项三部分组成,下面结合示例进行展示,希望可以帮助到大家,如有错误之处,欢迎大家批评指正。

项目效果
请添加图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、场景、视图和图形项的介绍

图形视图框架由以下三个部分组成:场景QGraphicsScene视图QGraphicsView图形项QGraphicsItem

QGraphicsScene:该类提供了图形视图框架中的场景,是图形项对象的容器,拥有以下功能
1.提供用于管理大量图形项的高速接口
2.传播事件到每一个图形项
3.管理图形项的状态,比如选择和处理焦点
4.提供无变换的渲染功能,主要用于打印

QGraphicsView:该类提供了视图部件,用来显示场景中的内容
1.可以连接多个视图到同一个场景,为相同的数据集提供多个视口
2.视图部件是一个可滚动的区域,提供了一个滚动条来浏览大的场景
3.通过setDragMode(QGraphicsView::ScrollHandDrag)将光标变为手掌形状,可以拖动场景
4.通过setDragMode(QGraphicsView::RubberBandDrag)实现鼠标拖出矩形框来选择场景中的图形项
5.通过setViewport()设置QOpenGLWidget作为视口,使用OpenGL进行渲染

QGraphicsItem:该类是场景中图形项的基类,在图形视图框架中有提供一些典型形状的图形项
1.鼠标按下、移动、释放、双击、悬停、滚轮和右键菜单事件
2.键盘输入焦点和键盘事件
3.拖放事件
4.使用QGraphicsItemGroup实现分组
5.碰撞检测

二、图形视图框架的坐标系统

图形视图框架中有三个有效的坐标系统:场景坐标视图坐标图形项坐标,这三个坐标系统可以通过特定函数进行坐标映射

场景坐标:场景坐标是所有图形项的基础坐标系统,其原点在场景的中心,x和y坐标分别向右和向下增大
视图坐标:视图坐标就是视图部件的坐标,原点在QGraphicsView视口的左上角,x和y坐标分别向右和向下增大
图形项坐标:图形项使用自己的本地坐标系统,坐标通常是以它们的中心为原点(0,0),而这也是所有变换的中心
坐标映射:实现坐标变换,不仅可以在视图、场景和图形项之间使用坐标映射,还可以在父子图形项等之间进行映射:
这里是坐标映射函数表格:
请添加图片描述

可以将我的示例中的pro文件内容修改为下面这样,来运行示例1,通过查看打印结果,直观的了解各坐标系统

#条件编译
DEFINES += EXAMPLE_1
#DEFINES += EXAMPLE_2

三、图形视图框架的事件处理

图形视图框架中的事件都是先由视图进行接收,然后传递给场景,再由场景传递给相应的图形项

1.键盘事件和图形效果:这里对图形项的键盘按下事件进行处理,并为图形项添加图形效果

//键盘按下事件处理,移动图形项
void MyItem::keyPressEvent(QKeyEvent *event)
{switch(event->key()){//移动图形项case Qt::Key_Up:   //上移{moveBy(0,-10);break;}case Qt::Key_Down:   //下移{moveBy(0,10);break;}case Qt::Key_Left:   //左移{moveBy(-10,0);break;}case Qt::Key_Right:   //右移{moveBy(10,0);break;}//添加图形效果case Qt::Key_1:   //模糊效果{QGraphicsBlurEffect *blurEffect = new QGraphicsBlurEffect;blurEffect->setBlurHints(QGraphicsBlurEffect::QualityHint);blurEffect->setBlurRadius(8);setGraphicsEffect(blurEffect);break;}case Qt::Key_2:   //染色效果{QGraphicsColorizeEffect *ColorizeEffect = new QGraphicsColorizeEffect;ColorizeEffect->setColor(Qt::white);ColorizeEffect->setStrength(0.6);setGraphicsEffect(ColorizeEffect);break;}case Qt::Key_3:   //阴影效果{QGraphicsDropShadowEffect *dropShadowEffect = new QGraphicsDropShadowEffect;dropShadowEffect->setColor(QColor(63,63,63,100));dropShadowEffect->setBlurRadius(2);dropShadowEffect->setXOffset(10);setGraphicsEffect(dropShadowEffect);break;}case Qt::Key_4:   //透明效果{QGraphicsOpacityEffect *opacityEffect = new QGraphicsOpacityEffect;opacityEffect->setOpacity(0.4);setGraphicsEffect(opacityEffect);break;}case Qt::Key_5:   //取消图形项的图形效果graphicsEffect()->setEnabled(false);break;}
}

2.鼠标悬停效果:设置鼠标悬停在图形项上面时的光标外观和提示

//悬停事件处理,设置光标外观和提示
void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *)
{setCursor(Qt::OpenHandCursor);setToolTip(QString("我是%1号图形项").arg(m_id));
}

3.鼠标移动事件和右键菜单:实现用鼠标拖动图形项,并为图形项添加一个右键菜单

//鼠标移动事件处理,获得焦点并改变光标外观
void MyItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{setFocus();setCursor(Qt::ClosedHandCursor);//鼠标拖动设置图形项的场景坐标//QPointF scenePos = mapToScene(event->pos());//setPos(scenePos);//直接用这一句顶上面两句QGraphicsItem::mouseMoveEvent(event);
}//右键菜单事件处理,为图形项添加一个右键菜单
void MyItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{QMenu menu;QAction *viewAction = menu.addAction("移动到视图原点");QAction *sceneAction = menu.addAction("移动到场景原点");QAction *selectedAction = menu.exec(event->screenPos());if(selectedAction == viewAction){setPos(-200,-150);   //与main函数中设置的场景矩形原点一致}else if(selectedAction == sceneAction){setPos(0,0);}
}

4.动画
(1)使用QPropertyAnimation类来为图形项的某属性创建动画

int main(int argc,char *argv[])
{...//为图形项的rotation属性创建动画MyItem *item_111 = new MyItem;item_111->setId(111);item_111->setColor(Qt::yellow);item_111->setPos(15,50);scene.addItem(item_111);QPropertyAnimation *animation = new QPropertyAnimation(item_111,"rotation");animation->setDuration(2000);animation->setStartValue(0);animation->setEndValue(360);animation->start(QAbstractAnimation::DeleteWhenStopped);...
}

(2)使用QGraphicsScene::advance()来推进场景

int main(int argc,char *argv[])
{...//创建定时器调用场景的advance()函数,并且会自动调用所有图形项的advance()函数QTimer timer;QObject::connect(&timer,&QTimer::timeout,&scene,&QGraphicsScene::advance);//timer.start(300);...
}//动画处理
void MyItem::advance(int phase)
{//第一个阶段不进行处理if(!phase){return;}//图形项向不同方向随机移动int value = qrand() % 100;if(value < 25){setRotation(45);moveBy(qrand() % 10,qrand() % 10);}else if(value < 50){setRotation(-45);moveBy(-qrand() % 10,-qrand() % 10);}else if(value < 75){setRotation(30);moveBy(-qrand() % 10,qrand() % 10);}else{setRotation(-30);moveBy(qrand() % 10,-qrand() % 10);}
}

5.碰撞检测
(1)重新实现使用QGraphicsItem::shape()函数来返回图形项准确的形状,结合碰撞判断函数使用
(2)重新实现collidesWithItem()函数来提供一个自定义的图形项碰撞算法

QGraphicsItem类中提供了下面这些碰撞判断函数:
collidesWithItem()来判断是否与指定的图形项进行了碰撞
collidesWithPath()来判断是否与指定的路径碰撞
collidingItems()来获取与该图形项碰撞的所有图形项的列表
这几个函数都有一个Qt::ItemSelectionMode参数来指定怎样进行图形项的选取,默认值是Qt::IntersectsItemShape
请添加图片描述

下面对第一种方式进行代码展示

//返回图形项对应的形状
QPainterPath MyItem::shape() const
{QPainterPath path;path.addRect(-10,-10,20,20);return path;
}//执行实际的绘图操作
void MyItem::paint(QPainter *painter,const QStyleOptionGraphicsItem *,QWidget *)
{if(hasFocus() || !collidingItems().isEmpty())   //是否获得焦点或者有碰撞{painter->setPen(QPen(QColor(255,255,255,200)));}else{painter->setPen(QPen(QColor(100,100,100,100)));}painter->setBrush(m_brushColor);painter->drawRect(-10,-10,20,20);
}

6.图形项组:QGraphicsItemGroup图形项组为图形项提供了一个容器,下面代码对其使用进行了展示

int main(int argc,char *argv[])
{...//创建图形项组MyItem *item_10 = new MyItem;item_10->setId(10);item_10->setColor(Qt::blue);MyItem *item_11 = new MyItem;item_11->setId(11);item_11->setColor(Qt::green);QGraphicsItemGroup *group = new QGraphicsItemGroup;   //手动创建图形项组group->setFlag(QGraphicsItem::ItemIsMovable);group->addToGroup(item_10);   //将图形项添加到项组group->addToGroup(item_11);item_11->setPos(30,0);scene.addItem(group);   //将项组添加到场景//QGraphicsItemGroup *group = scene.createItemGroup(scene.selectedItems());   //使用场景对象直接创建图形项组//group->QGraphicsItemGroup::setHandlesChildEvents(false);   //让项组内的图形项可以捕获自己的相关事件//group->removeFromGroup(item1);   //从项组中删除图形项//scene.destroyItemGroup(group);   //销毁整个图形项组...
}

(在QtCreator下的官方示例下有这个图形视图框架管理大量的图形项的示例:40000 Chips,可以作为参考)

7.打印:图形视图框架提供下面的渲染函数来完成打印功能
场景坐标上使用QGraphicsScene::render()函数实现打印
视图坐标上使用QGraphicsView::render()函数实现屏幕快照

int main(int argc,char *argv[])
{...//在打印机上进行打印QPrinter printer;if(QPrintDialog(&printer).exec() == QDialog::Accepted){QPainter painter1(&printer);painter1.setRenderHint(QPainter::Antialiasing);scene.render(&painter1);}//实现屏幕快照功能,在项目生成的目录中保存图像QPixmap pixmap(400,300);QPainter painter2(&pixmap);painter2.setRenderHint(QPainter::Antialiasing);view.render(&painter2);painter2.end();pixmap.save("view.png");...
}

8.使用OpenGL进行渲染:使用QGraphicsView::setViewport()更改QGraphicsView的视口,就可以使用OpenGL进行渲染了

int main(int argc,char *argv[])
{...//自定义视图MyView view;view.setViewport(new QOpenGLWidget);//view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));   //使用OpenGL进行渲染...
}

(在QtCreator下的官方示例下有这个图形视图框架与OpenGL渲染的示例:Boxes,可以作为参考)

可以将我的示例中的pro文件内容修改为下面这样,来运行示例2,学习图形视图框架下相关的事件处理

#条件编译
#DEFINES += EXAMPLE_1
DEFINES += EXAMPLE_2

四、示例完整代码

1.MyScene.pro

QT += widgets
QT += printsupport
QT += openglSOURCES += \main.cpp \myitem.cpp \myview.cppHEADERS += \myitem.h \myview.h#条件编译
#DEFINES += EXAMPLE_1
DEFINES += EXAMPLE_2

2.myitem.h

#ifndef MYITEM_H
#define MYITEM_H#include <QGraphicsItem>
#include <QPainter>
#include <QMenu>
#include <QCursor>
#include <QKeyEvent>
#include <QGraphicsSceneHoverEvent>
#include <QGraphicsSceneContextMenuEvent>
#include <QGraphicsEffect>
#include <QGraphicsObject>
#include <QPoint>
#include <QDebug>class MyItem : public QGraphicsObject
{
public:MyItem(QGraphicsItem *parent = 0);#if EXAMPLE_1QRectF boundingRect() const;void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget);
#endif#if EXAMPLE_2QRectF boundingRect() const;void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget);void advance(int phase);QPainterPath shape() const;void setId(int id);void setColor(const QColor &color);protected:void keyPressEvent(QKeyEvent *event);void mouseMoveEvent(QGraphicsSceneMouseEvent *event);void hoverEnterEvent(QGraphicsSceneHoverEvent *event);void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);private:int m_id;QColor m_brushColor;
#endif
};
#endif // MYITEM_H

3.myitem.cpp

#include "myitem.h"MyItem::MyItem(QGraphicsItem *parent) :QGraphicsObject(parent)
{
#if EXAMPLE_2m_brushColor = Qt::red;//开启图形项的特殊功能setFlag(QGraphicsItem::ItemIsFocusable);setFlag(QGraphicsItem::ItemIsMovable);setFlag(QGraphicsItem::ItemIsSelectable);setAcceptHoverEvents(true);   //使图形项支持悬停事件
#endif
}#if EXAMPLE_1
//返回绘制图形项的矩形区域
QRectF MyItem::boundingRect() const
{qreal penWidth = 1;return QRectF(0 - penWidth/2,0 - penWidth/2,20 + penWidth,20 + penWidth);
}//执行实际的绘图操作
void MyItem::paint(QPainter *painter,const QStyleOptionGraphicsItem *,QWidget *)
{painter->setBrush(Qt::red);painter->drawRect(0,0,20,20);
}
#endif#if EXAMPLE_2
//返回绘制图形项的矩形区域
QRectF MyItem::boundingRect() const
{qreal adjust = 0.5;return QRectF(-10 - adjust,-10 - adjust,20 + adjust,20 + adjust);
}//执行实际的绘图操作
void MyItem::paint(QPainter *painter,const QStyleOptionGraphicsItem *,QWidget *)
{if(hasFocus() || !collidingItems().isEmpty())   //是否获得焦点或者有碰撞{painter->setPen(QPen(QColor(255,255,255,200)));}else{painter->setPen(QPen(QColor(100,100,100,100)));}painter->setBrush(m_brushColor);painter->drawRect(-10,-10,20,20);
}//动画处理
void MyItem::advance(int phase)
{//第一个阶段不进行处理if(!phase){return;}//图形项向不同方向随机移动int value = qrand() % 100;if(value < 25){setRotation(45);moveBy(qrand() % 10,qrand() % 10);}else if(value < 50){setRotation(-45);moveBy(-qrand() % 10,-qrand() % 10);}else if(value < 75){setRotation(30);moveBy(-qrand() % 10,qrand() % 10);}else{setRotation(-30);moveBy(qrand() % 10,-qrand() % 10);}
}//返回图形项对应的形状
QPainterPath MyItem::shape() const
{QPainterPath path;path.addRect(-10,-10,20,20);return path;
}//设置图形项序号
void MyItem::setId(int id)
{m_id = id;
}//设置填充颜色
void MyItem::setColor(const QColor &color)
{m_brushColor = color;
}//键盘按下事件处理,移动图形项
void MyItem::keyPressEvent(QKeyEvent *event)
{switch(event->key()){//移动图形项case Qt::Key_Up:   //上移{moveBy(0,-10);break;}case Qt::Key_Down:   //下移{moveBy(0,10);break;}case Qt::Key_Left:   //左移{moveBy(-10,0);break;}case Qt::Key_Right:   //右移{moveBy(10,0);break;}//添加图形效果case Qt::Key_1:   //模糊效果{QGraphicsBlurEffect *blurEffect = new QGraphicsBlurEffect;blurEffect->setBlurHints(QGraphicsBlurEffect::QualityHint);blurEffect->setBlurRadius(8);setGraphicsEffect(blurEffect);break;}case Qt::Key_2:   //染色效果{QGraphicsColorizeEffect *ColorizeEffect = new QGraphicsColorizeEffect;ColorizeEffect->setColor(Qt::white);ColorizeEffect->setStrength(0.6);setGraphicsEffect(ColorizeEffect);break;}case Qt::Key_3:   //阴影效果{QGraphicsDropShadowEffect *dropShadowEffect = new QGraphicsDropShadowEffect;dropShadowEffect->setColor(QColor(63,63,63,100));dropShadowEffect->setBlurRadius(2);dropShadowEffect->setXOffset(10);setGraphicsEffect(dropShadowEffect);break;}case Qt::Key_4:   //透明效果{QGraphicsOpacityEffect *opacityEffect = new QGraphicsOpacityEffect;opacityEffect->setOpacity(0.4);setGraphicsEffect(opacityEffect);break;}case Qt::Key_5:   //取消图形项的图形效果graphicsEffect()->setEnabled(false);break;}
}//鼠标移动事件处理,获得焦点并改变光标外观
void MyItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{setFocus();setCursor(Qt::ClosedHandCursor);//鼠标拖动设置图形项的场景坐标//QPointF scenePos = mapToScene(event->pos());//setPos(scenePos);//直接用这一句顶上面两句QGraphicsItem::mouseMoveEvent(event);
}//悬停事件处理,设置光标外观和提示
void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *)
{setCursor(Qt::OpenHandCursor);setToolTip(QString("我是%1号图形项").arg(m_id));
}//右键菜单事件处理,为图形项添加一个右键菜单
void MyItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{QMenu menu;QAction *viewAction = menu.addAction("移动到视图原点");QAction *sceneAction = menu.addAction("移动到场景原点");QAction *selectedAction = menu.exec(event->screenPos());if(selectedAction == viewAction){setPos(-200,-150);   //与main函数中设置的场景矩形原点一致}else if(selectedAction == sceneAction){setPos(0,0);}
}
#endif

4.myview.h

#ifndef MYVIEW_H
#define MYVIEW_H#include <QGraphicsView>
#include <QGraphicsItem>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QDebug>class MyView : public QGraphicsView
{Q_OBJECTpublic:explicit MyView(QWidget *parent = 0);protected:
#if EXAMPLE_1void mousePressEvent(QMouseEvent *event);
#endif#if EXAMPLE_2void keyPressEvent(QKeyEvent *event);
#endif
};#endif // MYVIEW_H

5.myview.cpp

#include "myview.h"MyView::MyView(QWidget *parent) :QGraphicsView(parent)
{}#if EXAMPLE_1
void MyView::mousePressEvent(QMouseEvent *event)
{//视图坐标QPoint viewPos = event->pos();qDebug()<<"viewPos:"<<viewPos;//场景坐标QPointF scenePos = mapToScene(viewPos);qDebug()<<"scenePos:"<<scenePos;//图形项坐标QGraphicsItem *item = scene()->itemAt(scenePos,QTransform());if(item){QPointF itemPos = item->mapFromScene(scenePos);qDebug()<<"itemPos:"<<itemPos;}
}
#endif#if EXAMPLE_2
void MyView::keyPressEvent(QKeyEvent *event)
{switch(event->key()){case Qt::Key_Plus:scale(1.2,1.2);break;case Qt::Key_Minus:scale(1/1.2,1/1.2);break;case Qt::Key_Enter:rotate(30);break;}QGraphicsView::keyPressEvent(event);
}
#endif

6.main.cpp

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QPropertyAnimation>
#include <QTime>
#include <QTimer>
#include <QDialog>
#include <QPrinter>
#include <QPrintDialog>
#include <QPixmap>
#include <QPainter>
#include <QOpenGLWidget>
#include <qgl.h>
#include "myitem.h"
#include "myview.h"#if EXAMPLE_1
//示例1:图形视图框架的结构和坐标系统
int main(int argc,char *argv[])
{QApplication app(argc,argv);//场景QGraphicsScene scene;//scene.setSceneRect(0,0,400,300);   //设置场景矩形,指定视图显示的场景区域//自定义图形项MyItem *item = new MyItem;scene.addItem(item);item->setPos(10,10);   //设置坐标//item->setZValue(1);   //将item移动到rectItem之上//添加矩形图形项QGraphicsRectItem *rectItem = scene.addRect(QRect(0,0,100,100),QPen(Qt::blue),QBrush(Qt::green));rectItem->setPos(20,20);item->setParentItem(rectItem);   //将item作为rectItem子图形项,这样item默认显示在rectItem之上//rectItem->setRotation(30);   //设置旋转//自定义视图MyView view;view.setScene(&scene);view.setForegroundBrush(QColor(255,255,0,100));view.setBackgroundBrush(QPixmap("../myscene/background.jpg"));//view.setDragMode(QGraphicsView::ScrollHandDrag);   //设置鼠标为手掌形view.resize(400,300);view .show();return app.exec();
}
#endif#if EXAMPLE_2
//示例2:图形视图框架的事件处理
int main(int argc,char *argv[])
{QApplication app(argc,argv);qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));//场景QGraphicsScene scene;scene.setSceneRect(-200,-150,400,300);for(int i=0;i<5;i++){//自定义图形项MyItem *item = new MyItem;item->setId(i+1);item->setColor(QColor(qrand() % 256,qrand() % 256,qrand() % 256));item->setPos(i*50 - 90,-50);scene.addItem(item);}//自定义视图MyView view;//view.setViewport(new QOpenGLWidget);//view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));   //使用OpenGL进行渲染view.setScene(&scene);view.setBackgroundBrush(QPixmap("../myscene/background.jpg"));view.setDragMode(QGraphicsView::RubberBandDrag);   //设置鼠标可以在视图上拖出橡皮筋框view.show();//为图形项的rotation属性创建动画MyItem *item_111 = new MyItem;item_111->setId(111);item_111->setColor(Qt::yellow);item_111->setPos(15,50);scene.addItem(item_111);QPropertyAnimation *animation = new QPropertyAnimation(item_111,"rotation");animation->setDuration(2000);animation->setStartValue(0);animation->setEndValue(360);animation->start(QAbstractAnimation::DeleteWhenStopped);//创建定时器调用场景的advance()函数,并且会自动调用所有图形项的advance()函数QTimer timer;QObject::connect(&timer,&QTimer::timeout,&scene,&QGraphicsScene::advance);//timer.start(300);//创建图形项组MyItem *item_10 = new MyItem;item_10->setId(10);item_10->setColor(Qt::blue);MyItem *item_11 = new MyItem;item_11->setId(11);item_11->setColor(Qt::green);QGraphicsItemGroup *group = new QGraphicsItemGroup;   //手动创建图形项组group->setFlag(QGraphicsItem::ItemIsMovable);group->addToGroup(item_10);   //将图形项添加到项组group->addToGroup(item_11);item_11->setPos(30,0);scene.addItem(group);   //将项组添加到场景//QGraphicsItemGroup *group = scene.createItemGroup(scene.selectedItems());   //使用场景对象直接创建图形项组//group->QGraphicsItemGroup::setHandlesChildEvents(false);   //让项组内的图形项可以捕获自己的相关事件//group->removeFromGroup(item1);   //从项组中删除图形项//scene.destroyItemGroup(group);   //销毁整个图形项组//在打印机上进行打印//QPrinter printer;//if(QPrintDialog(&printer).exec() == QDialog::Accepted)//{//    QPainter painter1(&printer);//    painter1.setRenderHint(QPainter::Antialiasing);//    scene.render(&painter1);//}//实现屏幕快照功能,在项目生成的目录中保存图像QPixmap pixmap(400,300);QPainter painter2(&pixmap);painter2.setRenderHint(QPainter::Antialiasing);view.render(&painter2);painter2.end();pixmap.save("view.png");return app.exec();
}
#endif/*
*QtCreator下的演示示例
*图形视图框架管理大量的图形项:40000 Chips
*图形视图框架与OpenGL渲染:Boxes
*/

五、QtCreator官方示例

图形视图框架管理大量的图形项:40000 Chips
请添加图片描述

图形视图框架与OpenGL渲染:Boxes
请添加图片描述


总结

通过以上的学习,对于这个由场景、视图和图形项这三大类组成的图形视图框架有了更加清晰的认识。文中提到的QtCreator下的官方示例我也运行查看了下,作为参考也可以学习本文示例外的一些知识,推荐大家也去看看


hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

学习书籍:【Qt Creator快速入门_霍亚飞编著】

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

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

相关文章

Java配置47-Spring Eureka 未授权访问漏洞修复

文章目录 1. 背景2. 方法2.1 Eureka Server 添加安全组件2.2 Eureka Server 添加参数2.3 重启 Eureka Server2.4 Eureka Server 升级版本2.5 Eureka Client 配置2.6 Eureka Server 添加代码2.7 其他问题 1. 背景 项目组使用的 Spring Boot 比较老&#xff0c;是 1.5.4.RELEASE…

Linux生成静态库

GCC 什么是GCC GCC 是 GNU 编译器集合&#xff08;GNU Compiler Collection&#xff09;的缩写。它是一个开源的编程语言编译器&#xff0c;支持多种编程语言&#xff0c;包括 C、C、Objective-C、Fortran、Ada 和 Go 等。GCC 最初由理查德斯托曼&#xff08;Richard Stallman…

2022最新版-李宏毅机器学习深度学习课程-P32 Transformer

一、 seq2seq 1. 含义 输入一个序列&#xff0c;机器输出另一个序列&#xff0c;输出序列长度由机器决定。 文本翻译&#xff1a;文本至文本&#xff1b;  语音识别&#xff1a;语音至文本&#xff1b;  语音合成&#xff1a;文本至语音&#xff1b;  聊天机器人&#…

WPF布局控件之DockPanel布局

前言&#xff1a;博主文章仅用于学习、研究和交流目的&#xff0c;不足和错误之处在所难免&#xff0c;希望大家能够批评指出&#xff0c;博主核实后马上更改。 概述&#xff1a; DockPanel 位置子控件基于子 Dock 属性&#xff0c;你有 4 个选项停靠&#xff0c;左 (默认) &…

HarmonyOS 数据管理与应用数据持久化(二)

通过键值型数据库实现数据持久化 场景介绍 键值型数据库存储键值对形式的数据&#xff0c;当需要存储的数据没有复杂的关系模型&#xff0c;比如存储商品名称及对应价格、员工工号及今日是否已出勤等&#xff0c;由于数据复杂度低&#xff0c;更容易兼容不同数据库版本和设备…

Gradle笔记 一 Gradle的安装与入门

文章目录 Gradle 入门Gradle 简介学习Gradle 的原因&#xff1a; 常见的项目构建工具Gradle 安装Gradle 安装说明安装JDK 下载并解压到指定目录配置环境变量检测是否安装成功 Gradle 项目目录结构Gradle 创建第一个项目Gradle 中的常用指令修改maven 下载源Wrapper 包装器使用教…

项目管理之如何估算项目工作成本

在项目管理中&#xff0c;如何估算项目工作成本是一个关键问题。为了解决这个问题&#xff0c;我们可以采用自上而下的成本限额估算法和自下而上的成本汇总估算法。这两种方法各有优缺点&#xff0c;但都可以帮助我们准确地估算项目工作成本。 自上而下的成本限额估算法 自上…

InnoDB中Buffer Pool详解

1. 概念及特点 Buffer Pool 是 MySQL 中 InnoDB 存储引擎用来缓存表数据和索引数据的内存区域。这个内存区域被用来存储磁盘上的数据页的副本&#xff0c;这样常用的数据可以在内存中快速被访问&#xff0c;而不必每次都从磁盘中读取。 以下是 Buffer Pool 的一些重要特点&a…

串口通信(6)应用定时器中断+串口中断实现接收一串数据

本文为博主 日月同辉&#xff0c;与我共生&#xff0c;csdn原创首发。希望看完后能对你有所帮助&#xff0c;不足之处请指正&#xff01;一起交流学习&#xff0c;共同进步&#xff01; > 发布人&#xff1a;日月同辉,与我共生_单片机-CSDN博客 > 欢迎你为独创博主日月同…

I/O多路转接之select

承接上文&#xff1a;I/O模型之非阻塞IO-CSDN博客 简介 select函数原型介绍使用 一个select简单的服务器的代码书写 select的缺点 初识select 系统提供select函数来实现多路复用输入/输出模型 select系统调用是用来让我们的程序监视多个文件描述符的状态变化的; 程序会停在s…

unittest 通过TextTestRunner(failfast=True),失败或错误时停止执行case

failfast是unittest.TextTestRunner的一个参数&#xff0c;它用于控制测试运行过程中遇到第一个失败或错误的测试方法后是否立即停止执行。 当failfast设置为True时&#xff0c;一旦发现第一个失败或错误的测试方法&#xff0c;测试运行就会立即停止&#xff0c;并输出相应的失…

sql基础+考点+题

查询&#xff1a;select from 筛选&#xff1a;where and和or 排序&#xff1a;order by&#xff08;降序排列需要指定DESC关键字&#xff09; join&#xff1a;left join 、right join 和inner join 分组聚合&#xff1a;group by ---搭配count , sum , avg 过滤&#x…

安全防御——二、ENSP防火墙实验学习

安全防御 一、防火墙接口以及模式配置1、untrust区域2、trust区域3、DMZ区域4、接口对演示 二、防火墙的策略1、定义与原理2、防火墙策略配置2.1 安全策略工作流程2.2 查询和创建会话 3、实验策略配置3.1 trust-to-untrust3.2 trust-to-dmz3.3 untrust-to-dmz 三、防火墙的区域…

消息中间件-RabbitMQ介绍

一、基础知识 1. 什么是RabbitMQ RabbitMQ是2007年发布&#xff0c;是一个在AMQP(高级消息队列协议)基础上完成的&#xff0c;简称MQ全称为Message Queue, 消息队列&#xff08;MQ&#xff09;是一种应用程序对应用程序的通信方法&#xff0c;由Erlang&#xff08;专门针对于大…

SPSS单因素方差分析

前言&#xff1a; 本专栏参考教材为《SPSS22.0从入门到精通》&#xff0c;由于软件版本原因&#xff0c;部分内容有所改变&#xff0c;为适应软件版本的变化&#xff0c;特此创作此专栏便于大家学习。本专栏使用软件为&#xff1a;SPSS25.0 本专栏所有的数据文件请点击此链接下…

Python基础入门例程39-NP39 字符串之间的比较(运算符)

最近的博文&#xff1a; Python基础入门例程38-NP38 牛牛的逻辑运算&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程37-NP37 不低于与不超过&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程36-NP36 谁的数字大&#xff08;运算符&#xff09;-CSD…

航模模拟器训练

固定翼吃灰很久忘记咋么操作 故这里发帖防止忘记 准备物品 航模遥控器 aux线 即两端都是耳机插头的线 解密狗 电脑 phoenixRC 航模模拟软件(【飞舜极创】凤凰5.0飞行模拟器 安装和设置方法_哔哩哔哩_bilibili) 链接&#xff1a;https://pan.baidu.com/s/1XL4ZWhMR7MQMxDPC7B…

GraphQL入门与开源的GraphQL引擎Hasura体验

背景 Hasura 是一个开源的 GraphQL 引擎&#xff0c;它可以帮助开发人员快速构建和部署现代应用程序的后端。它提供了一个自动化的 GraphQL API &#xff0c;可以直接连接到现有的数据库&#xff0c;并提供实时数据推送和订阅功能。 Hasura 团队总部位于印度。 下载安装 脚本…

分享86个工作总结PPT,总有一款适合您

分享86个工作总结PPT&#xff0c;总有一款适合您 PPT下载链接&#xff1a;https://pan.baidu.com/s/12aRTr5NKG5YTnMnwNbqOrQ?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。知…

顶层模块【FPGA】

1顶层模块&#xff1a; 不能像C语言的h文件那样&#xff0c;把io的定义放在其他文件。 在Verilog中&#xff0c;顶层模块是整个设计的最高层次&#xff0c;它包含了所有其他模块和子模块。 顶层模块定义了整个设计的输入和输出端口&#xff0c;以及各个子模块之间的连接方式。…