前へ 次へ
技術文章qvi

本稿では以下の実装を行う。

Esc で、exモードキャンセル

QLineEdit には returnPressed() シグナルはあるのだが、escPressed() シグナルが無い。 Esc が押されたことを検知するには QLineEdit のサブクラスを定義して、keyEvent() をリインプリメントしてもいいのだが、 イベントフィルターを使った方がクラスを新たに宣言・定義する必要が無くお手軽だ。

 1: class MainWindow : public QMainWindow
 2: {
 3:     .....
 4: protected:
 5:     bool    eventFilter(QObject *obj, QEvent *event);
 6: };
 1: MainWindow::MainWindow(QWidget *parent, Qt::WFlags flags)
 2:     : QMainWindow(parent, flags)
 3: {
 4:     .....
 5:     statusBar()->addWidget(m_cmdLineEdit = new QLineEdit(), 1);
 6:     m_cmdLineEdit->installEventFilter(this);
 7:     .....
 8: }
 9: bool MainWindow::eventFilter(QObject *obj, QEvent *event)
10: {
11:     if( obj == m_cmdLineEdit && event->type() == QEvent::KeyPress &&
12:         m_viEngine->mode() == CMDLINE )
13:     {
14:         QKeyEvent *keyEvent = static_cast(event);
15:         if( keyEvent->key() == Qt::Key_Escape ) {
16:             m_viEngine->setMode(CMD);
17:             return true;
18:         }
19:     }
20:     return false;
21: }

以上で Esc でキャンセルする機能の実装は終わりだ。追加行数も少なく、なんと簡単ではなイカ。

Home で行頭の:(コロン)直後にカーソル移動

Home の動作を変更するので、Esc 同様にイベントフィルターで Home が押されたことを検出して、 :(コロン)直後にカーソルを設定してもいいのだが、もっと簡単な方法がある。

それは QLineEdit::cursorPositionChanged(int, int) シグナルを処理する方法だ。

下記の様に、シグナルを処理スロットにコネクトし、カーソルが先頭に移動した場合は:(コロン)直後にカーソルを再設定してあげる。 実は←カーソルキーでも:(コロン)直後までしか移動出来ないようにする必要があったのだが、この方法であればその対処も自動的に行われてしまう。 さらに、マウスでカーソルを設定した場合にもちゃんとうまくいく。
最小限のコードでいくつもの問題対処ができた。理想的である。

 1: MainWindow::MainWindow(QWidget *parent, Qt::WFlags flags)
 2:     : QMainWindow(parent, flags)
 3: {
 4:     .....
 5:     statusBar()->addWidget(m_cmdLineEdit = new QLineEdit(), 1);
 6:     connect(m_cmdLineEdit, SIGNAL(cursorPositionChanged(int, int)),
 7:             this, SLOT(cmdLineCursorPositionChanged(int, int)));
 8:     .....
 9: }
10: void MainWindow::cmdLineCursorPositionChanged(int oldPos, int newPos)
11: {
12:     if( newPos == 0 )
13:         m_cmdLineEdit->setCursorPosition(1);
14: }

行頭の:(コロン)が削除されたら ex モードキャンセル

BackSpace により行頭の:(コロン)が削除されたら ex モードをキャンセルする処理も簡単だ。
QLineEdit::textChanged(int, int) シグナルを受けて、行頭の文字が:(コロン)でなくなったら、CMDモードに遷移するとよい。
コードは以下のようになる。

 1: MainWindow::MainWindow(QWidget *parent, Qt::WFlags flags)
 2:     : QMainWindow(parent, flags)
 3: {
 4:     .....
 5:     statusBar()->addWidget(m_cmdLineEdit = new QLineEdit(), 1);
 6:     connect(m_cmdLineEdit, SIGNAL(textChanged(const QString &)),
 7:             this, SLOT(cmdLineTextChanged(const QString &)));
 8:     .....
 9: }
10: void MainWindow::cmdLineTextChanged(const QString & text)
11: {
12:     if( text.isEmpty() || text[0] != ':' )
13:         m_viEngine->setMode(CMD);
14: }

まとめ

本稿のソースコードは以下からDLできます。※ VS2008 でプロジェクトを作成しています。

    http://vivi.dyndns.org/dist2/qvi-006-src.zip

演習問題

本稿ではイベントフィルターを用いて QLineEdit の機能を変更したが、同様のことを QLineEdit の派生クラスを宣言・実装することで実現しなさい。
そのコードと本稿のコードとを比較し、それぞれの方法の長短所を述べなさい。

Tweet


前へ 次へ
技術文章qvi