解説

実例で学ぶWindowsプログラミング

第4回 操作性を向上させるファンクション・キーへの対応

― ユーザビリティを高めるファンクション・バーの実装(後編) ―

デジタルアドバンテージ 一色 政彦
2005/03/30
Page1 Page2 Page3 Page4

■FunctionMenuコントロールの作成

 ファンクション・メニューは、前回のファンクション・バーと同じ要領で、クラス・ライブラリ内に作成する。作成時に指定する項目は次のとおりだ。

  • ファイル名:「FunctionMenu.cs」
  • 名前空間名:「Insiders.Windows.Forms」
  • クラス名:「FunctionMenu」
  • 継承元クラス:「MainMenuコントロール(System.Windows.Forms名前空間)」

 また前回と同様に、Visual Studio .NET(以降、VS.NET)によって生成されたOnPaintメソッドを削除し、さらに次のようにFunctionMenuクラスに対してToolboxBitmap属性を指定しておこう。

[ToolboxBitmap(typeof(MainMenu))]
public FunctionMenu()

 これにより、VS.NET IDEのツールボックス上に登録したファンクション・メニューのアイコンが、MainMenuコントロールと同じになる。

■FunctionMenuコントロールへのメニュー項目の追加

 次にコントロール内にメニュー項目を追加するわけだが、前回作成したファンクション・バーと違って、IDE(コントロール・デザイナ)の[プロパティ]ウィンドウからは追加できない。これは、メニュー・バーのメニュー項目が([プロパティ]ウィンドウではなく)実際にメニュー・バーを配置したあとのWindowsフォーム・デザイナ上で直接、追加・編集するようになっているためである(ここではまだFunctionMenuコントロールをWindowsフォーム上に配置しているわけではないので、Windowsフォーム・デザイナは開かれていないことに注意)。

 従って、手で地道にコーディングするしかないだろう(ちなみに本稿では、すべてを手でコーディングするのではなく、いったん一時的なWindowsフォームを作成してそこにMainMenuコントロールを配置し、そのメニュー・バーをフォーム・デザイナを使って編集し、それにより自動生成されたメニュー・バーに関するソース・コードをコピーして若干の修正を加えたうえで使用した)。

 具体的には、次の表に挙げたメニュー項目を作成した。

親項目
子項目
名前 テキスト MergeOrder 名前 テキスト Shortcut
menuItemOperation 操作(&O) 6 … menuItemF1 (&1) F1
menuItemF2 (&2) F2
menuItemF3 (&3) F3
menuItemF4 (&4) F4
-
menuItemF5 (&5) F5
menuItemF6 (&6) F6
menuItemF7 (&7) F7
menuItemF8 (&8) F8
-
menuItemF9 (&9) F9
menuItemF10 (&10) F10
menuItemF11 (&11) F11
menuItemF12 (&12) F12
-
menuItemClose 閉じる(&E) × …
ファンクション・メニューに追加したメニュー項目
メニュー・バーに追加されるメニュー項目の実体は、System.Windows.Forms名前空間のMenuItemオブジェクトである。表中の「名前」は、このオブジェクトの(Name)プロパティ、テキストはTextプロパティ、MergeOrderはMergeOrderプロパティ、ShortcutはShortcutプロパティを意味する。Shortcutの列のデータは、Shortcut列挙体(System.Windows.Forms名前空間)の値を意味し、例えば「F1」は「System.Windows.Forms.Shortcut.F1」を示している。
[操作]メニュー項目のMergeOrderプロパティを「6」に設定することで、そのメニュー項目が[業務処理](5)と[ウィンドウ](7)の間に挿入されるようにした。
Shortcut列挙体には[Escape]キーが定義されていないため、ショートカット・キーを設定できない(詳細後述)。

 これを実際にコーディングしたのが、次のFunctionMenu.csのコードだ。

public class FunctionMenu : System.Windows.Forms.MainMenu
{
  ……中略……

  public FunctionMenu()
  {
    InitializeComponent();
    // メニュー項目の作成
    InitializeMenuItems();
  }

  private void InitializeComponent()
  {
    components = new System.ComponentModel.Container();
  }

  // メニュー項目の作成
  private void InitializeMenuItems()
  {
    // メニュー項目の生成
    this.menuItemOperation = new System.Windows.Forms.MenuItem();
    this.menuItemF1 = new System.Windows.Forms.MenuItem();
    ……中略(menuItemF2 〜 menuItemF12)……
    this.menuItemClose = new System.Windows.Forms.MenuItem();

    ……中略……
    // メニュー・バーへのメニュー項目の追加
    this.menuItemOperation.MenuItems.AddRange(
      new System.Windows.Forms.MenuItem[] {
        this.menuItemF1,
        ……中略(menuItemF2 〜 menuItemF12)……
        this.menuItemClose
      }
    );

    // 親メニュー項目のMergeOrderプロパティの設定
    this.menuItemOperation.MergeOrder = 6;
    ……中略……
    // 子メニュー項目のShortcutプロパティの設定
    this.menuItemF1.Shortcut = System.Windows.Forms.Shortcut.F1;
    ……中略(menuItemF2 〜 menuItemF12)……
    // Shortcut列挙体には[Escape]キーが定義されていない!

  }
}
ファンクション・メニューのメニュー項目の作成

 上記コードのInitializeMenuItemsメソッド内では、次の内容が実装されている。

メニュー項目の生成を行う。

メニュー・バーへメニュー項目を追加する。

ファンクション・メニューがMDI親ウィンドウのメニュー・バーの適切な位置にマージされるように、メニュー項目のMergeOrderプロパティを「6」に設定する。

各メニュー項目に対して[F1]〜[F12]キーのShortcutプロパティ(System.Windows.Forms 名前空間MenuItemクラスのプロパティ)を設定している。

 メニュー項目とショートカット・キーの関連付け(=[F1]などのショートカット・キーを押すと、該当するメニュー項目の処理が実行されること)は、のShortcutプロパティを設定するだけで実現できる。ただし[Escape]キーは、Shortcutプロパティに設定できないため、ショートカット・キーとの関連付けが、現時点では行われていない。この関連付けについては後述する。

■ファンクション・メニューのテキストや有効状態を切り替えるメソッド

 さらに前回のファンクション・バーと同じように、ファンクション・キーに対応したメニュー項目のテキストを変更するためのSetFunctionメソッドと、無効にするためのDisableFunctionメソッドを追加しておこう。

// 指定されたファンクション・メニュー項目の設定を変更し、有効にする
public void SetFunction(FunctionKey key, string setText);

// 指定されたファンクション・メニュー項目を無効にする
public void DisableFunction(params FunctionKey[] keys);
ファンクション・メニューのメニュー項目設定を行うメソッド
前回のファンクション・バーのメソッドとほぼ同じなので説明は割愛する。唯一の違いは、ファンクション・バーのSetFunctionメソッドではその第3パラメータにツールチップに対するテキスト文字列の指定があったが、ファンクション・メニューのSetFunctionメソッドにはこれがない。

■ファンクション・キー入力によるイベント通知の仕組み

 メニュー項目がクリックされたときに実行する処理は、それぞれのメニュー項目のClickイベント・ハンドラに実装する。また、ここまでの実装において、メニュー項目のShortcutプロパティが設定されているので、ファンクション・キーが押されたときも、メニュー項目のClickイベントが発行される。要するに、メニュー項目をクリックしたときと、ショートカット・キーを押したときの実行処理は、両方ともClickイベント・ハンドラで一括して実装することができるのだ。

 しかしここで1つ問題がある。それぞれのメニュー項目はフォーム上ではなく、FunctionMenuコントロールの中で生成しているので、基本的には、それぞれのメニュー項目のClickイベント・ハンドラも、フォーム上ではなく、そのコントロール内でハンドル(処理)することになる。つまりファンクション・メニューを配置した親フォーム側で、メニュー項目のClickイベントを処理するには何らかの工夫が必要なのだ(なお通常のMainMenuコントロールの利用では、MainMenuコントロールを配置したフォーム内にメニュー項目が生成されるため、そのClickイベントもフォーム内で簡単に処理できる)。

 そこで本稿では、次のようにしてこの問題を解決している。

(A)FunctionMenuコントロール内で各メニュー項目のClickイベントを処理する。具体的には、Clickイベント・ハンドラとしてmenuItem_Clickメソッドを追加して、このメソッドによりすべてのメニュー項目のClickイベントをハンドルする。

(B)そのmenuItem_Clickメソッド内で、どのメニュー項目がクリックされたかという情報(=ファンクション・キーの情報)を含む独自のイベント「FunctionKeyPress」を発行する。

(C)フォーム側にこのFunctionKeyPressイベントを処理するイベント・ハンドラを追加する。このイベント・ハンドラ内で、押されたファンクション・キーを判別して適切な処理を行うことになる。

 つまり本稿では独自イベントを定義してそれを経由させることで、コントロール内で発生したイベントをフォーム側で処理できるようにしているわけである。このように独自のイベントを利用すれば、柔軟にオブジェクト間(この場合は、コントロール − フォーム間)を連携させられるようになるのである。

 (A)と(B)はFunctionMenuコントロール内に実装し、(C)はフォーム側に実装する。まずはFunctionMenuコントロールの実装内容を見てみよう((C)の実装については後述)。


 INDEX
  解説:実例で学ぶWindowsプログラミング
  第4回 操作性を向上させるファンクション・キーへの対応(後編)
    1.ファンクション・メニューの実装
  2.FunctionMenuコントロールの作成
    3.独自イベントの実装方法
    4.ファンクション・バーとファンクション・メニューのフォームへの追加
 
インデックス・ページヘ  「解説:実例で学ぶWindowsプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH