Qt 項目之虛擬鍵盤 V1.0

  • 2019 年 10 月 6 日
  • 筆記

最近做了一個虛擬鍵盤的小Demo,分享給大家。

一般我在做一個東西之前會上網查找資料,看下有幾種實現的方式。在Qt下開發虛擬鍵盤總體上可分為兩種方式——進程內部和進程外部。

在進程內部,虛擬鍵盤可以是一個QWidget小部件,顯示鍵盤按鈕,對用戶按下的按鍵生成鍵盤事件,之後讓具有焦點的可輸入的部件響應鍵盤事件。

在進程外部,虛擬鍵盤則可以被其他應用程序使用,不過這需要進程間通信。Qt上使用DBus作為IPC通訊方式,虛擬鍵盤被開發完成則是一個插件,需要放到Qt指定的目錄下,Qt應用程序在使用虛擬鍵盤前需要註冊一下,關於虛擬鍵盤和插件以後我們有機會會介紹的。今天展示的是在進程內部開發虛擬鍵盤的方式。

我最終想要實現的是點擊任何可輸入部件鍵盤都可以彈出來,但是開發的過程中發現可輸入部件沒有在被點擊後發出信號或事件,最後只好用窗體的鼠標事件來替代。

提幾個項目中會遇到的問題:

①像鍵盤這種有眾多按鈕的窗體,如何創建按鈕及其信號和槽

②響應按鈕後如何轉換為鍵盤事件,事件的接收者是誰

③希望鍵盤隨着窗體焦點移動而移動

有些問題我是沒有解決的,這次和大家分享的是虛擬鍵盤的初版,以後會有更新。使用插件開發鍵盤上面考慮的問題插件都預留了接口,不用像自己開發這樣要考慮諸多問題,不過同樣也知道了很多知識。

程序平台:ubuntu Qt 5.5.1

一、 KeyBoard 類

1. 該類繼承QWidget,是鍵盤窗體的實現類,有以下幾個對外接口

    void showKeyboard(int globalX, int globalY);      void hideKeyboard();        void setFocusWidget(QWidget *focusWidget);

分別是鍵盤的顯示、隱藏以及生成鍵盤事件的接收對象。

2. 眾多鍵盤按鈕的布局,主要使用QSignalMapper。為方便閱讀,使用的數據結構沒有列出

KeyBoard::KeyBoard(QWidget *parent) : QWidget(parent)  {      QGridLayout *gridLayout = new QGridLayout(this);        QSignalMapper *mapper = new QSignalMapper(this);      connect(mapper, SIGNAL(mapped(int)), SLOT(buttonClicked(int)));        m_focusWidget = parent;      this->setStyle("#E4E4E4", "#A2A2A2", "#DCDCDC", "#000000");        int row = 0;      int column = 0;        for (int i = 0; i < layoutSize; ++i) {          if (keyboardLayout[i].key == NEXT_ROW_MARKER)          {              row++;              column = 0;              continue;          }            QPushButton *button = new QPushButton;          button->setFixedWidth(40);          button->setText(QString::fromLatin1(keyboardLayout[i].label));            mapper->setMapping(button, keyboardLayout[i].key);          connect(button, SIGNAL(clicked()), mapper, SLOT(map()));            gridLayout->addWidget(button, row, column);          column++;      }  }

3. 生成鍵盤事件

void KeyBoard::buttonClicked(int key)  {      QKeyEvent *keyPressEvent = NULL;        if ((key == Qt::Key_Enter) || (key == Qt::Key_Backspace))          keyPressEvent = new QKeyEvent(QEvent::KeyPress, key,                                        Qt::NoModifier);      else          keyPressEvent = new QKeyEvent(QEvent::KeyPress, key,                                        Qt::NoModifier, keyToCharacter(key));        if (keyPressEvent != NULL)      {          QGuiApplication::postEvent(m_focusWidget, keyPressEvent);      }  }

二、 用戶界面調用

主要重新實現了鼠標點擊事件,將位置發送給鍵盤顯示函數

void Widget::mousePressEvent(QMouseEvent *event)  {      if( event->type()== QEvent::MouseButtonPress )      {          qDebug()<<"LeftButton";          if(event->pos().x()<= pos().x())          {              m_keyboard->showKeyboard(this->pos().x(),this->y() +                                       this->frameGeometry().height());          }      }  }

總結:

①沒有找到獲取當前編輯框焦點的方法,QWidget中有焦點改變的信號,還有事件過濾 器,接下來會從這兩方面入手。

②QLineEdit等編輯框沒有響應鼠標點擊的信號或事件,需要重新繼承實現。

最後效果如圖: