vb.netradio-buttonpaint

Paint multiple radiobuttons based on variable


I've got multiple radio buttons and want to paint them based on a variable.

The base code I've found here: Changing 'lamp' Colour Indicator within the Graphical User Interface (Visual Studio 2019)

Now this one works for 1 radiobutton, but as I stated, I've multiple.

My code looks:

Private Sub cbStart_CheckedChanged(sender As Object, e As EventArgs) Handles cbStartEDD.CheckedChanged

    rbEDD.ForeColor = Color.White
    rbEDD.ForeColor = Color.Black
    rbCV.ForeColor = Color.White
    rbCV.ForeColor = Color.Black

End Sub

Private Sub rbEDD_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles rbEDD.Paint, rbCV
    If cbStart = -1 Then
        e.Graphics.FillEllipse(Brushes.Red, New RectangleF(1, 1, 10, 10))
    Else If cbStart =0 then
        e.Graphics.FillEllipse(Brushes.Orange, New RectangleF(1, 1, 10, 10))
    Else
        e.Graphics.FillEllipse(Brushes.Green, New RectangleF(1, 1, 10, 10))
    End If
End Sub

So, when I change/click the checkbox, all radio buttons.

What I can do is: a sub for every radiobutton:

Private Sub cbStart_CheckedChanged(sender As Object, e As EventArgs) Handles cbStartEDD.CheckedChanged

    rbEDD.ForeColor = Color.White
    rbEDD.ForeColor = Color.Black
    rbCV.ForeColor = Color.White
    rbCV.ForeColor = Color.Black

End Sub

Private Sub rbEDD_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles rbEDD.Paint
    If cbSV = -1 Then
        e.Graphics.FillEllipse(Brushes.Red, New RectangleF(1, 1, 10, 10))
    Else If cbSV =0 then
        e.Graphics.FillEllipse(Brushes.Orange, New RectangleF(1, 1, 10, 10))
    Else
        e.Graphics.FillEllipse(Brushes.Green, New RectangleF(1, 1, 10, 10))
    End If
End Sub

Private Sub rbCV_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles rbCV.Paint
    If cbCV = -1 Then
        e.Graphics.FillEllipse(Brushes.Red, New RectangleF(1, 1, 10, 10))
    Else If cbStart =0 then
        e.Graphics.FillEllipse(Brushes.Orange, New RectangleF(1, 1, 10, 10))
    Else
        e.Graphics.FillEllipse(Brushes.Green, New RectangleF(1, 1, 10, 10))
    End If
End Sub

And what I want is one sub that when it is called that changes the color of the radiobutton variable: following code is just describing what I want to have:

Private Sub cb<Name of the checkbox>_CheckedChanged(sender As Object, e As EventArgs) Handles cb<Name of the checkbox>.CheckedChanged

    Call buttoncolor(<name of the radiobutton>, <statusvalue(-1,0 or 1)>)

End Sub

Private Sub buttoncolor(radiobutton As Object, status As Integer) 
    If status = -1 Then
        ' do following to the radiobutton object
        radiobutton.e.Graphics.FillEllipse(Brushes.Red, New RectangleF(1, 1, 10, 10))
    Else If status = 0 then
        radiobutton.e.Graphics.FillEllipse(Brushes.Orange, New RectangleF(1, 1, 10, 10))
    Else
        radiobutton.e.Graphics.FillEllipse(Brushes.Green, New RectangleF(1, 1, 10, 10))
    End If
End Sub

Is there an easy way to do it or do I have to copy&paste the Paint-sub many times?


Solution

  • You need to keep the graphics in the Paint event because as you may have seen, you only have access to the graphics object there. You can access it elsewhere but the Paint event will override whatever you do outside of it. But you can make one handler for both RadioButtons' Paint events, note the Handles rbCV.Paint, rbEdd.Paint

    Add a dictionary to maintain a relationship between RadioButtons and CheckBoxes

    Private radioToCheck As New Dictionary(Of RadioButton, CheckBox)()
    
    Private Sub Form_Load() Handles Me.Load
        radioToCheck.Add(rbEdd, cbSV)
        radioToCheck.Add(rbCV, cbCV)
    End Sub
    

    Then the Paint event can handle multiple RadioButtons' Paint events

    Private Sub rb_Paint(sender As Object, e As PaintEventArgs) Handles rbCV.Paint, rbEdd.Paint
        Dim b As Brush
        Select Case radioToCheck(DirectCast(sender, RadioButton)).CheckState - 1
            Case -1 : b = Brushes.Red
            Case 0 : b = Brushes.Orange
            Case Else : b = Brushes.Green
        End Select
        e.Graphics.FillEllipse(b, New RectangleF(1, 1, 10, 10))
    End Sub
    

    I took a liberty in determining how status comes from the CheckBox, because cbCV = -1 won't work - a CheckBox can't equal -1. I guess it's the CheckState - 1, as a CheckBox has three states {0, 1, 2} and your status are {-1, 0, 1}. If that's wrong, you can change the logic radioToCheck(rb).CheckState - 1 to a function to get the status given the CheckBox.

    Ideally, the state is not stored in the UI, and you would use some model to represent the state and the UI is updated when the state changes, and is used to update the state. On a small scale, what you're doing is fine, but it will be very clumsy and the UI may become sluggish as you scale up.