DOBON.NET DOBON.NETプログラミング掲示板過去ログ

PictureBoxへの再描画について

環境/言語:[VB.NET XP .NET Framework3.5 SP1]
分類:[.NET]

VB.NETの質問です。よろしくお願いします。
PictureBoxへトリミングしてからそれを2倍に拡大した画像を表示し、その上からラインを引きたいのですが、ラインを引くときにマウスをドラッグ中にリアルタイムに描画しているのでトリミングして拡大した画像を同じくリアルタイムに描画すると重くてカクカクになってしまいます
BackgroundImageに読み込めればそこまで重くないのですがそうするとトリミングと拡大が出来なくなってしまうので困っています。
トリミングしたのをファイルに一旦保存してから表示すれば軽いのでしょうがゴミファイルが溜まってしまいそうなので避けたいです
色々考えたり検索してみましたがいい解決法が見つからないので、どうかお力をお貸し下さいo(_ _)o


http://www2.uploda.org/uporg1990075.avi.html
言葉が足りなかったりわかりにくいかもしれないので動画です。
ラインを再描画するとき一旦PictureBoxを消しているので画像が消えてしまっています。画像を消さずに上からのライン描画を軽く処理できる方法を探しています


Public Class Form1
Public Function AutoGraphics(ByVal picSource As PictureBox) As Graphics

If picSource.Image Is Nothing Then
picSource.Image = New Bitmap(picSource.ClientRectangle.Width, picSource.ClientRectangle.Height)
End If

Return Graphics.FromImage(picSource.Image)

End Function
'ラインを引く
Private Sub PictureBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove

If MouseButtons = Windows.Forms.MouseButtons.Left Then
PictureBox1.Image = Nothing

Dim X2 As Integer
Dim Y2 As Integer
Dim Pos As Point = PictureBox1.PointToClient(Windows.Forms.Cursor.Position)

X2 = Pos.X
Y2 = Pos.Y

Dim g2 As Graphics = AutoGraphics(PictureBox1)

g2.DrawLine(Pens.Red, 0, 0, X2, Y2)

End If

End Sub
'画像をトリミングして表示
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

PictureBox1.Image = Nothing

Dim img = New Bitmap("C:\d_o.jpg")

    '画像の一部を切り取って表示する(トリミング)
'元の画像の(10,10)-(200,200)の部分を切り取って表示
Dim rect As New Rectangle(10, 10, 200, 200)
Dim rectDst As New RectangleF(0, 0, rect.Width * 2, rect.Height * 2)

'PictureBox1のGraphicsオブジェクトの作成
Dim g As Graphics = AutoGraphics(PictureBox1)

'補間方法としてニアレストネイバー法を使用
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor

g.DrawImage(img, rectDst, rect, GraphicsUnit.Pixel)

'オブジェクトの破棄
img.Dispose()
g.Dispose()

End Sub
End Class
PictureBoxに画像を描画するのにImageプロパティを使用されているようですが、Paintイベントを使った方が良いのではないでしょうか。(Imageプロパティだけではできないというわけではありません。)

まず、背景となる画像(トリミング、拡大した画像)はBitmap型のフィールドに入れておきます。さらに、線を引くかどうか、線を引くとしたらどこからどこまで引くかという情報もフィールドで覚えておきます。

Paintイベントでは、背景の画像を表示した後、線を引くならば線も描画します。

MouseMoveイベントでは、フィールドの線の情報を変更し、PictureBox.InvalidateメソッドでPaintイベントを発生させ、PictureBoxを再描画します。(その他のマウスイベントでも同様の処理が必要だと思います。)

以上のような方法でいかがでしょうか?
管理人さん返信ありがとうございます
仰ったことがわからないわけではないのですが理解力不足で上手く書く方法がわかりませんでした。とりあえず管理人さんの言うとおりpaintイベントを使ってわかる範囲でやってみましたが・・・たぶん色々と間違ってると思いますが、表示上はやろうとしていることは出来ましたが何か余計なことまでやってそうで・・・これで大丈夫なのでしょうか?


Public Class Form1
Private _bmp As Bitmap = Nothing
Dim X2 As Integer
Dim Y2 As Integer

Public Function AutoGraphics(ByVal picSource As PictureBox) As Graphics

If picSource.Image Is Nothing Then
picSource.Image = New Bitmap(picSource.ClientRectangle.Width, picSource.ClientRectangle.Height)
End If

Return Graphics.FromImage(picSource.Image)

End Function
Private Sub PictureBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove

If MouseButtons = Windows.Forms.MouseButtons.Left Then
PictureBox1.Image = Nothing

'マウスの位置
Dim Pos As Point = PictureBox1.PointToClient(Windows.Forms.Cursor.Position)
X2 = Pos.X
Y2 = Pos.Y

End If

End Sub
'画像をトリミングして表示
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

PictureBox1.Image = Nothing

'画像の一部を切り取って表示する(トリミング)
Dim img = New Bitmap("C:\d_o.jpg")

'元の画像の(10,10)-(200,200)の部分を切り取って表示
Dim rect As New Rectangle(10, 10, 200, 200)
Dim rectDst As New RectangleF(0, 0, rect.Width * 2, rect.Height * 2)

'PictureBox1のGraphicsオブジェクトの作成
Dim g As Graphics = AutoGraphics(PictureBox1)

'補間方法としてニアレストネイバー法を使用
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor

g.DrawImage(img, rectDst, rect, GraphicsUnit.Pixel)

_bmp = PictureBox1.Image

'オブジェクトの破棄
img.Dispose()
g.Dispose()

End Sub

Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint

'画像を表示する
If Not (_bmp Is Nothing) Then
e.Graphics.DrawImage(_bmp, 0, 0, _bmp.Width, _bmp.Height)
End If

'ラインを描画する
e.Graphics.DrawLine(Pens.Red, 0, 0, X2, Y2)

End Sub
End Class
■No23928に返信(ぼるさんの記事)
> Dim img = New Bitmap("C:\d_o.jpg")

ここの「=」は、「As」にした方が良いでしょう。
(VB2008 ならば、= でも問題ありませんが)


> paintイベントを使って
拡大した画像を、Image に割り当てているのであれば、
Paint のたびに再割り当てする必要はありません。Invalid だけで十分かと。


Private Pos As Point
Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseMove
 If MouseButtons = System.Windows.Forms.MouseButtons.Left Then
  Pos = PictureBox1.PointToClient(Windows.Forms.Cursor.Position)
  PictureBox1.Invalidate()
 End If
End Sub

Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles PictureBox1.Paint
 e.Graphics.DrawLine(Pens.Red, Point.Empty, Pos)
End Sub
魔界の仮面弁士さん返信ありがとうございます
ご指摘の通りにコードを直してみました
若干気持ち軽くなったような気がします。管理人さん、魔界の仮面弁士さん本当にありがとうございましたo(_ _)o
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板