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