// 源 paint 产出真正进入窗口的 DisplayList;允许构造并修改本次计算的新命令,禁止改已有业务对象。 // 同一 rect 出现两次,两份命令随同一 tint 更新;业务身份共享,几何按 Mount 分开。 // 原生矩形测量不变,仅将绘制颜色切换为源字段 tint。 class TintRect: RectBlock { // 源颜色策略与原生构造颜色分别保存;两个出现都读取同一 tint,但用各自 geometry 生成命令。 tint: String // 从原生基类取得当前出现位置的矩形命令,再修改本次返回列表中的颜色并交回。 function paint(self: TintRect, mount: Mount, geometry: Bounds): DisplayList { // source_paint 在只读计算阶段调用,基类返回本轮新列表,修改其中命令不等于修改已有业务状态。 drawing = RectBlock.paint(self, mount, geometry) drawing.commands.at(0).color = self.tint return drawing } } // 在原生文字前增加圆角底色,背景大小使用实际分配 geometry 而不是固定猜测值。 class Badge: TextBlock { background: String // 先完整填写 roundedRect 命令,再取原生文字命令改成白色;列表顺序决定先画背景后画文字。 function paint(self: Badge, mount: Mount, geometry: Bounds): DisplayList { // Badge 的源覆盖构造一条新背景命令,再组合原生文字命令;并未创建额外的背景 Block 或 Mount。 fill = PaintCommand() // 命令 kind 决定宿主解码所需字段,坐标/宽高来自本次 Mount,radius/color 由业务策略提供。 fill.kind = "roundedRect" fill.x = geometry.x fill.y = geometry.y fill.width = geometry.width fill.height = geometry.height fill.radius = 6 fill.color = self.background // 复用原生文字塑形和换行所需参数,避免手工文字命令漏掉边界。 text = TextBlock.paint(self, mount, geometry).commands.at(0) text.color = "#FFFFFF" // ObjectList 的先后决定遮盖次序,返回时宿主统一验证命令字段和范围。 return DisplayList(ObjectList(fill, text)) } } // 保存目标 TintRect,onEvent 是托管事件目标方法覆盖,不额外创建另一份状态。 class RecolorButton: Button { target: TintRect // 事件阶段可修改已有业务字段;依赖跟踪检测 tint 变化后重绘两个出现位置。 function onEvent(self: RecolorButton, event: Event): Unit { // 分发器调用 Button 子类的对象方法,无需另写 button.on;这里可写 target,paint 中只能读它。 // onEvent 本身不限定 click:本覆盖没有检查 event.kind,其他经对象方法递送的事件也会执行改色。 self.target.tint = "#526AC7" } } // 两次使用 rect 是同一对象,Badge 与按钮独立;根容器只组合它们,不复制业务数据。 rect = TintRect(200, 60, 12, "#DDEEFF", "#ED6A5A") // Badge 的末尾字符串是新增 background 字段;TextBlock 的原生可选颜色省略,随后 paint 将文字改为白色。 badge = Badge("Endor 源码正在绘制这个背景", 2, "#237A45") button = RecolorButton("通过对象方法改变绘制颜色", rect) root = Column(24, 16, TextBlock("源码 paint 进入真实窗口", 2), rect, rect, badge, button) page = Page() page.render(root)