C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: Re: DataGridViewのCellDoublecli


(過去ログ 161 を表示中)

[トピック内 19 記事 (1 - 19 表示)]  << 0 >>

■93213 / inTopicNo.1)  DataGridViewのCellDoubleClick
  
□投稿者/ Rider (1回)-(2019/11/28(Thu) 10:39:20)

分類:[VB.NET/VB2005 以降] 

使用言語:VB2013
OS:Windows10

こんにちは。
クリックイベントについて質問があります。
これはDataGridViewだけの問題ではないのかも知れませんが、
DataGridViewに関連したイベントについて質問です。

あるDataGridViewでは、以下のイベントを行っています。
・CellDoubleClick
・CurrentCellChanged

CurrentCellChangedのイベントでは、グリッドの選択セルの内容に応じて
別のコンボボックスの中身を変更するような処理を行っています。
ただし、セルのダブルクリックを行った場合、
選択されているセルでのダブルクリックでは
CellDoubleClickイベントが発生するのですが、
選択されていないセルのダブルクリックでは、
先にCurrentCellChangedのイベントが発生しますが、
CurrentCellChangedイベント実行後、CellDoubleClickイベントが発生しません。
また、CurrentCellChangedイベントで実行している処理のうち、
別のコンボボックスの中身を変更するような処理をコメントアウトすると、
CellDoubleClickイベントが発生するようになります。

試しに、CurrentCellChangedイベントで行う処理をタイマーで
1秒(1000ミリ秒)遅延させて処理を行えば、CellDoubleClickイベントも発生し、
CurrentCellChangedイベントで行っていた内容も処理されることを確認しましたが、
このタイマーによる遅延を短くしすぎるとCellDoubleClickイベントが発生せず、
タイマー1秒が妥当なのかどうかも分かりません。

どうせならTimerを使わずに、CurrentCellChangedとCellDoubleClickの
両イベントを両立させたいのですが、何か良い方法はないでしょうか?
引用返信 編集キー/
■93217 / inTopicNo.2)  Re[1]: DataGridViewのCellDoubleClick
□投稿者/ 大谷刑部 (67回)-(2019/11/28(Thu) 13:41:34)
No93213 (Rider さん) に返信
> どうせならTimerを使わずに、CurrentCellChangedとCellDoubleClickの
> 両イベントを両立させたいのですが、何か良い方法はないでしょうか?
両立?って具体的に何をさせたいのですか?
どの状態のCellDoubleClickでもCurrentCellChangedで発生させている処理を発生させたいということですか?
.Netの場合6以前のVBと違って、Handlesのところに複数のイベントを記載すれば同じ処理を違うイベントプロシージャとして挙動させるのはやろうと思えば可能とは思いますが、
それは通常、同じような複数のテキストボックスに同じような処理(例えばLostFocusで日付フォーマットにするとか)をしたいときするもので、
本来異なるイベントそのものを同じイベントとしてハンドルするのは、Windows Formのイベントを無理やり変えるイメージなのであまりいい方法とは言えませんね。

引用返信 編集キー/
■93219 / inTopicNo.3)  Re[2]: DataGridViewのCellDoubleClick
□投稿者/ 大谷刑部 (68回)-(2019/11/28(Thu) 14:16:15)
No93217 (大谷刑部 さん) に返信
> ■No93213 (Rider さん) に返信
>>どうせならTimerを使わずに、CurrentCellChangedとCellDoubleClickの
>>両イベントを両立させたいのですが、何か良い方法はないでしょうか?
> 両立?って具体的に何をさせたいのですか?
> どの状態のCellDoubleClickでもCurrentCellChangedで発生させている処理を発生させたいということですか?

試してみましたが第二引数がcastできないっぽいですね。
引用返信 編集キー/
■93220 / inTopicNo.4)  Re[2]: DataGridViewのCellDoubleClick
□投稿者/ Rider (2回)-(2019/11/28(Thu) 14:48:19)
No93217 (大谷刑部 さん) に返信
> ■No93213 (Rider さん) に返信
>>どうせならTimerを使わずに、CurrentCellChangedとCellDoubleClickの
>>両イベントを両立させたいのですが、何か良い方法はないでしょうか?
> 両立?って具体的に何をさせたいのですか?
> どの状態のCellDoubleClickでもCurrentCellChangedで発生させている処理を発生させたいということですか?

いいえ、全然違います。
カレントセルが変わった時はCurrentCellChangedイベントを、
セルのダブルクリックを行った場合はCellDoubleClickイベントを実行して欲しいのです。
セルのダブルクリックを行ったとき、カレントセルが変われば
CellDoubleClickイベントとCurrentCellChangedイベントの両方を実行して欲しいのですが、
セルのダブルクリックを行ったとき、カレントセルが変わってなければCurrentCellChangedイベントは実行して欲しくないし、
セルのダブルクリックを行わずにカレントセルが変割った場合はCellDoubleClickイベントは実行して欲しくないのです。

簡単な例として、CurrentCellChangedイベントでMsgBox("CurrentCellChangedイベント")を実行するようにして、
CellDoubleClickイベントでMsgBox("CellDoubleClickイベント")を実行するようにします。
カレントセルをダブルクリックすると、MsgBox("CellDoubleClickイベント")が実行されます。(これは期待通り)
また、カレントセル以外のセルを選択すると、MsgBox("CurrentCellChangedイベント")が実行されます。(これも期待通り)
ただし、カレントセル以外のセルをダブルクリックすると、MsgBox("CurrentCellChangedイベント")は実行されますが、
MsgBox("CellDoubleClickイベント")は実行されません。
こちらの希望としては、このケースではMsgBox("CurrentCellChangedイベント")とMsgBox("CellDoubleClickイベント")の両方を実行して欲しいのです。

CurrentCellChangedイベントで実行する内容を、タイマーを使用して遅延させるとうまくいくのは、
おそらくCurrentCellChangedで行う処理により、CellDoubleClickイベントのメッセージを受け取れていないのだと思いますが、
そこのところがよく分かっていないので質問しました。
引用返信 編集キー/
■93222 / inTopicNo.5)  Re[3]: DataGridViewのCellDoubleClick
□投稿者/ 大谷刑部 (69回)-(2019/11/28(Thu) 15:41:59)
No93220 (Rider さん) に返信
> ■No93217 (大谷刑部 さん) に返信
>>■No93213 (Rider さん) に返信
> CurrentCellChangedイベントで実行する内容を、タイマーを使用して遅延させるとうまくいくのは、
> おそらくCurrentCellChangedで行う処理により、CellDoubleClickイベントのメッセージを受け取れていないのだと思いますが、
確かに普通に書いたらそういう挙動になりますが、それがWin Formsの仕様なんだと思いますが。

多分、グリッド云々じゃなくて、普通のコンボボックスでもおんなじようになりませんか?
コンボボックスはクリック自体にWindows標準で特別な意味を持つから、ダブルクリックイベントを思い通りに挙動させること自体が結構難しい気がしますけど。
コンボボックスのイベントはこだわりすぎると結構はまってバグ出しやすくなりますよ。私の経験上は。


引用返信 編集キー/
■93223 / inTopicNo.6)  Re[4]: DataGridViewのCellDoubleClick
□投稿者/ Rider (3回)-(2019/11/28(Thu) 16:15:02)
> 多分、グリッド云々じゃなくて、普通のコンボボックスでもおんなじようになりませんか?
> コンボボックスはクリック自体にWindows標準で特別な意味を持つから、ダブルクリックイベントを思い通りに挙動させること自体が結構難しい気がしますけど。
> コンボボックスのイベントはこだわりすぎると結構はまってバグ出しやすくなりますよ。私の経験上は。

あの...コンボボックスのイベントについては一言も書いていないんですけど...
引用返信 編集キー/
■93224 / inTopicNo.7)  Re[5]: DataGridViewのCellDoubleClick
□投稿者/ Hongliang (923回)-(2019/11/28(Thu) 16:41:28)
2019/11/28(Thu) 16:49:05 編集(投稿者)

MsgBoxは例が悪いですね。モーダルダイアログが出た場合、セルは実際ダブルクリックできていないのでイベントが出ないのは当然です。
(自分以外のセルを最初に1回クリックした時点でCellValueChangedが動いてダイアログが現れ、2回目のクリックはモーダルダイアログによって無効化される)

「別のコンボボックスの中身を変更するような処理」をしなければ問題ないのですから、今のところその処理の内容次第としか言えないです。
その処理に上のような問題があるのかもしれませんし。

<追記>
とりあえず別のComboBoxのSelectedIndexを変更するだけなら問題なくCellValueChangedとCellDoubleClickが両方発生しました。
引用返信 編集キー/
■93226 / inTopicNo.8)  Re[5]: DataGridViewのCellDoubleClick
□投稿者/ 大谷刑部 (70回)-(2019/11/28(Thu) 17:15:29)
No93223 (Rider さん) に返信
>>多分、グリッド云々じゃなくて、普通のコンボボックスでもおんなじようになりませんか?
>>コンボボックスはクリック自体にWindows標準で特別な意味を持つから、ダブルクリックイベントを思い通りに挙動させること自体が結構難しい気がしますけど。
>>コンボボックスのイベントはこだわりすぎると結構はまってバグ出しやすくなりますよ。私の経験上は。
>
> あの...コンボボックスのイベントについては一言も書いていないんですけど...
自分でグリッド上でコンボボックス使ってるって書いてるでしょ?
要するに、グリッドのイベントが原因じゃなくて、コンボボックスだからそういう動きするって言ってるんだけど。
引用返信 編集キー/
■93227 / inTopicNo.9)  Re[6]: DataGridViewのCellDoubleClick
□投稿者/ 大谷刑部 (71回)-(2019/11/28(Thu) 17:17:32)
No93224 (Hongliang さん) に返信
> 2019/11/28(Thu) 16:49:05 編集(投稿者)
> <追記>
> とりあえず別のComboBoxのSelectedIndexを変更するだけなら問題なくCellValueChangedとCellDoubleClickが両方発生しました。
それはそうでしょうね。クリックイベントが発生するわけじゃないですからね。
引用返信 編集キー/
■93228 / inTopicNo.10)  Re: DataGridViewのCellDoubleCli
□投稿者/ Rider (4回)-(2019/11/28(Thu) 17:19:26)
2019/11/28(Thu) 17:23:41 編集(投稿者)

> 自分でグリッド上でコンボボックス使ってるって書いてるでしょ?

何処に?グリッド上でコンボボックスを使っているとは一言も書いていないのですが...

引用返信 編集キー/
■93229 / inTopicNo.11)  Re[6]: DataGridViewのCellDoubleClick
□投稿者/ Rider (5回)-(2019/11/28(Thu) 17:24:34)
> MsgBoxは例が悪いですね。モーダルダイアログが出た場合、セルは実際ダブルクリックできていないのでイベントが出ないのは当然です。
> (自分以外のセルを最初に1回クリックした時点でCellValueChangedが動いてダイアログが現れ、2回目のクリックはモーダルダイアログによって無効化される)
>
> 「別のコンボボックスの中身を変更するような処理」をしなければ問題ないのですから、今のところその処理の内容次第としか言えないです。
> その処理に上のような問題があるのかもしれませんし。

こちらの都合上、詳細には説明できませんが、CellValueChangedで、別Formの処理を行う所がありました。
これが、「上のような問題」かも知れません。
とりあえず、タイマーで回避することで対応しようと思います。
解決済み
引用返信 編集キー/
■93230 / inTopicNo.12)  Re[7]: DataGridViewのCellDoubleClick
□投稿者/ 大谷刑部 (72回)-(2019/11/28(Thu) 17:25:17)
No93228 (Rider さん) に返信
>>MsgBoxは例が悪いですね。モーダルダイアログが出た場合、セルは実際ダブルクリックできていないのでイベントが出ないのは当然です。
>>(自分以外のセルを最初に1回クリックした時点でCellValueChangedが動いてダイアログが現れ、2回目のクリックはモーダルダイアログによって無効化される)
>>
>>「別のコンボボックスの中身を変更するような処理」をしなければ問題ないのですから、今のところその処理の内容次第としか言えないです。
>>その処理に上のような問題があるのかもしれませんし。
>
> こちらの都合上、詳細には説明できませんが、CellValueChangedで、別Formの処理を行う所がありました。
> これが、「上のような問題」かも知れません。
> とりあえず、タイマーで回避することで対応しようと思います。

根本的解決になってないけど、本人がいいならいいですけど。
けど、ちゃんとWindowsのイベントの仕組みは理解した方がいいですよ。
グリッドだから、コンボボックスのイベント関係ないってのは明らかな認識誤認なので。
解決済み
引用返信 編集キー/
■93234 / inTopicNo.13)  Re[8]: DataGridViewのCellDoubleClick
□投稿者/ Zurishin (1回)-(2019/11/28(Thu) 20:46:48)
こりゃ、ひでぇな。
お前はWindowsのイベントの仕組みを理解しろと人に言う前に、日本語を理解すべきだ。
質問者はコンボボックスのイベントのことは一切触れていないのに、
挙句の果てにはグリッド内にコンボボックスがあると抜かしたもんだ。
質問者もきっとビックリしているだろう。
そんなに恥を上塗りしたいのかい?

お前は波乗り君に色々と文句を言っているが、
読解力は波乗り君レベル、スキルはそれ以下だ。
解決済み
引用返信 編集キー/
■93238 / inTopicNo.14)  Re[1]: DataGridViewのCellDoubleClick
□投稿者/ KOZ (54回)-(2019/11/29(Fri) 09:03:25)
No93213 (Rider さん) に返信
> どうせならTimerを使わずに、CurrentCellChangedとCellDoubleClickの
> 両イベントを両立させたいのですが、何か良い方法はないでしょうか?

Windows Forms のダブルクリックってちょっと変わった処理をしていて、次のようになっています。

左ボタン    メッセージ          イベント

@ 押す     WM_LBUTTONDOWN      MouseDown
                                CurrentCellChanged
A 離す     WM_LBUTTONUP        MouseClick
                                MouseUp
B 押す     WM_LBUTTONDBLCLK    MouseDown

C 離す     WM_LBUTTONUP        CellDoubleClick
                                MouseDoubleClick
                                MouseUp

「B 押す」では、MouseDown イベントを起こし、「C 離す」で、CellDoubleClick/MouseDoubleClick イベントを起こしています。

ここで問題なのが、「C 離す」でダブルクリック系のイベントを起こすかどうかを判定していること。

判定はフラグ管理で行われているのですが、WM_LBUTTONUP が来る前に、フラグをリセット
するような処理が走ってしまうとイベントが起きなくなってしまいます。

私だったら Bで WM_LBUTTONDBLCLK を拾ってダブルクリックの処理をやっちゃいます。

# CurrentCellChanged で編集モードにする等の処理を行っていると動きは変わってきますので
# そこは注意深く観察してみてください。

引用返信 編集キー/
■93239 / inTopicNo.15)  Re[2]: DataGridViewのCellDoubleClick
□投稿者/ Rider (6回)-(2019/11/29(Fri) 09:27:56)
KOZ様、ありがとうございます。

> Windows Forms のダブルクリックってちょっと変わった処理をしていて、次のようになっています。

---中略---

> 私だったら Bで WM_LBUTTONDBLCLK を拾ってダブルクリックの処理をやっちゃいます。
>
> # CurrentCellChanged で編集モードにする等の処理を行っていると動きは変わってきますので
> # そこは注意深く観察してみてください。

詳細な解説、誠にありがとうございました。
ダブルクリックのイベントが発生するためには、WM_LBUTTONDBLCLKメッセージの後に
WM_LBUTTONUPメッセージを受け取る必要があるのですね。
今回のケースでは、2回目のWM_LBUTTONUPメッセージを受け取る前に、
ダブルクリック判断のフラグがリセットされてしまう処理が入っているのだとしたら、
WM_LBUTTONDBLCLKメッセージ受信時にダブルクリック時の処理を行うことで対応が可能かも知れませんね。

もちろん、WM_LBUTTONDBLCLK受信前にダブルクリック判断フラグがリセットされていればお手上げですが、
早速確認してみます。
引用返信 編集キー/
■93243 / inTopicNo.16)  Re: DataGridViewのCellDoublecli
□投稿者/ Rider (7回)-(2019/11/29(Fri) 10:02:20)
2019/11/29(Fri) 10:08:33 編集(投稿者)

KOZ様のご提案を元に、以下のことをやってみようと思います。

・DataGridViewを継承したクラスを作り、WndProcをオーバーライドする。
・オーバーライドしたWndProcでWM_LBUTTONDBLCLKを検知したら、
 マウス位置を元にHitTestで対象セルを特定。(範囲外の場合は終了)
 そのセルをダブルクリックした時に実行したい処理を行う。

考え方に間違いがあればご指摘ください。

週末にでも試してみようと思います。
引用返信 編集キー/
■93244 / inTopicNo.17)  Re[4]: Re: DataGridViewのCellDoublecli
□投稿者/ KOZ (55回)-(2019/11/29(Fri) 10:26:55)
No93243 (Rider さん) に返信
>  マウス位置を元にHitTestで対象セルを特定。(範囲外の場合は終了)

マウス位置はコントロールの範囲内にあるかどうかだけ判定し、対象のセルは CurrentCell を使ったほうが良いです。

スクロールすると位置がずれてしまいます。

TreeView の NodeDoubleClick イベントがいい例で、ノードをダブルクリックして下位ノードが展開され、
スクロールすると TreeNodeMouseClickEventArgs.Node にはスクロール後のマウス位置にあるノードが入っています。
引用返信 編集キー/
■93245 / inTopicNo.18)  Re[5]: Re: DataGridViewのCellDoublecli
□投稿者/ KOZ (56回)-(2019/11/29(Fri) 10:42:13)
No93244 (KOZ) に返信
> マウス位置はコントロールの範囲内にあるかどうかだけ判定し、対象のセルは CurrentCell を使ったほうが良いです。
範囲外ならメッセージも飛んでこないので判定いりませんね。

> TreeView の NodeDoubleClick イベントがいい例で、ノードをダブルクリックして下位ノードが展開され、
NodeMouseDoubleClick イベントでした。
引用返信 編集キー/
■93246 / inTopicNo.19)  Re[6]: Re: DataGridViewのCellDoublecli
□投稿者/ KOZ (57回)-(2019/11/29(Fri) 16:29:00)
サンプル投下します。

using System;
using System.Windows.Forms;

class DataGridViewEx : DataGridView
{
    protected override void WndProc(ref Message m) {
        switch (m.Msg) {
            case WM_LBUTTONDOWN:
                WmLButtonDown(ref m);
                break;
            case WM_LBUTTONDBLCLK:
                WmLButtonDblClk(ref m);
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }

    private bool fireCellDoubleClickEx;
    private HitTestInfo fireHitTest;

    private void WmLButtonDown(ref Message m) {
        int x = SignedLOWORD(m.LParam);
        int y = SignedHIWORD(m.LParam);
        fireHitTest = base.HitTest(x, y);

        base.WndProc(ref m);

        fireCellDoubleClickEx = false;
        switch (fireHitTest.Type) {
            case DataGridViewHitTestType.Cell:
                // ヘッダ付近だとリサイズ操作になるので
                if (Cursor != Cursors.SizeWE &&
                    Cursor != Cursors.SizeNS &&
                    CurrentCell.RowIndex == fireHitTest.RowIndex &&
                    CurrentCell.ColumnIndex == fireHitTest.ColumnIndex) {
                    fireCellDoubleClickEx = true;
                }
                break;
        }
    }

    private void WmLButtonDblClk(ref Message m) {
        base.WndProc(ref m);
        if (fireCellDoubleClickEx) {
            OnCellDoubleClickEx(new DataGridViewCellEventArgs(
                                        fireHitTest.ColumnIndex, fireHitTest.RowIndex));
        }
    }

    public event DataGridViewCellEventHandler CellDoubleClickEx;

    protected virtual void OnCellDoubleClickEx(DataGridViewCellEventArgs e) {
        if (CellDoubleClickEx != null) CellDoubleClickEx.Invoke(this, e);
    }

    private const int WM_LBUTTONDOWN = 0x201;
    private const int WM_LBUTTONDBLCLK = 0x203;

    private static int SignedHIWORD(IntPtr n) {
        return SignedHIWORD(unchecked((int)(long)n));
    }

    private static int SignedLOWORD(IntPtr n) {
        return SignedLOWORD(unchecked((int)(long)n));
    }

    private static int SignedHIWORD(int n) {
        return (short)((n >> 16) & 0xffff);
    }

    private static int SignedLOWORD(int n) {
        return (short)(n & 0xFFFF);
    }
}

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -