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

PictureBoxのパフォーマンスについて

環境/言語:[OS : Windows XP Professional / 言語 : Visual Basic .NET]
分類:[.NET]

【解決したい問題】

WindowsアプリケーションをVB.netで作成しています。
画面いっぱいのウィンドウに画像を描画して、任意の選択範囲に切り取る作業を行うモジュールを作成している(正確にはVB6から移行している)のですが、選択する画面の作成で困っています。お力を貸してください。

FormにはPictureBoxが1つ貼ってあり、以下のコードがあります。
Public Class Form1
Dim TempPic As Bitmap
Dim PenSize As Integer = 2
'再描画関数
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 Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
TempPic = Bitmap.FromFile("C:\test.jpg")
'サイズ調整
Me.WindowState = FormWindowState.Maximized
With PictureBox1
.Dock = DockStyle.Fill
'枠と画像描画
Dim g As Graphics = AutoGraphics(PictureBox1)
Dim p As New Pen(Color.Red, PenSize)
g.DrawImage(TempPic, 0, 0)
g.DrawRectangle(p, 0, 0, .Width - PenSize + 1, .Height - PenSize + 1)
p.Dispose()
g.Dispose()
End With
End Sub
'選択範囲
Dim sx, sy As Integer '始点(x,y)
Dim IsMouseDown As Boolean = False
Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
IsMouseDown = True
If e.Button = Windows.Forms.MouseButtons.Left Then
sx = e.X
sy = e.Y
End If
End Sub
Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
If IsMouseDown = True Then
Dim g As Graphics = AutoGraphics(PictureBox1)
Dim p As New Pen(Color.Red, PenSize)
g.DrawImage(TempPic, 0, 0)
g.DrawRectangle(p, 0, 0, PictureBox1.Width - PenSize + 1, PictureBox1.Height - PenSize + 1)
g.DrawLine(Pens.Red, sx, sy, sx, e.Y)
g.DrawLine(Pens.Red, sx, e.Y, e.X, e.Y)
g.DrawLine(Pens.Red, e.X, e.Y, e.X, sy)
g.DrawLine(Pens.Red, e.X, sy, sx, sy)
p.Dispose()
g.Dispose()
PictureBox1.Invalidate()
End If
End Sub
Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
IsMouseDown = False
End Sub
End Class

この時、ドラッグすれば赤枠が表示され、範囲を選択できるのですが、全画面表示を行っているためパフォーマンスが悪く、CPU利用率が高くなり、マウスの動作にたいして赤枠の描画が遅れます。

まぁ仕方ないと言えば仕方ないのですが、VB6時代の似たコードでは特に問題ありませんでした。
(PictureBox.Imageに画像を入れて、PictureBox.Drawで線を書かせていましたが、こんなに遅くなりません)

g.DrawImageと言う風に再描画を強制しているのが原因だとは思いますが、これ以外にいい手が思いつきません。


どのようにしたらパフォーマンスがあがるでしょうか?(マウスの動作にたいしてきびきび線を書くように…)

【解決するために何をしたか】

どぼん!の画像関係のページを一通り全て見て工夫を凝らしてみましたが、これ以外に正常に動作するコードがかけませんでした。(後ろの画像が消えてしまうなどで)
■No17111に返信(Wizardさんの記事)
> まぁ仕方ないと言えば仕方ないのですが、VB6時代の似たコードでは特に問題ありませんでした。
> (PictureBox.Imageに画像を入れて、PictureBox.Drawで線を書かせていましたが、こんなに遅くなりません)
VB6 に、PictureBox.Draw メソッドなんてありましたっけ…?


> g.DrawImageと言う風に再描画を強制しているのが原因だとは思いますが、これ以外にいい手が思いつきません。
画像を BackgroundImage に割り当ててみては如何でしょう。

''' for VB2005

Public Class Form1
  Private BorderPen As New Pen(Color.Red, 2)

  Private Sub Form1_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load
    BorderPen.Alignment = Drawing2D.PenAlignment.Inset
    Me.WindowState = FormWindowState.Maximized
    Dim bmp As Bitmap = Bitmap.FromFile("c:\test.JPG")
    With PictureBox1
      .Dock = DockStyle.Fill
      .BackgroundImageLayout = ImageLayout.None
      .BackgroundImage = bmp
    End With
  End Sub

  Private Sub Form1_FormClosing(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    BorderPen.Dispose()
  End Sub

  Private Start As Point
  Private Rect As Rectangle
  Private IsMouseDown As Boolean = False
  Private Sub PictureBox1_MouseDown(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    IsMouseDown = True
    If e.Button = Windows.Forms.MouseButtons.Left Then
      Start = e.Location
      Rect = New Rectangle(Start, Drawing.Size.Empty)
    End If
  End Sub

  Private Sub PictureBox1_MouseMove(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
    If IsMouseDown = True Then
      Dim P As Point = Start
      Dim S As Size = e.Location - Start
      If Start.X > e.X Then
        P.X = e.X
        S.Width = Start.X - e.X
      End If
      If Start.Y > e.Y Then
        P.Y = e.Y
        S.Height = Start.Y - e.Y
      End If
      Rect = New Rectangle(P, S)
      PictureBox1.Invalidate()
    End If
  End Sub

  Private Sub PictureBox1_MouseUp(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
    IsMouseDown = False
  End Sub

  Private Sub PictureBox1_Paint(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    With e.ClipRectangle
      e.Graphics.DrawRectangle(BorderPen, 0, 0, .Width, .Height)
    End With
    e.Graphics.DrawRectangle(Pens.Red, Rect)
  End Sub
End Class
>>(PictureBox.Imageに画像を入れて、PictureBox.Drawで線を書かせていましたが、こんなに遅くなりません)
> VB6 に、PictureBox.Draw メソッドなんてありましたっけ…?
間違えました。Me.Lineです…。

>>g.DrawImageと言う風に再描画を強制しているのが原因だとは思いますが、これ以外にいい手が思いつきません。
> 画像を BackgroundImage に割り当ててみては如何でしょう。
なるほど、かなりパフォーマンスがあがりました。
これならなんとか使用に耐えそうです。
ありがとうございました。
解決済み!

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