HotSpots Class and CustomView
Having done some work on the hotspot module in the last few days, it struck me that there might be an easier way to get the hotspots aligned with images by using the designer and this is the result.
The class provides the same functionality as the code module, you can use it all manually and except for the initialization requiring two subroutines, there is very little difference. Why does the initialization required two subroutines, because it is sharing the code with a CustomView, which has a strict signature for the initialization subroutine, but we need to pass additional information so we need to do it in a second subroutine.
Manual Creation
To set up and use the HotSpots manually wih the class we need to declare the Class:
Then Initialize it:
Then setup,
Which passes the activity (or Panel if preferred) and the size of the panel that the HotSpot class should create and add to the passed Activity or Panel.
Then we can add some hotspots:
We need to create a Touch sub for the EventName we passed in initialize:
We use a Param() array to pass parameters to the touch sub as we use CallSub which only supports passing two separate parameters, and we need three. So we bundle them into an array and then unpack them in the called subroutine as:
Then we can add the code to process the touch and check if any of the HotSpots are being touched (See the example Main Activity).
Designer Creation
In it's most basic form we can recreate the above with the designer by adding a CustomView to the designer and select HotSpotClass in the Customview field, the Customview object should be the size of the panel we want to monitor the touches on and save it as a layout, then use Activity LoadLayout in the Module in the usual way.
Then add the Dim to Globals, either from the designer or manually, we don't then need to initialize, or run the setup subroutine, this is taken care of by the designer and code in the Class.
We can then add our hotspots as in the example above.
Using a Second Layout File
In addition to this, we can use a second layoutfile to define our HotSpots. To do this, the second layout must contain a panel called panel1. On this panel we put:
If we add an image to the background of panel1 it makes aligning the HotSpots quite straightforward with just the outline of the panels and labels visible. We can also elect to display the image on the panel automatically, or we would need to display a relevant background separately and ensure that it is behind the Base Panel and that the base panel color is set to transparent.
We can get access to the Base panel by calling the HotSpot.GetPanel subroutine. It is then possible to add views or a Canvas to the panel to draw on or display other things or set it's size or color etc.
To get the HotSpots to generate, we can either add the name of the second layout file to the Tag of the CustomView Object in the first layout file (see image above), or we can call the subroutine:
Filename is the name of the second LayoutFile, and copy determines if the background from panel1 in the second layout file should be copied to the Base Panel and therefore displayed. We can also add the word 'copy' to the Tag of Panel1 in the second layout file to achieve the copy of it's background automatically.
I hope you find this useful.
Dependencies:
Reflection Library - Andrew Graham
V1 HotSpotClass attached to this post.
V1.1 added polygons - see post #4
- fixed bugs and omissions with find routines.
- added initcomplete call back for customview.
- draw the hotspots for visibility.
Having done some work on the hotspot module in the last few days, it struck me that there might be an easier way to get the hotspots aligned with images by using the designer and this is the result.
The class provides the same functionality as the code module, you can use it all manually and except for the initialization requiring two subroutines, there is very little difference. Why does the initialization required two subroutines, because it is sharing the code with a CustomView, which has a strict signature for the initialization subroutine, but we need to pass additional information so we need to do it in a second subroutine.
Manual Creation
To set up and use the HotSpots manually wih the class we need to declare the Class:
B4X:
Dim HotSpot As HotSpotClass
B4X:
Hotspot.Initialize(Me,"HotSpot") 'Requires the calling Module, and an EventName.
B4X:
HotSpot.SetUp(Activity,0,0,50%x,100%y)
Then we can add some hotspots:
B4X:
HotSpot.AddHotSpot(10Dip,10Dip,60Dip,70Dip,"Tag1")
HotSpot.AddHotSpot(100Dip,10Dip,160Dip,70Dip,"Tag2")
HotSpot.AddHotSpot(200Dip,10Dip,260Dip,70Dip,"Tag3")
We need to create a Touch sub for the EventName we passed in initialize:
B4X:
Sub HotSpot_Touch(Param() As Object)
B4X:
Dim Action As Int = Param(0)
Dim X As Float = Param(1)
Dim Y As Float = Param(2)
B4X:
#Project Attributes
#Activity Attributes
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
End Sub
Sub Globals
'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.
Dim HSPnl As Panel
Dim Canv As Canvas
Dim HotSpot As HotSpotClass
End Sub
Sub Activity_Create(FirstTime As Boolean)
'Do not forget to load the layout file created with the visual designer. For example:
'Activity.LoadLayout("Layout1")
HotSpot.Initialize(Me,"HotSpot")
HotSpot.SetUp(Activity,0,0,50%x,100%y)
'We can get the panel that the Hotspots are monitored on
'perhaps To add a Canvas and draw to, or to change parameters.
HSPnl = HotSpot.GetPanel
HSPnl.Color=Colors.White
Canv.Initialize(HSPnl)
Log(HotSpot.AddHotSpot(10Dip,10Dip,60Dip,70Dip,"Tag1"))
Log(HotSpot.AddHotSpot(100Dip,10Dip,160Dip,70Dip,"Tag2"))
Log(HotSpot.AddHotSpot(200Dip,10Dip,260Dip,70Dip,"Tag3"))
Log(HotSpot.AddHotCircle(20Dip,100Dip,80Dip,"Tag4"))
Log(HotSpot.AddHotSpot(10Dip,10Dip,260Dip,70Dip,"Tag5"))
Canv.DrawCircle(60Dip,140Dip,40Dip,Colors.Blue,True,1Dip)
Activity.Invalidate
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub HotSpot_Touch (Param() As Object)
Dim Action As Int = Param(0)
Dim X As Float = Param(1)
Dim Y As Float = Param(2)
'Use This Version for FindHotSpot,FindHotSpotFirst and FindHotSpotLast
' If Action = Activity.ACTION_DOWN Then
' Dim HS As HotSpotType = HotSpot.FindHotSpot(X,Y)
' 'If HotSpot is not found an uninitialized HotSpotType is returned.
' If HS.IsInitialized Then
' Log("X "&X&" Y "&Y&" "&HS.Tag)
' 'Edit the SLHotSpot, because we can
' If HS.Tag = "Tag3" Then HotSpot.EditHotSpot(HS.ID,10,200,70,270,"Ha Moved...")
' End If
' End If
'Use this version for FindHotSpotAll
If Action = Activity.ACTION_DOWN Then
Dim ResultsList As List
ResultsList=HotSpot.FindHotSpotAll(X,Y)
For Each HS As HotSpotType In ResultsList
'If HotSpot is not found an uninitialized HotSpotType is returned.
If HS.IsInitialized Then
Log("X "&X&" Y "&Y&" "&HS.Tag)
'Edit the HotSpot, because we can
If HS.Tag = "Tag3" Then
HotSpot.EditHotSpot(HS.ID,10Dip,200Dip,70Dip,270Dip,"Ha Moved...")
HotSpot.ChangeType(HS.ID,"C")
End If
End If
Next
End If
End Sub
In it's most basic form we can recreate the above with the designer by adding a CustomView to the designer and select HotSpotClass in the Customview field, the Customview object should be the size of the panel we want to monitor the touches on and save it as a layout, then use Activity LoadLayout in the Module in the usual way.
Then add the Dim to Globals, either from the designer or manually, we don't then need to initialize, or run the setup subroutine, this is taken care of by the designer and code in the Class.
We can then add our hotspots as in the example above.
Using a Second Layout File
In addition to this, we can use a second layoutfile to define our HotSpots. To do this, the second layout must contain a panel called panel1. On this panel we put:
- Panels to represent HotSpots and
- Labels to represent HotCircles.
If we add an image to the background of panel1 it makes aligning the HotSpots quite straightforward with just the outline of the panels and labels visible. We can also elect to display the image on the panel automatically, or we would need to display a relevant background separately and ensure that it is behind the Base Panel and that the base panel color is set to transparent.
We can get access to the Base panel by calling the HotSpot.GetPanel subroutine. It is then possible to add views or a Canvas to the panel to draw on or display other things or set it's size or color etc.
To get the HotSpots to generate, we can either add the name of the second layout file to the Tag of the CustomView Object in the first layout file (see image above), or we can call the subroutine:
B4X:
HotSpot.PopulateFromLayout(FileName As String, Copy As Boolean) As Int
B4X:
#Activity Attributes
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
End Sub
Sub Globals
'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.
Dim HSPnl As Panel
Dim Canv As Canvas
Dim HotSpot As HotSpotClass
End Sub
Sub Activity_Create(FirstTime As Boolean)
'Do not forget to load the layout file created with the visual designer. For example:
'Activity.LoadLayout("Layout1")
Activity.LoadLayout("1")
Activity.Invalidate
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub HotSpot_Touch (Param() As Object)
Dim Action As Int = Param(0)
Dim X As Float = Param(1)
Dim Y As Float = Param(2)
'Use This Version for FindHotSpot,FindHotSpotFirst and FindHotSpotLast
' If Action = Activity.ACTION_DOWN Then
' Dim HS As HotSpotType = HotSpot.FindHotSpot(X,Y)
' 'If HotSpot is not found an uninitialized HotSpotType is returned.
' If HS.IsInitialized Then
' Log("X "&X&" Y "&Y&" "&HS.Tag)
' 'Edit the HotSpot, because we can
' If HS.Tag = "Tag3" Then HotSpot.EditHotSpot(HS.ID,10,200,70,270,"Ha Moved...")
' End If
' End If
'Use this version for FindSLHotSpotAll
If Action = Activity.ACTION_DOWN Then
Dim ResultsList As List
ResultsList=HotSpot.FindHotSpotAll(X,Y)
For Each HS As HotSpotType In ResultsList
'If SLHotSpot is not found an uninitialized SLHotSpotType is returned.
If HS.IsInitialized Then
Log("X "&X&" Y "&Y&" "&HS.Tag)
'Edit the SLHotSpot, because we can
If HS.Tag = "Tag3" Then
HotSpot.EditHotSpot(HS.ID,10Dip,200Dip,70Dip,270Dip,"Ha Moved...")
HotSpot.ChangeType(HS.ID,"C")
End If
Return True
End If
Next
End If
End Sub
Dependencies:
Reflection Library - Andrew Graham
V1 HotSpotClass attached to this post.
V1.1 added polygons - see post #4
- fixed bugs and omissions with find routines.
- added initcomplete call back for customview.
- draw the hotspots for visibility.
Attachments
Last edited: