注册 登录
编程论坛 VB6论坛

真心求教,用VB实现动态曲线的绘制,总是有问题

nql_neu 发布于 2014-04-01 11:15, 6362 次点击
只有本站会员才能查看附件,请 登录

各位朋友,楼主小硕一枚,毕业论文里急需要用VB个上位机软件,实现数据的采集,显示和分析,我目前遇到的困难是无法实现动态曲线的绘制,我定义了一个120个数的数组,并且用随机数实现模拟采集,但是120以内的数可以实现动态绘制,但是120以后的就不可以了,请各位帮忙看看程序什么地方有问题。
40 回复
#2
nql_neu2014-04-01 13:09
程序代码:
Dim px(121) As Single, py(121) As Single '用来保存曲线数据的坐标值,程序中实时曲线通道为3.
Dim col As Integer             '当前需绘制的点数
Dim pl As Integer          '判断是否画动态曲线

Private Sub Command1_Click()
Timer2.Enabled = True
If Timer1.Enabled = True Then
Command1.Caption = "开始"
Timer1.Enabled = False
Else
Command1.Caption = "暂停"
Timer1.Enabled = True
End If
End Sub

Private Sub Command2_Click()
End
End Sub

Private Sub Command3_Click()
Timer2.Enabled = False
End Sub

Private Sub Form_Load()
HScroll1.value = 900
Picture1.Scale (900, 0)-(1200, 300)    '设置绘图区域坐标
End Sub

Private Sub HScroll1_Change()
Picture1.Cls    '清空绘图区域
num = HScroll1.value              '使绘图区域坐标和滚动条对应
Picture1.Scale (900 - (900 - num), 0)-(1200 - (900 - num), 300)
If pl >= 2 Then
Picture1.PSet (px(0), py(0))
For i = 1 To col
Picture1.Line -(px(i - 1), py(i - 1)), QBColor(2)  ' 重绘曲线
Next i
End If
End Sub

Private Sub Timer1_Timer()
Picture1.Cls
If col < 31 Then
For i = 0 To col
    px(i) = 900 + i * 10
    py(i) = Val(List1.List(i))       '利用随机数模拟实际数据
    Next i
      col = col + 1
      pl = pl + 1
      ElseIf col < 121 Then
      For j = 0 To col
      py(j) = Val(List1.List(j))
      px(j) = 1200 - 10 * (col - j) '如果数据点数》30  《121,数据的横坐标则用这个式子赋值
      Next j
      col = col + 1        '当数组装满时顺次前移,将数组第一个去掉
      Else
      For t = 0 To 119
      py(t) = py(t + 1)
      px(t) = 1200 - 10 * (col - t)
      Next t
      py(120) = Val(List1.List(i))
                                                   '数组的最后一个元素始终存放当前最新实时数据
      End If
      If pl >= 2 Then     '在两个或两个以上的数据点时,开始画动态曲线
      Picture1.PSet (px(0), py(0))
      For i = 1 To col
      Picture1.Line -(px(i - 1), py(i - 1)), QBColor(2)
      Next i
      End If
End Sub

Private Sub Timer2_Timer()
Dim value As Integer

 Randomize

 value = Int(200 * Rnd + 100)

 List1.AddItem value
End Sub
程序代码如上,窗体和工程文件在附件儿里,希望大神来帮助啊!
#3
lowxiong2014-04-01 14:36
      py(t) = py(t + 1)
      px(t) = 1200 - 10 * (col - t)
      Next t
      py(120) = Val(List1.List(i))
                                                   '数组的最后一个元素始终存放当前最新实时数据
      End If
      If pl >= 2 Then     '在两个或两个以上的数据点时,开始画动态曲线

红色部分显然错误,你的list内容不断增加,但list1的list指针固定在120了,应修改如下:
py(120) = Val(List1.List(List1.ListCount - 1))
#4
owenlu19812014-04-01 15:06
1.120以后希望继续采集还是?
2.Picture显示的是最后31个点,所以需要重画的是
    i,当col < = 31时,重画1到col
    ii,当col > 31时,重画col-31到col

[ 本帖最后由 owenlu1981 于 2014-4-1 15:16 编辑 ]
#5
nql_neu2014-04-01 15:56
回复 2楼 nql_neu
朋友,我按你说的改了,但是运行一会儿之后提示下标越界,我估计还是120个点儿往后出现的问题,程序本身不难理解,你可以下载我的附件用VB打开运行下,你帮我把这个问题搞定,我给你20分都可以,多谢了朋友
#6
nql_neu2014-04-01 15:58
回复 3楼 lowxiong
朋友,我按你说的改了,但是运行一会儿之后提示下标越界,我估计还是120个点儿往后出现的问题,程序本身不难理解,你可以下载我的附件用VB打开运行下,你帮我把这个问题搞定,我给你20分都可以,多谢了朋友,我和着急啊!
#7
lowxiong2014-04-01 16:09
要等多长时间?我已经等20分钟了。你两个时钟设置多少时间触发?
#8
nql_neu2014-04-01 16:24
回复 7楼 lowxiong
都是100毫秒,不好意思,我刚才没在电脑旁边!你可以把附件下载下来调试一下,多谢楼主
#9
lowxiong2014-04-01 16:29
主要是我没有出现错误,我都调到10ms了,最后是没有显示,list1.listcount为-20887,应该是list1数据不断增加造成的,应该定期清空list1的显示,或者修改算法
#10
nql_neu2014-04-01 16:51
回复 9楼 lowxiong
非常感谢楼主,给我解决了困扰了我两天的问题,我以后有啥问题还会向你请教的,这个问题差不多可以结贴了,这个例子很有代表性,需要的同志们可以下载附件,自己改编下就可以用了!
#11
nql_neu2014-04-01 16:58
回复 9楼 lowxiong
伟大的楼主,我咋给你分数啊,我第一次发帖,以前没有操作过这些东西
#12
lowxiong2014-04-01 17:00
无所谓
#13
风吹过b2014-04-01 21:01
晚上才上来。
我以前发过一个动态折线的程序,你可以找一找看一下。
#14
nql_neu2014-04-02 09:34
回复 13楼 风吹过b
好的,多谢朋友
#15
nql_neu2014-04-02 09:36
回复 12楼 lowxiong
楼主,我今天发现这个程序还是有点小问题,画前120个数的时候最右侧的直线一直在最picturebox的右上角,感觉不对吧,后120个数就正常了,什么原因呢?
#16
owenlu19812014-04-02 10:45
回复 15楼 nql_neu
稍微修改了下程序,看下是否OK
1. 界面只显示31个采样,所以每次重画只画31个点
2. 采样值和List1的值一一对应,py(0)=List1(0)
3. 采样数量超过900自动停止采样,List1数值超过900自动停止添加新值

程序代码:

Dim px(121) As Single, py(121) As Single '用来保存曲线数据的坐标值,程序中实时曲线通道为3.
Dim col As Integer             '当前需绘制的点数
Dim pl As Integer          '判断是否画动态曲线
Dim num As Integer

Private Sub Command1_Click()
If col > 900 Then
    MsgBox "超出采样数量!", vbExclamation, "提示"
    Exit Sub
End If
Timer2.Enabled = True
If Timer1.Enabled = True Then
    Command1.Caption = "开始"
    Timer1.Enabled = False
Else
    Command1.Caption = "暂停"
    Timer1.Enabled = True
End If
End Sub

Private Sub Command2_Click()
End
End Sub

Private Sub Command3_Click()
Timer2.Enabled = False
End Sub

Private Sub Form_Load()
HScroll1.value = 900
Picture1.Scale (900, 0)-(1200, 300)    '设置绘图区域坐标
col = 0
pl = 0
num = 0
End Sub

Private Sub HScroll1_Change()
Picture1.Cls    '清空绘图区域
num = HScroll1.value              '使绘图区域坐标和滚动条对应
'
Picture1.Scale (900 - (900 - num), 0)-(1200 - (900 - num), 300)
If pl >= 2 Then
    Picture1.PSet (px(0), py(0))
    For i = 0 To 30
        px(i) = 900 + i * 10
        py(i) = IIf(num < 31, Val(List1.List(i)), Val(List1.List(num - 30 + i)))
        Picture1.Line -(px(i), py(i)), QBColor(2) ' 重绘曲线
    Next i
End If
End Sub

Private Sub Timer1_Timer()
Picture1.Cls
If col > List1.ListCount Then
    MsgBox "采样数量超出列表数量!", vbExclamation, "Error"
    Timer1.Enabled = False
    Command1.Caption = "开始"
    Exit Sub
End If
If col < 31 Then
    For i = 0 To col
        px(i) = 900 + i * 10
        py(i) = Val(List1.List(i))       '利用随机数模拟实际数据
    Next i
    col = col + 1
    pl = pl + 1
ElseIf col <= 900 Then
    For i = 0 To 30
        py(i) = Val(List1.List(col - 30 + i))
        px(i) = 900 + i * 10
    Next i
    col = col + 1
Else
    Timer1.Enabled = False
    Command1.Caption = "开始"
End If

If pl >= 2 Then     '在两个或两个以上的数据点时,开始画动态曲线
    Picture1.PSet (px(0), py(0))
    For i = 0 To 30
        Picture1.Line -(px(i), py(i)), QBColor(2)
    Next i
    HScroll1.value = col
End If
End Sub

Private Sub Timer2_Timer()
Dim value As Integer

 Randomize

 value = Int(200 * Rnd + 100)

 List1.AddItem value

 If List1.ListCount > 900 Then
    Timer2.Enabled = False
End If
End Sub


[ 本帖最后由 owenlu1981 于 2014-4-2 11:44 编辑 ]
#17
nql_neu2014-04-02 11:08
回复 16楼 owenlu1981
楼主,你修改完的代码可以用,但是刚开始绘图的时候还是有问题,你可以把我的附件下载下来,把你修改的代码运行一下,希望能帮帮我,谢谢!
#18
风吹过b2014-04-02 11:25
你是 单条曲线,还是 多条曲线??

如果单条曲线,直接套的我 函数就是了。
https://bbs.bccn.net/thread-306299-1-1.html

里面有接口,注释。
    Call ADD数据(Time, 当前数据)
    Call 绘折线图(Picture1)
#19
风吹过b2014-04-02 11:36
测试了你的代码,没多大问题

改了你一个过程,120个点,很正确啊。

Private Sub Timer2_Timer()
Dim value As Integer
 Randomize                        '此行命令,在 load 过程中执行一次就可以了。
 value = Int(200 * Rnd + 100)
 If List1.ListCount > 120 Then    '你绘图函数里,限制数据 120个,那么 LIST 里,只保存最后的 120个数据。
    List1.RemoveItem 0            '干掉第一个数据
End If
 List1.AddItem value              '再添加新的数据
End Sub
#20
owenlu19812014-04-02 11:43
最右侧的直线一直在最picturebox的右上角
--> 这个效果不对吗? 需要什么效果?
#21
风吹过b2014-04-02 11:56
只有本站会员才能查看附件,请 登录


有点不适合套用我的函数画图。我的图是不支持滚动条。也就是说压了多少数据进去 ,就画多少点。
而你的要求是 120个点,界面上只显示 30个点,其它点可以通过滚动条来查看。
#22
nql_neu2014-04-02 12:40
回复 20楼 owenlu1981
画前120个点的时候你运行下可以发现有一条线总在picturebox的最上边沿,120个以后的绘图状态才是我想要的,你运行下代码就可以发现问题了,楼主,非常感谢
#23
nql_neu2014-04-02 12:44
回复 21楼 风吹过b
恩,单纯的画静态折线图我也会,但是这次毕业设计要求动态显示采集到的数据,遗憾的是目前的代码不是很完美,但是还是非常感谢你朋友!
#24
nql_neu2014-04-02 13:26
回复 19楼 风吹过b
朋友,你能把你改完的代码给我看一下吗,我改完效果不对啊,你改完了然后在回复这个界面里把代码给我看下呗,多谢!
#25
vbvcr512014-04-02 13:40
vb处理这类型的应用真是太经典了
#26
lowxiong2014-04-02 13:43
Private Sub Timer1_Timer()
Picture1.Cls
If col < 31 Then
  For i = 0 To col
    px(i) = 900 + i * 10
    py(i) = Val(List1.List(i))       '利用随机数模拟实际数据
  Next i
  col = col + 1
  pl = pl + 1
ElseIf col < 121 Then
  For j = 0 To col
    py(j) = Val(List1.List(j))
    px(j) = 1200 - 10 * (col - j) '如果数据点数》30  《121,数据的横坐标则用这个式子赋值
  Next j
  col = col + 1        '当数组装满时顺次前移,将数组第一个去掉
Else
  For t = 0 To 119
    py(t) = py(t + 1)
    px(t) = 1200 - 10 * (col - t)
  Next t
  py(120) = Val(List1.List(List1.ListCount - 1))
                                                   '数组的最后一个元素始终存放当前最新实时数据
End If
If pl >= 2 Then     '在两个或两个以上的数据点时,开始画动态曲线
  Picture1.PSet (px(0), py(0))
  For i = 1 To col - 1    '这里修改下可能复合你的要求
    Picture1.Line -(px(i - 1), py(i - 1)), QBColor(2)
  Next i
End If
End Sub
#27
lowxiong2014-04-02 13:52
完成这种功能的思路是:1,一个指示当前点位置的指针。2,一个前推出后推入的缓冲池,完成起来应该很简单的。
#28
nql_neu2014-04-02 14:30
回复 27楼 lowxiong
楼主你真是厉害,按你说的改完后果然对了,但是在运行几十秒之后画出的图像就很奇怪了,不是那种带尖儿的折线图,是那种平的,然后再运行一会儿又成了带尖的那种图了,由于采用的是随机数,应该都是那种带尖的折线才对,麻烦你再费下心,感激不尽!
#29
风吹过b2014-04-02 15:51
好吧。  给你 弄混乱了。。。。。。

1、数据来源:list1.list  ,无限。
2、数据缓冲:PX,PY , 121 个元素。
3、绘图开始位置指针:col
4、绘图点个数: 30
5、绘图滚动条 范围 : 0 - 900   
你数据缓冲只有 120 个点,你如何去绘制 900 的位置呢?混乱。
按你的思路重写时,发现这个混乱。

修改方案:有二种。
1、直接把 list1.list 当作数据缓冲,限制数据个数为 930 个。
2、重新定义 PX,Py ,定义为 930 个元素。

你先选吧。
#30
风吹过b2014-04-02 15:52
这是第1种的修改方案:

程序代码:
Dim px(121) As Single, py(121) As Single '用来保存曲线数据的坐标值,程序中实时曲线通道为30.      '仅使用前30个元素

Dim col As Integer             '当前需绘制的点数                '未使用
Dim pl As Integer          '判断是否画动态曲线                  '未使用

Private Sub Command1_Click()
Timer2.Enabled = True
If Timer1.Enabled = True Then
Command1.Caption = "开始"
Timer1.Enabled = False
Else
Command1.Caption = "暂停"
Timer1.Enabled = True
End If
End Sub

Private Sub Command2_Click()
End
End Sub

Private Sub Command3_Click()
Timer2.Enabled = False
End Sub

Private Sub Form_Load()
HScroll1.value = 1
Picture1.Scale (900, 0)-(1200, 300)    '设置绘图区域坐标

'移到这里
Randomize

 
End Sub

Private Sub HScroll1_Change()

Call Timer1_Timer

'此段函数清空
'
Picture1.Cls    '清空绘图区域
'
num = HScroll1.value              '使绘图区域坐标和滚动条对应
'
Picture1.Scale (900 - (900 - num), 0)-(1200 - (900 - num), 300)
'
If pl >= 2 Then
'
Picture1.PSet (px(0), py(0))
'
For i = 1 To col
'
Picture1.Line -(px(i - 1), py(i - 1)), QBColor(2)  ' 重绘曲线
'
Next i
'
End If
End Sub

Private Sub Timer1_Timer()


Picture1.Cls

Dim i As Long
Dim j As Long
Dim k As Long

'把 list1 当作数据缓冲,直接到里面读数据

i = List1.ListCount - 1        '总数据量
j = HScroll1.value              '滚动条位置,决定起始位置
If j > i Then Exit Sub          '如果没读到数据,不执行读数据和绘图功能,直接退出处理

If i - j > 31 Then i = j + 31   '确保只取 31 个值

'j 是滚动条的值,也就是开始位置
'
i 是终止值,list1 中的总记录数 或 比 J 大 30
For k = 0 To i - j
    px(k) = 900 + (k) * 10
    py(k) = Val(List1.List(k + j))
Next k
    For i = 1 To i - j
        Picture1.Line (px(i - 1), py(i - 1))-(px(i), py(i)), QBColor(2)           '使用省略参数进行绘图,老出错,只好用标准命令
    Next i


'If col < 31 Then
'
    For i = 0 To col
'
        px(i) = 900 + i * 10
'
        py(i) = Val(List1.List(i))       '利用随机数模拟实际数据
'
    Next i
'
    col = col + 1
'
    pl = pl + 1
'
ElseIf col < 121 Then
'
    For j = 0 To col
'
        py(j) = Val(List1.List(j))'Picture1.Cls
'
'
If List1.ListCount > 1 Then
'
Call ADDDATA(List1.List(List1.ListCount - 1))           '把最后一个数据加进去。
'
End If

'        px(j) = 1200 - 10 * (col - j) '如果数据点数》30  《121,数据的横坐标则用这个式子赋值
'
    Next j
'
    col = col + 1        '当数组装满时顺次前移,将数组第一个去掉
'
Else
'
    For t = 0 To 119
'
        py(t) = py(t + 1)
'
        px(t) = 1200 - 10 * (col - t)
'
    Next t
'
    py(120) = Val(List1.List(i))
'
                                             '数组的最后一个元素始终存放当前最新实时数据
'
End If

'If pl >= 2 Then     '在两个或两个以上的数据点时,开始画动态曲线
'
    Picture1.PSet (px(0), py(0))
'
    For i = 1 To col
'
        Picture1.Line -(px(i - 1), py(i - 1)), QBColor(2)
'
    Next i
'
End If
End Sub

Private Sub Timer2_Timer()
Dim value As Integer

value = Int(200 * Rnd + 100)
List1.AddItem value

 
'list1中最多保存930条记录,HScroll1.max + 30
If List1.ListCount > 930 Then
    List1.RemoveItem 0
End If

End Sub
#31
nql_neu2014-04-02 16:17
回复 30楼 风吹过b
程序代码:
Dim px(121) As Single, py(121) As Single  '用来保存曲线数据的坐标值,程序中实时曲线通道为3.
Dim col As Integer             '当前需绘制的点数
Dim pl As Integer          '判断是否画动态曲线

Private Sub Command1_Click()
Timer2.Enabled = True
Timer1.Enabled = True
End Sub

Private Sub Command2_Click()
End
End Sub

Private Sub Command3_Click()
Timer2.Enabled = False
Timer1.Enabled = False
End Sub

Private Sub Form_Load()
HScroll1.value = 900
Picture1.Scale (900, 0)-(1200, 300)    '设置绘图区域坐标
End Sub

Private Sub HScroll1_Change()
Picture1.Cls    '清空绘图区域
num = HScroll1.value              '使绘图区域坐标和滚动条对应
Picture1.Scale (900 - (900 - num), 0)-(1200 - (900 - num), 300)
If pl >= 2 Then
Picture1.PSet (px(0), py(0))
For i = 1 To col
Picture1.Line -(px(i - 1), py(i - 1)), QBColor(2)    ' 重绘曲线
Next i
End If
End Sub
Private Sub Timer1_Timer()
Picture1.Cls
If col < 31 Then
For i = 0 To col
    px(i) = 900 + i * 10
    py(i) = Val(List1.List(i))      '利用随机数模拟实际数据
    Next i
      col = col + 1
      pl = pl + 1
      ElseIf col < 121 Then
      For i = 0 To col
      py(i) = Val(List1.List(i))
      px(i) = 1200 - 10 * (col - i) '如果数据点数》30  《121,数据的横坐标则用这个式子赋值
      Next i
      col = col + 1        '当数组装满时顺次前移,将数组第一个去掉
      Else
      For t = 0 To 119
      py(t) = py(t + 1)
      px(t) = 1200 - 10 * (col - t)
      Next t
      py(120) = Val(List1.List(List1.ListCount - 1))  '数组的最后一个元素始终存放当前最新实时数据
      End If
      If pl >= 2 Then     '在两个或两个以上的数据点时,开始画动态曲
      Picture1.PSet (px(0), py(0))
      For i = 1 To col - 2
      Picture1.Line -(px(i - 1), py(i - 1)), QBColor(2)
      Next i
      End If
End Sub

Private Sub Timer2_Timer()
Dim value As Integer


 value = Int(100 * Rnd + 100)
List1.AddItem value
End Sub
楼主,我这段程序已经差不多可以运行了,你可以帮我运行下,你会发现在曲线绘制一会儿后突然就变形了,变的不像刚开始那样的尖峰那样的了,然后再过一会儿又恢复成带尖的那种峰值了,你能帮我指出是程序哪儿段有问题吗,谢谢!
#32
nql_neu2014-04-02 16:23
回复 30楼 风吹过b
楼主你编完的程序在你那儿能顺利运行吗,为啥我直接把代码粘过来曲线绘制30个点就不动了啊,你先帮我看看我刚才让你简查的那段代码哪儿有问题,然后我们再讨论这个!
#33
风吹过b2014-04-02 16:33
我直接把代码粘过来曲线绘制30个点就不动了啊。

你点滚动条啊。一共 930 个数据,需要 绘完这 930 个数据,曲线才会自动滚动啊。
---
也有可能我没看懂 你滚动条与 数据量的关系。如果这样的话,那需要重新修改我的代码。
--
为什么是 930 个,你的 滚动条的最大值设成了 930 了。
对了,滚动条的最小值要 设为 1 。

[ 本帖最后由 风吹过b 于 2014-4-2 16:43 编辑 ]
#34
风吹过b2014-04-02 16:42
看代码没问题。
关键在于,你是用了二个定时器。
一个定时器负责产生数据。另一个定时器负责去取数据,然后绘图。

有些时候,这二个定时器会不同步,造成取数,比如取到重复的数据,或者取漏数据。
#35
风吹过b2014-04-02 20:29
只有本站会员才能查看附件,请 登录


好吧,晚上按我自己思路重写过了一个。
你慢慢看吧。

只有本站会员才能查看附件,请 登录
#36
xo14374041522014-04-02 21:27
哇,版主就是厉害,我什么时候能达到版主的水平,我死也瞑目了
#37
nql_neu2014-04-03 09:22
回复 35楼 风吹过b
版主,真的非常非常感谢,没想到能得到这么大的帮助,我先研究下你的编程,然后再向你请教些问题,非常非常感谢,有人品,有能力,顶你!
#38
风吹过b2014-04-03 09:35
Private Sub Timer1_Timer()
'产生采样数据
Dim i As Long
i = Int(Rnd() * 200 + 100)
List1.AddItem i
If List1.ListCount > 900 Then           '采样保留最后多个数据。与绘图缓冲区无关
    List1.RemoveItem 0
End If

'同时把采样生成的数据压入绘图缓冲区
'缓冲区为 120 个数据,但绘图时,只使用其中 30 个数据。
Dim j As Long
Static wz As Long               '定义静态变量,为 缓冲区使用指针。

If wz <= 缓冲区大小 Then        '数据超出否
Else                            '超出,wz=缓冲区+1了
    For j = 1 To wz - 1         '数据向前移动
        py(j - 1) = py(j)
    Next j
End If

    If wz > 缓冲区大小 Then wz = 缓冲区大小
    py(wz) = i                  '压入绘图缓冲区。
    wz = wz + 1                 '指针向向移动

'debug
'Form2.Cls
'For i = 0 To 缓冲区大小
'    Form2.Print py(i);
'    If i Mod 10 = 0 Then Form2.Print
'Next i

End Sub

这个过程稍修改地一下。
原来的容易导致 在 第 90 号元素时,跳掉一个元素进行采样,
--------------------
如果采样总是把队列当作为满的,然后从右边进去,就不会导致这个问题,代码也就精减多少。
现在 从右边进,但队列是空的,就需要考虑二种情况。一不小心,就导致这种采样漏元素的情况。
#39
nql_neu2014-04-03 16:08
回复 38楼 风吹过b
我表示我都没有发现这种情况,呵呵,非常感谢版主,这个帖子得到这么多人的关注和解答,感觉非常有意义,希望对大家都有帮助,再次感谢!
#40
茅十八2014-04-03 22:16
好像在模拟电信号,想起大学实验室,模拟青蛙神经传导信号的程序。  好厉害
#41
八云2018-03-20 00:57
回复 38楼 风吹过b
帮上我的忙了,没想到能在这里找到实现方法,
我还要仔细研究一下,非常感谢。
1