vb.net中的图形对象

vb.net中的图形对象,.net,vb.net,gdi+,system.drawing,.net,Vb.net,Gdi+,System.drawing,我刚开始在vb.net中创建图形。 我创建了一个windows窗体并双击它。 然后我得到了一个方法,它是表单加载方法。 在这个方法中,我编写了以下代码 Dim g As Graphics g = Me.CreateGraphics Dim pencolor As New Pen(Color.Red) g.DrawLine(pencolor, 10, 20, 100, 200) 我知道必须在Paint事件中创建图形。 但是我试图在表单加载事件中显示它们。 由于某

我刚开始在vb.net中创建图形。 我创建了一个windows窗体并双击它。 然后我得到了一个方法,它是表单加载方法。 在这个方法中,我编写了以下代码

    Dim g As Graphics
    g = Me.CreateGraphics

    Dim pencolor As New Pen(Color.Red)
    g.DrawLine(pencolor, 10, 20, 100, 200)
我知道必须在Paint事件中创建图形。 但是我试图在表单加载事件中显示它们。 由于某种原因,我没有看到输出
可能是什么问题?。

永远不要使用
CreateGraphics
。我认为它实际上没有一个合法的用例

您的问题是,您在表单上绘制了一些内容,但一旦触发表单的下一次重画,它就会被重写,因为您以这种方式创建的图形不会被持久化

您基本上必须使用
Paint
事件(或
OnPaint
方法)进行绘制,这是无法避免的。如果您想在
表单加载中触发重画
,只需调用
Me.Invalidate
(但我认为这应该是多余的)

在(或
绘制
事件)内,使用参数中提供的
图形
对象:

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    MyBase.OnPaint(e) ' First, let the base class do its thing

    Dim g = e.Graphics

    Using p As New Pen(Color.Red)
        g.DrawLine(…)
    End Using
End Sub 
(请注意,
Pen
是一种一次性资源,因此您应该使用块将其包装在
中。)

尝试以下操作:

Public Class Form1

    Dim painted As Boolean = False

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        MyBase.OnPaint(e)
        If Not painted Then
            painted = True
            e.Graphics.Clear(Color.Blue)
        End If
    End Sub

End Class

我在VB.net(2010)中扩展了这个不错的答案,以处理DataGridView控件中文本的自动大小调整

首先,将函数修改为:

Private Function MeasureTextWidth(ByVal c As Control, ByVal text As String) As Integer
    If (c Is DBNull.Value) Then
        Return -1
    Else
        Dim g As Graphics = c.CreateGraphics
        Return CInt(Math.Ceiling(g.MeasureString(text, c.Font).Width))
    End If
End Function
在调用此函数的软件中,下一部分如下所示:

    With frm_Parameters_FITs
        .Show()
        With .DataGridView1
            .SuspendLayout()
            .DataSource = Nothing '  CRITICAL
            .AllowUserToAddRows = False
            .AllowUserToDeleteRows = False
            .AllowUserToResizeRows = False
            .AllowUserToOrderColumns = True
            .SelectionMode = DataGridViewSelectionMode.FullRowSelect
            .ReadOnly = True
            .MultiSelect = False
            .RowHeadersVisible = False
            .Columns.Clear()
            .Rows.Clear()
            ' setup columns
            .Columns.Add("Item", "Item#")
            .Columns(0).Width = 11
            .Columns(0).SortMode = DataGridViewColumnSortMode.NotSortable
            .Columns.Add("Parameter", "gHeaderTitle") ' (ColName, HeaderText)
            .Columns(1).Width = 25
            .Columns(1).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
            .Columns(1).SortMode = DataGridViewColumnSortMode.NotSortable
            .Columns.Add("ParamValue", "gHeaderInfo")
            .Columns(2).Width = 40
            .Columns(2).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            .Columns(2).SortMode = DataGridViewColumnSortMode.NotSortable
            .Columns.Add("Comments", "gHeaderComment")
            .Columns(3).Width = 50
            .Columns(3).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            .Columns(3).SortMode = DataGridViewColumnSortMode.NotSortable
            .Columns.Add("Comments", "Comments")
            .Columns(4).Width = 60
            .Columns(4).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            .Columns(4).SortMode = DataGridViewColumnSortMode.NotSortable
            .ResumeLayout(True)
        End With
        'Then you can add the data in rows to the cells of the DataGridView:
        Dim piIndex As Integer ' this is a row pointer
        Dim ColTextWidth(5) As Integer
        Dim TextToMeasure As String
        Dim IntTextWidthPixels As Integer

        With .DataGridView1
            For i As Integer = 1 To Globals.giHeaderLines
                .Rows.Add() ' increases the rows.count...the last index is (rows.count-1)
                piIndex = .Rows.Count - 1  ' pointer to the last row just added
                .Rows(piIndex).Cells(0).Value = i.ToString ' puts this text into the col 0 cell

                .Rows(piIndex).Cells(0).Style.WrapMode = DataGridViewTriState.True
                .Rows(piIndex).Cells(1).Value = gHeaderTitle(i)
                .Rows(piIndex).Cells(2).Value = gHeaderInfo(i)
                .Rows(piIndex).Cells(3).Value = gHeaderComment(i)
                .Rows(piIndex).Cells(4).Value = gHeaderComment(i)
                ' now determine the correct col width
                For j As Integer = 0 To 4
                    Try
                        TextToMeasure = .Rows(piIndex).Cells(j).Value
                        IntTextWidthPixels = MeasureTextWidth(frm_Parameters_FITs.DataGridView1, TextToMeasure)

                        If IntTextWidthPixels > ColTextWidth(j) Then
                            ColTextWidth(j) = IntTextWidthPixels
                        End If
                    Catch ex As Exception
                        Debug.Print("Error here in Class_FileIO_FITs. PutDataIntoHeaderDataGrid")
                    End Try
                Next j
            Next i
            ' now reset the cols to the correct width
            For j As Integer = 0 To 4
                .Columns(j).Width = ColTextWidth(j)
            Next j
        End With
        'make sure the row we added is visible
        .DataGridView1.FirstDisplayedScrollingRowIndex = piIndex
        .DataGridView1.ClearSelection()
        .DataGridView1.Rows(piIndex).Selected = True
        .Refresh()
    End With

这可以很好地为DataGridView控件提供正确的宽列。

如果您知道应该在
Paint
事件中执行此操作,为什么不直接执行呢?我看不出为什么代码应该出现在
Load
事件中。我的疑问是,为什么表单加载时,表单上没有显示行。。??我这样做是为了在表单加载时最初画一条线,因为它被
Paint
事件覆盖。这就是为什么你应该在那里执行每一个绘图操作。关于样式的一个小提示:在不初始化变量的情况下,永远不要声明变量。前两行应该是一行:
Dim g=Me.CreateGraphics()
(使用
选项推断)。但无论如何,这是错误的方法(
CreateGraphics()
是一个不应该存在的可怕方法)。。??我不明白。。请再解释一下……好的。现在我意识到我别无选择,只能使用paint事件。感谢您指出要在参数列表中使用对象。谢谢你的详细解释。清除了我的疑问。你也可以使用预定义的笔之一pens.Red,而不是创建自己的笔。如果您这样做,不要处理它!“永远不要使用CreateGraphics。我认为它实际上没有合法的用例。”。当然有。首先想到的是MouseMove中的橡皮筋…@DanByström No.您在
MouseMove
中跟踪移动和橡皮筋位置,然后通过使控件无效而触发
OnPaint
,并在那里执行实际的绘制。关注点分离。这就是我在回答中描述的情况。我不知道为什么
CreateGraphics
会存在,但我猜这是因为VB6程序员会有一个快速的脏方法来直接移植代码。不管怎样,我一开始就是这么用的。但是后来我学会了正确地使用WinFormsAPI,我认为恰恰相反。将OnPaint与仅在拖动操作期间使用的易失性绘图代码混在一起对我来说是违反关注点分离的行为。就在前几天,我在一个WinForms项目中实现了一个放大镜,CreateGraphics使代码比我刚从MouseMove调用Invalidate时要干净得多。您实际扩展了什么答案?我不知道,“以上”是,或者很快将是,无用的:答案是按默认投票排序的,这可能会改变。添加一个链接。该贡献将c#代码扩展为VB.net代码。它表明CreateGraphics是可用的,并且使文本宽度度量变得简单。这个问题没有C代码的答案,因此您扩展的任何答案都不在这里。请链接到实际答案,这是基于。