在 TouchGFX UI 设计中,让同一按钮通过短按 / 长按实现不同功能是高频需求。普通 Button 控件仅支持基础点击交互,需通过自定义配置实现长按识别。本文基于 ST 官方 LAT1300 应用笔记,详解 “ClickListener+handleTickEvent” 的实现方法,步骤简洁、可直接复用,适用于 TouchGFX 4.21.3 及以上版本。
1. 核心原理:长按识别的底层逻辑
实现长按的核心是 “触控状态监测 + 计时统计”,依赖 TouchGFX 的两个核心机制:
- ClickListenerMixin:为 Button 控件添加点击事件响应能力,可捕获
PRESSED(按下)和RELEASED(释放)两种状态; - handleTickEvent 函数:TouchGFX 引擎以 60Hz 频率自动调用(约 16.7ms / 次),用于实现精准计时,判断按键按下时长是否达到长按阈值。
2. 实操步骤:从配置到功能实现
以 “长按 3 秒切换文本显示” 为例,完整实现流程分 4 步,适配所有 TouchGFX 支持的 STM32 芯片。
2.1 第一步:创建按钮并启用 ClickListener
在 TouchGFX Designer 中完成基础配置,让按钮具备触控响应能力:
- 拖拽 Button 控件到 UI 界面,命名为
button1; - 勾选 Mixins 面板中的
ClickListener选项,启用触控事件响应;- 启用后,控件声明自动变为
touchgfx::ClickListener<touchgfx::Button> button1;,支持捕获点击事件。
- 启用后,控件声明自动变为
2.2 第二步:绑定回调函数,响应触控状态
在按钮所属 Screen 的代码中,声明并绑定回调函数,处理
PRESSED和RELEASED事件:(1)头文件(Screen1View.hpp)声明
class Screen1View : public Screen1ViewBase
{
public:
Screen1View();
virtual ~Screen1View() {}
virtual void setupScreen();
virtual void tearDownScreen();
virtual void handleTickEvent(); // 后续计时用,提前声明
protected:
// 回调函数声明:参数为按钮对象和点击事件
void ButtonClickHandler(const Button& b, const ClickEvent& e);
// 回调绑定对象:关联当前视图和处理函数
Callback<Screen1View, const Button&, const ClickEvent&> buttonClickedCallback;
// 新增变量:长按计时计数器、长按阈值(3秒=60Hz×3=180次)
uint32_t pressCounter = 0;
const uint32_t LONG_PRESS_THRESHOLD = 180;
bool isPressing = false; // 按压状态标记
};
(2)源文件(Screen1View.cpp)绑定与实现
// 构造函数:绑定回调对象与处理函数
Screen1View::Screen1View() :
buttonClickedCallback(this, &Screen1View::ButtonClickHandler) {}
// 初始化屏幕时,为按钮设置点击动作
void Screen1View::setupScreen()
{
Screen1ViewBase::setupScreen();
button1.setClickAction(buttonClickedCallback); // 绑定回调
}
// 回调处理函数:捕获按压/释放状态
void Screen1View::ButtonClickHandler(const Button& b, const ClickEvent& e)
{
if (&b == &button1) // 确认是目标按钮
{
if (e.getType() == ClickEvent::PRESSED)
{
// 按下时初始化:重置计数器、标记按压状态
pressCounter = 0;
isPressing = true;
}
else if (e.getType() == ClickEvent::RELEASED)
{
// 释放时重置状态
isPressing = false;
// 此处可添加短按功能(如需要)
// 示例:if (pressCounter < LONG_PRESS_THRESHOLD) { 短按逻辑 }
}
}
}
2.3 第三步:实现 handleTickEvent,完成计时与长按判断
handleTickEvent以 60Hz 频率调用,用于统计按压时长,达到阈值则触发长按功能:void Screen1View::handleTickEvent()
{
if (isPressing) // 仅在按压状态下计时
{
pressCounter++; // 每次调用计数+1(约16.7ms)
// 达到3秒阈值(180次计数),且未触发过长按(避免重复执行)
if (pressCounter >= LONG_PRESS_THRESHOLD)
{
// 长按功能实现:示例为切换文本显示
text1.setTypedText(TypedText(T_TEXT_LONG_PRESS));
text1.invalidate(); // 刷新文本控件
// 重置状态,避免持续触发
isPressing = false;
pressCounter = 0;
}
}
}
2.4 第四步:效果验证
编译工程并下载到开发板,测试效果符合预期:
- 短按按钮(少于 3 秒):仅触发
RELEASED事件,文本无变化; - 长按按钮(超过 3 秒):触发长按逻辑,文本从 “Please press the button” 切换为 “You have pressed more than 3s”。
3. 核心扩展:灵活适配不同需求
3.1 调整长按时长
修改
LONG_PRESS_THRESHOLD值即可,计算公式:阈值 = 目标时长(秒)× 60,示例:- 2 秒长按:
const uint32_t LONG_PRESS_THRESHOLD = 120; - 5 秒长按:
const uint32_t LONG_PRESS_THRESHOLD = 300;
3.2 同时支持短按 + 长按
在
RELEASED事件中添加短按判断,示例:else if (e.getType() == ClickEvent::RELEASED)
{
if (pressCounter < LONG_PRESS_THRESHOLD && pressCounter > 0)
{
// 短按逻辑:示例为恢复初始文本
text1.setTypedText(TypedText(T_TEXT_SHORT_PRESS));
text1.invalidate();
}
isPressing = false;
pressCounter = 0;
}
3.3 适配其他 Widget
除 Button 外,TextArea、Image 等控件均可通过勾选
ClickListener,复用本文逻辑实现长按功能,仅需修改回调函数中的控件判断条件。4. 注意事项与避坑指南
- 计时精度:
handleTickEvent调用频率为 60Hz,计时误差极小,满足绝大多数场景需求; - 状态重置:必须在长按触发后、按压释放时重置
isPressing和pressCounter,避免重复触发; - 控件刷新:修改文本、图片等 UI 元素后,需调用
invalidate()函数刷新显示; - 版本兼容性:TouchGFX 4.21.3 及以上版本均支持该方案,低版本需升级后使用。
5. 核心优势总结
阅读全文
660