【问题标题】:Which Event should I use to display drawing?我应该使用哪个事件来显示绘图?
【发布时间】:2014-07-24 08:36:14
【问题描述】:

我需要将一些图形放在 TableLayoutPanel 的一个部分中。

我通过在 TLP 的一个单元格中创建一个 PictureBox 来做到这一点。

不能让两件事起作用:

1) 初始显示为空白!绘图仅在您调整表单大小时出现

2) 与收缩相比,扩展大小时,resize 事件不会同样触发。

任何改善上述两个问题的建议都会很棒!

这是我的代码。表单中有一个 2x2 TableLayoutPanel,TLP 的一个单元格中有一个 PictureBox。 TLP 和 PictureBox 都设置为 Fill Parent:

Imports System.Drawing.Drawing2D

Public Class Form1
    Private g As Graphics
    Dim n As Integer = 0

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Debug.Print(String.Format("{0}{0}Form1_Load at {1}", vbCrLf, Now()))
    Me.SetDesktopLocation(800, 200)
End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
    n += 1
    Debug.Print(String.Format("MyBase.Paint: {0}", n))
    DisplayMyStuff()
End Sub

Private Sub PictureBox1_Resize(sender As Object, e As EventArgs) Handles Pict    ureBox1.Resize
    n += 1
    Debug.Print(String.Format("PictureBox1.Resize: {0}  PictureBoxSize = {1} / {2}", n, PictureBox1.Width, PictureBox1.Height))
    If g IsNot Nothing Then
        g.Dispose()
    End If
    g = PictureBox1.CreateGraphics()
End Sub

Private Sub DisplayMyStuff()
    Dim rect1 As Rectangle
    Dim rect2 As Rectangle
    Dim pt1 As New Point(50, 50)
    Dim pt2 As New Point(100, 100)
    Dim pt3 As New Point(150, 150)
    Dim brR As New SolidBrush(Color.Red)
    Dim linGradBr As New LinearGradientBrush(pt2, pt3, Color.Yellow, Color.Blue)
    Dim pictBoxSize As Size
    Dim sz As Size
    Dim width, height As Integer

    pictBoxSize = New Size(CType(PictureBox1.Size, Point))
    width = CInt(pictBoxSize.Width / 2)
    height = CInt(pictBoxSize.Height / 2)
    sz = New Size(width, height)
    n += 1
    Debug.Print(String.Format("DisplayMyStuff: {0}, Half-Size = {1} / {2}", n, width, height))
    g.Clear(Color.Bisque)
    rect1 = New Rectangle(pt1, sz)
    rect2 = New Rectangle(pt2, sz)
    g.FillRectangle(brR, rect1)
    g.FillRectangle(linGradBr, rect2)
    brR.Dispose()
    linGradBr.Dispose()
End Sub

结束类

【问题讨论】:

  • 另一个 CreateGraphics() 受害者。当图片框重新绘制自身时,您使用“g”绘制的任何内容都将再次消失。您只会偶然看到输出。您必须使用在 PictureBox.Paint 事件的事件处理程序中获得的 e.Graphics 对象。

标签: .net vb.net graphics gdi+


【解决方案1】:

显然,您正在尝试绘制到图片框 (g = PictureBox1.CreateGraphics())

东西消失的原因是当大小改变时,或者有东西经过窗口时,控件和窗体需要重新绘制。这发生在 Paint 事件中,因此您的代码需要在那里进行绘图。与 PictureBox 图像不同,绘制到窗体或控件的项目本身不是持久的,这是通过在 Paint 事件中绘制来完成的。

这实质上是您的 DrawMyStuff 过程重新定位到 Picbox 的 Paint 事件。

Private Sub PictureBox1_Paint(sender As Object, 
          e As PaintEventArgs) Handles PictureBox1.Paint
    Dim pt1 As New Point(50, 50)
    Dim pt2 As New Point(100, 100)
    Dim pt3 As New Point(150, 150)

    Dim sz As New Size(CInt(PictureBox1.Size.Width / 2),
                       CInt(PictureBox1.Size.Height / 2))
    n += 1
    Debug.Print(String.Format("DisplayMyStuff: {0}, 
            Half-Size = {1} / {2}", n, sz.Width, sz.Height))

    Dim rect1 As New Rectangle(New Point(50, 50), sz)
    Dim rect2 As New Rectangle(New Point(100, 100), sz)

    Using linGradBr As New LinearGradientBrush(pt2, pt3, Color.Yellow, Color.Blue)

        e.Graphics.Clear(Color.Bisque)

        e.Graphics.DrawRectangle(Pens.Black, rect1)
        e.Graphics.DrawRectangle(Pens.Black, rect2)

        e.Graphics.FillRectangle(Brushes.Red, rect1)
        e.Graphics.FillRectangle(linGradBr, rect2)

    End Using
End Sub

如果您实际上是在尝试在表单上绘画,那么 Grim 的答案就是解决方案。在那里您响应 Form Paint 事件。无论哪种情况,都使用 Windows 提供的 Graphics 对象作为 EventArg。

上面,您使用的是 PictureBox 的 Graphics 对象(通过事件参数),因此输出到 PictureBox。


Windows 不会知道您在 Paint 事件中绘制了什么东西,因此您需要告诉它图像需要在特定时间更新,例如在调整 PictureBox 大小时。在调整大小事件中,添加:

PictureBox1.Invalidate       ' tell windows it needs to be redrawn
' or
PictureBox1.Refresh          ' redraw now

Me.Refresh 有点矫枉过正,因为整个表单可能不需要重新绘制。

【讨论】:

  • 很好看的 Plutonix ... 我错过了绘制事件完全来自表单的事实!
  • 谢谢,非常有用。但是(见下面的评论)一个问题;为什么在调整表单大小时矩形的大小不变化? PictureBox 设置为 DockFill,并且 TableLayoutPanel 在调整窗体大小时调整大小,但矩形始终大小相同,尽管 sz 是变化的
  • 如果图片框是 Dock.Fill 到 TLP,而 TLP 是 Dock.Fill 到表单并且您将 Me.Refresh() 添加到您的 picbox Resize 事件中,它应该可以工作。 Windows 不知道它需要重新绘制矩形,因为没有违反该区域(IT 无法知道矩形大小取决于 PB 大小,因为这是您提供的东西)。因此,您必须通过使用 Refresh 告诉它在大小更改时重新绘制来强制它再次运行您的代码。如果你强迫它重新绘制 PB(在窗体上浮动一个窗口,它会重新绘制)。您可能必须使用 TLP 设置才能获得所需的效果。
  • Refresh() 做得很好! TVM 确实
  • @user3012629 欢迎您。 Grim 的回答可能也会引导您找到答案,您应该通过支持两个答案来承认他的努力。 (只是一个建议)
【解决方案2】:

正如汉斯·帕桑特所说。先摆脱;

Private g As Graphics

以及整个PictureBox1_Resize(...)... 例程。然后把下面的套路改成这样;

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
    DisplayMyStuff(e.Graphics)
End Sub

Private Sub DisplayMyStuff(pGraphics As Graphics)
    Dim pt1 As New Point(50, 50)
    Dim pt2 As New Point(100, 100)
    Dim pt3 As New Point(150, 150)
    Dim pictBoxSize As New Size(CType(PictureBox1.Size, Point))
    Dim width As Integer = CInt(pictBoxSize.Width / 2)
    Dim height As Integer = CInt(pictBoxSize.Height / 2)
    Dim sz As New Size(width, height)

    pGraphics.Clear(Color.Bisque)

    Dim rect1 As New Rectangle(pt1, sz)
    Dim rect2 As New Rectangle(pt2, sz)
    Using linGradBr As New LinearGradientBrush(pt2, pt3, Color.Yellow, Color.Blue)
        pGraphics.FillRectangle(Brushes.Red, rect1)
        pGraphics.FillRectangle(linGradBr, rect2)
    End Using
End Sub

.. 然后测试。请回来告诉我你学到了一些东西!特别是..您不需要创建新的红色画笔 - 所有“标准”颜色都是内置的 - 并且正确使用图形对象可以带来更好、更流畅的显示。

【讨论】:

  • 是的,慢慢学习! ;-) 我确实买了一本关于 GDI+ 编程的书,但它不适合使用各种事件。所以 Hans、Plutonix 和 Grim,谢谢你们。一件事我仍然无法上班;我用过 Plutonix 的代码;但绘制的矩形总是相同的大小。我试图让它们改变大小(图片框宽度和高度的一半) - 不明白为什么它们的大小没有改变......
  • 只是想强调一下我学到的另一件事-如何将图形事件作为参数传递给子例程-使用类型“图形”。谢谢! ;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-31
  • 2015-03-08
  • 1970-01-01
相关资源
最近更新 更多