Redrawing a line

mattps

Member
Joined
Aug 20, 2010
Messages
6
Programming Experience
Beginner
Can anyone help me. I have written an application that queries Active Directory for a list of server objects, then one by one system information such free RAM, CPU usage is queries and automatically added to a form using the Dim xxx new xxx approach.
What I would like to do next is add gauges to show graphically what resources are being used/free. I started by adding a LineShape dynamically but the quickly realised that this was difficult to manipulate when created a runtime. I have got all tied up and now don't where to go next. In a nutshell this is what I want to achieve and just need a nudge in teh right direction:

Query AD for server objects
Loop through results and draw gauges
Refresh gauges periodically

Any help would greatly appreciated.

Mat
 
Draw your line using GDI+. Handle the Paint event of the appropriate control and call e.Graphics.DrawLine. When you want to change the line, change the data that describes the line as appropriate and then call the Refresh or Invalidate and Update methods of the control. It's preferable to do the latter because it's more efficient to repaint as small an area as possible. If it's not too often though, you can take the lazy option, as Refresh means that you don't have to calculate the area(s) that's changed.
 
I more or less had the same approach. However, as each server is enumerated and it's appropriate gauge is drawn I can see the needle being drawn but at the end after all the gauges are drawn their needs suddenly drop to a horizontal position (zero on the gauge).
 
Right, as I said server objects are enumerated from Active Directory. When found the following sub is executed to draw a blank gauge:

VB.NET:
    Sub DrawCPUGauge(ByVal i As Integer, ByVal ComputerName As String)
        Dim connection As New ConnectionOptions
        Dim y As Integer = 0
        Dim CPULoad As Integer = 0
        Dim TotalCPULoad As Integer = 0
        Dim NewCPUGauge As New System.Windows.Forms.Panel()
        Dim NewCPULabel As New System.Windows.Forms.Label()
        Dim NewCPUValLabel As New System.Windows.Forms.Label()
        Dim CPUcanvas As New Microsoft.VisualBasic.PowerPacks.ShapeContainer
        Dim NewCPUNeedle As New Microsoft.VisualBasic.PowerPacks.LineShape
        NewCPUGauge.Name = "Pnl_CPU_" & i
        NewCPUGauge.BackgroundImage = Image.FromFile("c:\gauge3.jpg")
        NewCPUGauge.Size = New System.Drawing.Size(46, 24)
        NewCPUGauge.Location = New System.Drawing.Point(281, 31)
        AddHandler NewCPUGauge.MouseMove, AddressOf Dashboard1_MouseMove
        CPUcanvas.Parent = NewCPUGauge
        Me.Controls.Find("Pnl_" & ComputerName, True)(0).Controls.Add(NewCPUGauge)
        NewCPUNeedle.Name = "Needle_CPU_" & i
        NewCPUNeedle.BorderWidth = 3
        NewCPUNeedle.BorderColor = Color.Red
        AddHandler NewCPUGauge.Paint, AddressOf Panel7_Paint
        NewCPUNeedle.Parent = CPUcanvas
        NewCPULabel.Name = "Lbl_CPU_" & i
        NewCPULabel.Size = New System.Drawing.Size(41, 14)
        NewCPULabel.Location = New System.Drawing.Point(286, 14)
        NewCPULabel.Font = New Font("Arial", 8.25, FontStyle.Regular)
        NewCPULabel.ForeColor = Color.SandyBrown
        NewCPULabel.BackColor = Color.FromArgb(64, 64, 64)
        NewCPULabel.Text = "CPU %"
        Me.Controls.Find("Pnl_" & ComputerName, True)(0).Controls.Add(NewCPULabel)
        NewCPUValLabel.Name = "Lbl_CPU_Val_" & i
        NewCPUValLabel.Text = "xxx %"
        NewCPUValLabel.Size = New System.Drawing.Size(46, 14)
        NewCPUValLabel.Location = New System.Drawing.Point(286, 56)
        NewCPUValLabel.Font = New Font("Arial", 8.25, FontStyle.Regular)
        NewCPUValLabel.ForeColor = Color.SandyBrown
        NewCPUValLabel.BackColor = Color.FromArgb(64, 64, 64)
        Me.Controls.Find("Pnl_" & ComputerName, True)(0).Controls.Add(NewCPUValLabel)
    End Sub

Then the following is executed to the get the data:

VB.NET:
Sub ProcessorUsage(ByVal RemoteComputer)
        Dim connection As New ConnectionOptions
        Dim ComputerName As String
        Dim y As Integer = 0
        Dim CPULoad As Integer = 0
        Dim TotalCPULoad As Integer = 0
        connection.Username = "username"
        connection.Password = "password"
        connection.Authority = "ntlmdomain:domainname"
        ComputerName = RemoteComputer
        Dim scope As New ManagementScope("\\" & ComputerName & "\root\CIMV2", connection)
        scope.Connect()
        Dim query As New ObjectQuery("SELECT * FROM Win32_Processor")
        Dim searcher As New ManagementObjectSearcher(scope, query)
        For Each queryObj As ManagementObject In searcher.Get()
            y += 1
            CPULoad = (queryObj("LoadPercentage"))
            TotalCPULoad += CPULoad
        Next
        GaugeValue = TotalCPULoad / y
        Me.Controls.Find("Pnl_" & ComputerName, True)(0).Controls.Find("Lbl_CPU_Val_" & i, True)(0).Text = GaugeValue & " %"
        Gauge = "CPU"
        Me.Controls.Find("Pnl_" & ComputerName, True)(0).Controls.Find("Pnl_CPU_" & i, True)(0).Refresh()
    End Sub

The handler for the paint function looks like this:

VB.NET:
 Sub Panel7_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel7.Paint
        Dim Needle As New Pen(Color.Red, 2)
        Dim x2, y2 As Integer
        DegreeValue = (180 / 100) * GaugeValue
        y2 = (Math.Sin((DegreeValue / 57.2957) - 1.57) * 23) + 24 ' Sin(Radians) - 90deg * Radius + relative value of centre point
        x2 = (Math.Cos((DegreeValue / 57.2957) - 1.57) * 23) + 0
        e.Graphics.DrawLine(Needle, 23, 24, x2, y2)
    End Sub

The problem is that the gauges are all drawn (the all apear to have the same values however) and then the lines disappear almost immediately after execution.
 
I think I have worked out what was causing the problem :). I think (correct me here if I am off the mark) that the problem was that I was calling the gauge drawing routine and needle drawing routine from the Form Load sub. Everything was being created then the Form Load would reach the end and refresh the form causing everything that I had drawn to be removed.
To test, I moved the drawing routines to a timer control and set the interval to fire well after the form has displayed. It worked - kind off. The needles are drawn but the are all showing the same values. Could this be that they are all using the same handler?
Is there a way around this? Also if I want to redraw the needles do I have have to "clear" the old ones first or can I just reference the new values to them?

Thanks,
Matt
 
GDI+ drawing is not completely intuitive but the principles are very simple. You do ALL drawing on controls on that controls Paint event. That means either in that controls OnPaint method or in a Paint event handler. Do not do any drawing anywhere else. Note that I consider methods called from those two places to be part of those two places. Use member variables to store all the data that describes your drawing, e.g. Points, Sizes, Colors, etc. In the OnPaint method or Paint event handler, call methods on the e.Graphics object to do your drawing. Whenever you want to change the drawing, change the aforementioned member variables and then force the Paint event to be raised by calling Refresh or, preferably, Invalidate and Update.
 
Back
Top