Qt实现简单的漫游器

文章目录

  • Qt的OpenGL窗口
  • GLSL的实现
  • 摄像机类的实现
  • 简单的漫游器

Qt的OpenGL窗口

 Qt主要是使用QOpenGLWidget来实现opengl的功能。
 QOpenGLWidget 提供了三个便捷的虚函数,可以重载,用来重新实现典型的OpenGL任务:

  • paintGL:渲染OpenGL场景。widget 需要更新时调用。
  • resizeGL:设置OpenGL视口、投影等。widget 调整大小(或首次显示)时调用。
  • initializeGL:设置OpenGL资源和状态。第一次调用 resizeGL() / paintGL() 之前调用一次。
  • 如果需要从paintGL()以外的位置触发重新绘制(典型示例是使用计时器设置场景动画),则应调用widget的update()函数来安排更新。
  • 调用paintGL()、resizeGL()或initializeGL()时,widget 的OpenGL呈现上下文将变为当前。如果需要从其他位置(例如,在 widget 的构造函数或自己的绘制函数中)调用标准OpenGL API函数,则必须首先调用makeCurrent()。
  • QOpenGLFunctions_X_X_Core 提供OpenGL X.X版本核心模式的所有功能。是对OpenGL函数的封装:
  • initializeOpenGLFunctions:初始化OpenGL函数,将Qt里的函数指针指向显卡的函数。
#include <QOpenGLWidget> 
#include <QOpenGLFunctions_3_3_Core> class MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core 
{ 
Q_OBJECT 
public: 
explicit MyOpenGLWidget (QWidget *parent = nullptr); 
protected: 
virtual void initializeGL(); 
virtual void resizeGL(int w, int h); 
virtual void paintGL(); 
};
void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();
}
void MyOpenGLWidget::resizeGL(int w, int h)
{Q_UNUSED(w);Q_UNUSED(h);
}
void MyOpenGLWidget::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

在这里插入图片描述

以上是最简单的实现版本。

GLSL的实现

 由于是最简单的漫游器,所以我们实现的版本只需要一个顶点着色器和一个片段着色器即可。
shapes.vert

#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCoord;out vec2 texCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main(){gl_Position = projection * view * model * vec4(aPos, 1.0f);texCoord = aTexCoord;
}

shapes.frag

#version 330 core
out vec4 FragColor;
in vec2 texCoord;uniform sampler2D texturewall;
uniform sampler2D texturesmile;
uniform sampler2D textureSmall;uniform float ratio;
void main(){FragColor = mix(texture(texturewall,texCoord),texture(texturesmile,texCoord),ratio);
}

摄像机类的实现

 这边实现了一个可以对模型进行上下左右移动,移动视角,放大缩小的操作。
摄像机类初始化了几个变量

// 默认值
const float YAW         = -90.0f;
const float PITCH       =  0.0f;
const float SPEED       =  2.5f;
const float SENSITIVITY =  0.1f;
const float ZOOM        =  45.0f;

偏航角默认为90度,灵敏度主要用于控制鼠标移动时视角的变化量。

#ifndef CAMERA_H
#define CAMERA_H#include<QMatrix4x4>#include <vector>// 移动方向枚举量. 是一种抽象,以避开特定于窗口系统的输入方法
// 我们这里是WSAD
enum Camera_Movement {FORWARD,BACKWARD,LEFT,RIGHT
};// 默认值
const float YAW         = -90.0f;
const float PITCH       =  0.0f;
const float SPEED       =  2.5f;
const float SENSITIVITY =  0.1f;
const float ZOOM        =  45.0f;// 一个抽象的camera类,用于处理输入并计算相应的Euler角度、向量和矩阵,以便在OpenGL中使用
class Camera
{
public:// camera AttributesQVector3D Position;QVector3D Front;QVector3D Up;QVector3D Right;QVector3D WorldUp;// euler Anglesfloat Yaw;float Pitch;// camera optionsfloat MovementSpeed;float MouseSensitivity;float Zoom;// constructor with vectorsCamera(QVector3D position = QVector3D(0.0f, 0.0f, 0.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(QVector3D(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM){Position = position;WorldUp = up;Yaw = yaw;Pitch = pitch;updateCameraVectors();}// constructor with scalar valuesCamera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(QVector3D(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM){Position = QVector3D(posX, posY, posZ);WorldUp = QVector3D(upX, upY, upZ);Yaw = yaw;Pitch = pitch;updateCameraVectors();}// returns the view matrix calculated using Euler Angles and the LookAt MatrixQMatrix4x4 GetViewMatrix(){QMatrix4x4 theMatrix;theMatrix.lookAt(Position, Position + Front, Up);return theMatrix;}// 处理从任何类似键盘的输入系统接收的输入。接受摄像机定义枚举形式的输入参数(从窗口系统中提取)void ProcessKeyboard(Camera_Movement direction, float deltaTime){float velocity = MovementSpeed * deltaTime;if (direction == FORWARD)Position += Front * velocity;if (direction == BACKWARD)Position -= Front * velocity;if (direction == LEFT)Position -= Right * velocity;if (direction == RIGHT)Position += Right * velocity;}// 处理从鼠标输入系统接收的输入。需要x和y方向上的偏移值。void ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch = true){xoffset *= MouseSensitivity;yoffset *= MouseSensitivity;Yaw   += xoffset;Pitch += yoffset;// 确保当投球超出边界时,屏幕不会翻转if (constrainPitch){if (Pitch > 89.0f)Pitch = 89.0f;if (Pitch < -89.0f)Pitch = -89.0f;}// 使用更新的Euler角度更新前、右和上矢量updateCameraVectors();}// 处理从鼠标滚轮事件接收的输入。仅需要在垂直车轮轴上输入void ProcessMouseScroll(float yoffset){Zoom -= (float)yoffset;if (Zoom < 1.0f)Zoom = 1.0f;if (Zoom > 75.0f)Zoom = 75.0f;}private:// 根据相机的(更新的)Euler角度计算前矢量void updateCameraVectors(){// calculate the new Front vectorfloat PI=3.1415926;QVector3D front;front.setX(cos(Yaw*PI/180.0) * cos(Pitch*PI/180.0));front.setY( sin(Pitch*PI/180.0));front.setZ(sin(Yaw*PI/180.0) * cos(Pitch*PI/180.0));front.normalize();Front = front;// also re-calculate the Right and Up vectorRight = QVector3D::crossProduct(Front, WorldUp);// 标准化向量,因为向上或向下看得越多,向量的长度就越接近0,这会导致移动速度变慢。Right.normalize();Up    = QVector3D::crossProduct(Right, Front);Up.normalize();}
};
#endif

简单的漫游器

 漫游器的实现主要是通过Qt的窗口事件触发后将触发产生的位置偏量给摄像机类进行计算,从摄像机类中得到视图矩阵将模型的位置进行改变。
myopenglwidget.h


#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QTimer>
#include <QElapsedTimer>
#include "camera.h"class MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{Q_OBJECT
public:enum Shape{None,Circle,Rect,Triangle};explicit MyOpenGLWidget(QWidget *parent = nullptr);~MyOpenGLWidget();void DrawShape(Shape shape);void setWireFrameMode(bool enterWireframe);void onTimeout();
protected:virtual void initializeGL();virtual void resizeGL(int w, int h);virtual void paintGL();
signals:
private:Shape m_shape;QOpenGLShaderProgram shaderProgram;QOpenGLTexture *textureWall;QOpenGLTexture *textureSmile;QOpenGLTexture *textureSmall;QTimer *m_timer;QElapsedTimer m_time;Camera m_camera;// QWidget interface
protected:void keyPressEvent(QKeyEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;void wheelEvent(QWheelEvent *event) override;
};#endif // MYOPENGLWIDGET_H

myopenglwidget.cpp

#include "myopenglwidget.h"
#include <QImage>
#include <QKeyEvent>float vertices[] = {-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};QVector<QVector3D> cubePositions= {QVector3D( 0.0f, 0.0f, 0.0f),QVector3D( 2.0f, 5.0f, -15.0f),QVector3D(-1.5f, -2.2f, -2.5f),QVector3D(-3.8f, -2.0f, -12.3f),QVector3D( 2.4f, -0.4f, -3.5f),QVector3D(-1.7f, 3.0f, -7.5f),QVector3D( 1.3f, -2.0f, -2.5f),QVector3D( 1.5f, 2.0f, -2.5f),QVector3D( 1.5f, 0.2f, -1.5f),QVector3D(-1.3f, 1.0f, -1.5f)
};#define TIMEOUT 100unsigned int indices[] = { // note that we start from 0!0, 1, 3, // first triangle1, 2, 3 // second triangle
};unsigned int VBO, VAO ,EBO;float ratio = 0.5;
QPoint deltaPos;MyOpenGLWidget::MyOpenGLWidget(QWidget *parent): QOpenGLWidget{parent}
{setFocusPolicy(Qt::StrongFocus);setMouseTracking(true);m_timer = new QTimer(this);connect(m_timer,&QTimer::timeout,this,&MyOpenGLWidget::onTimeout);m_timer->start(TIMEOUT);m_time.start();m_camera.Position = QVector3D(0.0,0.0,3.0);
}MyOpenGLWidget::~MyOpenGLWidget()
{if(!isValid()) return;makeCurrent();glDeleteBuffers(1,&VBO);glDeleteBuffers(1,&EBO);glDeleteVertexArrays(1,&VAO);doneCurrent();
}void MyOpenGLWidget::DrawShape(Shape shape)
{m_shape=shape;update();
}void MyOpenGLWidget::setWireFrameMode(bool enterWireframe)
{makeCurrent();if(enterWireframe)glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);elseglPolygonMode(GL_FRONT_AND_BACK,GL_FILL);update();doneCurrent();
}void MyOpenGLWidget::onTimeout()
{update();
}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions();//创建VBO和VAO对象,并赋予IDglGenVertexArrays(1,&VAO);glGenBuffers(1,&VBO);//绑定VAO和VBO对象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);//为当前绑定到target的缓冲区对象创建一个新的数据存储。//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);//告知显卡如何解析缓冲里的属性值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,5*sizeof(float),(void *)0);//开启VAO管理的第一个属性值glEnableVertexAttribArray(0);//告知显卡如何解析缓冲里的属性值glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,5*sizeof(float),(void *)(3*sizeof(float)));//开启VAO管理的第三个属性值glEnableVertexAttribArray(1);glBindBuffer(GL_ARRAY_BUFFER,0);bool success;shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":Shaders/shapes.vert");shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":Shaders/shapes.frag");success = shaderProgram.link();if(!success){qDebug()<<"Error:"<<shaderProgram.log();}shaderProgram.bind();shaderProgram.setUniformValue("ratio",ratio);shaderProgram.setUniformValue("texturewall",0);shaderProgram.setUniformValue("texturesmile",1);shaderProgram.setUniformValue("textureSmall",2);unsigned int EBO;glGenBuffers(1, &EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);textureWall = new QOpenGLTexture(QImage(":Images/images/wall.jpg").mirrored());textureSmile = new QOpenGLTexture(QImage(":Images/images/awesomeface.png").mirrored());textureSmall = new QOpenGLTexture(QImage(":Images/images/small.png").mirrored());glBindVertexArray(0);}void MyOpenGLWidget::resizeGL(int w, int h)
{Q_UNUSED(w);Q_UNUSED(h);
}void MyOpenGLWidget::paintGL()
{QMatrix4x4 model;QMatrix4x4 view;QMatrix4x4 projection;view=m_camera.GetViewMatrix();glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glEnable(GL_DEPTH_TEST);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);shaderProgram.bind();projection.perspective(m_camera.Zoom,(float)width()/(height()),0.1,100.0);shaderProgram.setUniformValue("projection", projection);shaderProgram.setUniformValue("view", view);glBindVertexArray(VAO);//glDrawArrays(GL_TRIANGLES, 0, 3);switch(m_shape){case Rect:textureWall->bind(0);textureSmile->bind(1);textureSmall->bind(2);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);foreach (auto item, cubePositions){model.setToIdentity();model.translate(item);shaderProgram.setUniformValue("model", model);glDrawArrays(GL_TRIANGLES,0,36);}break;case None:break;case Triangle:break;case Circle:break;}}void MyOpenGLWidget::keyPressEvent(QKeyEvent *event)
{float deltatime=TIMEOUT / 1000.0;switch(event->key()){case Qt::Key_Up:ratio += 0.1;break;case Qt::Key_Down:ratio -= 0.1;break;case Qt::Key_W: m_camera.ProcessKeyboard(FORWARD,deltatime);break;case Qt::Key_S: m_camera.ProcessKeyboard(BACKWARD,deltatime);break;case Qt::Key_D: m_camera.ProcessKeyboard(RIGHT,deltatime);break;case Qt::Key_A: m_camera.ProcessKeyboard(LEFT,deltatime);break;}if(ratio > 1) ratio = 1;if(ratio < 0) ratio = 0;makeCurrent();shaderProgram.bind();shaderProgram.setUniformValue("ratio",ratio);update();doneCurrent();
}void MyOpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{static QPoint lastPos(width()/2,height()/2);auto currentPos=event->pos();deltaPos=currentPos-lastPos;lastPos=currentPos;m_camera.ProcessMouseMovement(deltaPos.x(),-deltaPos.y());update();
}void MyOpenGLWidget::wheelEvent(QWheelEvent *event)
{   m_camera.ProcessMouseScroll(event->angleDelta().y()/120);update();
}

完整代码链接

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

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

相关文章

【数据库系统】--【5】DBMS查询处理

DBMS查询处理 01查询处理概述02查询编译词法、语法分析语义分析查询重写查询优化 03查询执行算法04查询执行模型 01查询处理概述 02查询编译 词法、语法分析 语义分析 查询重写 查询优化 03查询执行算法 04查询执行模型 小结 ● 查询处理概述 ● 查询编译 词法、语法分析语义分…

2021年06月 C/C++(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;数对 给定2到15个不同的正整数&#xff0c;你的任务是计算这些数里面有多少个数对满足&#xff1a;数对中一个数是另一个数的两倍。 比如给定1 4 3 2 9 7 18 22&#xff0c;得到的答案是3&#xff0c;因为2是1的两倍&#xff0c;4是2个两倍&#xff0c;18是9的…

CNN卷积详解(三)

一、卷积层的计算 4 ∗ * ∗ 4的输入矩阵 I I I 和 3 ∗ * ∗ 3 的卷积核 K K K: 在步长&#xff08;stride&#xff09;为 1 时&#xff0c;输出的大小为 ( 4 − 3 1 ) ( 4 − 3 1) 计算公式&#xff1a; ● 输入图片矩阵 I I I 大小&#xff1a; w w w w ww ●…

微服务系列文章之 SpringBoot 最佳实践

Spring Boot 是一种广泛使用且非常流行的企业级高性能框架。 以下是一些最佳实践和一些技巧&#xff0c;我们可以使用它们来改进 Spring Boot 应用程序并使其更加高效。 Spring Boot 的四大核心 1、自动配置 针对很多Spring应用程序和常见的应用功能&#xff0c;Spring Boo…

攻防世界-fileclude

原题 解题思路 直接展示源码了&#xff0c;flag.php应该存放了flag&#xff0c;在file1与file2都不为空且file2是“hello ctf”时file1将被导入。接下来做法很明显&#xff0c;让file为flag.php&#xff0c;file2为“hello ctf”。“?file1php://filter/readconvert.base64-en…

Open3D 最小二乘拟合空间直线(方法一)

目录 一、算法原理1、空间直线2、最小二乘法拟合二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、空间直线 x −

基于web的停车场收费管理系统/基于springboot的停车场管理系统

摘 要 随着汽车工业的迅猛发展&#xff0c;我国汽车拥有量急剧增加。停车场作为交通设施的组成部分,随着交通运输的繁忙和不断发展&#xff0c;人们对其管理的要求也不断提高&#xff0c;都希望管理能够达到方便、快捷以及安全的效果。停车场的规模各不相同,对其进行管理的模…

ElasticSearch 数据聚合、自动补全(自定义分词器)、数据同步

文章目录 数据聚合一、聚合的种类二、DSL实现聚合1、Bucket&#xff08;桶&#xff09;聚合2、Metrics&#xff08;度量&#xff09;聚合 三、RestAPI实现聚合 自动补全一、拼音分词器二、自定义分词器三、自动补全查询四、实现搜索款自动补全&#xff08;例酒店信息&#xff0…

【rust/egui】(三)看看template的app.rs:序列化、持久化存储

说在前面 rust新手&#xff0c;egui没啥找到啥教程&#xff0c;这里自己记录下学习过程环境&#xff1a;windows11 22H2rust版本&#xff1a;rustc 1.71.1egui版本&#xff1a;0.22.0eframe版本&#xff1a;0.22.0上一篇&#xff1a;这里 serde app.rs中首先定义了我们的Templ…

Git判断本地是否最新

场景需求 需要判断是否有新内容更新,确定有更新之后执行pull操作&#xff0c;然后pull成功之后再将新内容进行复制到其他地方 pgit log -1 --prettyformat:"%H" HEAD -- . "origin/HEAD" rgit rev-parse origin/HEAD if [[ $p $r ]];thenecho "Is La…

域名解析和代理

购买域名 这里使用腾讯云进行购买。 对域名进行解析 通过添加记录接口对域名进行解析。 此时我们的服务器地址就被解析到域名上了。 我们可以通过以下格式进行访问&#xff1a; [域名]:[对应的项目端口] 效果为下: 通过nginx进行代理 如果我们使用上述的方式进行访问还是…

【hive】hive分桶表的学习

hive分桶表的学习 前言&#xff1a; 每一个表或者分区&#xff0c;hive都可以进一步组织成桶&#xff0c;桶是更细粒度的数据划分&#xff0c;他本质不会改变表或分区的目录组织方式&#xff0c;他会改变数据在文件中的分布方式。 分桶规则&#xff1a; 对分桶字段值进行哈…

react之react-redux的介绍、基本使用、获取状态、分发动作、数据流、reducer的分离与合并等

react之react-redux的介绍、基本使用、获取状态、分发动作、数据流、reducer的分离与合并等 一、react-redux介绍二、React-Redux-基本使用三、获取状态useSelector四、分发动作useDispatch五、 Redux 数据流六、代码结构七、ActionType的使用八、Reducer的分离与合并九、购物挣…

计算机视觉的应用11-基于pytorch框架的卷积神经网络与注意力机制对街道房屋号码的识别应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用11-基于pytorch框架的卷积神经网络与注意力机制对街道房屋号码的识别应用&#xff0c;本文我们借助PyTorch&#xff0c;快速构建和训练卷积神经网络&#xff08;CNN&#xff09;等模型&#xff0c;…

【Redis从头学-5】Redis中的List数据类型实战场景之天猫热销榜单

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 &#x1f4d6;所属专栏&#xff1a;Re…

git错误记录

露id没有影响&#xff0c;搞得微软不知道我ip一样 git fatal: 拒绝合并无关的历史的错误解决(亲测有效)

mybatis缓存

目的&#xff1a;提高查询效率。 映射语句文件中的所有 select 语句的结果将会被缓存。映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。缓存会使用最近最少使用算法&#xff08;LRU, Least Recently Used&#xff09;算法来清除不需要的缓存。缓存不会定时进行…

Matplotlib绘图知识小结--Python数据分析学习

一、Pyplot子库绘制2D图表 1、Matplotlib Pyplot Pyplot 是 Matplotlib 的子库&#xff0c;提供了和 MATLAB 类似的绘图 API。 Pyplot 是常用的绘图模块&#xff0c;能很方便让用户绘制 2D 图表。 Pyplot 包含一系列绘图函数的相关函数&#xff0c;每个函数会对当前的图像进行…

爬虫框架- feapder + 爬虫管理系统 - feaplat 的学习简记

文章目录 feapder 的使用feaplat 爬虫管理系统部署 feapder 的使用 feapder是一款上手简单&#xff0c;功能强大的Python爬虫框架 feapder 官方文档 文档写的很详细&#xff0c;可以直接上手。 基本命令&#xff1a; 创建爬虫项目 feapder create -p first-project创建爬虫 …

根据源码,模拟实现 RabbitMQ - 实现消息持久化,统一硬盘操作(3)

目录 一、实现消息持久化 1.1、消息的存储设定 1.1.1、存储方式 1.1.2、存储格式约定 1.1.3、queue_data.txt 文件内容 1.1.4、queue_stat.txt 文件内容 1.2、实现 MessageFileManager 类 1.2.1、设计目录结构和文件格式 1.2.2、实现消息的写入 1.2.3、实现消息的删除…