【Qt之Quick模块】6. QML语法详解_4 集成QML和JavaScript

QML语法详解_4 集成QML和JavaScript

  • 1. JavaScript表达式和属性绑定
    • 1.1 属性绑定
  • 1.2 JavaScript函数
  • 2. 从JavaScript动态创建QML对象
    • 2.1 动态创建对象
      • 2.1.1 Qt.createComponent()动态创建组件
      • 2.1.2 Qt.createQmlObject()从QML字符串创建对象
    • 2.2 维护动态创建的对象
    • 2.3 动态删除对象
  • 3. 在QML中定义JavaScript资源
    • 3.1 代码隐藏实现资源
    • 3.2 共享JavaScript资源库
  • 4. 在QML中导入JavaScript资源
    • 4.1 在QML文档中导入JavaScript资源
    • 4.2 在JavaScript资源中进行导入
  • 5. JavaScript宿主环境

1. JavaScript表达式和属性绑定

QML语言允许表达式和方法使用JavaScript函数进行定义。

1.1 属性绑定

  1. 一般绑定
    当创建一个属性绑定,而且为属性设置一个表达式,那么表达式的计算结果就是属性的值。
import QtQuickWindow {width: 640height: 480visible: truetitle: qsTr("Hello World")Rectangle{width: 100height: parent.height/2border.color: "red"anchors.centerIn: parent}
}

如上,当Windowheight改变时,Rectangleheight也会自动更新新的值。
image.png

还可以使用别的JavaScript表达式或语句,如下:

import QtQuickWindow {width: 640height: 480visible: truetitle: qsTr("Hello World")Rectangle{width: 100height: parent.height > 480 ? parent.height/2 : parent.height/3border.color: "red"anchors.centerIn: parent}
}

当Window的parent.height值发生变化时,QML引擎都会重新计算这些表达式,并将更新后的值设置给QRectangle的height属性。
parent.height > 480时:
image.png
parent.height < 480时:
image.png
根据其语法可以看出,绑定是复杂的,因此不建议绑定中包含过多的代码。而且如果绑定复杂,可以考虑将绑定代码重构,放到一个函数里。
注意
如果绑定后,再次赋值,绑定会失效的。
如,设置Qrectangle的width属性为别的item的width:

Rectangle{
width:otherItem.width
}

当设置为下面代码时:

Rectangle{
Component.OnCompleted:{width = otherItem.width
}
}

当程序初始化完成,绑定就会失效。
2. 使用binding()绑定
属性一旦绑定一个表达式,属性就会根据表达式进行自动更新。如果再次给属性赋值一个静态值,则绑定关系失效。
如果需求是这样,那就没问题。如果是想重新建立一个新的绑定,则需要使用Qt.binding()来实现,向Qt.binding()传递一个函数来返回需要的结果。
如下:

import QtQuickWindow {id:rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")Rectangle{id:recttanglewidth: 100height: parent.height > 480 ? parent.height/2 : parent.height/3border.color: "red"anchors.centerIn: parent}Component.onCompleted: {recttangle.height = Qt.binding(function(){return root.height/4})}
}

image.png
当初始化完成,会创建新的绑定。
3. 在属性绑定中使用this关键字
this可以在属性绑定中用于消除歧义。
当使用JavaScript创建一个属性绑定时,QML允许使用this关键字引用该属性绑定将要分配的对象。
如下,当在Component.onCompleted中进行recttangle.height属性绑定时,后面的this则是rectangle对象,而不是Window对象。

import QtQuickWindow {id:rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")Rectangle{id:recttanglewidth: 100height: parent.height > 480 ? parent.height/2 : parent.height/3border.color: "red"anchors.centerIn: parent}Component.onCompleted: {recttangle.height = Qt.binding(function(){return this.width*2})}
}

打印recttangle.height,结果为200

1.2 JavaScript函数

  1. 自定义函数或方法
import QtQuickWindow {id:rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")Text {id: texttext: qsTr("text")anchors.centerIn: parentfont.pixelSize: 23}function add(a, b){return a+b}Component.onCompleted: {text.text = add(1, 2)}
}

当初始化完成,屏幕正中间会显示3
2. 导入JavaScript文件中的函数
当有一个js文件,里面定义一个add方法,
如下:

// funAdd.js
function add(a, b) {return a+b
}

导入:

import QtQuick
import "./funAdd.js" as FunAddWindow {id:rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")Text {id: texttext: qsTr("text")anchors.centerIn: parentfont.pixelSize: 23}Component.onCompleted: {text.text = FunAdd.add(1, 2)console.log(text.text) // "3"}
}
  1. 关联信号和JavaScript函数
    发射信号的QML对象类型会提供一个默认的信号处理器。但有时需要从一个对象发射一个信号来触发另一个对象的定义的函数,这时需要用到connect()函数。
// funAdd.js
function prin(){console.log("helloworld")
}

调用:

import QtQuick
import "./funAdd.js" as FunAddWindow {id:rootwidth: 640height: 480visible: truetitle: qsTr("Hello World")color: "gray"MouseArea {id: mouseAreaanchors.fill: parent}Component.onCompleted :{mouseArea.clicked.connect(FunAdd.prin) // 当点击屏幕时,打印"helloworld"}
}

在这里插入图片描述

2. 从JavaScript动态创建QML对象

QML支持从JavaScript内部动态创建对象。这有助于将对象的实例化延迟到必要的时候,从而改善应用程序的启动时间。它还允许根据用户输入或其他事件动态创建视觉对象并将其添加到场景中。

2.1 动态创建对象

有两种方法可以从JavaScript动态创建对象。一是可以调用Qt.createComponent()来动态地创建一个Component对象;二是使用Qt.createQmlObject()从一个QML字符串创建一个对象。如果在QML文档中定义了现有组件,并且希望动态创建该组件的实例,则第一种方式更好。当对象QML本身在运行时生成时,可以使用第二种方式。

2.1.1 Qt.createComponent()动态创建组件

要动态加载在QML文件中定义的组件,可以调用Qt对象中的Qt. createcomponent()函数。该函数将QML文件的URL作为其唯一参数,并从该URL创建一个Component对象。
一旦有了一个组件,就可以调用它的createObject()方法来创建组件的实例。这个函数可以接受一个或两个参数:

  • 第一个是新对象的父对象。父对象可以是图形对象(即Item类型)或非图形对象(即QtObject或c++ QObject类型)。只有具有图形父对象的图形对象才会呈现到Qt Quick可视化画布中。如果希望稍后设置父类,可以将null传递给此函数。
  • 第二个是可选的,它是一个属性值对的映射,用于定义对象的初始属性值。此参数指定的属性值在对象的创建完成之前应用于该对象,从而避免了在必须初始化特定属性以启用其他属性绑定时可能发生的绑定错误。此外,与在创建对象之后定义属性值和绑定相比,还有一些性能优势。
    示例:
    先创建一个Sprite.qml文件
 import QtQuick 2.0Rectangle { width: 80; height: 50; color: "red" }

再创建一个componentCreation.js文件

 var component;var sprite;function createSpriteObjects() {component = Qt.createComponent("Sprite.qml");if (component.status == Component.Ready)finishCreation();elsecomponent.statusChanged.connect(finishCreation);}function finishCreation() {if (component.status == Component.Ready) {sprite = component.createObject(appWindow, {x: 100, y: 100});if (sprite == null) {// 错误处理console.log("Error creating object");}} else if (component.status == Component.Error) {// 错误处理console.log("Error loading component:", component.errorString());}}

最后在main.qml中进行调用

 import QtQuick 2.0import "componentCreation.js" as MyScriptRectangle {id: appWindowwidth: 300; height: 300Component.onCompleted: MyScript.createSpriteObjects();}

调用createObject前检查了组件的状态是否是Component.Ready,因为如果QML文件是从网络上加载的,它不会立即可用。
如果是本地文件加载,可以直接在createSpriteObjects函数内调用createObject方法。

 function createSpriteObjects() {component = Qt.createComponent("Sprite.qml");sprite = component.createObject(appWindow, {x: 100, y: 100});if (sprite == null) {// 错误处理console.log("Error creating object");}}

注意,在这两个实例中,createObject()被调用时,appWindow作为父参数传递,因为动态创建的对象是一个可视化(Qt Quick)对象。创建的对象将成为main中appWindow对象的子对象。Qml,并出现在场景中。

当使用具有相对路径的文件时,路径应该相对于执行Qt.createComponent()的文件。

要将信号连接到(或从)动态创建的对象接收信号,可以使用signal connect()方法。
也可以通过incubateObject()函数实例化组件,该函数是非阻塞的。

2.1.2 Qt.createQmlObject()从QML字符串创建对象

如果QML直到运行时才定义,可以使用Qt.createQmlObject()函数从QML字符串创建一个QML对象,如下例所示:

 const newObject = Qt.createQmlObject(`import QtQuick 2.0Rectangle {color: "red"width: 20height: 20}`,parentItem,"myDynamicSnippet");
  • 第一个参数是要创建的QML字符串。就像在新文件中一样,您需要导入希望使用的任何类型。
  • 第二个参数是新对象的父对象,应用于组件的父参数语义同样适用于createQmlObject()。
  • 第三个参数是要与新对象关联的文件路径;这用于错误报告。

如果QML字符串使用相对路径导入文件,则该路径应该相对于定义父对象(方法的第二个参数)的文件.
重要:在构建静态QML应用程序时,将扫描QML文件以检测导入依赖项。这样,所有必要的插件和资源都可以在编译时解析。但是,只考虑显式导入语句(在QML文件顶部找到的语句),而不考虑包含在字符串字面量中的导入语句。因此,为了支持静态构建,需要确保使用Qt.createQmlObject()的QML文件在文件顶部显式地包含所有必要的导入,而不是在字符串文字中。

2.2 维护动态创建的对象

在管理动态创建的对象时,必须确保创建上下文比创建的对象更长寿。否则,如果首先销毁创建上下文,则动态对象中的绑定和信号处理程序将不再工作。
实际的创建上下文取决于对象是如何创建的:

  • 如果使用了Qt.createComponent(),那么创建上下文就是调用该方法的QQmlContext
  • 如果调用Qt.createQmlObject(),则创建上下文是传递给该方法的父对象的上下文
  • 如果定义了一个Component{}对象,并且在该对象上调用了createObject()或cucubateobject(),那么创建上下文就是定义组件的上下文

另外,请注意,虽然动态创建的对象可以与其他对象一样使用,但它们在QML中没有id。

2.3 动态删除对象

在许多用户界面中,将可视对象的不透明度设置为0或将可视对象移出屏幕而不是删除它就足够了。但是,如果有很多动态创建的对象,那么如果删除未使用的对象,可能会获得有价值的性能优势。
注意,永远不要手动删除由方便的QML对象工厂(如Loader和Repeater)动态创建的对象。此外,应该避免删除不是自己动态创建的对象。
可以使用destroy()方法删除项。此方法有一个可选参数(默认为0),该参数指定对象被销毁前的大约毫秒延迟。
如下例子:application.qml创建了5个SelfDestroyingRect.qml组件。每个实例都运行一个NumberAnimation,当动画结束时,调用它的根对象destroy()来销毁自己:

// application.qmlimport QtQuick 2.0Item {id: containerwidth: 500; height: 100Component.onCompleted: {var component = Qt.createComponent("SelfDestroyingRect.qml");for (var i=0; i<5; i++) {var object = component.createObject(container);object.x = (object.width + 10) * i;}}}
// SelfDestroyingRect.qmlimport QtQuick 2.0Rectangle {id: rectwidth: 80; height: 80color: "red"NumberAnimation on opacity {to: 0duration: 1000onRunningChanged: {if (!running) {console.log("Destroying...")rect.destroy();}}}}

或者,application.qml可以通过调用object.destroy()来销毁创建的对象。

注意,在对象内部的对象上调用destroy()是安全的。对象不会在destroy()被调用的瞬间被销毁,而是在脚本块结束和下一帧之间的某个时间被清理(除非指定了非零延迟)。

还要注意,如果像这样静态地创建一个SelfDestroyingRect实例:

 Item {SelfDestroyingRect {// ...}}

这将导致错误,因为对象只有在动态创建时才能动态销毁。

使用Qt.createQmlObject()创建的对象也可以使用destroy()销毁。

 const newObject = Qt.createQmlObject(`import QtQuick 2.0Rectangle {color: "red"width: 20height: 20}`,parentItem,"myDynamicSnippet");newObject.destroy(1000);

3. 在QML中定义JavaScript资源

QML应用程序的程序逻辑可以用JavaScript定义。JavaScript代码可以在QML文档中内联定义,也可以分离到JavaScript文件中(在QML中称为JavaScript资源)。

QML中支持两种不同类型的JavaScript资源:代码隐藏实现文件和共享(库)文件。这两种JavaScript资源都可以被其他JavaScript资源导入,或者包含在QML模块中。

3.1 代码隐藏实现资源

导入到QML文档中的大多数JavaScript文件都有状态的。在这些情况下,文档中定义的QML对象类型的每个实例都需要JavaScript对象和状态的单独副本才能正确运行。

导入JavaScript文件时的默认行为是为每个QML组件实例提供唯一的、隔离的副本。如果该JavaScript文件没有使用.import语句导入任何资源或模块,则其代码将在与QML组件实例相同的作用域中运行,因此可以访问和操作在该QML组件中声明的对象和属性。否则,它将有自己独特的作用域,如果需要的话,QML组件的对象和属性应该作为参数传递给JavaScript文件的函数。

代码隐藏实现资源的示例如下:

 // my_button_impl.jsvar clickCount = 0;   // this state is separate for each instance of MyButtonfunction onClicked(button) {clickCount += 1;if ((clickCount % 5) == 0) {button.color = Qt.rgba(1,0,0,1);} else {button.color = Qt.rgba(0,1,0,1);}}
 // MyButton.qmlimport QtQuick 2.0import "my_button_impl.js" as Logic // A new instance of this JavaScript resource// is loaded for each instance of Button.qml.Rectangle {id: rectwidth: 200height: 100color: "red"MouseArea {id: mouseareaanchors.fill: parentonClicked: Logic.onClicked(rect)}}

一般来说,应该在QML文件中内联定义简单的逻辑,但是为了可维护性和可读性,应该将更复杂的逻辑分离到代码隐藏实现资源中。

3.2 共享JavaScript资源库

默认情况下,从QML导入的JavaScript文件与QML组件共享它们的上下文。这意味着JavaScript文件可以访问相同的QML对象并可以修改它们。因此,每次导入必须具有这些文件的唯一副本。

前一节介绍了JavaScript文件的有状态导入。然而,有些JavaScript文件是无状态的,更像是可重用的库,因为它们提供了一组不需要从它们被导入的地方获取任何东西的辅助函数。如果使用特殊的pragma标记这些库,可以节省大量内存并加快QML组件的实例化速度,如下面的示例所示。

 // factorial.js.pragma libraryvar factorialCount = 0;function factorial(a) {a = parseInt(a);// factorial recursionif (a > 0)return a * factorial(a - 1);// shared statefactorialCount += 1;// recursion base-case.return 1;}function factorialCallCount() {return factorialCount;}

pragma声明必须出现在除注释以外的任何JavaScript代码之前。

注意,多个QML文档可以导入“factorial.js”并调用它提供的factorial和factorialCallCount函数。JavaScript导入的状态在导入它的QML文档之间共享,因此在从未调用阶乘函数的QML文档中调用factoralcallcount函数时,其返回值可能是非零的。

例如:

 // Calculator.qmlimport QtQuick 2.0import "factorial.js" as FactorialCalculator // This JavaScript resource is only// ever loaded once by the engine,// even if multiple instances of// Calculator.qml are created.Text {width: 500height: 100property int input: 17text: "The factorial of " + input + " is: " + FactorialCalculator.factorial(input)}

因为它们是共享的,所以.pragma库文件不能直接访问QML组件实例对象或属性,尽管QML值可以作为函数参数传递。

4. 在QML中导入JavaScript资源

JavaScript资源可以通过QML文档和其他JavaScript资源导入。JavaScript资源可以通过相对url或绝对url导入。在相对URL的情况下,相对于包含导入的QML文档或JavaScript资源的位置解析位置。如果脚本文件不可访问,则会出现错误。如果需要从网络资源中获取JavaScript,则该组件的状态被设置为“Loading”,直到脚本下载完成。

JavaScript资源也可以导入QML模块和其他JavaScript资源。JavaScript资源中的导入语句的语法与QML文档中的导入语句略有不同,下面将详细说明这一点。

4.1 在QML文档中导入JavaScript资源

QML文档可以用以下语法导入JavaScript资源:

 import "ResourceURL" as Qualifier

如:

 import "jsfile.js" as Logic

导入的JavaScript资源总是使用“as”关键字进行限定。JavaScript资源的限定符必须以大写字母开头,并且必须是唯一的,因此限定符和JavaScript文件之间始终存在一对一的映射。(这也意味着限定符的命名不能与内置JavaScript对象(如Date和Math)相同。)

通过“Qualifier.functionName(params)”语法,导入的JavaScript文件中定义的函数可用于导入的QML文档中定义的对象。JavaScript资源中的函数可以接受参数,这些参数的类型可以是任何受支持的QML基本类型或对象类型,也可以是普通的JavaScript类型。当从QML调用这些函数时,普通的数据类型转换规则将应用于参数和返回值。

4.2 在JavaScript资源中进行导入

在QtQuick 2.0中,添加了支持,允许JavaScript资源使用标准QML导入语法的一种变体导入其他JavaScript资源和QML类型名称空间(其中应用前面描述的所有规则和限定条件)。
由于JavaScript资源能够在QtQuick 2.0中以这种方式导入另一个脚本或QML模块,因此定义了一些额外的语义:

  • 带有导入的脚本不会从导入它的QML文档继承导入(因此访问组件)。(例如,无法访问Component.errorString)
  • 没有导入的脚本将从导入它的QML文档继承导入(因此访问组件)。(例如,可以访问Component.errorString)
  • 共享脚本(即,定义为.pragma库)不继承任何QML文档的导入,即使它不导入其他脚本或模块

第一种语义在概念上是正确的,因为一个特定的脚本可以被任意数量的QML文件导入。保留第二个语义是为了向后兼容。第三种语义与当前共享脚本的语义保持不变,但在这里针对新的可能情况(脚本导入其他脚本或模块)进行了澄清。
从另一个JavaScript资源中导入JavaScript资源:

 import * as MathFunctions from "factorial.mjs";

或者

 .import "filename.js" as Qualifier

前者是用于导入ECMAScript模块的标准ECMAScript语法,并且只能在由mjs文件扩展名表示的ECMAScript模块中工作。后者是由QML引擎提供的对JavaScript的扩展,也可以与非模块一起工作。作为一个被ECMAScript标准取代的扩展,不鼓励使用它。

当以这种方式导入JavaScript文件时,它是用限定符导入的。然后可以从导入脚本中通过限定符(即qualifier.functionname (params))访问该文件中的函数。

有时,希望在导入上下文中提供可用的函数,而不需要对它们进行限定。在这种情况下,ECMAScript模块和JavaScript import语句应该不带as限定符。

例如,下面的QML代码在脚本中调用script.mjs中的showcalculation()。而在script.mjs中调用了factorial.mjs中的factorial()函数。

 import QtQuick 2.0import "script.mjs" as MyScriptItem {width: 100; height: 100MouseArea {anchors.fill: parentonClicked: {MyScript.showCalculations(10)console.log("Call factorial() from QML:",MyScript.factorial(10))}}}
 // script.mjsimport { factorial } from "factorial.mjs"export { factorial }export function showCalculations(value) {console.log("Call factorial() from script.js:",factorial(value));}
 // factorial.mjsexport function factorial(a) {a = parseInt(a);if (a <= 0)return 1;elsereturn a * factorial(a - 1);}

5. JavaScript宿主环境

QML提供了一个专门用于编写QML应用程序的JavaScript主机环境。该环境不同于浏览器提供的主机环境或服务器端JavaScript环境(如Node.js)。例如,QML不提供在浏览器环境中常见的窗口对象或DOM API。

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

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

相关文章

go执行静态二进制文件和执行动态库文件

目的和需求&#xff1a;部分go的核心文件不开源&#xff0c;例如验证&#xff0c;主程序核心逻辑等等 第一个想法&#xff0c;把子程序代码打包成静态文件&#xff0c;然后主程序执行 子程序 package mainimport ("fmt""github.com/gogf/gf/v2/os/gfile"…

git在本地创建dev分支并和远程的dev分支关联起来

文章目录 git在本地创建dev分支并和远程的dev分支关联起来1. 使用git命令2. 使用idea2.1 先删除上面建的本地分支dev2.2 通过idea建dev分支并和远程dev分支关联 3. 查看本地分支和远程分支的关系 git在本地创建dev分支并和远程的dev分支关联起来 1. 使用git命令 git checkout…

DrGraph原理示教 - OpenCV 4 功能 - 颜色变幻

二值化是逐像素处理&#xff0c;而逐像素处理会有很多效果&#xff0c;这主要是给人眼看的&#xff0c;因为像素值的变化&#xff0c;直观的就是图像变化&#xff0c;比如颜色。 颜色变幻处理 OpenCV提供了一些图片&#xff0c;如下&#xff1a; 粗看是一些风格&#xff0c;…

【Nginx】反向代理和负载均衡

反向代理 nginx 反向代理&#xff0c;就是将前端发送的动态请求由 nginx 转发到后端服务器。 server {listen 80;server_name localhost;# 反向代理,处理管理端发送的请求location /api/ {proxy_pass http://localhost:8080/admin/;#proxy_pass http://webservers/…

通过聚道云软件连接器实现金蝶软件与红圈CRM软件的无缝对接

一、客户介绍 某知名汽车行业公司&#xff0c;致力于为汽车行业提供全面的研发、检测和技术支持服务。该公司拥有一支高素质的研发团队和先进的实验设备&#xff0c;具备强大的研发能力和技术实力。同时&#xff0c;该公司与国内外众多知名汽车企业建立了紧密的合作关系&#…

重新认识一下 vue3 应用实例

重新认识一下 vue 应用实例 &#x1f495; 创建应用实例 每个 Vue 应用都是通过 createApp 函数创建一个新的 应用实例 应用实例必须在调用了 .mount() 方法后才会渲染出来。该方法接收一个“容器”参数&#xff0c;可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串 //…

【Java期末】学生成绩管理系统

诚接计算机专业编程任务(C语言、C、Python、Java、HTML、JavaScript、Vue等)10/15R&#xff0c;如有需要请私信我&#xff0c;或者加我的企鹅号&#xff1a;1404293476 本文资源下载地址&#xff1a;https://download.csdn.net/download/weixin_47040861/88697244 —————…

Plantuml之nwdiag网络图语法介绍(二十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

GPU的硬件架构

SM: streaming Multiprocessor 流多处理器 sm里面有多个(sp)cuda core 32个线程称为一个warp&#xff0c;一个warp是一个基本执行单元 抽象概念&#xff1a;grid 网格 block 块 thread 线程 块中的线程大小是有讲究的&#xff0c;关乎到资源的调度&#xff0c;一般是128&#x…

[Ray Tracing: The Rest of Your Life] 笔记

前言 开年第一篇博客~ 整理了三四个小时才整理完orz。 这一部分是光线追踪三部曲的最后一部&#xff0c;主要介绍了蒙特卡洛积分、重要性采样等内容。场景上没有什么大的改变&#xff0c;基本上就是在Cornell Box中渲染的&#xff0c;本篇主要在加速收敛&#xff0c;提升渲染效…

60.Go反射库reflect

文章目录 一、简介二、前置总结三、接口四、反射基础五、反射用法1、透视数据组成2、调用函数或方法3、设置值4、StructTag 六、实战案例 一、简介 反射是一种机制&#xff0c;在编译时不知道具体类型的情况下&#xff0c;可以透视结构的组成、更新值。使用反射&#xff0c;可…

目标检测-One Stage-RetinaNet

文章目录 前言一、RetinaNet的网络结构和流程二、RetinaNet的创新点Balanced Cross EntropyFocal Loss 总结 前言 根据前文目标检测-One Stage-YOLOv2可以看出YOLOv2的速度和精度都有相当程度的提升&#xff0c;但是One Stage目标检测模型仍存在一个很大的问题&#xff1a; 前…