Using VB.NET timer in plotting a curve

Omnibus
06-21-2004, 11:40 AM
I am trying to display on a graph, using VB.NET, points corresponding to data I am getting from an external device. The data is collected every minute so I have set the timer to trigger the acquisition and the display of data every minute. Unfortunately, every time the timer is triggered it causes only the new point to be displayed and the old one is erased. Thus, I cannot obtain a continuous curve on the screen but only see one point moving as the data keeps acquiring. Is there a way to retain the previous view of the screen when plotting the new point when using a timer (this is the opposite of the usual application of a timer in programming a digital clock)?

Iceplug
06-21-2004, 12:08 PM
The previous view of the screen should remain, unless you have told the Graphics object to clear the display. What is the Graphics object drawing to?
How are you drawing your points?

Omnibus
06-21-2004, 12:41 PM
I am using the GDI method described in http://www.visualbasicforum.com/showthread.php?t=147590

Iceplug
06-21-2004, 12:45 PM
There are tons of examples there. Which one are you using?

Omnibus
06-21-2004, 12:58 PM
Sorry, I didn't quote the exact example. Here it is:




Imports System.Drawing

Public Class Form1
Inherits System.Windows.Forms.Form

'The Windows-Designer code region would be here

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
'This is the declare of the Graphics object
Dim g As Graphics = e.Graphics
'Declare the pen
Dim pPen As Pen = New Pen(Color.Maroon, 4)

'Let's draw us a line
g.DrawLine(pPen, 10, 10, 110, 110)

'Declare the Rectangle
Dim rRect As Rectangle = New Rectangle(150, 150, 100, 100)

'Fill it!
g.FillRectangle(New SolidBrush(Color.Blue), rRect)
'Let's draw us a rectangle!
g.DrawRectangle(pPen, rRect)

'Dim the font
Dim fFont As Font = New Font("Verdana", 10, FontStyle.Bold)

'Draw some text
g.DrawString("Hello World! I'm GDI!", fFont, New SolidBrush(Color.Orange), 30, 10)
End Sub
End Class




To test the program I insert in the above code the following lines, which change the value of x each time the timer is triggered:




Dim obj As MyCounter
obj = New MyCounter
x = obj.Count



The timer itself has the following code:



#Region " Timer Code "
'This starts the timer
Private Sub EnableTimer(ByRef iInterval As Integer)
'Declare the callback
Dim tCallBack As New Threading.TimerCallback(AddressOf TimerTick)

'Create the timer
ThreadedTimer = New System.Threading.Timer(tCallBack, Nothing, 0, iInterval)
End Sub

'This will get rid of the timer
Private Sub DisableTimer()
'Dispose of the timer and set the object to nothing
ThreadedTimer.Dispose()
ThreadedTimer = Nothing
End Sub

'The timer callback sub
Private Sub TimerTick(ByVal State As Object)
'This will cause us to redraw the form
Me.Invalidate()
End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Enable the timer
EnableTimer(1000)
End Sub

Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
'Disable the timer
DisableTimer()
End Sub
#End Region

Iceplug
06-21-2004, 01:07 PM
Me.Invalidate() causes your form to be cleared... sometimes.
If you don't want to clear the form, you can just create your own graphics object and just draw onto the form, without using the Paint event or invalidating the form. :)

Omnibus
06-21-2004, 01:35 PM
I’m not sure I understand you correctly. I started using the said GDI method from the link because the simple way I thought initially the task could be accomplished didn’t work. Say, I wanted to draw a horizontal line. I open VB.NET and I see the template of Form1.vb whose default size is x = 292, y = 266. It turned out it was possible to draw the horizontal line with initial coordinates, say (1,1) only to final coordinates (292,1). No matter how one re-sizes Form1.vb, the end coordinates of the line can only reach (292,1). This made me look around to find a way to get around that problem. This is how I got into the example from the link I gave you.

As for the Timer code, it appears that the problem lies in it, if I understand you correctly. I tried to get rid of the Timer code I gave you in the previous post and replaced it with a timer from the Tools menu – I enabled it, gave it 1000 ms interval, enabled the rest (Advanced configuration properties) etc. but nothing happened – it does not even appear to have any Timer working when I start the program.

Iceplug
06-21-2004, 01:48 PM
You drew a line from (1,1) to some point like (1000,1) when the form was at a default size of 292 x 266?
While this immediately draws the line, you only see the line going to 292... even when the form is resized... this is probably due to the fact that you drew the line off of the form in the first place, and resizing the form doesn't fix the fact that your line was clipped by the form, so that you only see the line ending at 292. Also, if you resize the form to a width shorter than the line, the line will be clipped as well. In order to make a persistent line, you need to redraw the line in the Paint event or in some Timer control, or in the form's Resize, or probably lots of other places... while the Paint event does fire for drawing the line on the form, calling the Paint event by using Invalidate causes your form to be cleared, in some cases, which will cause anything that you have drawn to the form to be removed, as windows is cleaning the form so that you have a fresh picture to work with.

Omnibus
06-21-2004, 02:09 PM
One way to solve the problem, probably, is to set a different, larger, default size of Form1.vb (which will allow you to plot lines and points in a simpler way, without invoking GDI) and not bother resizing it. How is this setting of the new defaults done, however? I tried changing the properties of Form1.vb, but that did not change the default values of 296 x 266 upon subsequent opening of the project.

Also, I don’t know any other way of calling the Paint event except by using Invalidate. Could you suggest one? Just for the sake of trial I started choosing other calls form the help-list which pops up when trying to change “Invalidate” but nothing worked.

Omnibus
06-24-2004, 08:06 AM
I continue to struggle with the timer problem. Now I'm using the following code in a Windows Application project:

Imports System
Imports System.Threading
Imports System.Timers

Private Sub EnableTimer(ByRef iInterval As Integer)

'Create the timer
Dim aTimer As System.Timers.Timer
aTimer = New System.Timers.Timer

AddHandler aTimer.Elapsed, AddressOf OnTimer

aTimer.Interval = 100
aTimer.Enabled = True

End Sub


Public Sub OnTimer(ByVal source As Object, ByVal e As ElapsedEventArgs)

Me.Refresh()

End Sub

Unfortunately, still every next triggering of the timer causes the disappearance of the previous page. As is seen, the timer fires depending on Me.Refresh(). I have tried every possibility offered by the drop-down menu which appears when typing the command after Me. It appears that they either do not work or they erase the previous page (use, e.g. Me.Invalidate etc. to see that.) I wonder if this is not an inherent feature of VB.NET in this particular case? If so, what would be the way to trigger consecutively events in VB.NET without affecting the previous page?

Omnibus
06-26-2004, 09:24 AM
The solution turned out to be very simple and obvious – just add the data to an array at every firing of the timer and then re-paint it every time the timer fires. Another problem came up, though. Now I can’t stop the timer properly.
Any of the following

aTimer.Enabled = False

or

ThreadedTimer.Dispose()
ThreadedTimer = Nothing

gives me an error: ‘Object reference not set to an instance of an object’. I thought maybe I’m not initializing the aTimer properly and dimmed it like this: Dim aTimer As New System.Timers.Timer. It didn’t work either.

Iceplug
06-26-2004, 09:50 AM
Also, I don’t know any other way of calling the Paint event except by using Invalidate.
You don't need to call the Paint event in the first place... just draw.
Dim GFX As Graphics = Me.CreateGraphics()
Now, use GFX to draw things onto the form.
If so, what would be the way to trigger consecutively events in VB.NET without affecting the previous page?

Why do you need a paint event to tell you when to draw? The timer or button click should be enough to tell you that you need to redraw your figure.

Omnibus
06-26-2004, 03:29 PM
Agreed. I fixed that but now I can’t get the timer to stop. Here’s what I do:

The timer I’m using is the following:

Dim ThreadedTimer As System.Threading.Timer

#Region " Timer Code "

'This starts the timer
Private Sub EnableTimer(ByRef iInterval As Integer)

'Create the timer
Dim aTimer As System.Timers.Timer
aTimer = New System.Timers.Timer

AddHandler aTimer.Elapsed, AddressOf OnTimer

aTimer.Interval = 100
aTimer.Enabled = True

End Sub

Public Sub OnTimer(ByVal source As Object, ByVal e As ElapsedEventArgs)
'Timer fires ...
Me.Refresh()
End Sub

'This will get rid of the timer
Private Sub DisableTimer()
'Dispose of the timer and set the object to nothing
ThreadedTimer.Dispose()
ThreadedTimer = Nothing
End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Enable the timer
EnableTimer(100)
End Sub

Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
'Disable the timer
DisableTimer()
End Sub

#End Region

I’m creating a button:

Public Sub Button1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim aTimer As System.Timers.Timer
aTimer = New System.Timers.Timer

aTimer.Enabled = False

ThreadedTimer.Dispose()
ThreadedTimer = Nothing

End Sub

but the system crashes and the following error message pops up when I click the button and try to stop the timer:

An unhandled exception of type 'System.NullReferenceException' occurred in Graphing Project.exe

Additional information: Object reference not set to an instance of an object.

Omnibus
06-26-2004, 08:29 PM
I solved this problem again in a very simple way. I abandoned the code I posted earlier and resorted to the drag-n-drop timer tool available in VB.NET. And then, of course, I placed Timer1.Enabled = False in the Stop button code. All seems to work fine now.

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum