Menu

Components

Help
Mike
2010-08-26
2013-11-19
1 2 > >> (Page 1 of 2)
  • Mike

    Mike - 2010-08-26

    Hi!  First off, great work.  I've been trying to find a way to add better graphics to my Panelviews without a lot of luck.  This solution is a step in the right direction.  My question is whether you could provide a tutorial on creating components.  I've been trying to modify yours without much luck.

    Thanks!

     
  • Archie

    Archie - 2010-08-26

    Building components can get very complex. The best thing to do is to start by making a copy of a component that is closest to the one you want to create. You would create the graphics in PNG format and add them to the resources of the project. You can them search the code for the references of the graphic and change it to your newly created graphic.

    If you give me an idea of what you want to create and what problems you are running into, I can give you more specific help.

     
  • Mike

    Mike - 2010-08-26

    Thats what I tried to do. :)  I used your pilot light component.  I was trying to do a simple switch of two duplicate graphics with different gradients to simulate rotation, like you did with the motor shaft.  On my last attempt before posting, I just went through and changed the references to redlightoff/on and what not but I get an error when I try to put it on the form.

    Imports System.Drawing
    '*******************************************************************************
    '* 2-MAY-09 Added ReverseLogic and PLCAddressForButton
    '*********************************************************************************
    Public Class Screw
        Inherits System.Windows.Forms.UserControl

        Private StaticImage As Bitmap
        Private ButtonImage, LightOnImage, LightOffImage As Bitmap
        Private TextRect As New Rectangle
        Private ImageRatio As Single
        Private m As New System.Drawing.Drawing2D.Matrix

    #Region "Properties"
        Private m_Value As Single
        Public Property Value() As Boolean
            Get
                Return m_Value
            End Get
            Set(ByVal value As Boolean)
                If value <> m_Value Then
                    m_Value = value

                    If (m_Value Xor Not m_ReverseLogic) Then
                        ButtonImage = LightOffImage
                    Else
                        ButtonImage = LightOnImage
                    End If
                    Me.Invalidate()

                    Me.Invalidate(New Rectangle(Me.Width * 0.14, Me.Height * 0.14, Me.Width * 0.72, Me.Height * 0.63))
                End If
            End Set
        End Property

        Private m_ReverseLogic As Single
        Public Property ReverseLogic() As Boolean
            Get
                Return m_ReverseLogic
            End Get
            Set(ByVal value As Boolean)
                If value <> m_ReverseLogic Then
                    m_ReverseLogic = value

                    If (m_Value Xor Not m_ReverseLogic) Then
                        ButtonImage = LightOnImage
                    Else
                        ButtonImage = LightOffImage
                    End If
                    Me.Invalidate()

                    Me.Invalidate(New Rectangle(Me.Width * 0.14, Me.Height * 0.14, Me.Width * 0.72, Me.Height * 0.63))
                End If
            End Set
        End Property

        '*****************************************
        '* Property - Color and type of button
        '*****************************************
        Public Enum ButtonColors
            Red
            Green
        End Enum
        Private m_ButtonColor As ButtonColors = ButtonColors.Green
        Public Property ButtonColor() As ButtonColors
            Get
                Return (m_ButtonColor)
            End Get
            Set(ByVal value As ButtonColors)
                m_ButtonColor = value
                RefreshImage()
                Me.Invalidate()
            End Set
        End Property

        '*****************************************
        '* Property - Text on Legend Plate
        '*****************************************
        Private m_LegendText As String = "Text"
        Public Property LegendText() As String
            Get
                Return m_LegendText
            End Get
            Set(ByVal value As String)
                m_LegendText = value
                RefreshImage()
                Me.Invalidate()
            End Set
        End Property

        '*****************************************************
        '* Property - Component to communicate to PLC through
        '*****************************************************
        Private m_CommComponent As ICommComponent
        Public Property CommComponent() As ICommComponent
            Get
                Return m_CommComponent
            End Get
            Set(ByVal value As ICommComponent)
                m_CommComponent = value
            End Set
        End Property

        '*****************************************
        '* Property - Address in PLC to Link to
        '*****************************************
        Private m_PLCaddress As String = "B3/0"
        Public Property PLCaddress() As String
            Get
                Return m_PLCaddress
            End Get
            Set(ByVal value As String)
                m_PLCaddress = value
            End Set
        End Property

        Private m_PLCaddressForButton As String = "B3/1"
        Public Property PLCaddressForButton() As String
            Get
                Return m_PLCaddressForButton
            End Get
            Set(ByVal value As String)
                m_PLCaddressForButton = value
            End Set
        End Property

        '*****************************************
        '* Property - What to do to bit in PLC
        '*****************************************
        Public Enum OutputTypes
            MomentarySet
            MomentaryReset
            SetTrue
            SetFalse
            Toggle
        End Enum
        Private m_OutputType As OutputTypes = OutputTypes.MomentarySet
        Public Property OutputType() As OutputTypes
            Get
                Return m_OutputType
            End Get
            Set(ByVal value As OutputTypes)
                m_OutputType = value
            End Set
        End Property

        '* This is necessary to make the background draw correctly
        '*  http://www.bobpowell.net/transcontrols.htm
        '*part of the transparent background code
        Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
            Get
                Dim cp As System.Windows.Forms.CreateParams = MyBase.CreateParams
                cp.ExStyle = cp.ExStyle Or 32
                Return cp
                Return MyBase.CreateParams
            End Get
        End Property
    #End Region

    #Region "Events"
        'UserControl overrides dispose to clean up the component list.
        <System.Diagnostics.DebuggerNonUserCode()> _
        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            Try
                If disposing And m_CommComponent IsNot Nothing Then
                    m_CommComponent.UnSubscribe(NotificationID)
                End If
            Finally
                MyBase.Dispose(disposing)
            End Try
        End Sub

        '* This is part of the transparent background code and it stops flicker
        Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
            'MyBase.OnPaintBackground(e)
        End Sub

        '*************************************************************************
        '* Manually double buffer in order to allow a true transparent background
        '**************************************************************************
        Private _backBuffer As Bitmap
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            If StaticImage Is Nothing Or _backBuffer Is Nothing Then Exit Sub

            Dim g As Graphics = Graphics.FromImage(_backBuffer)

            g.DrawImage(StaticImage, 0, 0)

            g.DrawImage(ButtonImage, CInt((StaticImage.Width / 2 - ButtonImage.Width / 2)), CInt(StaticImage.Height * 0.43))

            'Copy the back buffer to the screen
            e.Graphics.DrawImage(_backBuffer, 0, 0)
        End Sub

        Private WithEvents tmrError As New Timer

        '****************************
        '* Event - Mouse Down
        '****************************
        Private Sub MomentaryButton_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
            'Exit Sub

            'ButtonImage = LightOnImage
            'Me.Invalidate()

            '*** TODO:
            Try
                'Select Case m_OutputType
                '    Case OutputTypes.MomentarySet : m_CommComponent.WriteData(m_PLCaddress, 1)
                '    Case OutputTypes.MomentaryReset : m_CommComponent.WriteData(m_PLCaddress, 0)
                '    Case OutputTypes.SetTrue : m_CommComponent.WriteData(m_PLCaddress, 1)
                '    Case OutputTypes.SetFalse : m_CommComponent.WriteData(m_PLCaddress, 0)
                '    Case OutputTypes.Toggle
                Dim CurrentValue As Boolean
                CurrentValue = m_CommComponent.ReadAny(m_PLCaddressForButton)
                If CurrentValue Then
                    m_CommComponent.WriteData(m_PLCaddressForButton, 0)
                Else
                    m_CommComponent.WriteData(m_PLCaddressForButton, 1)
                End If
                'End Select

                If tmrError.Enabled Then
                    tmrError.Enabled = False
                End If
            Catch
                '* Start the message flashing
                tmrError.Enabled = True
            End Try
        End Sub

        '****************************
        '* Event - Mouse Up
        '****************************
        Private Sub MomentaryButton_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
            Exit Sub

            ButtonImage = LightOffImage
            Me.Invalidate()

            Try
                Select Case m_OutputType
                    'Case OutputTypes.MomentarySet : m_CommComponent.WriteData(m_PLCaddress, 0)
                    'Case OutputTypes.MomentaryReset : m_CommComponent.WriteData(m_PLCaddress, 1)
                End Select
                'tmrError.Enabled = False
            Catch
                tmrError.Enabled = True
            End Try

        End Sub

        '********************************************************************
        '* When an instance is added to the form, set the comm component
        '* property. If a comm component does not exist, add one to the form
        '********************************************************************
        Protected Overrides Sub OnCreateControl()
            MyBase.OnCreateControl()

            If Me.DesignMode Then
                'If Me Is Nothing OrElse Me.Parent Is Nothing OrElse Me.Parent.Site Is Nothing Then Exit Sub

                '********************************************************
                '* Search for ICommComponent component in parent form
                '* If one exists, set the client of this component to it
                '********************************************************
                Dim i = 0
                Dim j As Integer = Me.Parent.Site.Container.Components.Count - 1
                While m_CommComponent Is Nothing And i < j
                    If Me.Parent.Site.Container.Components(i).GetType.GetInterface("ICommComponent") IsNot Nothing Then m_CommComponent = Me.Parent.Site.Container.Components(i)
                    i += 1
                End While

                '************************************************
                '* If no comm component was found, then add one and
                '* point the CommComponent property to it
                '*********************************************
                If m_CommComponent Is Nothing Then
                    Me.Parent.Site.Container.Add(New DF1Comm)
                    m_CommComponent = Me.Parent.Site.Container.Components(Me.Parent.Site.Container.Components.Count - 1)
                End If
            End If
        End Sub

        Private WithEvents SetupDelay As New Timer
        Private Sub Meter_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If Not Me.DesignMode Then
                If m_CommComponent IsNot Nothing And m_PLCaddress.Length > 0 Then
                    SetupDelay.Enabled = True
                End If
            End If
        End Sub

        Private NotificationID As Integer
        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SetupDelay.Tick
            If IsHandleCreated Then
                SetupDelay.Enabled = False
                NotificationID = m_CommComponent.Subscribe(Me.m_PLCaddress, 1, AddressOf PolledDataReturned)

                If NotificationID < 0 Then
                    LegendText = "INVALID PLC ADDRESS!"
                End If

                SetupDelay.Dispose()
                SetupDelay = Nothing
            End If
        End Sub

        Private Sub PolledDataReturned(ByVal Values() As String)
            Try
                Value = Values(0)
            Catch
                If Values(0).Length < 10 Then
                    LegendText = "INVALID VALUE!"
                Else
                    LegendText = Values(0)
                End If
            End Try
        End Sub

        Private Sub tmrError_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrError.Tick
            'If Label1.Text = m_LegendText Then
            '    Label1.Text = "COMM ERROR!"
            'Else
            '    Label1.Text = m_LegendText
            'End If
        End Sub
    #End Region

        'Private NamePlateRatio As Single = My.Resources.NamePlate.Height / My.Resources.NamePlate.Width
        Private LegendPlateRatio As Single = My.Resources.screw1.Height / My.Resources.screw1.Width
        Private LastWidth, LastHeight As Integer
        Private Sub MomentaryButton_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
            If LastHeight < Me.Height Or LastWidth < Me.Width Then
                If Me.Height / Me.Width > LegendPlateRatio Then
                    Me.Width = Me.Height / LegendPlateRatio
                Else
                    Me.Height = Me.Width * LegendPlateRatio
                End If
            Else
                If Me.Height / Me.Width > LegendPlateRatio Then
                    Me.Height = Me.Width * LegendPlateRatio
                Else
                    Me.Width = Me.Height / LegendPlateRatio
                End If
            End If

            LastWidth = Me.Width
            LastHeight = Me.Height

            RefreshImage()
        End Sub

        Private Sub RefreshImage()
            Dim WidthRatio As Single = CSng(Me.Width) / CSng(My.Resources.screw1.Width)
            Dim HeightRatio As Single = CSng(Me.Height) / CSng(My.Resources.screw1.Height)

            If WidthRatio < HeightRatio Then
                ImageRatio = WidthRatio
            Else
                ImageRatio = HeightRatio
            End If

            '****************************************************************
            ' Scale the gauge image so it will draw faster in Paint event
            '****************************************************************
            ' Make a bitmap for the result.
            If StaticImage IsNot Nothing Then StaticImage.Dispose()
            StaticImage = New Bitmap(CInt(My.Resources.screw1.Width * ImageRatio), CInt(My.Resources.screw1.Height * ImageRatio))

            ' Make a Graphics object for the result Bitmap.
            Dim gr_dest As Graphics = Graphics.FromImage(StaticImage)
            m.Reset()
            m.Scale(ImageRatio * 1.25, ImageRatio * 1.25)
            gr_dest.Transform = m

            ' Copy the source image into the destination bitmap.
            gr_dest.DrawImage(My.Resources.screw1, 0, 0)

            TextRect.X = 5
            TextRect.Width = StaticImage.Width / 1.25 / ImageRatio - 10
            TextRect.Y = 5
            TextRect.Height = StaticImage.Height / 1.25 / ImageRatio * 0.33
            Dim sf As New StringFormat
            sf.Alignment = StringAlignment.Center
            sf.LineAlignment = StringAlignment.Center

            'gr_dest.DrawRectangle(Pens.Black, TextRect)
            Dim b As New SolidBrush(Color.FromArgb(250, 130, 140, 160))
            gr_dest.DrawString(m_LegendText, New Font("Arial", 22, FontStyle.Regular, GraphicsUnit.Point), b, TextRect, sf)

            Dim x() As Int16 = {My.Resources.screw1.Width, My.Resources.screw2.Width}

            Select Case m_ButtonColor
                Case ButtonColors.Red
                    LightOffImage = New Bitmap(CInt(My.Resources.screw1.Width * ImageRatio * 0.8), CInt(My.Resources.screw1.Height * ImageRatio * 0.8))
                    LightOnImage = New Bitmap(CInt(My.Resources.screw2.Width * ImageRatio * 0.8), CInt(My.Resources.screw2.Height * ImageRatio * 0.8))
                Case Else
                    LightOffImage = New Bitmap(CInt(My.Resources.screw1.Width * ImageRatio * 0.8), CInt(My.Resources.screw1.Height * ImageRatio * 0.8))
                    LightOnImage = New Bitmap(CInt(My.Resources.screw2.Width * ImageRatio * 0.8), CInt(My.Resources.screw2.Height * ImageRatio * 0.8))
            End Select

            gr_dest = Graphics.FromImage(LightOffImage)
            Dim gr_dest2 As Graphics = Graphics.FromImage(LightOnImage)

            m.Reset()
            m.Scale(ImageRatio * 1.25, ImageRatio * 1.25)
            gr_dest.Transform = m
            gr_dest2.Transform = m

            Select Case m_ButtonColor
                Case ButtonColors.Red
                    gr_dest.DrawImage(My.Resources.screw1, 0, 0)
                    gr_dest2.DrawImage(My.Resources.screw1, 0, 0)
                Case Else
                    gr_dest.DrawImage(My.Resources.screw2, 0, 0)
                    gr_dest2.DrawImage(My.Resources.screw2, 0, 0)
            End Select

            ButtonImage = LightOffImage

            '* Perform some cleanup
            gr_dest.Dispose()
            gr_dest2.Dispose()

            '* Create a new resized backbuffer for double buffering
            If _backBuffer IsNot Nothing Then _backBuffer.Dispose()
            _backBuffer = New Bitmap(Me.Width, Me.Height)
        End Sub
    End Class

    The error is : Failed to create component 'Screw'/ the error message follows: 'System.NullReferenceException:  Object reference not set to an instance of an object.  at AdvancedHMI.Screw…ctor() in blah blah Screw.vb:line 292

    Any ideas?

    Thanks

     
  • Archie

    Archie - 2010-08-26

    I copy and pasted your code, created a couple generic graphics to represent screw1 and 2. I then added a screw and a windows button to the MainForm. I added code to toggle screw1.value everytime I clicked the button. It's working here on my computer with no problems. What is the code that you have on line 292?

     
  • Mike

    Mike - 2010-08-26

    That's it.  I gave it to you. :)  Line 292 starts the SetupDelay event timer

     
  • Mike

    Mike - 2010-08-26

    code there be a size requirement for the images?

     
  • Mike

    Mike - 2010-08-26

    And by the way, I'm using VB express 2010

     
  • Archie

    Archie - 2010-08-26

    I'm testing on Visual Studio 2008, so there may be some difference. Try these couple code changes:

        Private WithEvents SetupDelay As Timer
        Private Sub Meter_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            If Not Me.DesignMode Then
                If m_CommComponent IsNot Nothing AndAlso m_PLCaddress.Length > 0 Then
                    SetupDelay = New Timer
                    AddHandler SetupDelay.Tick, AddressOf Timer1_Tick
                    SetupDelay.Enabled = True
                End If
            End If
        End Sub

        Private NotificationID As Integer
        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)

     
  • Mike

    Mike - 2010-08-26

    changes the error line to 199, but that's it.

     
  • Archie

    Archie - 2010-08-26

    It seems like there is a trend here with the timers.  Comment out every reference to the tmrError because it is not used anyway in this component.

     
  • Mike

    Mike - 2010-08-26

    I'll give it a shot, but I think I tried that.  Yes I did. lol now the error is at line 138

     
  • Mike

    Mike - 2010-08-26

    comment that out and it's at 108, which is kinda important.

     
  • Mike

    Mike - 2010-08-26

    ok, I created a copy of the pilot light again, built the project and tested it.  Put the new control on the form, no problem.  Went into the code, and changed JUST THIS:     Private LegendPlateRatio As Single = My.Resources.screw1.Height / My.Resources.screw1.Width
    which is line 343, the first place I ran into reference to the original graphics.  saved it, rebuilt and I get the error. (at line 292)

     
  • Mike

    Mike - 2010-08-26

    I put the original graphic back in, saved and rebuilt and it's fine again.  Must be something to do with the way I added those images to the project, don't you think?

     
  • Archie

    Archie - 2010-08-26

    I am in the process of Installing VB Express 2010 to test things.

    Are you adding the graphic files using the Resources tab in the project properties? What format is your graphics file?

     
  • Mike

    Mike - 2010-08-26

    I added the graphics files by 1)right click the resources folder in solution explorer, add, then existing and picking the graphic.  After that, I had to also add (via copy and past) them to the Resources.Designer.vb file.  The graphic is .png

     
  • Archie

    Archie - 2010-08-26

    The method I use is to go to the project properties by right clicking the project name in the Solution Explorer. Then select the resources tab. You can then drop down the Add Resources and select Existing File.
    That way you do not have to modify the designer file. VB tends not to like the Designer files modified manually.

     
  • Mike

    Mike - 2010-08-26

    I was looking at that, as there was an unexpected space bwt obj,System.Drawing.Bitmap that isn't with the original components.  I couldn't make it go away either.  So, I started poking around in the project folder and found Resources.resx, which I added to the resources folder and got this whole new screen which I'm sure you saw before.:)  Using your method, that is the same screen that comes up to add resources.  That screen didn't contain my .png files, which would explain the error.  I'm going to try it, but I think that was the problem.

     
  • Mike

    Mike - 2010-08-26

    Well, looks like I need to start over. Building the project after all my screwing around throws off error after error.  LOL  I guess I'll delete it and start from scratch in the AM.  Thanks for your help!

     
  • Archie

    Archie - 2010-08-26

    Hope that resolves the issue. Let me know how it works out.

     
  • Mike

    Mike - 2010-08-27

    Sooooo, No more error but now the images won't display right.  I'm seeing both images in the containing image.  I did manage to get one to go away, but was still having problems with scaling.  How do you determine the values used here:

    Private _backBuffer As Bitmap
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            If StaticImage Is Nothing Or _backBuffer Is Nothing Then Exit Sub

            Dim g As Graphics = Graphics.FromImage(_backBuffer)

            g.DrawImage(StaticImage, 0, 0)

            g.DrawImage(ButtonImage, CInt((StaticImage.Width / 2 - ButtonImage.Width / 2)), CInt(StaticImage.Height * 0.43))

            'Copy the back buffer to the screen
            e.Graphics.DrawImage(_backBuffer, 0, 0)
        End Sub

    I notice they are different on the components I looked at.

    Thanks,
    Mike

     
  • Archie

    Archie - 2010-08-27

    The best thing to do is to use PNG format and save them at 96DPI. My first components I built used 72DPI and I had to put in 1.25 scale factors. I later learned that 72 is the Apple way of doing things and 96 is Windows.

    Look in the code where it creates the static images. I think it is the last subroutine.

     
  • Mike

    Mike - 2010-08-27

    I saved it at 96 dpi but it's still clipping the bottom and right sides of the image.

    That is caused by this:
    Select Case m_ButtonColor
                Case ButtonColors.Red
                    LightOffImage = New Bitmap(CInt(My.Resources.screw1.Width * ImageRatio * 0.8), CInt(My.Resources.screw1.Height * ImageRatio * 0.8))
                    LightOnImage = New Bitmap(CInt(My.Resources.screw2.Width * ImageRatio * 0.8), CInt(My.Resources.screw2.Height * ImageRatio * 0.8))
                Case Else
                    LightOffImage = New Bitmap(CInt(My.Resources.screw1.Width * ImageRatio * 0.8), CInt(My.Resources.screw1.Height * ImageRatio * 0.8))
                    LightOnImage = New Bitmap(CInt(My.Resources.screw2.Width * ImageRatio * 0.8), CInt(My.Resources.screw2.Height * ImageRatio * 0.8))
            End Select
    right?

    Thanks,
    Mike

     
  • Archie

    Archie - 2010-08-27

    The original buttons are 72DPI, so there is a 1.25 scale factor. If you are using the 96, remove this 1.25 in this line:

            m.Scale(ImageRatio * 1.25, ImageRatio * 1.25)

     
  • Mike

    Mike - 2010-08-27

    That took care of the clipping!  Now the image won't scale with the box though. LOL   I'll start over and just comment that line.

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.