Step 3-4:Q_PROPERTY + 颜色平滑过渡(核心)
← Step 1-2 · 手册首页 · 下一步 Step 5-6 闪烁 →
这两步是整个控件的核心——把 step 2 的「突变色」升级成「300ms 丝滑过渡」。诀窍不在动画本身,而在用一个 Q_PROPERTY 把「当前显示色」暴露出去,让 QPropertyAnimation 每帧去写它。
Step 3:把 status 升级为 Q_PROPERTY
目标
给类加一行 Q_PROPERTY(Status status READ status WRITE setStatus NOTIFY statusChanged),补上 statusChanged 信号。功能上和 step 2 一样,但 status 现在是「Qt 认识的属性」——能被元系统枚举、被 Designer 编辑、被动画按名字驱动。
提示
- Q_PROPERTY 三件:READ 一个 getter、WRITE 一个 setter、NOTIFY 一个信号
- setStatus 末尾
emit statusChanged(s) - 注意:这步 WRITE 还指 setStatus(业务入口)。step 4 加颜色属性时,color 的 WRITE 要指向一个纯赋值的回调——别搞混(见 troubleshooting 的「递归栈溢出」)
检查点
编译过(moc 不报错)+ metaObject()->propertyCount() 能数到 status = Q_PROPERTY 生效了。
Q_PROPERTY 机制不熟?QObject 与元对象系统、进阶 属性系统深度拆解。
对照答案
- Q_PROPERTY(status) 声明:
include/status_led.h:28 - statusChanged 信号:
include/status_led.hsignals 区
Step 4:颜色丝滑过渡(QPropertyAnimation 驱动 QColor)
目标
加 Q_PROPERTY(QColor color ...),setStatus 时启动一个 QPropertyAnimation 把 color 从当前值过渡到目标状态色。切换时颜色 300ms 平滑渐变,不是突变。
提示(按顺序)
- 新增成员
QColor current_color_——这才是 paintEvent 实际画的色(不再直取statusColor(status_)) - 新增
setAnimatedColor(const QColor&)作为 color 的 WRITE 回调:纯赋值current_color_ = c+emit colorChanged+update()。这是动画每帧调的——只赋值,不启动画 - 改 setStatus:不再直接换色,而是
color_anim_->stop()setStartValue(current_color_)(从当前显示色接力,不是从上一次的目标色)setEndValue(statusColor(new_status))start()
- color_anim_ 用持久成员指针(构造时
new QPropertyAnimation(this, "color", this),配setDuration(300)+setEasingCurve(OutCubic)),不要用DeleteWhenStopped——否则频繁切换时指针悬空崩(见 troubleshooting) - paintEvent 改成画
current_color_
关键认知
- Qt 内置 QColor 插值(RGB 线性),所以
QPropertyAnimation(this, "color")能直接对颜色做动画,不用手写 lerp - WRITE 指 setAnimatedColor(纯赋值)而非 setStatus(会启动画)——否则动画驱动 setStatus → setStatus 又启动画 → 无限递归栈溢出
- 从 current_color_ 接力而非从目标色重启——快速连切时颜色连续过渡,不跳变
检查点
切换状态时颜色 300ms 渐变过渡(不是突变)= 动画对了。快速连点 Cycle 不崩、过渡不跳变 = 接力逻辑对了。
对照答案
- color_anim_ 配置(duration/easing):
src/status_led.cpp:58-59 - setStatus 启动过渡(stop/setStart/setEnd/start):
src/status_led.cpp:98-101 - setAnimatedColor 回调(赋值+emit+update):
src/status_led.cpp:115-117 - paintEvent 改画 current_color_:
src/status_led.cpp:220