Author Topic: rotational indicator arrow  (Read 1787 times)

MrPike

  • Sr. Member
  • ****
  • Posts: 297
    • View Profile
rotational indicator arrow
« on: February 07, 2018, 10:36:47 PM »
Is it possible to change the arrow on the rotational indicator to something else?  i would like just a straight line that i can adjust the length/width of.  I'm really not a fan of the arrow graphic.  is this something that can be done?  thanks.  AHMI399x(latest download)

Godra

  • Hero Member
  • *****
  • Posts: 1436
    • View Profile
Re: rotational indicator arrow
« Reply #1 on: February 07, 2018, 11:07:30 PM »
As an experiment, you could try modifying the code in the files posted here: https://www.advancedhmi.com/forum/index.php?topic=1143.0

Give a different name to the class if it conflicts with current control.
« Last Edit: May 19, 2019, 10:03:33 PM by Godra »

MrPike

  • Sr. Member
  • ****
  • Posts: 297
    • View Profile
Re: rotational indicator arrow
« Reply #2 on: February 08, 2018, 08:15:23 PM »
Hi Godra.  I looked at this code and I don't see how this changes the appearance of the pointer.  I see that it adds a property, but am I missing something?  I know it's way over my head but how would I view the source code for this control?  I would think there is some OnPaint method that draws the pointer???? Any help is greatly appreciated.  BTW, I am trying to achieve something like the pic attached, thanks.   

Godra

  • Hero Member
  • *****
  • Posts: 1436
    • View Profile
Re: rotational indicator arrow
« Reply #3 on: February 08, 2018, 10:12:43 PM »
You cannot change the code for the built-in RotationalIndicator control, since its base control is inside the dll file.

If you follow Archie's instructions from the provided link then you will add another 2 controls to the project, which will be named RotationalPositionIndicator and RotationalIndicatorHMI. If you check the code of the RotationalPositionIndicator control, there is this section inside RefreshImage() sub:

Code: [Select]
        '********************************************
        '* Arrow
        '********************************************
        CurvedArrowBottomBounds = New Rectangle(New Point(CInt(Me.Width / 2.0F - m_ArrowWidth / 2.0F), CInt(Me.Height / 2 - m_ArrowWidth / 2.0F)), _
                                         New Size((m_ArrowWidth), (m_ArrowWidth)))

        '* Draw Arrow pointing to right
        '* Top left
        ArrowPoints(0) = New PointF(Me.Width / 2.0F, Me.Height / 2.0F - m_ArrowWidth / 2.0F) ' Me.Height * 3.1F / 7.0F)
        ArrowPoints(1) = New PointF(Me.Width * 5.25F / 7.0F, Me.Height / 2.0F - m_ArrowWidth / 2.0F)
        ArrowPoints(2) = New PointF(Me.Width * 5.25F / 7.0F, Me.Height / 2.0F - m_ArrowWidth) ' Me.Height * 6.0F / 16.0F)
        '* Arrow Tip
        ArrowPoints(3) = New PointF(Me.Width - (Me.Width - InnerCircleBounds.Width) / 2.0F, Me.Height / 2.0F) '* 3.0F / 7.0F)
        ArrowPoints(4) = New PointF(Me.Width * 5.25F / 7.0F, Me.Height / 2.0F + m_ArrowWidth) ' Me.Height * 10.0F / 16.0F)
        ArrowPoints(5) = New PointF(Me.Width * 5.25F / 7.0F, Me.Height / 2.0F + m_ArrowWidth / 2.0F)
        '* Bottom Left
        ArrowPoints(6) = New PointF(Me.Width / 2.0F, Me.Height / 2.0F + m_ArrowWidth / 2.0F)

These points are defined as (x, y) coordinates, where x goes from left to right and y goes from top to bottom.

If, for example, you make ArrowPoints(4) equal to ArrowPoints(3) and rebuild the project then you should be able to see how it changed the appearance of the control's arrow (provided you dropped this control on the form initially).

As another example, set --> Private ArrowPoints(3) As PointF, then comment out ArrowPoints(2), ArrowPoints(3) and ArrowPoints(4), then rename ArrowPoints(5) to ArrowPoints(2) and also ArrowPoints(6) to ArrowPoints(3) --> this should give you what you seem to be looking for.

You can always manipulate other parts of these points for different appearances, or create some new property whose value you could use to let's say change the length by adding it to x coordinate of ArrowPoints(1) and ArrowPoints(2) in the previous example (this since the arrow is initially drawn as pointing to the right).

That's how you would go about experimenting.

Make sure to read the rest of the posts to also add the missing property if needed.

All together, it is possible to make things look like the attached picture where OrientedTextLabel was also added as a control to the RotationalPositionIndicator by properly sizing and positioning both controls in the upper left corner of the form and then using this code:

Code: [Select]
    Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.RotationalPositionIndicator21.Controls.Add(Me.OrientedTextLabel1)
    End Sub

The RotationalPositionIndicator control can be positioned anywhere on the form. The upper left corner would be used for a bit easier sizing & positioning and once the desired look is achieved then just move the RotationalPositionIndicator control and leave the OrientedTextLabel control where it is.

Do let me know if you need any more information.
« Last Edit: February 20, 2018, 07:54:31 AM by Godra »

MrPike

  • Sr. Member
  • ****
  • Posts: 297
    • View Profile
Re: rotational indicator arrow
« Reply #4 on: February 10, 2018, 06:03:28 PM »
Thanks Godra, I was able to get what I needed(attached) by some crude methods and experimenting.  I guess I thought the improved version of the control was in the latest version of AHMI so I did not know that code was there.  I did notice the property to hide the outer circle was not in Archie's version.  Also, the modifications to this code affects all copies of the control.  How can I add a property that allows me to adjust the length of the pointer individually?.  Thank you.   

Godra

  • Hero Member
  • *****
  • Posts: 1436
    • View Profile
Re: rotational indicator arrow
« Reply #5 on: February 10, 2018, 08:37:03 PM »
You can add a property like this one:

Code: [Select]
    Private m_ArrowLength As Integer = 75
    <Browsable(True), RefreshProperties(RefreshProperties.All), Description("The arrow length."), DefaultValue(75), System.ComponentModel.Category("Appearance")> _
    Public Property RPI_ArrowLength As Integer
        Get
            Return m_ArrowLength
        End Get
        Set(value As Integer)
            If m_ArrowLength <> value Then
                m_ArrowLength = Math.Max(5, Math.Min(100, value))
                RefreshImage()
            End If
        End Set
    End Property

and then use it like this:

Code: [Select]
        ArrowPoints(0) = New PointF(Me.Width / 2.0F, Me.Height / 2.0F - m_ArrowWidth / 2.0F)
        ArrowPoints(1) = New PointF(Me.Width / 2.0F + m_ArrowLength * 0.9F * (Me.Width / 200.0F), Me.Height / 2.0F - m_ArrowWidth / 2.0F)
        ArrowPoints(2) = New PointF(Me.Width / 2.0F + m_ArrowLength * 0.9F * (Me.Width / 200.0F), Me.Height / 2.0F + m_ArrowWidth / 2.0F)
        ArrowPoints(3) = New PointF(Me.Width / 2.0F, Me.Height / 2.0F + m_ArrowWidth / 2.0F)


This length property would go from 5 to 100, kind of representing the percentage of (9/10 * Width/2), because the needle is drawn from the center and it cannot be longer than 1/2 of the width of the control, I have decided to limit the needle showing up to 9/10 of its possible full length so it doesn't cover the outer circle.
 
You could probably figure out a bit different way with different numbers (ex. if you want the property value to go from 0 to 1).


If you want to be able to hide the outer circle then add a property like this:

Code: [Select]
    Private m_ShowOuterCircle As Boolean = True
    <Browsable(True), RefreshProperties(RefreshProperties.All), Description("Show target bands."), DefaultValue(True) _
    , System.ComponentModel.Category("Appearance")> _
    Public Property ShowOuterCircle As Boolean
        Get
            Return m_ShowOuterCircle
        End Get
        Set(value As Boolean)
            If m_ShowOuterCircle <> value Then
                m_ShowOuterCircle = value
                RefreshImage()
            End If
        End Set
    End Property

and then look for the comment "Outside Circle" and use the property value like this:

Code: [Select]
            If m_ShowOuterCircle Then
                '* Outside circle
                g.FillEllipse(GetOuterRingColors, OuterCircleBounds)
            End If

« Last Edit: February 25, 2018, 12:34:58 PM by Godra »

MrPike

  • Sr. Member
  • ****
  • Posts: 297
    • View Profile
Re: rotational indicator arrow
« Reply #6 on: February 12, 2018, 07:35:50 PM »
Thank you Godra!  You have been a big help.  I will implement this over the next few days and I will touch back if I need more help.  Thanks again

MrPike

  • Sr. Member
  • ****
  • Posts: 297
    • View Profile
Re: rotational indicator arrow
« Reply #7 on: February 19, 2018, 03:14:03 PM »
Hello again.  I have this working for the most part except I don't see a scale value for this control.  How would I implement this? thank you.  I have tried this code but it does not work. 

'scale the value from raw
    Private Sub rotindSynchscope_ValueChanged(sender As Object, e As EventArgs) Handles rotindSynchscope.ValueChanged
        rotindSynchscope.Value = rotindSynchscope.Value * 0.01
    End Sub

Godra

  • Hero Member
  • *****
  • Posts: 1436
    • View Profile
Re: rotational indicator arrow
« Reply #8 on: February 19, 2018, 05:38:14 PM »
You could possibly try using these properties (modify or replace the existing Value property and add the new ValueScaleFactor property):

Code: [Select]
    Private m_string As String = "0" & "°"
    Private m_Value As Double = 0.0F
    <Browsable(True), RefreshProperties(RefreshProperties.All), _
    Description("Indicates the actual received arrow angle value in degrees. It could be any double-precision floating point value."), DefaultValue(0.0F)> _
    Public Property Value() As Double
        Get
            Return Me.m_Value
        End Get
        Set(ByVal value As Double)
            If Me.m_Value <> value Then
                Me.m_Value = value
                OnValueChanged(System.EventArgs.Empty)
                Me.Invalidate()
            End If
        End Set
    End Property

    Private m_ValueScaleFactor As Double = 1.0F
    <Browsable(True), RefreshProperties(RefreshProperties.All), Description("Value scale factor."), DefaultValue(1.0F)> _
    Public Property ValueScaleFactor As Double
        Get
            Return m_ValueScaleFactor
        End Get
        Set(value As Double)
            If value <= 0 Then value = 1
            If m_ValueScaleFactor <> value Then
                m_ValueScaleFactor = value
                Me.Invalidate()
            End If
        End Set
    End Property

and then modify the OnPaint sub, in the Events region, to look like this (or just replace it):

Code: [Select]
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        '* Prevent an exception if RefreshImage was not called
        If ForeColorBrush Is Nothing Then Exit Sub

        e.Graphics.SmoothingMode = SmoothingMode.HighQuality

        '* Static Back Image
        e.Graphics.DrawImage(BackImage, 0, 0)


        If Not String.IsNullOrEmpty(Me.Text) Then
            e.Graphics.DrawString(Me.Text, Me.Font, ForeColorBrush, New Point(CInt(Me.Width / 2.0F), CInt(Me.Height * 0.55)), sf)
        End If

        '*************************************
        '* Draw the Arrow
        '*************************************
        e.Graphics.TranslateTransform(CSng(Me.ClientRectangle.Width) / 2.0F, CSng(Me.ClientRectangle.Height) / 2.0F)
        e.Graphics.RotateTransform(CSng(Me.m_Value * m_ValueScaleFactor - CSng(Me.m_zeroPosition)))
        e.Graphics.TranslateTransform(-CSng(Me.ClientRectangle.Width) / 2.0F, -CSng(Me.ClientRectangle.Height) / 2.0F)

        e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
        e.Graphics.FillEllipse(ArrowGradientBrush, CurvedArrowBottomBounds)
        e.Graphics.FillPolygon(ArrowGradientBrush, ArrowPoints)

        '***************************************
        e.Graphics.ResetTransform()

        Me.m_string = String.Format(CStr(CDec(Me.m_Value * m_ValueScaleFactor) Mod CDec(360.0F)), "0") & "°"
        e.Graphics.DrawString(Me.m_string, Me.Font, ForeColorBrush, New Point(CInt(Me.Width / 2.0F), CInt(Me.Height * 2.0F / 3.0F)), sf)
    End Sub

Do observe all locations of the "°" character in case if you wanted it to be "%".

This Value suffix can also be changed from within the Designer if you add a property like this:

Code: [Select]
    Private m_ValueSuffix As String = "°"
    <Browsable(True), RefreshProperties(RefreshProperties.All), Description("Value suffix to show on the control."), DefaultValue("°")> _
    Public Property ValueSuffix As String
        Get
            Return Me.m_ValueSuffix
        End Get
        Set(ByVal value As String)
            If String.Compare(Me.m_ValueSuffix, value) <> 0 Then
                Me.m_ValueSuffix = value
                Me.Invalidate()
            End If
        End Set
    End Property

and modify the following 2 lines of code:

Code: [Select]
    Private m_string As String = "0" & "°"

to this

    Private m_string As String = "0" & m_ValueSuffix

Code: [Select]
        Me.m_string = String.Format(CStr(CDec(Me.m_Value * m_ValueScaleFactor) Mod CDec(360.0F)), "0") & "°"

to this

        Me.m_string = String.Format(CStr(CDec(Me.m_Value * m_ValueScaleFactor) Mod CDec(360.0F)), "0") & m_ValueSuffix
« Last Edit: February 25, 2018, 12:39:30 PM by Godra »

Godra

  • Hero Member
  • *****
  • Posts: 1436
    • View Profile
Re: rotational indicator arrow
« Reply #9 on: February 24, 2018, 03:50:12 PM »
Attached in this post is the RotationalPositionIndicator AHMI control which includes all these changes mentioned in the previous posts of this topic.

It also has the ability to show the arrow at the end of the needle and has the compass directions color property as well so it can look like the attached picture.

It is the AHMI control with all the PLC related properties so it doesn't require any other files (just add it as existing item to your project and off you go).

It is Mono compatible AHMI control.

MrPike can explain what he did to get the background look the way it looks in his pictures.
« Last Edit: May 19, 2019, 10:04:45 PM by Godra »