QT实现键盘复用:单击、双击、长按
来源:互联网 发布:mysql数据库默认密码 编辑:程序博客网 时间:2024/05/29 12:25
由于项目需求,需要实现基于键盘按键的复用,查了很多资料都不满足我的需求,其中Mango的吐槽一下Qt的按键消息响应对我启发很大,他阐述了关于按键长按的问题,我的测试结果和他有些出入,但总体思路是一样的,也欢迎大家指正。下面来说一下具体的实现过程。
键盘按键单击、双击
首先键盘按键的单击、双击实现,没错!就是用的QTimer,一说到这估计大部分人都知道怎么回事了,但这里也有个误区,那就是如何区分单击和双击的问题,这也是我实现过程中遇到的问题。我最开始的做法是根据按下和释放的时间间隔来区分的,现在看来这显然是不对的,但当时脑袋可能蒙圈了(>_<),这样是无法准确的区分单击和双击的,应该用两次按键的时间间隔来区分,这里在按下、或释放里实现都是可以的,我最后选择在释放里实现,后面再说原因。如果谁不清楚按下、释放什么意思,自己去查qt帮助文档吧。。。
头文件里定义几个相关变量
//MyClass.h QTimer* timer_; bool LongPress_;//后面用到 int ClickCount_;//按键计数 KeyFlag KeyFlag_;//枚举
enum KeyFlag{ kKey_NULL, kKey_A, kKey_S, kKey_D, kKey_F, kKey_J, kKey_K};
构造函数连接timeout信号到单击函数
//MyClass.cpp timer_ = new QTimer(this); connect(timer_, SIGNAL(timeout()), this, SLOT(KeyOneClick())); ClickCount_ = 0; LongPress_ = false; KeyFlag_ = kKey_NULL;
重写void keyReleaseEvent(QKeyEvent *event)
void MyClass::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_A: if (!timer_->isActive()) {//计数期间,如果QTimer已开始,则不重新开始 timer_->start(400);//400ms是判断双击的时间间隔,不唯一,可根据实际情况改变 KeyFlag_ = kKey_A;//单击函数的按键标识 } ClickCount_++;//点击计数,在400ms内如果点击两次认为是双击 if (ClickCount_ == 2){ timer_->stop();//停止计时 ClickCount_ = 0;//计数清零 cout << "this is A double click" << endl; DoDoubleThings();//执行按键A双击动作 } break; case Qt::Key_S://注意到没?我实现的都是字母键,其他键是不一样的 break; case Qt::Key_D: break; case Qt::Key_F: break; case Qt::Key_J: break; case Qt::Key_K: break; default: break; }}
单击函数,在400ms内未达到双击次数,也就是未执行timer_->stop();时间耗尽触发timeout信号,执行单击动作。这里提一下stop()函数,QTimer执行start(n)后,如果不stop(),那它会循环执行。
void MyClass::KeyOneClick() { switch (KeyFlag_)//判断点击的是哪个按键 { case kKey_A: ClickCount_ = 0;//计数清零 timer_->stop();//停止计时 cout << "this is A ckick" << endl; DoSigalClickThings();//单击A的动作 break; case kKey_S: break; case kKey_D: break; case kKey_F: break; case kKey_J: break; case kKey_K: break; default: break; }}
键盘按键长按
至此实现键盘单击和双击复用,那么我们再来看一下长按怎么处理呢?
先看一下按键长按的过程分析,我们知道一按一松实现一次click动作,那我们测试一下qt键盘长按的具体过程,重写void keyPressEvent(QKeyEvent *event)、void keyReleaseEvent(QKeyEvent *event)函数。
为了区分是否是长按,QKeyEvent 提供了一个isAutoRepeat()函数自动检测按键是否长按
- 长按返回true
- 非长按返回false
为了方便表示我定义
- P:press动作
- R:release动作
- T:isAutoRepeat()返回true
- F:isAutoRepeat()返回false
下面看一下长按会发生什么吧。
void MyClass::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_A: if (!event->isAutoRepeat()) { //非长按输出press、not repeat等关键词 cout << "this is A press: not Auto Repeat" << endl; } else{ //长按输出press、is repeat等关键词 cout << "this is A press: is Auto Repeat" << endl; } break; default: break; }}
void MyClass::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_A: if (!event->isAutoRepeat()) { //非长按输出release、not repeat等关键词 cout << "this is A release: not Auto Repeat" << endl; } else{ //非长按输出release、is repeat等关键词 cout << "this is A release: is Auto Repeat" << endl; } break; default: break; }}
运行结果用我的方式表示为:P(F)R(T)P(T)R(T)…P(T)R(T)P(T)R(F),也就是当你长按时会循环发生press和release动作,
- 第一次执行press动作,此时QKeyEvent 不认为你在长按,而在release时,QKeyEvent 已经开始认为你在长按了;
- 第二次到倒数第二次QKeyEvent 认为你都在长按;
- 最后一次,press动作依然为长按,但release却变成非长按了;
也就是不管你按多久最开始的press肯定为非长按状态,最后的release肯定为非长按状态。结合这些特性,我们来实现键盘按键的复用,即同时实现单击双击和长按三个动作。
前面提到单击和双击的区分,其实在void keyPressEvent(QKeyEvent *event)、void keyReleaseEvent(QKeyEvent *event)函数里都可以,反正都是记录时间差,press-press或release-release没分别,那最后为什么选择在keyReleaseEvent(QKeyEvent *event)函数里实现呢?
问题就在还得同时实现长按功能,刚刚分析得出无论你长按还是非长按,第一次的press动作他都是P(F)的,如果在void keyPressEvent(QKeyEvent *event)里实现,那长按必然会附加一次单击,这当然不是我们想要的;
再来看看在void keyReleaseEvent(QKeyEvent *event),如果长按,它第一次就是R(T)了,那就可以通过判断isAutoRepeat()的状态来区分长按和非长按了。
还有一个问题就是,虽然可以判断长按了,但是长按时是会循环执行的,如不控制,岂不会执行n次长按要实现的动作,因此还要加一个flag来控制,让它只执行一次。
最后,还要讨论一下长按的最后一次release动作,它和非长按的release是相同的R(F),为了避免这种情况,我们正好利用控制长按的flag来进行区分。
至此分析完毕,我想我们该开始写代码了。
void MyClass::keyReleaseEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_A: //是否是长按可以从release中直接判断 if (!event->isAutoRepeat()) { //LongPress_初始值为false,如果非长按执行单击或双击动作判断 //如果长按会在长按里将其置true,在最后的R(F)里就不会执行单击、双击判断的动作 if (!LongPress_) { if (!timer_->isActive()) { timer_->start(400); KeyFlag_ = kKey_A; } ClickCount_++; if (ClickCount_ == 2){ timer_->stop(); ClickCount_ = 0; cout << "this is A doubleclick" << endl; DoDoubleThings();//执行按键A双击动作 } } LongPress_ = false;//置false } else{ if (!LongPress_) { cout << "this is longpress" << endl; //限定长按只执行一次,最后会在R(F)里将LongPress_重新置false LongPress_ = true; DoLongPressThings(); } } break; case Qt::Key_S: break; case Qt::Key_D: break; case Qt::Key_F: break; case Qt::Key_J: break; case Qt::Key_K: break; default: break; } }
亲测有效,如有不同方法,欢迎讨论,或是有更好的方法,也请不吝分享!
- QT实现键盘复用:单击、双击、长按
- Android通过onTouch事件实现单击,双击,长按
- Android通过onTouch事件实现单击,双击,长按
- View单击双击长按事件
- Qt 单击和双击事件响应实现
- qt 实现、区分鼠标单击,双击事件
- STM32学习笔记:单片机按键单击、双击、长按功能实现
- STM32学习笔记:单片机按键单击、双击、长按功能实现
- Android 单击+双击+短按+长按 逻辑
- Android中触控单击、双击、长按、滑动效果
- Android中触控单击、双击、长按、滑动效果
- 键值判断单击双击和长按事件
- 单片机三种按键模式 单击 双击 长按
- Android view的单击,双击,长按事件监听
- 题目:多功能按键设计。利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按。
- Qt 单击双击的区分
- 多功能按键设计——利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按
- 多功能按键设计——利用一个I/O口,接一个按键,实现3功能操作:单击 + 双击 + 长按
- To B产品经理,如何转型AI产品经理?
- session概念与购物车例子
- 研究100位同行,我总结了从0到5年的新媒体晋级宝典
- 从5个维度,对傅盛演讲「生物学思维模型」解读
- docker-compose ERROR: network jumpserver_default has active endpoints
- QT实现键盘复用:单击、双击、长按
- 栈帧的创建和销毁
- poj 2823 Sliding Window(单调队列)
- python2.7实现杨辉三角
- 从零开始学 Java
- nbtscan扫描指定网段的主机
- android 用多线程提升性能
- JAVA中如何将以Date型的数据保存到数据库以Datetime型的字段中
- 不想写程序,其实程序和功夫一样,就是一进一出而已,搞懂了也就不用再学程序了