Learn OpenGL In Qt之炫酷进度条

news2024/9/30 2:27:31

在这里插入图片描述

竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~
公众号: C++学习与探索  |  个人主页: rainInSunny  |  个人专栏: Learn OpenGL In Qt

文章目录

  • 设计实现
    • 目录结构
    • 需要哪些类
    • 接口设计
    • 关键函数
  • 实现效果
  • Shader解析
    • GLSL基本函数
      • clamp
      • smoothstep
    • 实现分析
    • 效果一
    • 效果二

  经过之前内容的学习,我们已经掌握了如何通过OpenGL在Qt提供的环境下绘制一个三角形,我们知道绘制一个三角形需要VAO,VBO,在一些场景还需要EBO,然后我们需要搞定着色器,最后我们绑定VAO,调用绘制接口就能绘制出想要的三角形。下面是时候来绘制一些有趣的进度条了。

设计实现

目录结构

  先让我们看看完成后的目录结构:
在这里插入图片描述
  文件很简单,因为在工程实现的角度,绘制有趣的进度条和绘制一个三角形基本是一样的。CMakeLists是CMake的构建配置文件,它帮我们将下面这些文件添加到构建体系。coolprogress.h/.cpp就是核心实现进度条绘制的文件,它提供了一个进度条的控件类,可以像使用Qt其它控件一样使用它。main.cpp是整个程序的入口函数,所有C++程序都有这样一个入口函数。progressexample.h/.cpp主要是构造一个控件去使用coolprogress.h/.cpp中提供的进度条。progressshader.h提供了绘制进度条所需要的着色器程序,这一部分十分复杂,需要很好的数学功底才能完全弄懂,可惜我还没有>-<,只能看懂一些简单的,但在工程实现的角度,我们不用太关心这其中的原理,抄过来也许是个不错的选择。最后是shaderprogram.h,这就是我们之前写的shader类,更换了命名防止后续会发生命名冲突,然后稍微做了一些修改。

需要哪些类

  所需要的类也很简单,当然如果你有更好的设计完全可以按照自己的想法去写。
在这里插入图片描述
  这里的ShaderProgram提供着色器构造、激活、Uniform变量设置等功能。CoolProgress是一个继承于QOpenGLWidget的控件类,对外提供接口。CoolProgressImpl类包含进度条实现过程中的数据集合,不对外暴露,该类的实例被CoolProgress类创建,并由智能指针管理生命周期。pImpl设计模式经常会在实际过程中用到,这样做的好处是能够保证一定的二进制兼容性。

接口设计

  核心的接口都在coolprogress.h文件中:

#ifndef COOL_PROGRESS_H
#define COOL_PROGRESS_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <memory>

class CoolProgressImpl;

class CoolProgress : public QOpenGLWidget
{
	Q_OBJECT

public:
	enum ProgressStyle
	{
		Ring_1 = 0,
		Ring_2,
		Ring_3,
		FlashDot_1,
		FlashDot_2,
		FlashDot_3,
		FlashDot_4,
		Rect_1,
		Rect_2,
		Rect_3,
		Polygon_1,
		WaterWave_1
	};
public:
	CoolProgress(bool bTransparent, ProgressStyle style, int width = 100, int height = 100, QWidget *parent = nullptr);
	~CoolProgress();

	void startProgress(float speed = 1.0);
	void stopProgress();
	void updateProgress();
	// only valid in Ring style
	void setRingRadius(float r1, float r2);

protected:
	void initializeGL() override;
	void paintGL() override;
	void resizeGL(int w, int h) override;

private:
	void initShader();
	void setShaderUniform();

private:
	std::unique_ptr<CoolProgressImpl> m_impl;
};
#endif
  • CoolProgressImpl是上面提到的数据类,m_impl指针指向该类实例,通过std::unique_ptr管理生命周期。
  • ProgressStyle枚举表示进度条的样式类型。
  • CoolProgressbTransparent表示是否需要背景透明,透明则背景显示底层控件的颜色,不透明显示黑色。
  • startProgressstopProgress表示开始和结束进度动效,开始时可以设置一个动画效果速度。
  • updateProgress用于更新进度条界面。
  • setRingRadius用于给圆环类进度设置内外半径。
  • initializeGLpaintGLresizeGL前面文章有解释过。
  • initShadersetShaderUniform用于初始化shader内容和设置初始Uniform值。

关键函数

  关键的实现依旧是前面讲到的initializeGLpaintGL

void CoolProgress::initializeGL()
{
	if (m_impl->m_bInit)
		return;

	m_impl->m_bInit = true;
	makeCurrent();
	QOpenGLContext *pContext = context();
	if (pContext)
		m_impl->m_funcs = pContext->versionFunctions<QOpenGLFunctions_3_3_Core>();
	if (!m_impl->m_funcs)
	{
		qWarning() << "Could not obtain required OpenGL context version";
		Q_ASSERT(false);
		return;
	}
	m_impl->m_funcs->glViewport(0, 0, width(), height());

    ShaderProgram *pShaderProgram = new ShaderProgram(pContext);
    m_impl->m_shaderProgram.reset(pShaderProgram);
    const char *vertexShaderSource = m_impl->vShaderMap[m_impl->m_style].c_str();
    const char *fragmentShaderSource = m_impl->fShaderMap[m_impl->m_style].c_str();
    if (!m_impl->m_shaderProgram->compileSourceCode(vertexShaderSource, fragmentShaderSource))
    {
        Q_ASSERT(false);
        return;
    }

	float vertices[] = {
		// 第一个三角形
		1.0f, 1.0f, 0.0f,   // 右上角
		1.0f, -1.0f, 0.0f,  // 右下角
		-1.0f, 1.0f, 0.0f,  // 左上角
		// 第二个三角形
		1.0f, -1.0f, 0.0f,  // 右下角
		-1.0f, -1.0f, 0.0f, // 左下角
		-1.0f, 1.0f, 0.0f   // 左上角
	};

	m_impl->m_funcs->glGenVertexArrays(1, &m_impl->m_VAO);
	m_impl->m_funcs->glGenBuffers(1, &m_impl->m_VBO);
	m_impl->m_funcs->glBindVertexArray(m_impl->m_VAO);

	m_impl->m_funcs->glBindBuffer(GL_ARRAY_BUFFER, m_impl->m_VBO);
	m_impl->m_funcs->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	m_impl->m_funcs->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	m_impl->m_funcs->glEnableVertexAttribArray(0);
	m_impl->m_funcs->glBindBuffer(GL_ARRAY_BUFFER, 0);
	m_impl->m_funcs->glBindVertexArray(0);

	setShaderUniform();
}

  initializeGL:

  1. 判断是否初始化过,防止重入。
  2. 获取QOpenGLFunctions_3_3_Core对应的函数指针,获取后就能使用OpenGL接口。
  3. 通过ShaderProgram类构造着色器。
  4. 定义绘制的顶点,这里顶点对应一个铺满控件的正方形,x、y坐标范围在(-1,1)。
  5. 设置VAB、VBO。
void CoolProgress::paintGL()
{
	m_impl->m_funcs->glClear(GL_COLOR_BUFFER_BIT);
	m_impl->m_funcs->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	m_impl->m_funcs->glEnable(GL_BLEND);
	m_impl->m_funcs->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	m_impl->m_shaderProgram->use();
	if (m_impl->m_timer.isActive())
	{
		qint64 time = m_impl->m_elapsedTimer.elapsed();
		float value = time / 1000.0 * m_impl->m_speed;
		m_impl->m_shaderProgram->setFloat("deltaTime", value);
	}
	m_impl->m_funcs->glBindVertexArray(m_impl->m_VAO);
	m_impl->m_funcs->glDrawArrays(GL_TRIANGLES, 0, 6);
}

  paintGL:

  1. 进行颜色清理,开启颜色混合。
  2. 激活着色器。
  3. 设置deltaTime对应Uniform的值。
  4. 绑定VAO。
  5. 绘制三角形。

实现效果

  背景不透明:
在这里插入图片描述
  背景透明:
在这里插入图片描述

Shader解析

GLSL基本函数

  GLSL提供了一些基本函数供我们使用:

  • abs(x):绝对值
  • ceil(x):向上取整
  • floor(x):向下取整
  • fract(x):小数部分
  • sqrt(x):平方根
  • pow(x, y):x 的 y 次幂
  • exp(x):e 的 x 次幂
  • log(x):自然对数
  • sin(x), cos(x), tan(x):三角函数
  • asin(x), acos(x), atan(x):反三角函数
  • min(x, y) / max(x, y):取最小/最大值
  • clamp(x, minVal, maxVal):限制 x 的范围
  • smoothstep(edge0, edge1, x):edge0和edge1区间进行平滑插值

  这里对clamp函数和smoothstep函数进行简单说明:

clamp

  • 函数原型
genType clamp(genType x, genType minVal, genType maxVal);
  • 参数说明

    • x:要限制的值(可以是标量、向量或矩阵)。
    • minVal:限制的最小值。
    • maxVal:限制的最大值。
  • 返回值

    • 如果x < minVal,返回 minVal。
    • 如果x > maxVal,返回 maxVal。
    • 如果minVal <= x <= maxVal,返回x。
  • 使用示例

void main()
{
    float value = 1.5;
    float clampedValue = clamp(value, 0.0, 1.0);
    // clampedValue 将被限制为 1.0,因为 1.5 超出了范围

    vec3 color = vec3(1.2, -0.5, 0.7);
    vec3 clampedColor = clamp(color, vec3(0.0), vec3(1.0));
    // clampedColor 将变为 (1.0, 0.0, 0.7)
}
  • 应用场景
    • 颜色处理:在处理颜色值时,确保其在有效范围内(如0到1)。
    • 位置或尺寸限制:在计算物体位置或尺寸时,确保其不会超出特定范围。
    • 控制效果:可以用来限制某些效果的强度,如光照、透明度等。

smoothstep

  • 函数原型
float smoothstep(float edge0, float edge1, float x);
  • 参数说明

    • edge0:插值的起始边界。
    • edge1:插值的结束边界。
    • x:输入值,将在edge0和edge1之间进行插值。
  • 返回值
      smoothstep根据输入值x的位置返回一个平滑插值的值:

    • 如果x < edge0,返回 0。
    • 如果x > edge1,返回 1。
    • 如果edge0 <= x <= edge1,返回一个平滑过渡的值,通常采用S型曲线插值。
  • 使用示例

void main()
{
    float value = 0.5;  // 输入值
    float edge0 = 0.0;  // 起始边界
    float edge1 = 1.0;  // 结束边界
    
    float result = smoothstep(edge0, edge1, value);
    // result 将会是 0.5 的平滑插值
}
  • 应用场景
    • 抗锯齿效果:在渲染时,可以使用smoothstep处理边缘,减少锯齿现象。
    • 渐变效果:在颜色或透明度变化中使用,以实现更平滑的过渡。
    • 生成自然的动画:在动画中,使物体的移动或变化更加自然平滑。

实现分析

  水平有限,只能分析下两个圆环进度动效的实现,这里标识上面效果图中从左到右依次为效果一、二、三。简单从动效分析可以得到下面基本的规律,下面片段着色器的实现也是围绕这些点来展开的。

  • 需要在整个画布上绘制圆环,圆环以外的点颜色值都为黑色或者透明。
  • 效果一在固定某一时刻,圆环上的的像素随上图中角1变化而变化。
  • 效果一在时间变化过程中,可以看作是点(固定颜色值)在绕圆心旋转,或者可以看成是点不动,每个点的颜色随着时间周期变化。由于我们操作的是片段着色器,所以看作是后者。
  • 效果二圆环上颜色随着圆环半径变化,圆环半径随着时间周期性变化。

效果一

  片段着色器代码:

"#version 330 core\n"
"#define SMOOTH(r) (mix(1.0, 0.0, smoothstep(0.9,1.0, r)))\n"
"#define M_PI 3.1415926535897932384626433832795\n"
"out vec4 fragColor;\n"
"in vec3 aPosFrag;\n"
"uniform float deltaTime;\n"
"uniform float r1;\n"
"uniform float r2;\n"
"float movingRing(vec2 uv, vec2 center, float r1, float r2)\n"
"{\n"
"	vec2 d = uv - center;\n"
"	float r = sqrt( dot( d, d ) );\n"
"	d = normalize(d);\n"
"	float theta = -atan(d.y,d.x);\n"
"	theta  = mod(-deltaTime+0.5*(1.0+theta/M_PI), 1.0);\n"
"	//anti aliasing for the ring's head (thanks to TDM !)\n"
"	theta -= max(theta - 1.0 + 1e-2, 0.0) * 1e2;\n"
"	return theta*(SMOOTH(r/r2)-SMOOTH(r/r1));\n"
"}\n"
"void main()\n"
"{\n"
"	vec2 uv = aPosFrag.xy;\n"
"	float ring = movingRing(uv, vec2(0.0), r1, r2);\n"
"	fragColor = vec4( 0.0 + 0.9*ring );\n"
"}\0";

  过程解析如下:

  • #version 330 core:版本号是330。
  • #define SMOOTH® (mix(1.0, 0.0, smoothstep(0.9,1.0, r))):定义SMOOTH®用于抗锯齿。
  • #define M_PI 3.1415926535897932384626433832795:定义PI。
  • out vec4 fragColor:定义输出颜色变量。
  • in vec3 aPosFrag:顶点着色器传入的坐标,由于绘制二维图形,z坐标都是0,没有意义。
  • uniform float deltaTime:主程序中传入的时间变量,随程序运行改变。
  • uniform float r1/r2:主程序传入的圆环半径。
  • float movingRing(vec2 uv, vec2 center, float r1, float r2):定义函数。
    • vec2 d = uv - center:计算当前点坐标向量和中心向量的差。
    • float r = sqrt( dot( d, d ) ):计算当前点的半径。
    • d = normalize(d):将差值向量归一化。
    • float theta = -atan(d.y,d.x):计算当前点与圆心连线和x轴的角度,用角1标识。
    • theta = mod(-deltaTime+0.5*(1.0+theta/M_PI), 1.0):构造了一个函数,该函数满足当deltaTime固定时,计算得到的theta值(可以看作颜色值)随当前点对应角1周期变化,当角1不变,当前点颜色值随时间周期性变化,满足上面的规律,并且得到的值在0到1范围(mod保证)可以表示颜色值。
    • theta -= max(theta - 1.0 + 1e-2, 0.0) * 1e2:存疑。
    • return theta*(SMOOTH(r/r2)-SMOOTH(r/r1)):由于smoothstep的特点,(SMOOTH(r/r2)-SMOOTH(r/r1))可以表示一个半径为r1和r2的圆环(r1 > r2),根据r的值不同分析可得r > r1 > r2时,表达式值为0,此时表示圆环外部的点;当r1 > r > r2,表达式的值为1,表示圆环中的点;当r1 > r2 > r,表达式值为0,表示圆环内部的点。另外这里添加了抗锯齿,当r在0.9至1.0倍r1大小和在0.9至1.0倍r2大小时,由于smoothstep中间段的插值,有抗锯齿的效果。最后再乘上颜色值theta,保证了只有圆环中的点颜色值不为0(笼统表述,抗锯齿边界部分除外)。
  • void main():定义main函数。
    • vec2 uv = aPosFrag.xy:获取当前点坐标。
    • float ring = movingRing(uv, vec2(0.0), r1, r2):调用函数计算颜色值。
    • fragColor = vec4( 0.0 + 0.9*ring ):输出颜色值。

效果二

  片段着色器代码:

"#version 330 core\n"
"uniform float deltaTime;\n"
"out vec4 fragColor;\n"
"in vec3 aPosFrag;\n"
"vec4 DARK_UI = vec4(0.0);\n"
"vec4 BU_BLUE = vec4(.2,.4,.7, 1.0);\n"
"vec4 BU_BLUE_END = vec4(.2,.4,.7, 0.0);\n"
"void main()\n"
"{\n"
"	vec2 uv = aPosFrag.xy * 0.5;\n"
"	vec4 c = DARK_UI;\n"
"	float q = smoothstep(0.,1.,mod(deltaTime/15.,.1)/.1);\n"
"	float m = clamp(length(uv)*2.5,0.,1.);\n"
"	if (abs(length(uv)-q/5.)<.01) {\n"
"		c=mix(BU_BLUE,BU_BLUE_END,m);\n"
"	}\n"
"	fragColor = c;\n"
"}\0";

  过程解析如下:

  • #version 330 core:版本号是330。
  • uniform float deltaTime:主程序中传入的时间变量,随程序运行改变。
  • out vec4 fragColor:输出颜色变量。
  • in vec3 aPosFrag:顶点着色器传入的坐标。
  • vec4 DARK_UI = vec4(0.0):定义背景色。
  • vec4 BU_BLUE = vec4(.2,.4,.7, 1.0):定义起始颜色。
  • vec4 BU_BLUE_END = vec4(.2,.4,.7, 0.0):定义终止颜色。
  • void main():定义main函数。
    • vec2 uv = aPosFrag.xy * 0.5:根据顶点着色器传入坐标转换为绘制的坐标,这里相当于将图形宽高放大两倍。
    • vec4 c = DARK_UI:将颜色值设置为背景色。
    • float q = smoothstep(0.,1.,mod(deltaTime/15.,.1)/.1):构造一个基准半径q,该半径随着时间变量在0.0至1.0范围做周期变化。
    • float m = clamp(length(uv)*2.5,0.,1.):构造一个混合系数,该系数随着距离圆心距离增加在0.0至1.0范围变化。
    • if (abs(length(uv)-q/5.)<.01):相当于构造了一个圆环,圆环基准半径随着q周期变化,圆环宽度在0.01*2。满足判断条件表示在圆环内。
    • c=mix(BU_BLUE,BU_BLUE_END,m):圆环内的颜色值设置为起始颜色和终止颜色根据m值混合,半径越大,m越大,越接近终止颜色。
    • fragColor = c:输出颜色值。

  对于其他效果,大家有兴趣可以自行下载源码尝试。(终于写完这篇了,时间仓促,有错误的地方大家多多指正~)

在这里插入图片描述


关注公众号:C++学习与探索,有惊喜哦~

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

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

相关文章

【Python】Beaker:轻量级缓存与会话管理的解决方案

Beaker 是一个简单、灵活的 Python 库&#xff0c;主要用于缓存管理和会话管理。作为一个开源项目&#xff0c;Beaker 提供了多种缓存存储后端&#xff0c;帮助开发者在应用中高效管理缓存数据&#xff0c;同时支持会话存储&#xff0c;适合 Web 应用中的用户状态管理。其轻量级…

WebAPI编程(第一天,第二天)

WebAPI编程&#xff08;第一天&#xff0c;第二天&#xff09; day01 - Web APIs1.1. Web API介绍1.1.1 API的概念1.1.2 Web API的概念1.1.3 API 和 Web API 总结 1.2. DOM 介绍1.2.1 什么是DOM1.2.2. DOM树 1.3. 获取元素1.3.1. 根据ID获取1.3.2. 根据标签名获取元素1.3.3. H5…

端侧多模态 | 不到10亿参数的端侧Agent竟媲美GPT-4V?AI手机不远了!

引言 简介 相关工作 模型 编码视觉信息 函数token 多阶段训练 模型评估 发送邮件 发送短信 Google搜索 Amazon购物 智能回收 失物招领 室内设计 Instacart购物 DoorDash(外卖平台)示例 动物护理 总结 引言 青山一道同云雨&#xff0c;明月何曾是两乡。 小伙…

王道-数据结构

1 设数组data[m]作为循环队列的存储空间,front为队头指针,rear为队尾指针,则执行出队操作后其头指针front值为____ 答案:D 解析:队列的头指针指向队首元素的实际位置,因此出队操作后,头指针需向上移动一个元素的位置。循环队列的容量为m,所以头指针front加1以后,需…

CVPR论文《DSVT: Dynamic Sparse Voxel Transformer with Rotated Sets》

1、整体思维导图 2、个人收获 这篇论文在理论上对于我来说可能就是让我大致了解了这个领域&#xff08;因为我的研究方向不是这方面&#xff09;&#xff0c;看完以后也没有看得特别懂&#xff08;说实话&#xff09;。 更多的收获应该是在论文的写作思路上吧 3、下面欣赏论…

分享几个可以免费使用GPT的网站【2024年必备】

1、ChatGPT 链接&#xff1a;点击直达 这个网站可以免费使用GPT4.0和GPT-4o模型&#xff0c;反应速度也很快&#xff0c;还有AI绘画可以体验喔~ 推荐指数&#xff1a;⭐⭐⭐⭐⭐ 2、AI智慧岛 链接&#xff1a;点击直达 推荐指数&#xff1a;⭐⭐⭐⭐⭐ 这个网站可以免费使…

Linux基础(四):文件权限与目录配置

1.使用者、群组、其他人概念 linux下每个文件都有三种权限类别&#xff0c;分别为使用者&#xff08;User&#xff09;、群组&#xff08;Group&#xff09;、其他人&#xff08;Others&#xff09;。这三种权限类别针对的是账号&#xff0c;也就是登录这个Linux系统的用户的账…

告别盲目推广!Xinstall为社交App带来精准流量

在移动互联网时代&#xff0c;社交类App如雨后春笋般涌现&#xff0c;但如何在众多竞争者中脱颖而出&#xff0c;成为用户首选&#xff1f;这不仅是开发者们面临的难题&#xff0c;也是推广者必须攻克的难关。今天&#xff0c;我们就来揭秘一种全新的社交类App推广策略&#xf…

64.【C语言】再议结构体(下)(未完)

本文衔接第63篇 目录 6.复习 7.修改默认对齐数 8.结构体传参 01.传递非指针参数 02.传递指针参数(传递地址) 03.对比 9.结构体实现位段 01.位段的定义 02.格式 03.例题 答案速查 分析 前置知识:位段的内存分配 解析 若按浪费空间处理 验证 6.复习 20.【C语言…

《OpenCV 计算机视觉》—— Harris角点检测、SIFT特征检测

文章目录 一、Harris 角点检测1.基本思想2.检测步骤3.OpenCV实现 二、SIFT特征检测1. SIFT特征检测的基本原理2. SIFT特征检测的特点3. OpenCV 实现 一、Harris 角点检测 OpenCV中的Harris角点检测是一种基于图像灰度值变化的角点提取算法&#xff0c;它通过计算每个像素点的响…

vue2 自定义empty指令

主要思路 定义一个echarts图标&#xff0c;数据为空&#xff0c;image采用base64编码图标宽高根据父宽高自适应渲染echarts函数&#xff0c;切换清除图例定义暂无数据指令 定义option /*** 暂无数据* param {number} width* param {number} height* returns option*/ functi…

全局思维下的联合创新:华为携手ISV伙伴助推银行核心平稳升级

文 | 螳螂观察 作者 | 李永华 随着数字金融快速发展&#xff0c;对核心系统提出了“海量、高效、弹性、扩展、敏捷”等新需求&#xff0c;区域性银行面临核心系统升级的迫切需要&#xff0c;对金融科技厂商而言也催生了庞大的机遇和空间。 只是&#xff0c;银行核心系统是金…

深度学习|求导公式:梯度逆传播规律

文章目录 引言基础函数的求导常数函数幂函数指数函数对数函数三角函数反三角函数双曲函数 复合函数的梯度逆传播链式法则函数相加函数相乘函数相除 结语 引言 我们知道&#xff0c;神经网络的能够学习处理任务的核心是计算损失的梯度&#xff0c;而误差逆传播算法是求梯度的一…

基于OpenCV的实时年龄与性别识别(支持CPU和GPU)

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色…

842真题上的各种简答题

线性表 1. 应选用链式存储结构&#xff0c;因为链式存储结构采取动态内存分配&#xff0c;可以在操作过程中增加或减少线性表的长度&#xff0c;且插入删除操作更方便 2应该选用顺序存储结构&#xff0c;因为顺序存储结构的访问和存取&#xff0c;都是按照元素序号的随机访问…

VisualGLM-6B——原理与部署

VisualGLM-6B技术原理介绍 VisualGLM-6B 是一种多模态预训练模型&#xff0c;它旨在将视觉和语言模型进行结合&#xff0c;使得语言模型能够理解图像信息并与文本对话无缝结合。为了更好地理解 VisualGLM-6B 的内容&#xff0c;我们可以从以下几个方面来解析它的原理、结构、训…

基于springboot+小程序的自习室选座与门禁管理系统(自习室1)(源码+sql脚本+视频导入教程+文档)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 1、管理员实现了首页、基础数据管理、论坛管理、公告信息管理、用户管理、座位管理等 2、用户实现了在论坛模块通过发帖与评论帖子的方式进行信息讨论&#xff0c;也能对账户进行在线充值…

低代码可视化-uniapp蓝牙标签打印-代码生成器

蓝牙标签打印 蓝牙标签打印技术结合了蓝牙通信与标签打印的功能&#xff0c;为用户提供了一种便捷、高效的打印解决方案。以下是对蓝牙标签打印的详细解析&#xff1a; 蓝牙标签打印机的特点 无线连接&#xff1a;蓝牙标签打印机最大的亮点在于其无线连接方式。用户可以通过蓝…

【Redis基础篇】超详细♥Redis安装教程、5种常用数据结构和常见命令、Jedis和SpringDataRedis的使用

文章目录 一、Redis与客户端安装教程1、NoSQL介绍&#xff08;1&#xff09;结构化与非结构化&#xff08;2&#xff09;关联和非关联&#xff08;3&#xff09;查询方式&#xff08;4&#xff09;事务&#xff08;5&#xff09;总结 2、Redis介绍3、安装Redis&#xff08;1&am…

毕业论文设计javaweb+VUE高校教师信息管理系统

目录 一、系统概述 二、功能详解 1. 教师管理 2. 部门管理 3. 奖惩管理 4. 业绩管理 5. 培训管理 6. 报表查询 三、总结 四、示例代码 1 前端VUE 2 后端SpringBootjava 3 数据库表 随着教育信息化的发展&#xff0c;传统的手工管理方式已经不能满足现代学校对教师…