惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Last Watchdog
The Last Watchdog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Troy Hunt's Blog
L
LINUX DO - 最新话题
C
Check Point Blog
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
V
Vulnerabilities – Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
J
Java Code Geeks
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
S
Security @ Cisco Blogs
IT之家
IT之家
T
The Exploit Database - CXSecurity.com
The GitHub Blog
The GitHub Blog
D
Docker
Engineering at Meta
Engineering at Meta
AWS News Blog
AWS News Blog
S
Security Affairs
U
Unit 42
P
Palo Alto Networks Blog
V
Visual Studio Blog
Y
Y Combinator Blog
D
DataBreaches.Net
Forbes - Security
Forbes - Security
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
Security Latest
Security Latest
aimingoo的专栏
aimingoo的专栏
Simon Willison's Weblog
Simon Willison's Weblog
A
Arctic Wolf
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hacker News: Front Page
博客园 - 司徒正美
博客园 - Franky
宝玉的分享
宝玉的分享
TaoSecurity Blog
TaoSecurity Blog
Latest news
Latest news
Scott Helme
Scott Helme
MongoDB | Blog
MongoDB | Blog
量子位
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cisco Blogs
P
Privacy International News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog

夜行人

回家路上 第一期的直播演示项目 震动检测器 正能量 在线参观CodeLab Neverland 发布 CodeLab Adapter 3.3.1 DynamicTable 之 纸糊方向盘 CodeLab DynamicTable: 一个可实施的技术方案 CodeLab Insight 发布 Alpha 版 情人节 Home Assistant 周报 && IoT 周报 (02) Joplin: 关注隐私的 Evernote 开源替代软件 浏览器的未来与 Web 传感器 Home Assistant 周报 && IoT 周报 (01) 百宝箱(01) 论自由 介绍 WebThings Home Assistant 周报 && iot 周报 (00) 百宝箱(00) 毛姆读书心得 传世之作 周末徒步 CodeLab Adapter ❤️ Jupyter/Python 航班 躲雨 夏令营途中 [译]思想--作为一种技术 The future of coding 美国之行 三门问题的程序模拟 从Python转向Pharo https://blog.just4fun.site/post/iot/iot-open-source-projects/ Python异步编程笔记 https://blog.just4fun.site/post/iot/iot-open-source-hardware-community/ 万物积木化开发者社区 CodeLab ❤️ Blender Scratch3技术分析之云变量 API(第7篇) [译]对管道(Pipes)的偏爱 [译]提出正确的问题比得到正确答案更重要 蓝牙设备与Scratch3.0 创建你的第一个Scratch3.0 Extension Scratch3技术分析之项目内部数据(第6篇) Scratch3技术分析之社区 API(第5篇) Scratch3技术分析之User API(第4篇) Scratch3技术分析之项目主页API(第3篇) Scratch3技术分析之静态资源API(第2篇) Scratch3.0、micro:bit与Windows7 https://blog.just4fun.site/post/iot/zerynth-vs-micropython/ 核聚变、方所与半宅空间 可视化编程为何是个糟糕的主意 codelab.club周末聚会 关于codelab.club '下一件大事'是一个房间 Hungry Robot - Eat everything 编程作为一种思考方式 今日简史 史蒂夫·乔布斯传 罗素自选文集 https://blog.just4fun.site/post/edx/tianjin-scratch-ai/ https://blog.just4fun.site/post/edx/richie-cms-openedx/ 徒步武功山 WebUSB与micro:bit 积木化编程与3D场景 夜宿武功山顶 scratch3-adapter接入优必选Alpha系列机器人 https://blog.just4fun.site/post/edx/video-migration-note/ scratch3-adapter重构笔记 https://blog.just4fun.site/post/edx/edx-community-members/ 两种硬件编程风格的比较 使用micro:bit自制PPT翻页笔 柏拉图对话集 scratch3.0 + micro:bit 七月电影放映计划 非营利组织的管理 Screenly--用树莓派让任何屏幕变为可编程的数字标牌 以最佳实践开始你的Django项目 micro:bit与事件驱动 为Scratch3.0设计的插件系统(上篇) OCR应用一例 近两年读过的一些好书 blockly开发之使用python驱动浏览器中的turtle(2) 牛顿新传 文学理论入门 逻辑的引擎 人生的意义 blockly开发之生成并运行js代码(1) blockly开发之hello world(0) micro:bit使用笔记 神器之Termux https://blog.just4fun.site/post/iot/micropython-notes/ Cozmo what is this Scratch的前世今生 下段旅程 我行在远方 爆裂 途中杂记 https://blog.just4fun.site/post/edx/open-edx-startup/ cozmo系列之入门 - 有性格且可编程的机器人 PaperWeekly开发笔记 创业二三事
[译] Morphic 的工作原理
种瓜 · 2022-08-24 · via 夜行人

前言

近期重读 An introdution to Morphic, 本文翻译自其中的部分章节。

Morphic 是我最喜欢的 UI 框架, An introdution to Morphic 则是我最喜欢的 Morphic 教程,教程的作者正好也是 Morphic 的设计者: John Maloney。

教程中涉及的一些例子,我已经整理放到了 Github 上 (修复了因 Squeak 的版本变化导致的 bug): Morphic-Fun

Morphic 介绍

Morphic 是一个用户界面框架,它使构建生动的(lively)交互式用户界面变得简单而有趣。Morphic 处理了大部分显示更新、事件调度、拖放、动画和自动布局的繁琐工作,从而将编程者解放出来,专注于设计而不是机制。有些用户界面框架需要大量的模板代码来完成简单的事情, 而在 Morphic 中,少量的代码就能发挥很大的作用,几乎不浪费任何努力。

译文

这一节概述了 Morphic 的工作原理,其详细程度足以帮助 Morphic 编程者从系统中获得最大收益。

UI 循环(The UI Loop)

每个交互式用户界面框架的核心, 都是最早的交互式计算机系统中的 “读取(read)-评估(evaluate)-打印(print)” 循环(loop)的现代版。然而,在这个现代版本中,“读取” 处理事件而不是字符,“打印” 执行绘图操作以更新图形显示而不是输出文本。Morphic 版本的这个循环增加了两个额外的步骤,为自动布局和活性(liveness)提供钩子(hook)。

1
2
3
4
5
do forever:
    process inputs
    send step to all active morphs
    update morph layouts
    update the display

有时,这些步骤都无事可做;没有事件需要处理,没有 Morph 需要步进(step),没有布局更新,也没有显示更新。在这种情况下,Morphic 会休眠几毫秒,这样它就不会在空闲的时候占用 CPU 了。

输入处理(Input Processing)

输入处理是将传入的事件分派给适当的 Morph 的问题。击键事件被发送到当前的键盘焦点 Morph,它通常由鼠标点击建立。如果没有建立键盘焦点,按键事件就会被丢弃。在任何时候,最多只有一个键盘焦点 Morph。

鼠标按下(Mouse down)事件是按位置派发的;事件发生位置的最前面的 Morph 可以处理该事件。事件不会穿过 Morph;你不可能意外地按下藏在其他 Morph 后面的按钮。Morphic 需要知道哪些 Morph 对获取鼠标事件感兴趣。它通过向每个候选 Morph 发送 handlesMouseDown: 消息来实现这一目的。事件的提供是为了让 Morph 可以根据事件发生时 按下的鼠标键和按下的修饰键 来决定是否要处理这个事件。如果没有找到处理该事件的 Morph,默认行为是拾起光标下最前面的 Morph。

在一个复合 Morph 中,其最前面的 submorph 被给予第一个机会来处理一个事件,这与 submorph 出现在其所有者(owner)前面的事实一致。如果该 submorph 不想处理该事件,它的所有者会得到一个机会。如果它的所有者不想处理,那么它的所有者的所有者就会得到一次机会,以此类推,沿着所有者链向上。这个策略允许一个对鼠标敏感的 Morph,比如一个按钮,被装饰上标签或图形,仍然可以得到鼠标的点击。在我们第一次尝试事件调度的时候,鼠标在 submorph 上的点击并没有传递给它的所有者,所以点击被按钮的标签阻止了。 要想点击一个按钮而不碰到它的标签,并不是那么容易的事。

鼠标移动(mouse move)和鼠标抬起(mouse up)的事件呢?考虑一下当用户拖动一个滚动条的手柄时会发生什么。当鼠标在滚动条上向下移动时,滚动条开始跟踪被拖动的鼠标。如果光标移动到滚动条之外,甚至光标被拖到一个按钮或其他滚动条上,它也会继续跟踪鼠标。这是因为 Morphic 认为鼠标按下、鼠标重复移动和鼠标抬起的整个序列是一个单一事务。无论哪个 Morph 接受了鼠标按下的事件,都被认为是鼠标焦点,直到鼠标再次抬起。鼠标焦点 Morph 保证获得整个鼠标拖动事务:一个鼠标按下事件,至少一个鼠标移动事件,以及一个鼠标抬起事件。因此,Morph 可以在鼠标按下时执行一些初始化,在鼠标抬起时进行清理,并保证初始化和清理总是能够完成的。

活性(Liveness)

活性的处理方法是保留一个需要被步进(step)的 Morph 列表,以及它们所期望的下一个步进时间。每一个周期,步进信息都会被发送到任何一个需要步进的 Morph 上,并且更新它们的下一个步进时间。被删除的 Morph 将从步进列表中删减掉,这既是为了避免步进不再出现在屏幕上的 Morph,也是为了让这些 Morph 能够被垃圾回收。

布局更新(Layout Updating)

Morphic 渐进地维护 Morph 的布局。当一个 Morph 的变化可能影响到布局时(例如,当一个新的 submorph 被添加到它上面时),消息 layoutChanged 就会被发送给它。这将触发一连串的活动。首先,改变后的 Morph 的布局被更新。这可能会改变分配给它的 submorp(s)的空间量,导致它们的布局被更新。然后,如果改变后的 Morph 的空间需求发生了变化(例如,如果它需要更多的空间来容纳一个新增加的 submorph),它的所有者的布局就会被更新,可能还有它的所有者的所有者的布局,依此类推。在某些情况下,一个深度嵌套的复合 Morph 中的每个 submorph 的布局都可能需要更新。幸运的是,在很多情况下,布局的更新可以被局部化,从而节省大量的工作。

和改变消息(changed message)一样,Morph 客户端通常不需要明确地发送 layoutChanged,因为影响 Morph 布局的最常见的操作已经做了这个, 这些常见操作包括添加和删除 submorph 或改变 Morph 的大小…警觉的读者可能会担心,在建立一个有很多 submorph 的行或列时,在添加 Morph 后更新布局可能会使事情变得缓慢。事实上,由于更新布局的成本与该行或列中已存在的 Morph 数量成正比,那么一次添加 N 个 Morph,并在每个 Morph 之后更新布局,其成本与 N 的平方成正比。当建立像 ScorePlayerMorph 这样复杂的 Morph 时,这个成本会迅速增加。为了避免这个问题,Morphic 将所有布局的更新推迟到下一个显示周期。毕竟,在下一次重绘屏幕之前,用户无法看到任何布局的变化。因此,一个程序可以在两个显示周期之间对一个给定的 Morph 进行任何数量的布局改变操作,而 Morphic 只会更新这个 Morph 的布局一次。

显示更新(Display Updating)

Morphic 使用一种双缓冲、增量的算法来保持屏幕的更新。这种算法是高效的(它试图在变化后做尽可能少的工作来更新屏幕)和高质量的(用户不会看到屏幕被重新绘制)。它也大多是自动的;许多应用程序可以在编程者不知道如何维护显示的情况下建立。这里的描述主要是为了让那些对该系统的工作原理感到好奇的人受益。

Morphic 保留了一个列表,称为损坏列表(必须重新绘制的屏幕部分)。每个 Morph 都有一个边界矩形,包围着它的整个可见表示。当一个 Morph 改变了外观的任何方面(例如,它的颜色),它就会向自己发送改变(changed)消息,这就把它的边界矩形添加到损坏列表中。Morphic UI 循环的显示更新阶段负责将屏幕更新。对于损坏列表中的每个矩形,它都会重绘(按从后到前的顺序)所有与损坏矩形相交的 Morph。这种重绘是在屏幕外的缓冲区完成的,然后复制到屏幕上。由于单个 Morph 是在屏幕外绘制的,用户永远不会看到绘制过程的中间阶段,而且从屏幕外的缓冲区到屏幕的最终拷贝也相当快。其结果是,无论单个绘制操作的顺序如何,物体的动画效果都很流畅,看起来很牢固。当所有的损坏矩形都被处理后,Morphic 清除损坏列表,为下一个周期做准备。