5

ユーザーがカスタマイズ可能なホットキーを使用してQtGUIアプリケーションを設計しようとしています。私が直面している主な問題は、特定のホットキー(コピーなど)が複数のウィジェット/コンポーネントによって使用される可能性があるため、アプリケーション全体でホットキーを同期する方法です。

私の現在の戦略は、QKeySequence異なるホットキーごとにオブジェクトのリストを保持する参照クラスを使用することです。keyPressEvent各ウィジェットには、このマスターリストを参照する方法が必要であり、入力されたキーとホットキーを比較する低レベルのカスタム実装が必要です。ただし、この戦略は特に好きではありません。各ウィジェットで大幅な再実装が必要であり、車輪の再発明を試みているように感じるからです。

また、内部でショートカットQActionを保持できるオブジェクトを使用してみQKeySequenceました。次に、これらを使用して、スロットとシグナルを使用して処理できる高レベルのイベントをトリガーしました。ただし、ここでの主な問題は、信号がルーティングされるスロットを管理する方法です。

たとえば、2つの開いているウィジェットがあり、どちらもcopyアクション信号を受信できるとします。これらの両方のスロットを同じ信号に接続し、ショートカットの単一の更新ポイントを利用できますが、両方のウィジェットではなく、アクティブなウィジェットのみがコピー信号に作用する必要があるため、事態は厄介になります。focusOutEventとハンドラーを再実装してfocusInEventスロットを手動で接続/切断することはできますが、これも上記と同じ問題が発生し、車輪の再発明を試みて必要以上の作業を行っているようです。

この問題を回避する簡単な方法はありますか?

4

1 に答える 1

7

この問題に対して特に簡単で面倒な解決策はないと思いますが、ユーザーがカスタマイズ可能なホットキーをアプリケーションに追加する必要がある場合は、次のようにしました。

1)ハードコードされたキーショートカットがあるアプリケーションから始めます。たとえば、次のようなコードです。

QMenu * editMenu = new QMenu;
QAction * copyItem = menu->addAction(tr("Copy"), this, SLOT(CopyData()));
copyItem->setShortcut(tr("Ctrl+C"));

2)次のようなGetKeySequence()関数を作成します。

static QHash<QString, QKeySequence> _usersKeyPreferences;
static bool _usersKeyPreferencesLoaded = false;

QKeySequence GetKeySequence(const QString & keySequence, const QString & contextStr)
{
   if (_usersKeyPreferencesLoaded == false)
   {
      // Oops, time to load in the user's saved custom-key settings from a file somewhere
      _usersKeyPreferences = LoadUsersKeyPreferencesFromFile();
      _usersKeyPreferencesLoaded = true;  // so we'll only try to load the file once
   }
   if (_usersKeyPreferences.contains(contextStr)) 
   {
      return _usersKeyPreferences[contextStr];
   }
   else 
   {
      // No user preference specified?  Okay, fall back to using the 
      // hard-coded default key sequence instead.
      return QKeySequence(qApp->translate(contextStr, keySequence));
   }
}

3)面倒な部分:すべてのコードを調べ、キーシーケンスを明示的に指定した場所(手順1で示したコードの3行目など)で、GetKeySequence()の呼び出しでラップします。このような:

copyItem->setShortcut(GetKeySequence(tr("Ctrl+C"), tr("Edit_Menu|Copy")));

4)この時点で、プログラムのキーシーケンスはカスタマイズ可能になります。GUI作成コードを実行する前に、key-settings-fileがディスク上に存在することを確認してください。これが私のプログラムのキーマッピングファイル(単純なASCIIテキストファイルとして保存している)からの抜粋です。

Edit_Menu|Copy   = Ctrl+C
Edit_Menu|Cut    = Ctrl+X
Edit_Menu|Paste  = Ctrl+V
[... and so on for all other menu items, etc...]

...もちろん、このアプローチの1つの欠点は、GUIが作成されると、キーバインディングを「オンザフライ」で変更できないことです(少なくとも、多くの追加コーディングがなければ)。私のプログラムは、ユーザーが[キーバインドの編集]ダイアログで[保存して適用]をクリックした後、すべてのウィンドウを閉じて再作成するだけでこれを回避できます。

5)オプションの追加ステップ(前もって追加の作業ですが、長期的には時間を節約します)は、プログラムのコードベース内のすべての.cppファイルを取得してGetKeySequence()の呼び出しを探すプログラム(またはスクリプト)を作成することです。コード。GetKeySequence()呼び出しが見つかると、呼び出しに対する2つの引数を解析し、デフォルト設定でキーバインディングファイルの行として出力します。これは、このスクリプトを自動ビルドの一部にすることができ、その後、新しいメニュー項目(または他のキーシーケンス指定子)を追加するたびにデフォルトのキー設定ファイルを手動で更新することを覚えておく必要がないため便利です。プログラム。

とにかく、これは私にとってはうまくいきました。利点は、既存のプログラムをリファクタリングする必要がまったくないことです。プログラムのより大きなロジック/構造をそのままにして、必要に応じてGetKeySequence()を挿入するだけで実行できます。

于 2012-11-18T03:52:35.480 に答える