# vb 2005 picturebox绘图

• ### 問題

• 这段代码主要是实现将从串口接收过来的数据在picturebox中画出曲线

并且每画完一个屏幕以后就自动保存图像；当然后期还有许多功能要做。

画曲线的代码在timer的tick事件中实现：

Public Class Form1
Dim i As Integer = 0
Dim DataPointf(1000) As PointF
Dim bmp As Bitmap
Dim grr As Graphics
Dim filename As String

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
bmp = New Bitmap(PicBOX1.Width, PicBOX1.Height)
grr = Graphics.FromImage(bmp)
grr.Clear(PicBOX1.BackColor)

Timer1.Interval = 100
Timer1.Enabled = True

End Sub
Private Sub Drawset()

grr.DrawLine(Pens.Black, 44, 280, 524, 280)    'draw x-axis

grr.DrawLine(Pens.Black, 44, 280, 44, 0)            'draw Temperature-axis

grr.DrawLine(Pens.Black, 524, 280, 524, 0)            'draw Pressure-axis

Dim i As Integer = 0
Do
grr.DrawLine(Pens.Black, i * 60 + 104, 275, i * 60 + 104, 285)    ' draw x-axis tick mark
i = i + 1
Loop While i < 7

Dim j As Integer = 0
Do
grr.DrawLine(Pens.Black, 40, j * 28, 48, j * 28)            ' draw deeee-axis tick mark
j = j + 1
Loop While j < 10

Dim k As Integer = 0
Do
grr.DrawLine(Pens.Black, 520, k * 28, 528, k * 28)      ' draw EEV opening tick mark
k = k + 1
Loop While k < 10

grr.DrawString("50℃", Me.Font, Brushes.Black, 10, 0)
grr.DrawString("40℃", Me.Font, Brushes.Black, 10, 18 + 28 + 5)
grr.DrawString("30℃", Me.Font, Brushes.Black, 10, 18 + 28 * 3 + 5)
grr.DrawString("20℃", Me.Font, Brushes.Black, 10, 18 + 28 * 5 + 5)
grr.DrawString("10℃", Me.Font, Brushes.Black, 10, 18 + 28 * 7 + 5)
grr.DrawString("0", Me.Font, Brushes.Black, 20, 18 + 28 * 9 + 5)

grr.DrawString("3", Me.Font, Brushes.Black, 104, 295)
grr.DrawString("6", Me.Font, Brushes.Black, 104 + 60 * 1, 295)
grr.DrawString("9", Me.Font, Brushes.Black, 104 + 60 * 2, 295)
grr.DrawString("12", Me.Font, Brushes.Black, 104 + 60 * 3, 295)
grr.DrawString("15", Me.Font, Brushes.Black, 104 + 60 * 4, 295)
grr.DrawString("18", Me.Font, Brushes.Black, 104 + 60 * 5, 295)
grr.DrawString("21", Me.Font, Brushes.Black, 104 + 60 * 6, 295)
grr.DrawString("24", Me.Font, Brushes.Black, 104 + 60 * 7, 295)

grr.DrawString("2.5 Mpa", Me.Font, Brushes.Black, 530, 0)
grr.DrawString("2.25 MPa", Me.Font, Brushes.Black, 530, 18 + 5)
grr.DrawString("2 MPa", Me.Font, Brushes.Black, 530, 18 + 28 + 5)
grr.DrawString("1.75 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 2 + 5)
grr.DrawString("1.5 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 3 + 5)
grr.DrawString("1.25 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 4 + 5)
grr.DrawString("1 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 5 + 5)
grr.DrawString("0.75 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 6 + 5)
grr.DrawString("0.5 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 7 + 5)
grr.DrawString("0.25 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 8 + 5)
grr.DrawString("0", Me.Font, Brushes.Black, 530, 18 + 28 * 9 + 5)
End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Timer1.Enabled = False
grr.DrawLine(Pens.Blue, i + 80, 30, i + 81, 30)
PicBOX1.Image = bmp

ReDim Preserve DataPointf(i)
DataPointf(i).X = i + 80
DataPointf(i).Y = 30

i += 1
filename = Convert.ToString(Now)
filename = Replace(filename, ":", "_")

If i > 300 Then
i = 0
Call Drawset()
bmp.Save("E:\" & filename & ".bmp", System.Drawing.Imaging.ImageFormat.Bmp)
PicBOX1.Refresh()

End If
Timer1.Enabled = True

End Sub

Private Sub PicBOX_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PicBOX1.Paint

e.Graphics.Clear(PicBOX1.BackColor)
e.Graphics.DrawLine(Pens.Black, 44, 280, 524, 280)    'draw x-axis

e.Graphics.DrawLine(Pens.Black, 44, 280, 44, 0)            'draw Temperature-axis

e.Graphics.DrawLine(Pens.Black, 524, 280, 524, 0)            'draw Pressure-axis

Dim n As Integer = 0
Do
e.Graphics.DrawLine(Pens.Black, n * 60 + 104, 275, n * 60 + 104, 285)    ' draw x-axis tick mark
n = n + 1
Loop While n < 7

Dim j As Integer = 0
Do
e.Graphics.DrawLine(Pens.Black, 40, j * 28, 48, j * 28)            ' draw deeee-axis tick mark
j = j + 1
Loop While j < 10

Dim k As Integer = 0
Do
e.Graphics.DrawLine(Pens.Black, 520, k * 28, 528, k * 28)      ' draw EEV opening tick mark
k = k + 1
Loop While k < 10

e.Graphics.DrawString("50℃", Me.Font, Brushes.Black, 10, 0)
e.Graphics.DrawString("40℃", Me.Font, Brushes.Black, 10, 18 + 28 + 5)
e.Graphics.DrawString("30℃", Me.Font, Brushes.Black, 10, 18 + 28 * 3 + 5)
e.Graphics.DrawString("20℃", Me.Font, Brushes.Black, 10, 18 + 28 * 5 + 5)
e.Graphics.DrawString("10℃", Me.Font, Brushes.Black, 10, 18 + 28 * 7 + 5)
e.Graphics.DrawString("0", Me.Font, Brushes.Black, 20, 18 + 28 * 9 + 5)

e.Graphics.DrawString("3", Me.Font, Brushes.Black, 104, 295)
e.Graphics.DrawString("6", Me.Font, Brushes.Black, 104 + 60 * 1, 295)
e.Graphics.DrawString("9", Me.Font, Brushes.Black, 104 + 60 * 2, 295)
e.Graphics.DrawString("12", Me.Font, Brushes.Black, 104 + 60 * 3, 295)
e.Graphics.DrawString("15", Me.Font, Brushes.Black, 104 + 60 * 4, 295)
e.Graphics.DrawString("18", Me.Font, Brushes.Black, 104 + 60 * 5, 295)
e.Graphics.DrawString("21", Me.Font, Brushes.Black, 104 + 60 * 6, 295)
e.Graphics.DrawString("24", Me.Font, Brushes.Black, 104 + 60 * 7, 295)

e.Graphics.DrawString("2.5 Mpa", Me.Font, Brushes.Black, 530, 0)
e.Graphics.DrawString("2.25 MPa", Me.Font, Brushes.Black, 530, 18 + 5)
e.Graphics.DrawString("2 MPa", Me.Font, Brushes.Black, 530, 18 + 28 + 5)
e.Graphics.DrawString("1.75 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 2 + 5)
e.Graphics.DrawString("1.5 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 3 + 5)
e.Graphics.DrawString("1.25 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 4 + 5)
e.Graphics.DrawString("1 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 5 + 5)
e.Graphics.DrawString("0.75 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 6 + 5)
e.Graphics.DrawString("0.5 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 7 + 5)
e.Graphics.DrawString("0.25 MPa", Me.Font, Brushes.Black, 530, 18 + 28 * 8 + 5)
e.Graphics.DrawString("0", Me.Font, Brushes.Black, 530, 18 + 28 * 9 + 5)

e.Graphics.DrawLines(Pens.Blue, DataPointf)
e.Dispose()
End Sub
End Class

现在的问题是，单步运行的时候程序不会报错，但是全速运行时会出现错误

错误出现在e.Graphics.DrawLines(Pens.Blue, DataPointf)这一句

错误是：parameter is not valid.而且此刻datapointf数组里面只有一个

元素（80，30），问题就在这儿。

但是我不明白，为什么这个数组里面会只有一个元素而报错呢；

当我把重绘语句改成

Dim m As Integer
For m = 0 To i
e.Graphics.DrawLine(Pens.Blue, m + 80, 30, m + 81, 30)
Next

一切运行正常，我不明白前面的那种方法为什么不可以；

请各位前辈赐教！

谢谢
2009年3月17日 上午 02:28

### 解答

• HI,

DataPointF陣列中必須至少有兩點, 才能繪一直線, 您的狀況應該是在某個時間點, DataPointF陣列中只有一點, 而發生錯誤
2009年3月17日 上午 04:28
•  ReDim Preserve DataPointf(i)

上列會把陣列重新宣告為i的大小，您宣告i初始值為0，paint事件觸發時，這時陣列只有1個;而單步執行時，Timer已產生好幾個陣列了...
• 已編輯 2009年3月17日 下午 01:00
• 已標示為解答 2009年3月21日 上午 04:00
2009年3月17日 上午 08:54

### 所有回覆

• HI,

DataPointF陣列中必須至少有兩點, 才能繪一直線, 您的狀況應該是在某個時間點, DataPointF陣列中只有一點, 而發生錯誤
2009年3月17日 上午 04:28
• 什么情况下会出现只有一个点呢？

关键是全速运行一开始就会有error出现

2009年3月17日 上午 05:21
•  版大，能幫我看看嗎

我知道是因為datapointf陣列里隻有一個元素

但是為什么會出現這種情況呢？

單步運行是不會有error的

另外我的這種情況采用這種方式畫圖是否閤適啊？

謝謝
2009年3月17日 上午 07:12
•          If UBound(DataPointf) > 0 Then
e.Graphics.DrawLines(Pens.Blue, DataPointf)
End If

一開始時，陣列只有一個，就會造成例外，改成以上，應該就可以了吧?!
2009年3月17日 上午 07:53
• 問題解決了

謝謝前輩

可是為什么？

我預先已經定義了Dim DataPointf(1000) As PointF

盡管沒有賦值，可是單步運行的時候可以看到陣列中

缺省賦值都是(0,0);

为什么会在程序中会突然陣列只有一个值?

这种情况是怎么产生的？

2009年3月17日 上午 08:16
• 而且这个值是（80，30），

很顯然是執行到ｔｉｃｋ事件中

ReDim Preserve DataPointf(i)
DataPointf(i).X = i + 80
DataPointf(i).Y = 30

上麵的代碼后才産生的錯誤？

難道這個時候paint事件會被觸髮？

謝謝
2009年3月17日 上午 08:20
•  ReDim Preserve DataPointf(i)

上列會把陣列重新宣告為i的大小，您宣告i初始值為0，paint事件觸發時，這時陣列只有1個;而單步執行時，Timer已產生好幾個陣列了...
• 已編輯 2009年3月17日 下午 01:00
• 已標示為解答 2009年3月21日 上午 04:00
2009年3月17日 上午 08:54
•  土土的問

難道不是先執行ｐａｉｎｔ事件

然后執行ｔｉｍｅｒ的ｔｉｃｋ事件嗎？
2009年3月17日 上午 10:03
•          PicBOX1.Image = bmp

在下前面寫錯了，上列會觸發paint 事件，執行完Timer的tick事件，才會執行paint，第一次時，陣列只有一個，就會造成錯誤...
2009年3月17日 下午 01:04
• 非常非常感谢！

bow
2009年3月18日 上午 02:08
• paint 事件是在螢幕發生重繪時，強制發生應加在 Form_Load / Form_Active 等事件
Timer 事件是依 Tick 密度發生

當 Form_Load -> Tick 較短，且尚未 Form.Show 時
就有可能先發生 Timer 事件
T.L. Cheng
2009年3月21日 上午 04:03