サイト検索
検索
サイトメニュー
Menu
RTB SoftLab ラテベ ソフトラボ (ラテベラボ)
私の知っているソフトの操作を解りやすく、解説していきます。
サイト検索
検索
サイトメニュー
Menu

投稿日:2021年3月14日

更新日:2021年3月10日

DataGridViewカスタムコントロールの機能アップの内容

前回、機能アップとして、セル編集時のカラーを設定しました。
これで、ユーザにどこにフォーカスが当たっているかが解ると思います。

前回の内容は、こちらから参照願います。
カスタムDataGridView③ 編集時のカラー設定

前回の作成終了までは、ここまでとなります。

セルの編集時にカラーを付けた後
セルの編集時にカラーを付けた後

そうなると、欲が出てきます。
Enterで次のセルにフォーカスが移れば、すごく優しいシステムになると思いませんか?

ということで、既存イベントを使って、Enter押下時に次のセルにフォーカスを移す処理を行いたいと思います。

前回の技術を取り入れれば、ほんの少しだけ難しいだけになりますので、
問題なく出来ると思います。

Enterを取得するのは、キーイベントになりますが・・・。

Enterを取得するのは、キーベントになると思いますが、キーイベントをまず整理したいと思います。

基本発生順イベントセル編集完了セル編集中
ProcessCmdKey
ProcessDialogKeyイベントが発生
OnKeyDown
OnKeyPress
キーイベントの発生順

このようになっていると思います。

これが、微妙に使い方が異なってしまっているので、悩みどころになります。
例えば!

  • OnKeyPress
    • 漢字変換のEnterとの区別が・・・。
  • OnKeyDown
    • 一部のコントロール(Buttonなど)イベントが発生しない。
  • ProcessDialogKey
    • セル編集でない時は、イベントが発生しない。

結論は、私は『ProcessCmdKey』を使用して作るようにしています。
(ものによっては、『ProcessDialogKey』を使用しますが、今回は省略します)

では、やってみましょ~♪

Enter時、次のセルにフォーカスを移動するロジックは?

前回までの記事と同様に、『Overrides』を使って、ロジックを作っていきます。
ちなみに今回のロジックは、あくまで簡易的になります。実際は、いろいろ工夫が必要になってきますので、最後のまとめでそちらを記載しておきます。
記載したロジックは、下記になります。

 Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean

     Dim isShift As Boolean = False : If (ModifierKeys) = Keys.Shift Then isShift = True
     Dim isCtrl As Boolean = False : If (ModifierKeys) = Keys.Control Then isCtrl = True
     Dim isAlt As Boolean = False : If (ModifierKeys) = Keys.Alt Then isAlt = True

     If isCtrl Then Return MyBase.ProcessCmdKey(msg, keyData)
     Dim cell As DataGridViewCell = Me.CurrentCell
     If cell Is Nothing OrElse cell.RowIndex < 0 OrElse cell.ColumnIndex < 0 Then
         Return MyBase.ProcessCmdKey(msg, keyData)
     End If


     Select Case (keyData And Keys.KeyCode)

         Case Keys.Enter

             If isShift AndAlso cell.RowIndex = 0 AndAlso cell.ColumnIndex = 0 Then
                 If cell.IsInEditMode Then Me.Select()
                 Me.TopLevelControl.SelectNextControl(Me, False, True, True, True)
                 Return True
             Else
                 If Not isShift AndAlso cell.RowIndex = Rows.Count - 1 AndAlso cell.ColumnIndex = Columns.Count - 1 Then
                     If cell.IsInEditMode Then Me.Select()
                     Me.TopLevelControl.SelectNextControl(Me, True, True, True, True)
                     Return True
                 End If
             End If

             If (isShift) Then
                 Return MyBase.ProcessDialogKey(Keys.Shift Or Keys.Tab)
             Else
                 Return MyBase.ProcessDialogKey(Keys.Tab)
             End If

             Return True
     End Select

     Return MyBase.ProcessCmdKey(msg, keyData)

ちょっと、長いですね~www^^;
説明を記載しておきます。

If isCtrl Thenまでキーイベントには、いつも記載しているロジックです。
簡単なロジックなので、無視して結構です。
Select Case (keyData And Keys.KeyCode)より上対象外のキーを除外している処理になります。
If cell.IsInEditMode Then Me.Select()【重要です】後で、説明します。
SelectNextControlこれは、最初のセルと最後のセルで、他のコントロールにセルをフォーカスを移動しています。
Return MyBase.ProcessDialogKey(後は、Tabに変換して、次のセルにフォーカスを映しているということです。
追加したコードの説明

ロジックは長いですが、部分部分を見れば、そんなに難しくはないと思っています。
さらに、メソッドにすれば、もっと見やすくなると思います♪

摩訶不思議(仕様だと思いますけどwww^^;)動きをすることがよくあります。

【重要です】と書いたこの部分です!
If cell.IsInEditMode Then Me.Select()
これは、何をやっているかと言いますと!
cell.IsInEditModeは、セルの編集中かを判定しています。
もし編集中であれば、セルからDetaGlidViewに移しています。
これがないと、フォーカスは、他のコントロールに移るのですが、入力可能な状態にならないのですwww^^;
時間がある方は、上記をコメントにしてやって見て下さい。現象が出ると思います。(EditMode=EditOnEnterで行えば、再現出来ます!)

上記のロジックのテスト結果はこのようになります。

始めに、EditMode=EditOnEnterで、動作確認しています。
その後、ボタンを押して、EditMode=EditOnKeystrokeOrF2に変えています。

フォーカスロジックの検証結果

いかかでしょうか?
このような感じで、徐々にプロパティーやイベント、そして、メッソドと追加して、カスタムコントロールを作っていきます。

今回は、説明の為に、プロパティーは、追加していませんが、
例えば、isEnterNextCellというプロパティで、この機能をOnやOffにすることが可能になります。
カスタムコントロールを作って、それを使うのは、作成側にお任せするということになります。
これで、カスタムコントロールを使って、通常のDataGlidViewみたいな使い方も出来るということです。
勿論、機能を強制する事も出来ます。
テキストボックスとDataGlidViewにて、カスタムコントロールの作成方法を明記致しました。
皆さんの参考になれば、幸いです。

残っている懸案

分類懸案結論完了
現在なし
これからの懸案一覧

今回のまとめ

冒頭で、
『ちなみに今回のロジックは、あくまで簡易的になります。実際は、いろいろ工夫が必要になってきます』
と書きました。

実際使用できるレベルに持っていくには、まだまだロジックが必要になります。
今のままでは、出来ないことは、下記になります。

  1. Enable、TabStop、などを考えた場合。
    1. 今回は、最初と最後のセルを固定で行っていますが、実際は、Enableなどを考慮する必要があります。
      1. 動的にするには、フォーカス取得時、最初と最後のセルを取得するメソッドが必要になります。
    2. って、書きましたが、よく考えたら、そんなプロパティなかったですね!(www^^)
      今後実装する予定だったので、思わず書いてしまいましたwww^^;
  2. 他のコントロールからフォーカスを受け取った時。
    1. 前のテキストボックスからフォーカスが移った時は、始めのセルにフォーカスしたいはずです。
    2. 次のテキストボックスからフォーカスが移った時は、最後のセルにフォーカスしたいはずです。
    3. これは、流石に、このカスタムコントロールだけでは出来ません。
      1. フォーカス履歴を持っているクラスからそこを参照すれば出来ると思います。

このような工夫や子細工が必要になってきます。
たぶんその時に、今回のような、不可思議な現象にハマったりします。(笑)

でも、一つ言えることは、小分けで考えて、一つずつ作っていけば、必ず完成すると思います♪

RTB カレンダー

31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
通販サイト(ECサイト)デモへ
ラテベラボブログへ
ナノシスへ

RTBアーカイブ(旧 Widget 版)

RTB ポストランキング (旧)

RTBアーカイブ(旧 Widget 版)