【问题标题】:Update only part of graphics仅更新部分图形
【发布时间】:2015-10-16 17:05:43
【问题描述】:

我想知道,有没有一种简单的方法可以只更新一部分图形?在下面的例子中,我画了 1560 个 10x10px 的小方块,并将其中的 3 个涂成蓝色。这需要相当长的时间(大约 1 秒),可以看到它们是如何在屏幕上绘制的。在下一步中,我想将 3 个蓝色方块移动到不同的位置,这意味着我想保留所有绘制的图形,但是只将 3 个方块重新绘制为灰色,并将另外 3 个方块绘制为蓝色。 如果我完全重新绘制图片,大约需要“很多”时间。 1秒。上文提到的。我想达到每秒至少几帧,因为我正在做一个小的“动画”模拟。这意味着,代码不必很性感,但要足够简单,可以在寿命很短的程序中使用。

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

如果我用谷歌搜索了一个现成的解决方案,我深表歉意;在这种情况下请提供链接。

问候,

Libor

【问题讨论】:

    标签: vb.net graphics refresh


    【解决方案1】:

    我通过一种变通方法解决了这个问题 - 每次更改时,我都会绘制位图并使用该位图更新 PictureBox。由于我可以绘制到位图的特定位置,因此重新绘制没有问题:

    在类标题中定义位图:

    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 事件的重绘,我认为这对于这种情况是没有用的。大部分样品都是一次性图纸。

    问候

    Libor

    【讨论】:

      【解决方案2】:

      控件的Invalidate 方法指定控件的特定区域需要重新绘制,Update 方法启动重新绘制。 Refresh方法简单调用Invalidate不带参数,表示整个控件需要重绘,然后调用Update。而不是Refresh,请自己致电InvalidateUpdate。这样,您可以将适当的参数传递给Invalidate 以准确指定要重绘控件的哪些部分。对于一个或多个复杂区域,您可以多次致电Invalidate

      【讨论】:

      • 我决定将此标记为正确答案,因为它是。但是,我解决了这个问题,我在下面解释。
      猜你喜欢
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 2019-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多