イベントを呼び出し

タグの編集
投稿者 ゆうさく  (社会人) 投稿日時 2018/6/5 21:10:41
   

ボタンをクリック時にピクチャボックスに線が描画されるように作りたいのですが
どうしていいかわかりません。コードは下記です。
エラーになる理由とどうすれば描画のイベントを呼び出せるか教えてください

 Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        Dim canvas As New Bitmap(PictureBox1.Width, PictureBox1.Height)

        Dim g As Graphics = Graphics.FromImage(canvas)

        g.DrawLine(Pens.Black, a, b, c, d)

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Call Form1_Paint(Me, EventArgs.Empty)
    End Sub

投稿者 るきお  (社会人) 投稿日時 2018/6/6 07:28:19
できるだけ近い構造で実現しようとするとこのようになります。

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown

    'ShownはForm1が初めて表示されるときに1回だけ実行されます。 
    'このタイミングでPictureBoxとBitmapを関連付けます。 

    '引数は描画領域の幅と高さ 
    canvas = New Bitmap(PictureBox1.Width, PictureBox1.Height)
    PictureBox1.Image = canvas

End Sub

Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click
    '関連付けられたBitmapに描画します。 
    Dim g As Graphics = Graphics.FromImage(canvas)
    g.DrawLine(Pens.Black, a, b, c, d)

    'Bitmapの内容が変わってもPictureBox1は自動的に気が付いてくれないので、 
    '一旦現状の表示をリセットして関連付けられたBitmapを表示してもらいます。 
    PictureBox1.Invalidate()
End Sub


ゆうさくさんのプログラムでは、canvasとPictureBoxが関連付けられていないため、canvasに描画してもPicturBoxは無反応です。
g.DrawLineのすぐ下に次の行を挿入すると線は描かれます。
PictureBox1.Image = canvas

でも、Form1のPaintイベントにプログラムが書かれているので、ボタンのクリック時ではなく、フォームの描画時に実行されてしまいます。
また、フォームの描画時に毎回canvasを生成してPictureBoxと関連付けるのは非効率です。
これらを改善すると上記のようになります。

なお、下記のような作り方もあります。
Private Lines As New List(Of Rectangle)

Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click
    Lines.Add(New Rectangle(a, b, c, d))
    PictureBox1.Invalidate()
End Sub

Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint

    For Each line As Rectangle In Lines
        e.Graphics.DrawLine(Pens.Black, line.X, line.Y, line.X + line.Width, line.Y + line.Height)
    Next

End Sub


このプログラムはPictureBoxの描画にPictureBoxのPaintイベントを使用しており素直な作りです。
このつくりの良いところは、ボタンを押すたびにまっさらなところから描画を開始するので(といって人間には一瞬のできごとです)、動的に変化する図形を描画しやすいことです。
たとえば、マウスやキーボードなどの操作に追従してグラフィックスが変化していく場合は、こちらの作りの方がやりやすいです。
投稿者 るきお  (社会人) 投稿日時 2018/6/6 08:16:24
ゆうさくさんのプログラムがうまく動かない理由が不正確でしたので補足します。
(ゆうさくさんのプログラムではなく、私が少しいじってみたプログラムをもとに書いてしまいました。)

ゆうさくさんのプログラムがエラーになら直接的な理由は型変換ができないからです。

Form1_Paintの第2引数はPaintEventArgs型です。

Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint

ゆうさくさんはこれを下記のように呼び出そうとしています。

Call Form1_Paint(Me, EventArgs.Empty)

この第2引数はEventArgs型です。

EventArgs型からPaintEventArgs型への型変換は定義されていないためエラーになります。

一般的に、型Aから型Bに変換をする場合、
型Aと型Bが異なっていても、下記の場合成功します。
・型Bが型Aの基底クラスの場合。
・型Bが型Aが実装しているインターフェースの場合。

例外として特別に型変換がプログラムされている場合(=CTypeがオーバーロードされている場合)も型変換は成功します。

今回はこのどれでもないので失敗します。

次のプログラムで確認できます。
Dim typeA As EventArgs = EventArgs.Empty
Dim typeB As PaintEventArgs = Nothing

typeB = typeA


ちなみに Nothing は必ず代入できるので、
Call Form1_Paint(Me, Nothing)
ならば呼び出す自体は可能です。
投稿者 ゆうさく  (社会人) 投稿日時 2018/6/6 19:02:40
ありがとうございます。

参考にさせていただきます