动手创造 · PROJECT LAB
准备探索你的新作品
投票App
0%
★★☆ 项目难度每一步,都离作品更近
先了解你将做出什么
应用介绍
这次做一个最小但完整的多人投票:所有用户看到同一个问题,点击“赞成”或“反对”后,云数据库 会把最新票数推给所有在线设备。重点不是画复杂图表,而是理解云数据“发起请求、等待回调、实时同步”的流程。

投票App教程(难度系数:★★☆)
准备组件
| 组件类型 | 组件名称 | 关键设置 |
|---|---|---|
| 标签 | 标签_问题 |
显示投票问题 |
| 按钮 | 按钮_是 |
文本:赞成 |
| 按钮 | 按钮_否 |
文本:反对 |
| 标签 | 标签_是 |
显示赞成票数 |
| 标签 | 标签_否 |
显示反对票数 |
| 标签 | 标签_状态 |
显示同步状态 |
| 按钮 | 按钮_重置 |
管理员重置 |
| 云数据库 | 云数据库1 |
非可视组件 |
云数据库 使用两个标签保存列表:yes 存赞成票,no 存反对票。列表长度就是票数,列表内容本身不重要。
统一更新票数
云数据库 的 GotValue 和 DataChanged 都会带回标签和值。把两种事件都交给同一个过程,
可以避免写两份几乎一样的计数逻辑。
global 赞成票 = []
global 反对票 = []
procedure 更新票数(tag, value) {
if tag = "yes" {
赞成票 = value
} else if tag = "no" {
反对票 = value
}
标签_是.Text = join("赞成:", length(赞成票))
标签_否.Text = join("反对:", length(反对票))
}
when Screen1.Initialize() {
云数据库1.GetValue("yes", [])
云数据库1.GetValue("no", [])
标签_状态.Text = "正在读取票数……"
}
when 云数据库1.GotValue(tag, value) {
更新票数(tag, value)
标签_状态.Text = "票数已更新"
}
when 云数据库1.DataChanged(tag, value) {
更新票数(tag, value)
}
GetValue 不会立刻返回列表,结果在 GotValue 事件里;其他用户投票时,本机则会收到 DataChanged。
这就是云数据库和本地 微数据库 最大的使用差别。
记录赞成和反对
用 AppendValueToList 向云端列表追加一项。按钮禁用是为了防止同一台设备连续点击多次;测试时可以暂时不禁用,
但正式使用时应保留这两行。它只能限制一台设备,不能替代服务端的身份校验。
when 按钮_是.Click() {
云数据库1.AppendValueToList("yes", "yes")
按钮_是.Enabled = false
按钮_否.Enabled = false
标签_状态.Text = "你的赞成票已提交"
}
when 按钮_否.Click() {
云数据库1.AppendValueToList("no", "no")
按钮_是.Enabled = false
按钮_否.Enabled = false
标签_状态.Text = "你的反对票已提交"
}
清空测试数据
重置按钮只给管理员使用。清空两个标签后把本地列表也重置,并重新启用投票按钮;实际发布时应给这个按钮加密码或移出普通用户界面。
when 按钮_重置.Click() {
云数据库1.ClearTag("yes")
云数据库1.ClearTag("no")
赞成票 = []
反对票 = []
按钮_是.Enabled = true
按钮_否.Enabled = true
标签_状态.Text = "投票已重置"
更新票数("yes", 赞成票)
}
开始测试
- 两台设备连接同一个 云数据库 项目,分别投一票,双方票数是否都更新。
- 点击一次后按钮是否禁用,重新打开 App 后能否读到已有票数。
- 测试网络暂时断开时,是否给用户明确的连接失败提示。
- 点击重置后两边票数是否回到 0。
- 管理员按钮是否没有直接暴露给普通投票者。
剩余工作
可以增加百分比、进度条或 Chart 图表;也可以给每个投票者生成唯一身份,防止同一人重复投票。
真实项目还要考虑 云数据库 权限、隐私和并发写入,不能只靠按钮禁用保证公平。
边做边查
打开全部组件速查
卡在哪一步?直接查操作
不用退出当前教程。速查会在新页面打开,查完回来继续刚才的进度。