Qt 鍵盤事件 長按按鍵反覆觸發event事件問題解決
1.問題描述
上一篇文章中,簡單實現了利用qt檢測使用者按鍵操作並將鍵按下\釋放操作列印在Qt介面上的一個小程式。但是在測試過程中會出現一個現象,那就是長按某個鍵不放,介面一直在重新整理press、release、press、release……(如下圖)
也就是說,在長按某個鍵不釋放的情況下,keyPressEvent和keyReleaseEvent事件會不斷被觸發。儘管這是Qt設計實現好的事件機制,但在使用者體驗上,這是不合常理的。我們希望實現的是:按下某個鍵(比如Tab鍵),介面只打印一次"Key_Tab Press";當手鬆開時,介面上才打印"Key_Tab Release"。
2.問題說明event->isAutoRepeat()
為此查詢了Qt官方文件和幾篇部落格。
官方文件上提到一個QKeyEvent的成員函式isAutoRepeat:
bool QKeyEvent::isAutoRepeat () const
Returns true if this event comes from an auto-repeating key; returns false if it comes from an initial key press.Note that if the event is a multiple-key compressed event that is partly due to auto-repeat, this function could return either true or false indeterminately.
可以看到,當event來自於auto-repeating key,isAutoRepeat返回true;當event事件來自於最初的按鍵,則sAutoRepeat返回false。這麼說可能不好理解,那不妨Jungle做個小測試。
2.1.在keyPressEvent裡列印isAutoRepeat返回值
操作:長按Tab鍵,在keyPressEvent裡列印isAutoRepeat返回值,鬆開Tab鍵後,再次長按Tab鍵,再鬆開
1 void QKeyBoard::keyPressEvent(QKeyEvent *event){
2 switch(event->key()){
3 case Qt::Key_Tab:
4 if(event->isAutoRepeat()==true){
5 this->ui.textEdit_press->append("true");
6 }
7 else{
8 this->ui.textEdit_press->append("false");
9 }
10 this->ui.textEdit_press->append("Key_Tab Press");
11 break;
12 /*default:
13 this->ui.textEdit->append("KeyEvent");*/
14 }
15 }
測試結果如下圖:
從測試結果可以看到,長按下Tab鍵第一次觸發keyPressEvent事件時isAutoRepeat返回false,之後長按過程中isAutoRepeat返回值均為true。鬆鍵後再次長按,isAutoRepeat返回false,之後長按過程中isAutoRepeat返回值均為true。即只有首次按下Tab鍵時,isAutoRepeat返回值為false。結合這個結果來看Qt官方文件的描述,似乎更好理解一點。
2.2.在keyReleaseEvent裡列印isAutoRepeat返回值
同樣,Jungle在keyReleaseEvent裡列印isAutoRepeat返回值,執行結果如下(程式碼略):
可以看到,長按下Tab鍵,自動觸發keyReleaseEvent事件時isAutoRepeat返回true,真正鬆鍵後觸發keyReleaseEvent事件時isAutoRepeat返回true。
2.3.測試總結
結合Qt官方文件和上述測試,可以得出如下結論:
- 按鍵觸發的keyPressEvent事件,isAutoRepeat返回false;自動觸發的keyPressEvent事件,isAutoRepeat返回true;
- 鬆鍵觸發的keyReleaseEvent事件,isAutoRepeat返回true;自動觸發的keyReleaseEvent事件,isAutoRepeat返回false。
3.解決
在真正按鍵和鬆鍵事件觸發時,加上對isAutoRepeat返回值的判斷,具體判斷如2.3總結所言,示例程式碼如下:
1 void QKeyBoard::keyPressEvent(QKeyEvent *event){
2 switch(event->key()){
3 case Qt::Key_Tab:
4 if(!event->isAutoRepeat()){
5 this->ui.textEdit_press->append("Key_Tab Press");
6 /* add your code here*/
7 }
8 break;
9
10 /*default:
11 this->ui.textEdit->append("KeyEvent");*/
12 }
13 }
14
15 void QKeyBoard::keyReleaseEvent(QKeyEvent *event){
16 switch(event->key()){
17 case Qt::Key_Tab:
18 if(!event->isAutoRepeat()){
19 this->ui.textEdit_release->append("Key_Tab Release");
20 /* add your code here*/
21 }
22 break;
23 /*default:
24 this->ui.textEdit->append("KeyEvent");*/
25 }
26 }
在某些部落格裡,作者可能增設了某個變數來標記鍵是否被按下,並在按下和鬆鍵時更新標記。但Jungle認為並沒有必要,像上述那樣加入判斷即可。