用 GenieFramework 制作带动态表格的机场记分牌¶
本文将介绍如何创建一个网络应用程序--带有航班表的机场记分牌。要熟悉 GenieFramework 中网络应用程序的基本逻辑,建议阅读介绍性文章。在这里,我们将重点介绍通过DataTable
处理表格、与 CSV 文件交互以及使用异步循环动态更新数据。我们将特别关注为什么DataTable
用于显示表格,而不仅仅是DataFrame
。
应用代码¶
使用 GenieFramework
使用 Stipple
使用 Stipple.Tables
使用 DataFrames
使用日期
使用 CSV
函数 generate_flight_data()
DataFrame(
"航班号"=>["SU123", "AF456", "BA789"]、
"目的地"=>["莫斯科"、"巴黎"、"伦敦"]、
"Departure Time" => [Dates.format(now() + Hour(rand(1:5)), "HH:MM") for _ in 1:3]、
"状态" => ["准时"、"延迟"、"取消"] )
)
结束
@app begin
@out current_time = "当前时间:" * Dates.format(now(), "HH:MM:SS")
@out flight_table = DataTable(DataFrame()) # 初始为空表
@onchange isready begin
initial_df = generate_flight_data()
CSV.write("flight_data.csv", initial_df)
flight_table = DataTable(initial_df)
@async while true
sleep(5)
current_time = "当前时间:" * Dates.format(now(), "HH:MM:SS")
df = CSV.read("flight_data.csv", DataFrame, types=String)
df.Status[rand(1:3)] = rand(["准时"、"延误"、"取消"])
CSV.write("flight_data.csv", df)
flight_table = DataTable(df)
结束
结束
结束
函数 ui()
[
h3("{{current_time}}"),
table(:flight_table; dense=true, flat=true)
]
结束
@page("/", ui)
程序逻辑:逐步分析¶
连接软件包¶
使用了以下软件包:
GenieFramework
:创建网络应用程序的主要框架。Stipple
:提供服务器和界面之间的反应和通信。Stipple.Tables
:提供DataTable
,以便在网络界面显示表格。DataFrames
,Dates
,CSV
:需要用于表格数据、时间格式化和文件操作。
每个软件包都扮演着不同的角色,为应用程序提供一套最基本的工具。
数据生成¶
函数generate_flight_data()
可创建航班表:
- 返回一个包含四列的对象
DataFrame
:
-FlightNumber
: 航班号("SU123"、"AF456"、"BA789")。
-Destination
: 目的地("莫斯科"、"巴黎"、"伦敦")。
-DepartureTime
: 出发时间,格式为 "HH:MM",基于当前时间加上随机偏移(1-5 小时)。
-Status
: 航班状态("准时"、"延误"、"取消")。 - 该函数模拟记分牌的初始数据,然后随着应用程序的运行进行修改。
数据模型:变量¶
@app
块定义了数据模型:
@out current_time
:一个包含当前时间字符串("Current time: HH:MM:SS")的反应式变量。启动时初始设置,随后更新。@out flight_table
:一个DataTable
类型的反应式变量,最初为空 (DataTable(DataFrame())
)。加载应用程序时,它将被填入数据。
这些变量可在界面中显示,并在发生变化时自动更新。
数据模型:初始化和更新¶
@onchange isready
处理程序管理应用程序逻辑:
isready
及其作用:
-isready
是一个嵌入式反应式 Stipple 变量,初始值为false
。当客户端(浏览器)完全加载页面并通过 WebSocket 与服务器建立连接后,它就会变成true
。
-@onchange isready
意味着,当isready
从false
变为true
时,即应用程序首次在客户端成功加载时,代码块内的代码会被执行一次。这并不意味着更新仅限于这一点--@onchange
运行一次代码,但我们可以在其中启动持久进程。- 我们使用
@onchange isready
,以确保数据初始化和更新周期的启动仅在界面准备好运行时发生。否则,代码可能会在与客户端建立通信之前过早执行,从而导致同步错误。
- 我们使用
- 初始化**:
- 通过
generate_flight_data()
创建初始表initial_df
。 - 数据被写入文件
flight_data.csv
。
-flight_table
通过DataTable(initial_df)
更新。
- 通过
- 异步循环:
- 通过
@async while true
运行,创建后台任务。 - 每 5 秒 (
sleep(5)
):- 刷新
current_time
。 - 从文件中读取数据,参数
types=String
保存字符串格式。 - 随机改变一个航班的状态。
- 更新后的数据将写入文件并分配给
flight_table
。
- 刷新
- 通过
界面¶
函数ui()
定义了外观:
-h3("{{current_time}}")
**:显示自动更新的当前时间。
table(:flight_table; dense=true, flat=true)
:创建与flight_table
相链接的表格。
-dense=true
使表格更加紧凑。
-flat=true
删除阴影,使设计更简洁。
-DataTable
根据列名自动生成标题DataFrame
。
页面注册¶
@page("/", ui)
:表示接口可通过根路由"/"访问。至此,应用程序配置完成。
为什么是DataTable
,而不是DataFrame
?¶
DataFrame
- 是 Julia 在代码中处理表格数据的强大工具。它非常适合处理数据:过滤、排序和计算。不过,DataFrame
本身并不打算在网页界面上显示。它在程序内存中表示数据,但没有将数据传输到浏览器或渲染为 HTML 表格的内置逻辑。
DataTable
Stipple.Tables
解决了这一问题:
- 反应:
DataTable
与 Stipple 反应系统集成。当flight_table
中的数据发生变化时,界面会自动更新,无需手动重绘表格。 - 网络格式化:
DataTable
将DataFrame
转换为与 Quasar(Stipple 用于界面的框架)兼容的结构,添加所需的标题和数据格式。 - 简单:使用
table(:flight_table)
,我们无需编写复杂的 HTML 或 JavaScript 代码即可显示数据。如果只使用DataFrame
,我们就必须手动将其转换为字典数组 (Vector{Dict}
) 并将其传递给接口,这样就会使代码变得复杂。
因此,DataFrame
是 "原始 "数据,而DataTable
则是它与网络界面之间的 "桥梁",提供了便利性和自动化。
如何运行应用程序?¶
进入包含当前脚本的文件夹,执行下面的方框。
这将打开一个包含网络应用程序的窗口。
如果没有在单独的标签页中打开,请单击输出单元格中的链接。
-match(r"'(https?://[^']+)'"
允许您使用[正则表达式]根据 engee.genie.start 函数的输出查找链接(https://engee.com/helpcenter/stable/ru/interactive-scripts/language_basics/regex.html)
-Markdown.parse
用于在输出单元格中显示 "可点击 "链接。
using Markdown
cd(@__DIR__)
app_url = string(engee.genie.start(string(@__DIR__,"/app.jl")))
Markdown.parse(match(r"'(https?://[^']+)'",app_url)[1])
结论¶
本应用程序演示了使用动态表格创建机场记分牌的过程。我们介绍了生成数据、将数据保存到文件、通过异步循环更新数据以及使用DataTable
显示数据。每个代码块都执行了各自的任务,提供了简约而实用的实现方式。DataTable
是简化表格数据与网络界面整合的关键要素,而这是通常的DataFrame
无法实现的。要充分理解其中的逻辑,我们建议您浏览一下整个代码--这将有助于您了解所有部分之间的关系。