Link to home
Start Free TrialLog in
Avatar of thunder44
thunder44

asked on

How to create VB strip chart?

HI,
   Anyone know where I could find some source to program a strip chart in VB? I define a 'strip chart' as one in which the whole trace moves across the screen like a stock ticker display, as opposed to a graph that draws its trace from one side of the screen to the other.
ASKER CERTIFIED SOLUTION
Avatar of aikimark
aikimark
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of adg
adg

I have one at home.  If you're interested, I'll post the code.  If the EE goes down again, try reposting your question at carobit.com.
Avatar of thunder44

ASKER

Thanks for the example aikimark, however your describing 'stock ticker' display if I'm not mistaken, scrolling text across the screen. Forgive my inadequate description in my initial question. a 'strip chart' is similar to what your describing in that it scrolls horizonatally or vertically on the screen, but its not string data but x/y coordinate data in the form of a scrolling graph.
          adg, if your code resembles the above description I'd appreciate your posting it here or at carobit.com. Any kind of general example would be appreciated.
1. Are you scrolling repeating static graphical data or constantly changing data?
2. Are you trying to create a control similar to the NT Task Manager's Performance tab or some other configuration?
3. Is the timing of the scroll static (timer interval) or based on some data push / data change / data update?

In order to provide an accurate answer, you will need to be specific about what you want to see.  There are some third-party controls that might provide you with a codeless solution.
This example uses sockets to pass the generated data to the chart.  Naturally that would make more sense if there were two different processes but for the example it's all one process.

1. Paste the two forms and the Class into a standard exe project
2. Change the names to ShiftArray.cls and StripChart.frm. (form1.frm stays the same)
3. Change project startup object to StripChart.frm
4. Add Project component references to the ms chart control 6.0 and the ms winsock control 6.0
5. Add a picturebox, a winsock and an mschart control to Stripchart.frm
6. Change the protocol of the winsock control in StripChart.frm to UDP (not TCP)
7. Add a timer, two buttons and a winsock control to Form1.frm
8. Change the protocol of this winsock to UDP also.
9. Change the names of the two buttons to match the code in Form1.  
10. Run it and click on the cmdStart in form1.

Hope this helps.  Let me know if you need more info.  


'**************************************************************
' ShiftArray.Cls
'**************************************************************
Option Explicit
Private mTag As Variant
Private varArray() As Variant
Private mCapacity As Long
Private WithEvents Winsock1 As Winsock
Event DataArrival()

Friend Function Init(Capacity As Integer, Winsocker As Winsock, Optional InitValue As Long = 0) As Boolean
    Dim i As Integer
    If Capacity < 1 Then
        Init = False
        Exit Function
    End If
    ReDim varArray(Capacity)
    mCapacity = Capacity
    For i = 1 To Capacity
        varArray(i) = InitValue
    Next i
    Set Winsock1 = Winsocker
    With Winsock1
        .RemoteHost = "localhost"
        .RemotePort = 1001
        .Bind 1002
    End With
    Init = True
End Function

Friend Sub Clear()
    ReDim varArray(0)
    mCapacity = 0
End Sub

Friend Function GetArray() As Variant()
    GetArray = varArray
End Function

Friend Property Get Capacity() As Integer
    Capacity = mCapacity
End Property

Friend Property Get Tag() As String
    Tag = mTag
End Property

Friend Property Let Tag(ByVal strNewValue As String)
    mTag = strNewValue
End Property

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    Dim sglData As Single
    Dim i As Long
    If mCapacity > 1 Then
        For i = 1 To mCapacity - 1
            varArray(i) = varArray(i + 1)
        Next i
    End If
    Winsock1.GetData sglData
    varArray(mCapacity) = sglData
    RaiseEvent DataArrival
End Sub

'**************************************************************
' Stripchart.frm - contains a picturebox, a winsock and a mschart control
'**************************************************************
Option Explicit

Private Const WM_PAINT = &HF
Private Const WM_PRINT = &H317
Private Const PRF_CLIENT = &H4&
Private Const PRF_CHILDREN = &H10&
Private Const PRF_OWNED = &H20&

Private Declare Function SendMessage Lib "user32" Alias _
   "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
   ByVal wParam As Long, ByVal lParam As Long) As Long
   
Private WithEvents sa As ShiftArray

Private Sub Form_Load()
    Form1.Show      
    Set sa = New ShiftArray
    sa.Init 80, Winsock1, 0.5
    With MSChart1
        .AutoIncrement = True
        .chartType = VtChChartType2dLine
        .DoSetCursor = False
        .Plot.Axis(VtChAxisIdX).AxisGrid.MajorPen.Style = VtPenStyleNull
        .Plot.Axis(VtChAxisIdX).Tick.Style = VtChAxisTickStyleNone
        .Plot.Axis(VtChAxisIdY).ValueScale.Auto = False
        .Plot.Axis(VtChAxisIdY).ValueScale.Minimum = -1
        .Plot.Axis(VtChAxisIdY).ValueScale.Maximum = 2
    End With
    Picture1.AutoRedraw = True
End Sub

Private Sub Form_Resize()
    MSChart1.Visible = False
    MSChart1.Move 0, 0, ScaleWidth, ScaleHeight
    Picture1.Move 0, 0, ScaleWidth, ScaleHeight
End Sub

Private Sub DrawChart(n As Integer, arr() As Variant)
    With MSChart1
        .ColumnCount = 1
        .RowCount = n
    End With
    Dim k As Integer
    For k = 1 To n
        MSChart1.Data = arr(k)
    Next k
    SendMessage MSChart1.hwnd, WM_PAINT, Picture1.hDC, 0
    SendMessage MSChart1.hwnd, WM_PRINT, Picture1.hDC, PRF_CHILDREN + PRF_CLIENT + PRF_OWNED
    Picture1.Picture = Picture1.Image
End Sub

Private Sub sa_DataArrival()
    DrawChart sa.Capacity, sa.GetArray
End Sub


'**************************************************************
' Form1.Frm - contains a timer, two buttons  and winsock control.
'**************************************************************

Option Explicit

Private Sub cmdStart_Click()
    Timer1.Enabled = True
End Sub

Private Sub CmdStop_Click()
    Timer1.Enabled = False
End Sub

Private Sub Form_Load()
    With Winsock1
        .RemoteHost = "localhost"
        .RemotePort = 1002
        .Bind 1001
    End With
    Timer1.Enabled = False
    Timer1.Interval = 55
End Sub

Private Sub Timer1_Timer()
    Winsock1.SendData Rnd
End Sub
Thats weird, I'm posting as someone else!
Did aikimark or adopo post the long section of src? I assume its aikimark posting as adopo. My app is taking string data representing sampled amplitude data (originally via an analog to digital converter) thats held in a serial data file and being able to scroll backwards or forwards through it (in graph form). I think this used to be called a 'scrolling window' display, if the graph were scrolling to the left, it would disappear off the left portion of the window, and new points would be added on the right (the stock ticker idea). Nothing real-time needed here. Yeah there are commmercial components out there, but I'd like to try it myself. Am going to try that src with VB5 tommorrow, as its 1 am now.
Well a pictures worth a thousand words so heres what I'm trying to code, but in a Java-app:

http://www.visualmining.com/examples/javaexamples/StripChart1.html

I don't need anything so fancy, just trying to scroll thru xy data like that is what I'd like to figure out how to code.
Actually, it was me.  I tried to look at your example but couldn't get it to load. I don't really have an easy way to do this in VB.  I could remove the winsock stuff but most of the complexity would remain.  It's due to using the mschart control which is not easy to use.  It may be that the approach suggested by aikimark might be better for you. You'd have to code the chart yourself in more detail but you wouldn't have to deal with the mschart control which as you can see is a bit of a pain.  Good luck to you.
I looked at the Java strip chart examples and don't know which one (flavor) you want.  You can certainly use a single picturebox control and use the .Print and .Line methods to create the strip chart you want.  On successive iterations, drop one data point from the start and add one to the end, if moving forward in the dataset.

You would need to examine your data points to determine the low and high values for drawing proportions (relative to picturebox.scaleheight) and axis labeling.  It seems that your data points are a fixed distance from each other, so divide the picturebox.Scalewidth by the number of data points you are drawing.

Clear the picturebox before drawing by using the .CLS method.

For persistence, you'll need to set the picturebox.AutoRedraw = True.
Tryed the large program posted here without any luck. Putting it together went ok though I don't have ms chart control 6.0 and had to use VB5's mschart control. Don't have ms winsock control 6.0 and used 5.0 instead.
    Hitting the start button gives me the error of 'method or data member not found', and in the function private sub sa_data arrival, 'GetArray' is highlighted.
    Noted in the ShiftArray.cls that in the function friend function getarray () as variant was colored in red, so somethings wrong.
    Retyped this function and the red type turned to blue which I assume means some error was fixed.
    However, rerunning the program I get an error of 'array or user defined type expected', and in the function private sub sa_data arrival, 'GetArray' is highlighted once again.
    Could it be the older winsock and chart controls causing this?



I'll remove as much bells and whistles as I can and post it again. The chart will flicker horribly but if you get it working, we can put back the code to remove the flicker.  Does that work for you?
I'll sure give it a try, thanks. I still don't get why it didn't work the 1st time.
Maybe something to do with improved passing of arrays as parameters in VB6?  I don't know - I've never used VB5.  Anyway I have to admit the example was really overblown (But it does work for me).   Here's another try, just a timer and mschart control needed.  If this fails, it will be much easier to debug.  


Option Explicit
Dim ShiftArray() As Single
Dim Capacity As Long

Private Sub Form_Load()
    Dim k As Integer
    Randomize Timer
    Capacity = 80
    ReDim ShiftArray(1 To Capacity)
    For k = 1 To Capacity
        ShiftArray(k) = Rnd
    Next k
    With MSChart1
        .AutoIncrement = True
        .chartType = VtChChartType2dLine
        .ColumnCount = 1
        .RowCount = Capacity
        .Plot.Axis(VtChAxisIdX).AxisGrid.MajorPen.Style = VtPenStyleNull
        .Plot.Axis(VtChAxisIdX).Tick.Style = VtChAxisTickStyleNone
        .Plot.Axis(VtChAxisIdY).ValueScale.Auto = False
        .Plot.Axis(VtChAxisIdY).ValueScale.Minimum = -1
        .Plot.Axis(VtChAxisIdY).ValueScale.Maximum = 2
    End With
    Timer1.Interval = 100
End Sub

Private Sub Form_Resize()
    MSChart1.Move 0, 0, ScaleWidth, ScaleHeight
    MSChart1.Refresh
End Sub

Private Sub Timer1_Timer()
    Dim k As Integer
    'shift array values to left
    For k = 1 To Capacity - 1
        ShiftArray(k) = ShiftArray(k + 1)
    Next k
    ' add random value at end of array
    ShiftArray(Capacity) = Rnd
    ' load the chart with data
    For k = 1 To Capacity
        MSChart1.Data = ShiftArray(k)
    Next k
End Sub
In this example, I generate random values during form_load and then walk through the array.  If you have a LOT of external data, you would reposition the file pointer and read the next set of values.  Otherwise, you would read all the values into an array and use this code (excluding the random number generation).  In this example, I'm charting 5 values at a time.  To view this example, you will need to add two command buttons (cmdNext and cmdPrev) and a chart object (MSChart1).  

Option Explicit
Dim intValues(250) As Integer
Dim intPosn As Integer

Private Sub cmdNext_Click()
    If (UBound(intValues) - intPosn) >= 5 Then
        intPosn = intPosn + 1
        Me.DrawStrip
    Else
        MsgBox "You are at the end of the data"
    End If
End Sub

Private Sub cmdPrev_Click()
    If (intPosn) > 0 Then
        intPosn = intPosn - 1
        Me.DrawStrip
    Else
        MsgBox "You are at the beginning of the data"
    End If
End Sub

Private Sub Form_Load()
    For intPosn = LBound(intValues) To UBound(intValues)
        intValues(intPosn) = 1 + Rnd * 20
    Next
    intPosn = 0
    Me.DrawStrip
End Sub

Public Sub DrawStrip()
    Dim intLoop As Integer
    Dim intDataPosn As Integer
    intDataPosn = 1
    For intLoop = intPosn To intPosn + 4
        Me.MSChart1.Row = intDataPosn
        Me.MSChart1.Column = 1
        Me.MSChart1.RowLabel = CStr(intLoop)
        Me.MSChart1.Data = intValues(intLoop)
       
        intDataPosn = intDataPosn + 1
    Next
    Me.MSChart1.Refresh
End Sub
Thanks aikimark, those last two examples were great. I really appreciate your going out of your way to help me. Its true the scrolling on the 2nd to last ex. flickers but the example does show the general idea. The last example really hits it on the head. Its more important to me to be able to scan thru my data and have x and y axis markings than it is to have some sort of autoscroll like in the Java example. Setting MSChart to 2d line gets me a line graph.  
Also thanks to adg for the second to last example which was his. I think the aikimark 'walk back and forth thru the data' program does it for me. I think that I'd have to use the picturebox control to get away from whatever flickering redraws create, so I'll dig for some web-tutorials on that.