1. 程式人生 > 實用技巧 >Qt 鍵盤事件 長按按鍵反覆觸發event事件問題解決

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認為並沒有必要,像上述那樣加入判斷即可。