Qt。 グラフィカルアプリケーション用のコンソールウィジェットの作成

良い人たちにこんにちは。

この見出しを読むとき、読者は次のように思うかもしれません:コンソールとグラフィカルアプリケーションを混在させる理由-コンソールはGUIアプリケーションでは必要ありません。 しかし、いや、あえて言う。 機能的なコンソールとコマンドの完全なセットおよびグラフィカルディスプレイを組み合わせて、簡単なナビゲーションとデータの表示を行うと、強力なツールになることがあります。

そして、私は例を持っています。

私のプロジェクトでRedis高速Key-Valueデータウェアハウスの使用を開始すると、現時点では、Redisデータベースを表示、編集、管理するための単一の健全なデスクトップアプリケーションは存在しないことがわかりました。 開発者からのコンソール、Redis Admin UI Webインターフェースのみがあり、その作業には.NETが必要です(それ自体はすでに怖がっています)。

Redisデータベース自体のように、便利で高速なものが欲しいです。 したがって、私はこのギャップを埋めてそのようなツールを作成することにしました。 クロスプラットフォームが必要なので-速いので、C ++が必要です。



RedisConsole



すべてのデータベース機能を実装することはできず、毎日新しく表示される可能性があるため、グラフィカルインターフェイスにコンソールを追加する必要がありました。 Qtのどのウィジェットをシミュレートするか、どのように、そしてどのように伝えたいかに基づいています。





無法から完全管理まで





ベースコンソールウィジェットには、QPlainTextEditを選択しました。 まず、必要な高度なテキスト編集機能が含まれています。次に、書式設定を追加できます。色で異なる要素を強調表示しても問題ありません。



したがって、QPlainTextEditの子孫を作成します。



class Console : public QPlainTextEdit{};
      
      







QPlainTextEditはQTextEditの単純化されたバージョンであるという事実にもかかわらず、ユーザーは適切なコンソールには許可されないあまりにも多くのアクションを実行できます。



したがって、最初に行うことは、可能なすべてを制限することです。 私たちは完全な無法状態から完全な制御に移行します。



これを行うには、キーストロークとマウスクリックを受け取る組み込みスロットを再定義します。



 void Console::keyPressEvent(QKeyEvent *){} void Console::mousePressEvent(QMouseEvent *){} void Console::mouseDoubleClickEvent(QMouseEvent *){} void Console::contextMenuEvent(QContextMenuEvent *){}
      
      







これらの行の後、ユーザーはウィジェットフィールドに文字を入力したり、テキストを選択したり、行を削除したりすることはできません-完全なブロック。



自由化の段階





では、必要なすべてを同時に解決しながら、全面禁止から合理的な民主主義に移行しましょう。



最初に行うことは、プロンプト行を定義することです。



 // class definition QString prompt; // contructor prompt = "redis> ";
      
      







そして、コンソールにプロンプ​​ト行を印刷します。



 // constructor insertPrompt(false); // source void Console::insertPrompt(bool insertNewBlock) { if(insertNewBlock) textCursor().insertBlock(); textCursor().insertText(prompt); }
      
      







マウスでクリックするとき、カーソルを再配置することは不可能である必要がありますが、コンソールをアクティブにすることは可能でした:



 void Console::mousePressEvent(QMouseEvent *) { setFocus(); }
      
      







通常の文字、数字、その他の有用な文字を入力するときは、コマンドラインに追加する必要があります。



 void Console::keyPressEvent(QKeyEvent *event) { // … if(event->key() >= 0x20 && event->key() <= 0x7e && (event->modifiers() == Qt::NoModifier || event->modifiers() == Qt::ShiftModifier)) QPlainTextEdit::keyPressEvent(event); // … }
      
      







シンボルはBackspaceキーを使用して消去できますが、すべてではなく、特定のポイントまでのみです。したがって、招待ラインは失われません。



 void Console::keyPressEvent(QKeyEvent *event) { // … if(event->key() == Qt::Key_Backspace && event->modifiers() == Qt::NoModifier && textCursor().positionInBlock() > prompt.length()) QPlainTextEdit::keyPressEvent(event); // … }
      
      







コマンド入力に対するウィジェットの応答を決定します(Enterキーを押したとき)。



 void Console::keyPressEvent(QKeyEvent *event) { // … if(event->key() == Qt::Key_Return && event->modifiers() == Qt::NoModifier) onEnter(); // … }
      
      







コマンドを入力するとき、プロンプト行からテキストブロックの最後までテキストを切り取り、スロットを接続できる信号を出力します。



 void Console::onEnter() { if(textCursor().positionInBlock() == prompt.length()) { insertPrompt(); return; } QString cmd = textCursor().block().text().mid(prompt.length()); emit onCommand(cmd); }
      
      







また、アプリケーションがコマンドを処理している間、チェックボックスを設定してテキストフィールドをブロックします。



 void Console::onEnter() { // … isLocked = true; } void Console::keyPressEvent(QKeyEvent *event) { if(isLocked) return; // … }
      
      







アプリケーション-ウィジェットの親はコマンドを処理し、実行結果をコンソールに渡し、ロックを解除します:



 void Console::output(QString s) { textCursor().insertBlock(); textCursor().insertText(s); insertPrompt(); isLocked = false; }
      
      







チームの歴史





入力したすべてのコマンドの履歴を保存して、上/下キーを押すとナビゲートできるようになります:



 // class definition QStringList *history; int historyPos; // source void Console::keyPressEvent(QKeyEvent *event) { // … if(event->key() == Qt::Key_Up && event->modifiers() == Qt::NoModifier) historyBack(); if(event->key() == Qt::Key_Down && event->modifiers() == Qt::NoModifier) historyForward(); } void Console::onEnter() { // … historyAdd(cmd); // … } void Console::historyAdd(QString cmd) { history->append(cmd); historyPos = history->length(); } void Console::historyBack() { if(!historyPos) return; QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::StartOfBlock); cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); cursor.removeSelectedText(); cursor.insertText(prompt + history->at(historyPos-1)); setTextCursor(cursor); historyPos--; } void Console::historyForward() { if(historyPos == history->length()) return; QTextCursor cursor = textCursor(); cursor.movePosition(QTextCursor::StartOfBlock); cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); cursor.removeSelectedText(); if(historyPos == history->length() - 1) cursor.insertText(prompt); else cursor.insertText(prompt + history->at(historyPos + 1)); setTextCursor(cursor); historyPos++; }
      
      







美しくする:コンソールの色付け





これを行うには、ウィジェットコンストラクターで、コンソールの一般的な色域を定義します-背景は黒、入力コマンドの文字は緑です:



 QPalette p = palette(); p.setColor(QPalette::Base, Qt::black); p.setColor(QPalette::Text, Qt::green); setPalette(p);
      
      







プロンプト文字列が表示されたら、フォントを緑色にします:



 void Console::insertPrompt(bool insertNewBlock) { // … QTextCharFormat format; format.setForeground(Qt::green); textCursor().setBlockCharFormat(format); // … }
      
      







コマンドの結果を出力するとき、白いフォントを作成します。



 void Console::output(QString s) { // … QTextCharFormat format; format.setForeground(Qt::white); textCursor().setBlockCharFormat(format); // … }
      
      







ダウン!





また、ユーザーがコマンドを入力すると、コンソールテキストフィールドのスクロールバーが一番下までスクロールされるようにしたいと思います。



 void Console::insertPrompt(bool insertNewBlock) { // … scrollDown(); } void Console::scrollDown() { QScrollBar *vbar = verticalScrollBar(); vbar->setValue(vbar->maximum()); }
      
      







結果





結果は楽しく、美しく、快適なコンソールです。 わずか120行のコードで済みました。 もちろん、できることはもっとたくさんありますが、基本的な機能は実装されています。



参照資料





GitHubのRedisConsoleプロジェクトのソースコード: https : //github.com/ptrofimov/RedisConsole



コンソールウィジェットクラスを確認し、[ダウンロード]ボタンをクリックして、Windows用のコンパイル済みアプリケーションバイナリをダウンロードできます。



ありがとう




All Articles