只更新部分图形
Update only part of graphics
请问有没有简单的方法可以只更新部分图文?在下面的示例中,我绘制了 1560 个 10x10px 的小方块,并将其中的 3 个涂成蓝色。这需要相当长的时间(大约 1 秒),可以看到它们是如何在屏幕上绘制的。在下一步中,我想将 3 个蓝色方块移动到不同的位置,这意味着我想保留所有绘制的图形,但是 只将 3 个方块涂回灰色并将另外 3 个方块涂成蓝色。
如果我完全重新绘制图片,大约需要 "lot" 的时间。 1 秒。上文提到的。我希望每秒至少达到几帧,因为我正在做一个小型 "animated" 模拟。这意味着,代码不必很性感,但足够简单以用于生命周期很短的程序。
Button4_click 代码中描述的方法很快,但只是因为 只绘制 新方块,清除旧图形。
请注意,我在 Panel1 上绘制,而不是 PictureBox1,这是出于性能方面的建议(避免一些不必要的事件处理程序和刷新)。
草图测试代码:
Private drawPattern As Boolean = False
Private drawBlueRects As Boolean = False
Dim blueBrush As New SolidBrush(Color.Blue)
Dim grayBrush As New SolidBrush(Color.Gray)
Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
Dim g As Graphics = e.Graphics
If drawPattern Then
Dim StartY As Integer = 250 - 60 ' just set Y for upper set of squares
For ir = 1 To 6 ' paint upper set of squares
For ic = 0 To 120
g.DrawRectangle(New Pen(Color.Gray), 5 + ic * 10, StartY + ir * 10, 8, 8)
Next
Next ir
StartY = 250 + 10 ' just set Y for bottom set of squares
For ir = 1 To 6 ' paint bottom set of squares
For ic = 0 To 120
g.DrawRectangle(New Pen(Color.Gray), 5 + ic * 10, StartY + ir * 10, 8, 8)
Next
Next ir
For ic = 0 To 120 ' paint middle set of squares
g.FillRectangle(grayBrush, 5 + ic * 10, 250 + 10, 8, 8)
Next
' paint 3 blue squares
g.FillRectangle(blueBrush, 155, 250 + 10, 8, 8)
g.FillRectangle(blueBrush, 165, 250 + 10, 8, 8)
g.FillRectangle(blueBrush, 175, 250 + 10, 8, 8)
ElseIf drawBlueRects = True Then
' paint 3 blue squares
g.FillRectangle(blueBrush, 255, 250 + 10, 8, 8)
g.FillRectangle(blueBrush, 265, 250 + 10, 8, 8)
g.FillRectangle(blueBrush, 275, 250 + 10, 8, 8)
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
drawPattern = True
Panel1.Refresh()
'Panel1.Refresh()
End Sub
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
drawPattern = False
drawBlueRects = True
Panel1.Refresh()
End Sub
如果我用谷歌搜索到了现成的解决方案,我深表歉意;在这种情况下请提供 link。
此致,
Libor
控件的Invalidate
方法指定控件的特定区域需要重绘,Update
方法启动重绘。 Refresh
方法只是调用了Invalidate
,没有参数,说明整个控件需要重新绘制,然后调用Update
。不要 Refresh
,而是自己调用 Invalidate
和 Update
。这样,您可以将适当的参数传递给 Invalidate
以准确指定要重绘控件的哪个或哪些部分。对于一个或多个复杂区域,您可以多次调用 Invalidate
。
我通过变通方法解决了这个问题 - 我绘制到位图中并在每次更改时使用该位图更新 PictureBox。由于我可以绘制到位图的特定位置,因此 re-drawing:
没有问题
在 class 标题中定义位图:
Dim bm As New Bitmap(1910, 500)
初始图纸:
Private Sub CreateImage()
Dim w As Integer = bm.Width ' or PictureBox1.Width
Dim h As Integer = bm.Height ' or PictureBox1.Height
Dim bmp As New Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
bm = bmp
Using g As Graphics = Graphics.FromImage(bmp) ' get it from current state of bitmap
Me.DoubleBuffered = True
Dim Ypos As Integer = 0
Call DrawRecArray(StartY - 100, g, NoOfBaysInSet)
Call DrawRecArray(StartY + 10, g, NoOfBaysInSet)
For ic = 0 To icLimit ' paint middle set of squares
g.FillRectangle(grayBrush, 5 + ic * 10, StartY + 10, 8, 8)
Call DrawStringFunc(5 + ic * 10, StartY - 70 + Ypos * 5, ic + 1, g, drawFont)
Ypos += 1
If Ypos = 3 Then Ypos = 0
If Ypos = 1 Then Call DrawStringFunc(5 + ic * 10, StartY - 90 + Ypos * 5, (ic + 1 * 3) / 3, g, drawFontB)
Next
End Using
PictureBox1.Image = bmp ' put the bitmap into Picturebox !!!
End Sub
更新位图:
Private Sub UpdateImage(FromPos As Int16, ToPos As Int16)
Dim w As Integer = bm.Width
Dim h As Integer = bm.Height
Dim bmp As New Bitmap(Me.PictureBox1.Image) ' now get the bitmap from the PictureBox
bm = bmp
Using g As Graphics = Graphics.FromImage(bmp)
Me.DoubleBuffered = True
g.FillRectangle(backBrush, 5 + FromPos * 10, StartY + 10, 28, 8)
g.FillRectangle(grayBrush, 5 + FromPos * 10, StartY + 10, 8, 8)
g.FillRectangle(grayBrush, 15 + FromPos * 10, StartY + 10, 8, 8)
g.FillRectangle(grayBrush, 25 + FromPos * 10, StartY + 10, 8, 8)
g.FillRectangle(blueBrush, 5 + ToPos * 10, StartY + 10, 28, 8)
End Using
PictureBox1.Image = bmp ' update pictureBox with modified bitmap
End Sub
我相信这是一个有价值的答案。我处理 GDI 好几年了,反复遇到这个问题,在成千上万的答案中,只有少数人描述了没有 _paint 事件的重绘,我认为这对这种情况毫无用处。大多数样本是 one-off 图纸。
此致
Libor
请问有没有简单的方法可以只更新部分图文?在下面的示例中,我绘制了 1560 个 10x10px 的小方块,并将其中的 3 个涂成蓝色。这需要相当长的时间(大约 1 秒),可以看到它们是如何在屏幕上绘制的。在下一步中,我想将 3 个蓝色方块移动到不同的位置,这意味着我想保留所有绘制的图形,但是 只将 3 个方块涂回灰色并将另外 3 个方块涂成蓝色。 如果我完全重新绘制图片,大约需要 "lot" 的时间。 1 秒。上文提到的。我希望每秒至少达到几帧,因为我正在做一个小型 "animated" 模拟。这意味着,代码不必很性感,但足够简单以用于生命周期很短的程序。
Button4_click 代码中描述的方法很快,但只是因为 只绘制 新方块,清除旧图形。
请注意,我在 Panel1 上绘制,而不是 PictureBox1,这是出于性能方面的建议(避免一些不必要的事件处理程序和刷新)。
草图测试代码:
Private drawPattern As Boolean = False
Private drawBlueRects As Boolean = False
Dim blueBrush As New SolidBrush(Color.Blue)
Dim grayBrush As New SolidBrush(Color.Gray)
Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
Dim g As Graphics = e.Graphics
If drawPattern Then
Dim StartY As Integer = 250 - 60 ' just set Y for upper set of squares
For ir = 1 To 6 ' paint upper set of squares
For ic = 0 To 120
g.DrawRectangle(New Pen(Color.Gray), 5 + ic * 10, StartY + ir * 10, 8, 8)
Next
Next ir
StartY = 250 + 10 ' just set Y for bottom set of squares
For ir = 1 To 6 ' paint bottom set of squares
For ic = 0 To 120
g.DrawRectangle(New Pen(Color.Gray), 5 + ic * 10, StartY + ir * 10, 8, 8)
Next
Next ir
For ic = 0 To 120 ' paint middle set of squares
g.FillRectangle(grayBrush, 5 + ic * 10, 250 + 10, 8, 8)
Next
' paint 3 blue squares
g.FillRectangle(blueBrush, 155, 250 + 10, 8, 8)
g.FillRectangle(blueBrush, 165, 250 + 10, 8, 8)
g.FillRectangle(blueBrush, 175, 250 + 10, 8, 8)
ElseIf drawBlueRects = True Then
' paint 3 blue squares
g.FillRectangle(blueBrush, 255, 250 + 10, 8, 8)
g.FillRectangle(blueBrush, 265, 250 + 10, 8, 8)
g.FillRectangle(blueBrush, 275, 250 + 10, 8, 8)
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
drawPattern = True
Panel1.Refresh()
'Panel1.Refresh()
End Sub
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
drawPattern = False
drawBlueRects = True
Panel1.Refresh()
End Sub
如果我用谷歌搜索到了现成的解决方案,我深表歉意;在这种情况下请提供 link。
此致,
Libor
控件的Invalidate
方法指定控件的特定区域需要重绘,Update
方法启动重绘。 Refresh
方法只是调用了Invalidate
,没有参数,说明整个控件需要重新绘制,然后调用Update
。不要 Refresh
,而是自己调用 Invalidate
和 Update
。这样,您可以将适当的参数传递给 Invalidate
以准确指定要重绘控件的哪个或哪些部分。对于一个或多个复杂区域,您可以多次调用 Invalidate
。
我通过变通方法解决了这个问题 - 我绘制到位图中并在每次更改时使用该位图更新 PictureBox。由于我可以绘制到位图的特定位置,因此 re-drawing:
没有问题在 class 标题中定义位图:
Dim bm As New Bitmap(1910, 500)
初始图纸:
Private Sub CreateImage()
Dim w As Integer = bm.Width ' or PictureBox1.Width
Dim h As Integer = bm.Height ' or PictureBox1.Height
Dim bmp As New Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
bm = bmp
Using g As Graphics = Graphics.FromImage(bmp) ' get it from current state of bitmap
Me.DoubleBuffered = True
Dim Ypos As Integer = 0
Call DrawRecArray(StartY - 100, g, NoOfBaysInSet)
Call DrawRecArray(StartY + 10, g, NoOfBaysInSet)
For ic = 0 To icLimit ' paint middle set of squares
g.FillRectangle(grayBrush, 5 + ic * 10, StartY + 10, 8, 8)
Call DrawStringFunc(5 + ic * 10, StartY - 70 + Ypos * 5, ic + 1, g, drawFont)
Ypos += 1
If Ypos = 3 Then Ypos = 0
If Ypos = 1 Then Call DrawStringFunc(5 + ic * 10, StartY - 90 + Ypos * 5, (ic + 1 * 3) / 3, g, drawFontB)
Next
End Using
PictureBox1.Image = bmp ' put the bitmap into Picturebox !!!
End Sub
更新位图:
Private Sub UpdateImage(FromPos As Int16, ToPos As Int16)
Dim w As Integer = bm.Width
Dim h As Integer = bm.Height
Dim bmp As New Bitmap(Me.PictureBox1.Image) ' now get the bitmap from the PictureBox
bm = bmp
Using g As Graphics = Graphics.FromImage(bmp)
Me.DoubleBuffered = True
g.FillRectangle(backBrush, 5 + FromPos * 10, StartY + 10, 28, 8)
g.FillRectangle(grayBrush, 5 + FromPos * 10, StartY + 10, 8, 8)
g.FillRectangle(grayBrush, 15 + FromPos * 10, StartY + 10, 8, 8)
g.FillRectangle(grayBrush, 25 + FromPos * 10, StartY + 10, 8, 8)
g.FillRectangle(blueBrush, 5 + ToPos * 10, StartY + 10, 28, 8)
End Using
PictureBox1.Image = bmp ' update pictureBox with modified bitmap
End Sub
我相信这是一个有价值的答案。我处理 GDI 好几年了,反复遇到这个问题,在成千上万的答案中,只有少数人描述了没有 _paint 事件的重绘,我认为这对这种情况毫无用处。大多数样本是 one-off 图纸。
此致
Libor