Learn OpenGL In Qt之炫酷进度条

在这里插入图片描述

竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~
公众号: 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_OBJECTpublic: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 stylevoid 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.xdnf.cn/news/1550463.html

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

相关文章

2.点位管理——帝可得后台管理系统

目录 前言点位管理菜单模块1.需求说明2.库表设计3.生成基础代码0 .使用若依代码生成器最终目标1.创建点位管理2.添加数据字典3.配置代码生成信息4.下载代码并导入项目 4.优化菜单——点位管理1.优化区域管理2.增加点位数3. 合作商 前言 提示&#xff1a;本篇介绍点位管理模块&…

[论文精读]AI-Guardian: Defeating Adversarial Attacks using Backdoors

会议名称&#xff1a;2023 IEEE Symposium on Security and Privacy (SP) 发布链接&#xff1a;AI-Guardian: Defeating Adversarial Attacks using Backdoors | IEEE Conference Publication | IEEE Xplore 中文译名&#xff1a;AI-Guardian:利用后门防御对抗攻击 阅读原因…

记一次教学版内网渗透流程

信息收集 如果觉得文章写的不错可以共同交流 http://aertyxqdp1.target.yijinglab.com/dirsearch dirsearch -u "http://aertyxqdp1.target.yijinglab.com/"发现 http://aertyxqdp1.target.yijinglab.com/joomla/http://aertyxqdp1.target.yijinglab.com/phpMyA…

IT基础监控范围和对象

监控易作为一款由美信时代独立自主研发的分布式一体化集中监控平台&#xff0c;其监控范围极为广泛&#xff0c;几乎涵盖了所有主流的IT基础设施以及相关的设备和系统。以下是对监控易监控范围的详细介绍&#xff1a; 一、IT基础资源监控 服务器硬件监控&#xff1a;监控易支…

fmql之Linux阻塞和非阻塞IO

继续学习正点原子吧。 概念简介 什么是阻塞、非阻塞IO 阻塞/非阻塞访问的代码示例 等待队列&#xff08;阻塞访问使用&#xff09; 轮询&#xff08;非阻塞访问使用&#xff09; poll操作函数的使用&#xff08;轮询的一种&#xff09; 阻塞IO的实验 blockio.c blockioAPP.c 运…

大模型能力扩展之——提示词(Prompt),知识库,思维链(CoT)和Agent(代理)

前言 “大模型的推理能力配合外部工具才能真正发挥大模型的作用” 在学习和使用大模型的过程中&#xff0c;我们会发现大模型只能用来进行一下简单的问答&#xff1b;一旦涉及到复杂的问题&#xff0c;大模型就无能为力了。 其原因就在于我们并不会使用大模型&#xff0c;或…

【韩顺平Java笔记】第3章:变量

只记录我觉得重点的&#xff0c;自用&#xff0c;如果有漏的请自己看视频 文章目录 33. 内容梳理34. 变量原理34.1 为什么需要变量35. 变量概念35.1 概念35.2 变量使用的基本步骤36. 变量入门36.1 变量使用入门案例 37. 变量细节37.1 变量使用注意事项 38. 加号使用38.1 程序中…

Node.js安装Express,Node.js支持Typescript以及Express支持Typescript的步骤

1. Node.js 安装Express 运行如下命令&#xff1a; $ mkdir express-demo $ cd express-demo$ npm install express $ npm install body-parser //(可选)中间件&#xff0c;用于处理 JSON, Raw, Text 和 URL 编码的数据 $ npm install cookie-parser //(可选)通过req.cookies…

如何使用ssm实现大学生校园招聘网的设计与实现

TOC ssm738大学生校园招聘网的设计与实现jsp 第1章 绪论 1.1 课题背景 二十一世纪互联网的出现&#xff0c;改变了几千年以来人们的生活&#xff0c;不仅仅是生活物资的丰富&#xff0c;还有精神层次的丰富。在互联网诞生之前&#xff0c;地域位置往往是人们思想上不可跨域…

网页WebRTC电话和软电话哪个好用?

关于WebRTC电话与软件电话哪个更好用&#xff0c;这实际上取决于多个因素&#xff0c;并没有一个绝对的答案。不过&#xff0c;我可以根据WebRTC技术的一些特点&#xff0c;以及与传统软件电话相比的优劣势&#xff0c;为你提供一个清晰的对比。 首先&#xff0c;让我们了解一下…

单细胞miloR分析(基于 KNN 图的细胞差异丰度分析方法)

通常情况下&#xff0c;对两组或多组样本进行了不同处理/干预之后&#xff0c;研究者首先会进行同种细胞亚群处理前后的细胞数量的比较&#xff0c;但在单细胞分辨率时代之后&#xff0c;即使是同一个亚群中的不同细胞也应当看成不同的样本。 那么问题就来了&#xff0c;既然应…

算法:按既定顺序创建目标数组

力扣1389 提示&#xff1a; 1 < nums.length, index.length < 100nums.length index.length0 < nums[i] < 1000 < index[i] < i 题解&#xff1a; class Solution {public int[] createTargetArray(int[] nums, int[] index) {int[] target new int[num…

SD2.0 Specification之CRC(Cyclic Redundancy Code)

文章目录 本文章主要讲解关于SD2.0中的CRC应用&#xff0c;其它基础概念和其它内容请参考以下文章。 SD2.0 Specification简述 CRC全称为Cyclic Redundancy Code&#xff0c;中文名称是循环冗余校验&#xff0c;该方法通过附加冗余数据来保证数据的完整性&#xff0c;即用于检…

RabbitMQ的高级特性-限流

消息分发: RabbitMQ队列拥有多个消费者时, 队列会把收到的消息分派给不同的消费者. 每条消息只会发送给订阅列表⾥的⼀个消费者. 这种⽅式⾮常适合扩展, 如果现在负载加重,那么只需要创建更多的消费者来消费处理消息即可. 默认情况下, RabbitMQ是以轮询的⽅法进⾏分发的, ⽽不管…

BetterAndBetter--Mac上强大的手势操控软件,让你的Mac更加得心应手

很多新人在开始使用Mac的时候&#xff0c;很难脱离鼠标操作&#xff0c;但是Mac的触摸板可以说是Mac的一大特色&#xff0c;能够完成非常多的操作&#xff0c;甚至在有些时候比鼠标更加的好用&#xff0c;那么新手该如何使用触摸板呢&#xff0c;BetterAndBetter可以帮助新手快…

Alternative Reconciliation Accounts 备选统驭科目

业务场景&#xff1a; #1 海外项目对于应付账款&#xff0c;超过1年期的需要转入到其他科目&#xff1b; #2. 通过备选统驭科目进行 从应付账款&#xff0c;到应付账款-长期的结转 备选统驭科目的使用与配置 备选统驭科目&#xff08;AlternativeReconciliation Accounts)就…

Dynamics 365 dependency EntityType

导解决方案时经常会碰到组件依赖导致导入报错&#xff0c;而错误提示中组件只有type, 比如下图中的type 20和60, 初看之下并不知道是什么意思&#xff0c;从parentDisplayName能看出来&#xff0c;这个parent是个实体&#xff0c;但实体中的什么呢&#xff0c;目测是看不出来的…

怎样用python+sqlalchemy获得mssql视图对应物理表关系(二)

话不多说 目标:为了实现低代码数据视图对接,有必要得到视图所对应物理表及字段名称,字段类型等 1)约束:视图中用到的物理表不能起别名,所以修改上一篇中存储过程建立语句 USE [agui_conn] GO /****** Object: StoredProcedure [dbo].[sp_GetOrdersByTimestamp] Script D…

生信机器学习入门4 - 构建决策树(Decision Tree)和随机森林(Random Forest)分类器

机器学习文章回顾 生信机器学习入门1 - 数据预处理与线性回归&#xff08;Linear regression&#xff09;预测 生信机器学习入门2 - 机器学习基本概念 生信机器学习入门3 - Scikit-Learn训练机器学习分类感知器 生信机器学习入门4 - scikit-learn训练逻辑回归&#xff08;L…

第五周做题总结_数据结构_队列与应用

id:43 A. DS队列之银行排队 题目描述 银行营业大厅共服务3种客户&#xff0c;类型为A\B\C&#xff0c;大厅分别设置了3个窗口分别服务三种客户&#xff0c;即每个窗口只服务一种客户。现有一批客户来银行办理业务&#xff0c;每个客户都有类型和办理业务时间。每个窗口按照客…