投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/12/25 20:01:23
taka さんが提示されたサンプルでは、Graphics の後始末が漏れているようですね。

本来はイベントの最後に「g.Dispose()」と書いて、
使い終わった Grapchis を処分することが望ましいです。


また、CreateGraphics() で行える描画処理は一時的なものです。

描いた画面が最小化されたり、あるいは描いた内容の上に
他のウィンドウが重なったりすると、折角描いた内容は消えてしまいます。

そのため、継続的な描画処理が必要な場面では、CreateGraphics() 以外の方法で
Graphics インスタンスを得る手法がしばしば用いられます。
(Graphics.FromImage メソッドや、Paint イベントの e.Graphics プロパティなど)



> センダーはピクチャーボックス型 gはグラフィックス型で「コントロールのGraphicsを作成します」ということのようです。

以下、ちょっと細かい話になりますが:


★イベントの第一引数は、「そのイベントの対象となったオブジェクト」を示しています。
これは通常、「sender As Object」と書かれることになります。

Button1_Click なら、sender の中身は Button1 になります。
PictureBox1_MouseMove なら、 sender の中身は、PictureBox1 になります。

下記のように、一つの Click イベントに Button1 と Button2 の二つが
割り当てられている場合、引数 sender を使って、どちらが押されたのかを調べられます。

Private Buttons_Click(sender As Object, e As EventArgs) Handles Button1.Click, Button2.Click
    MsgBox(sender.Text)
End Sub



★イベントの第二引数は、「そのイベントの追加情報」を示します。
これは、「e As EventArgs」もしくは「e As 何某EventArgs」の形式を取ります。

たとえば MouseDown や MouseUp イベントの時は、e As MouseEventArgs となっており、
この引数から、マウスの座標や押されたマウスボタンなどの情報を得ることができます。


> Dim g As Graphics = sender.CreateGraphics()

sender が As PictureBox や As TextBox なデータ型で宣言されていれば、
sender.CreateGraphics() を呼び出すことができますし、IntelliSense でも表示されます。

sender が String や Integer なデータ型であった場合には、それらの型には
.CreateGraphics() メソッドが存在しないので、呼び出すことができません。


そして通常、sender は As Object なデータ型で宣言されています。
Object 型とは、ざっくり言えば「何でも入る万能な型」です。


' Object 型には、どんなものでも入れられる 
Dim a As Object = PictureBox1
Dim b As Object = 123
Dim c As Object = "abc"


何でも入るのは良いですが、PictureBox1 と String では、使用可能なメソッドも当然異なりますよね。

変数の型は Object 型でも、その中身が本当に CreateGraphics を
利用可能であるのかどうかは、そこに入っているインスタンス次第です。

PictureBox などのインスタンスであれば、.CreateGraphics を利用できますが、
String などのインスタンスだった場合には 利用できない、ということになります。

つまり中身が確定するのは実行時であり、コンパイル時には中身が未確定のため、
IntelliSense のサポートが受けられない……という事情だったわけです。


' a も b も Object 型。この場合、.CreateGraphics は IntelliSense に現れない。 
Dim g1 As Graphics = a.CreateGraphics()  'a は PictureBox1 なので、コレは呼び出せる 
Dim g2 As Graphics = b.CreateGraphics()  'b は Integer なので、実行時にエラーとなる 


ちなみに、.ToString() であれば IntelliSense に現れるかと思いますが、
これは ToString メソッドが「Object 型によって提供されているメソッド」だからです。

一方、CreateGraphics メソッドは「Control 型によって提供されているメソッド」なので、
変数のデータ型が As Control の時の場合に、IntelliSense に現れるようになっています。
あるいは、「Control を継承した型」であっても呼び出せますので、
As PictureBox や As Form や As TextBox などの場合にも、CreateGraphics を使えます。



> センダーのあとのワードがインテリセンスされません。これは何ですか?

IntelliSense には現れるのは「その変数の型で提供されているメンバー」に限られるためです。
存在しないメンバーを記述すれば、エラーになります。

ただし変数が Object 型であった場合に限り、IntelliSense で
現れなかったメンバーでも記述することが可能です。
これを実行時バインディングと呼びます。

実行時バインディングの場合、スペルミスをしてもコンパイル時には検出されません。
もしもスペルが間違っていた場合、そんなメソッドは存在しないので、
実際に呼び出そうとした段階でエラー通知されることになります。

実行するまで分からないので、不具合に気がつきにくいのが難点です。
スペルミスは、コンパイル時に検出された方が安全ですよね。

そこで前回の回答のように、DirectCast を使うなどして、明示的な型変換(キャスト)を
行ってあげる方法を取ることが望ましいです。これを事前バインディングと呼びます。

事前バインディングであれば、コンパイル時にメソッド名の存在チェックが行われるので、
スペルミスの可能性を避けることができるので、より安全なコードとなります。