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

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

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

Re[3]: Form のキーイベント


(過去ログ 171 を表示中)

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

■98420 / inTopicNo.1)  Form のキーイベント
  
□投稿者/ 星は昴 (16回)-(2021/11/15(Mon) 06:52:58)

分類:[C#] 

 Form でのキーイベントを発生させるとき、デザイナーを使わないときは
@
public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
    this.KeyDown += Form1_KeyDown;
    //または this.Click += new EventHandler(Form1_KeyDown);
  }

  private void Form1_KeyDown(object sender, KeyEventArgs e)
  {
    if (e.KeyCode == Keys.Left)
    ・・・・
  }
}

とやるのが普通だと思うのですが、ネット上で

A
public partial class Form1 : Form
{
  protected override void OnKeyDown(KeyEventArgs e)
  {
    if (e.KeyCode == Keys.Left)
    ・・・・
    base.OnKeyDown(e); // base とは?
  }
}

というコードを見つけました。Aは大変簡潔でいいと思うのですが、両者のメリット、デメリットにはどんなものがあるのでしょうか。

引用返信 編集キー/
■98421 / inTopicNo.2)  Re[1]: Form のキーイベント
□投稿者/ 774RR (876回)-(2021/11/15(Mon) 09:19:40)
後者はデザイナで KeyDown にイベントを追加しているだけだと思うのだが、
元ネタで「デザイナを使わないでやった」と明記してあるのかな?
Form1.Designer.cs でデザイナが追加した this.KeyDown += new KeyEventHandlerごにょごにょ が生成されてるはず。

なので前者も後者もやっていることは全く同じで優劣の差はないっス。

引用返信 編集キー/
■98422 / inTopicNo.3)  Re[2]: Form のキーイベント
□投稿者/ ぶなっぷ (278回)-(2021/11/15(Mon) 09:21:27)
コードを眺めてみる限り、Aのベースクラスは Form じゃない気がしてならない。

InitializeComponent();なしで、Formがまともに動作するとは思えないし、
OnKeyDown()がKeyDownの直接のイベントハンドラなら、引数がおかしい
(object senderが足りない)。

さらに、OnKeyDown()の宣言がprotected overrideでしょ。
これって、ベースクラスに
  public virtual void OnKeyDown(KeyEventArgs e)
みたいなのがあってオーバーライドしてますって言ってるようなもんだから。

おそらくは、以下のようなベースクラスがあった上で、
  public class FormBase : Form
  {
    public FormBase()
    {
        InitializeComponent();
        this.KeyDown += Form1_KeyDown;
    }
    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        OnKeyDown(e);
    }
    public virtual void OnKeyDown(KeyEventArgs e)
    {
      ・・・・
    }
  }

Aは以下だと思われる。
public partial class Form1 : FormBase
{
    protected override void OnKeyDown(KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Left)
        ・・・・
        base.OnKeyDown(e); // base とは?
    }
}

で、質問のあった
  base.OnKeyDown(e)
ですが、上記例で言えば、FormBase.OnKeyDown()を呼んでいます。

また、見て分かる通り、ベースクラスの実装と合わせると、
結局は@Aともやってることは変わりません。

ただし、Aなら、派生クラスをいっぱい作るときに、個々の派生クラスが
簡潔になるというメリットがあります。

引用返信 編集キー/
■98423 / inTopicNo.4)  Re[1]: Form のキーイベント
□投稿者/ 魔界の仮面弁士 (3215回)-(2021/11/15(Mon) 09:51:45)
No98420 (星は昴 さん) に返信
> Form でのキーイベントを発生させるとき、
「イベントを発生させる」のは、OnKeyDown(e); の役目です。
this.KeyDown += Form1_KeyDown; というのは、それを利用するイベントハンドラー。

親クラスの内部実装が OnKeyDown を呼び出さなかった場合、
継承先のクラスで this.KeyDown += Form1_KeyDown; を割り当てていたとしても
KeyDown イベントは発生しないため、継承先のクラスでイベントを利用できません。


> public partial class Form1 : Form
まず、Form1 は、Form クラスを継承していますよね。

もしもこれを
 public partial class Form2 : Form1
のように、さらに継承するかどうかで意味が変わってきます。


> 両者のメリット、デメリットにはどんなものがあるのでしょうか。
継承先クラスで "Onイベント名" 仮想メソッドをオーバーライドすると、その中で
継承元クラスの "base.Onイベント名(e);" の呼び出しを制御できます。これによって
 本来のイベントが発生する直前/直後に別の処理を行ったり
 特定の条件の時には、そのイベントがそもそも呼ばれないようにしたり
 イベント引数 e の内容を編集してから本来の処理を呼び出すことで振る舞いを操作したり
 本来のイベントの代わりに(あるいは本来のイベントに加えて)自作イベントを発生させたり
といったことができます。
引用返信 編集キー/
■98424 / inTopicNo.5)  Re[3]: Form のキーイベント
□投稿者/ Hongliang (1203回)-(2021/11/15(Mon) 09:52:51)
2021/11/15(Mon) 09:53:29 編集(投稿者)

> InitializeComponent();なしで、Formがまともに動作するとは思えないし、

投稿者さんのコードには存在していますが…?

> さらに、OnKeyDown()の宣言がprotected overrideでしょ。
> これって、ベースクラスに
> public virtual void OnKeyDown(KeyEventArgs e)
> みたいなのがあってオーバーライドしてますって言ってるようなもんだから。

Formの祖先であるControlクラスに
protected virtual void OnKeyDown(KeyEventArgs)
が定義されていますが…。


大雑把にはこういう構成です。

// キー入力時にシステムが送信したWM_KEYDOWNメッセージをここで受け取る
protected virtual void WndProc(ref Message m) {
if (m.Msg == WM_KEYDOWN) this.OnKeyDown(new KeyEventArgs(...))
}
protected virtual void OnKeyDown(KeyEventArgs e) {
if (this.KeyDown != null) this.KeyDown(this, e);
}

なのでbase.OnKeyDownを呼び出さないとKeyDownイベントに追加したイベントハンドラは実行されなくなります。
FormでOnKeyDownをオーバーライドする場合はKeyDownイベントに追加することはあんまりないでしょうけど。
引用返信 編集キー/
■98425 / inTopicNo.6)  Re[3]: Form のキーイベント
□投稿者/ 魔界の仮面弁士 (3216回)-(2021/11/15(Mon) 10:00:44)
No98422 (ぶなっぷ さん) に返信
> コードを眺めてみる限り、Aのベースクラスは Form じゃない気がしてならない。
> InitializeComponent();なしで、Formがまともに動作するとは思えないし、

partial なので、別の場所に書いてある可能性もあるかも?


> OnKeyDown()がKeyDownの直接のイベントハンドラなら、引数がおかしい
> (object senderが足りない)。
> さらに、OnKeyDown()の宣言がprotected overrideでしょ。

イベントハンドラーではなく、Control クラスの
protected virtual void OnKeyDown(KeyEventArgs e)
に対するオーバーロードだと思います。なので間違ってはいないかと。


> おそらくは、以下のようなベースクラスがあった上で、
むしろそっちの方が不自然だと思いますよ。(多分、何らかの警告が出るはず)

その実装だと、OnKeyDown のシグネチャがベースクラスと被るはずなので
public virtual new void OnKeyDown(KeyEventArgs e)
にしてシャドーイングするか、元実装のように override にするべきかと。
引用返信 編集キー/
■98426 / inTopicNo.7)  Re[2]: Form のキーイベント
□投稿者/ ぶなっぷ (279回)-(2021/11/15(Mon) 10:18:59)
なるほど、Control.OnKeyDown()というメソッドがいるのね。
であれば、先の私の話は忘れてください。

それだけで終わっちゃうとなんなので、
MSDNから解説文を抜粋。
--------------------------------------------------------------------------------
OnKeyDown メソッドを使用すると、デリゲートを結び付けずに、派生クラスでイベントを
処理することもできます。
派生クラスでイベントを処理する場合は、この手法をお勧めします。

継承時の注意
派生クラスで OnKeyDown をオーバーライドする場合は、登録されているデリゲートが
イベントを受け取ることができるように、基本クラスの OnKeyDown メソッドを
呼び出してください。
--------------------------------------------------------------------------------

base.OnKeyDown(e); は、Control.OnKeyDown()の呼び出しになります。

@はデリゲートを結びつけて、イベントを処理する例。
Aはデリゲートを結びつけずに直接イベントを処理する例。

引用返信 編集キー/
■98427 / inTopicNo.8)  Re[3]: Form のキーイベント
□投稿者/ 星は昴 (17回)-(2021/11/15(Mon) 10:52:30)
 皆さん、丁寧な回答まことにありがとうございました。いろいろ勉強になりました。
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -