Android Question Raising events

davemorris

Active Member
Licensed User
Longtime User
Hi (I am new to B4A - coming from vb.net background)
The question is - I want to raise events in a class module which can be detected (consumed) by the main activity. How do I do it?

Thanks for the help
Dave Morris
 

DonManfred

Expert
Licensed User
Longtime User
I want to raise events in a class module
at the top of your class you need to define the events the class is raising

Example code from my PhilipsHUE-Class
The first line are the definition of the event the Class is raising
#Event: can be used multipletimes
B4X:
#Event: LightList(lights As List)

Sub Class_Globals
    Private bridgeurl As String = ""
    Private mCallback As Object
    Private mEvent As String
End Sub
'initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(Callback As Object, EventName As String, bridgeIP As String, username As String)
    mCallback = Callback
    mEvent = EventName
    bridgeurl = $"http://${bridgeIP}/api/${username}/"$
End Sub

' Get a List of all known Lights
Sub getLights()
    Dim l As List
    l.Initialize
    Dim Job As HttpJob
    Job.Initialize("", Me)
    Job.Download(bridgeurl&"lights")
    wait for (Job) Jobdone(Job As HttpJob)
    If Job.Success Then
        Log(Job.GetString)
    
        Dim parser As JSONParser
        parser.Initialize(Job.GetString)
        Dim root As Map = parser.NextObject
        For i = 1 To 512
            Dim key As String = i
            If root.ContainsKey(key) Then
                Dim m1 As Map = root.Get(key)
                l.Add(m1)
                Log(m1)
            End If
        Next
        Log("Size of Lightslist = "&l.Size)
        For i = 0 To l.Size-1
            getLight(i+1)
        Next
        If SubExists(mCallback, mEvent & "_LightList") Then
            CallSub2(mCallback, mEvent & "_LightList", l) ' l in this case is a List (see event definition)
        End If
    Else
        Log(Job.ErrorMessage)
    End If

End Sub

This is the code which raises the event
B4X:
        If SubExists(mCallback, mEvent & "_LightList") Then
            CallSub2(mCallback, mEvent & "_LightList", l)
        End If
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
Also, it should be noted that the underscore in the event name in the callsub (e.g. "_LightList") isn't just a style-convention. You need to have an underscore in the event name so when you compile in release (obfuscated) mode the event name is preserved (any names with underscores are not scrambled so you calls will still work). Without the underscore the procedure names in your target activity would be changed and your callsub in your class would fail.
 
Upvote 0

davemorris

Active Member
Licensed User
Longtime User
at the top of your class you need to define the events the class is raising

Example code from my PhilipsHUE-Class
The first line are the definition of the event the Class is raising
#Event: can be used multipletimes
B4X:
#Event: LightList(lights As List)

Sub Class_Globals
    Private bridgeurl As String = ""
    Private mCallback As Object
    Private mEvent As String
End Sub
'initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(Callback As Object, EventName As String, bridgeIP As String, username As String)
    mCallback = Callback
    mEvent = EventName
    bridgeurl = $"http://${bridgeIP}/api/${username}/"$
End Sub

' Get a List of all known Lights
Sub getLights()
    Dim l As List
    l.Initialize
    Dim Job As HttpJob
    Job.Initialize("", Me)
    Job.Download(bridgeurl&"lights")
    wait for (Job) Jobdone(Job As HttpJob)
    If Job.Success Then
        Log(Job.GetString)
  
        Dim parser As JSONParser
        parser.Initialize(Job.GetString)
        Dim root As Map = parser.NextObject
        For i = 1 To 512
            Dim key As String = i
            If root.ContainsKey(key) Then
                Dim m1 As Map = root.Get(key)
                l.Add(m1)
                Log(m1)
            End If
        Next
        Log("Size of Lightslist = "&l.Size)
        For i = 0 To l.Size-1
            getLight(i+1)
        Next
        If SubExists(mCallback, mEvent & "_LightList") Then
            CallSub2(mCallback, mEvent & "_LightList", l) ' l in this case is a List (see event definition)
        End If
    Else
        Log(Job.ErrorMessage)
    End If

End Sub

This is the code which raises the event
B4X:
        If SubExists(mCallback, mEvent & "_LightList") Then
            CallSub2(mCallback, mEvent & "_LightList", l)
        End If

Thanks for the quick response - I have tried some test code see below and it don't work, what have I done wrong.

Main module
----------------------
Main module:
#Region  Project Attributes
    #ApplicationLabel: EventInClass
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
End Sub

Sub Globals
    Dim EventTest As clsSpecialEvent
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")
    EventTest.Initialize(EventTest, "DmDoEvent")
    EventTest.DmRaiseEvent
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub EventTest_DmDoEvent
    ' do something    - To test I put a breakpoint here and it don't trip
End Sub

Code for special event class

Special Event class:
' The Code for the class "clsSpecialEvent" which is supposed to raise the event
#Event: DmDoEvent

Sub Class_Globals
    Private mCallback As Object
    Private mEvent As String
End Sub

Public Sub Initialize(callback As Object, eventName As String)
    mCallback = callback
    mEvent = eventName
End Sub

Sub DmRaiseEvent()
    If SubExists(mCallback, mEvent & "_DmDoEvent") Then
        CallSub2(mCallback, mEvent & "_DmDoEvent", "")     ' <--- This bit of code never gets called!
    End If
End Sub

Thanks again for your help
Dave Morris
 
Last edited:
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
I'll jump in first since I was just here ;)

1. Always use the "code" tags when posting code samples.
2. You should be more specific on your error, "it don't work" doesn't give us a lot to go on ;)

I think you have incorrectly defined your event name:
B4X:
EventTest.Initialize(EventTest, "DmDoEvent")
should probably be
B4X:
EventTest.Initialize(EventTest, "EventTest")
as you have named your receiving event "EventTest_DmDoEvent".
 
Upvote 0

davemorris

Active Member
Licensed User
Longtime User
I'll jump in first since I was just here ;)

1. Always use the "code" tags when posting code samples.
2. You should be more specific on your error, "it don't work" doesn't give us a lot to go on ;)

I think you have incorrectly defined your event name:
B4X:
EventTest.Initialize(EventTest, "DmDoEvent")
should probably be
B4X:
EventTest.Initialize(EventTest, "EventTest")
as you have named your receiving event "EventTest_DmDoEvent".

Sorry, an oversight on my part the handler "EventTest_DmDoEvent()" in main is not called (I tested it with a breakpoint). I did try the change you suggested and as before the breakpoint was not activated.
P.s. Can you please tell me how to put the "code tags" in my postings?
 
Upvote 0

Jeffrey Cameron

Well-Known Member
Licensed User
Longtime User
There are many code tag examples here on the forum, such as: https://www.b4x.com/android/forum/threads/how-to-format-code-with-code-tags.51218/

Did you change your initialize event to match your declared procedure as I suggested? As your class was coded, that line would never be called because "DmDoEvent_DmDoEvent" does not exist in your target activity.

And I'm not sure breakpoints on comment lines will actually be executed. Try adding
B4X:
Log("In the event!")
instead of a breakpoint.

Additionally, you really only need CallSub as you are not supplying any parameter. Also, generally speaking, unless you need to wait for a return value from the method you are calling you should use the various CallSubDelayed methods in lieu of the CallSub methods.
 
Last edited:
Upvote 0

davemorris

Active Member
Licensed User
Longtime User
There are many code tag examples here on the forum, such as: https://www.b4x.com/android/forum/threads/how-to-format-code-with-code-tags.51218/

Did you change your initialize event to match your declared procedure as I suggested? As your class was coded, that line would never be called because "DmDoEvent_DmDoEvent" does not exist in your target activity.

And I'm not sure breakpoints on comment lines will actually be executed. Try adding
B4X:
Log("In the event!")
instead of a breakpoint.

Additionally, you really only need CallSub as you are not supplying any parameter. Also, generally speaking, unless you need to wait for a return value from the method you are calling you should use the various CallSubDelayed methods in lieu of the CallSub methods.

Thanks for the information on the "code tags" hopefully I have go it right in this post.
B4X:
#Region  Project Attributes
    #ApplicationLabel: EventInClass
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals

End Sub

Sub Globals
    Dim EventTest As clsSpecialEvent
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Layout1")
    EventTest.Initialize(EventTest, "£ventTest")
    EventTest.DmRaiseEvent
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub EventTest_DmDoEvent
    ' do something     - To test I put a breakpoint here and it don't trip
End Sub

This is the code in the event class clsSpecialEvent

B4X:
#Event: DmDoEvent
Sub Class_Globals
    Private mCallback As Object
    Private mEvent As String
End Sub

Public Sub Initialize(callback As Object, eventName As String)
    mCallback = callback
    mEvent = eventName
End Sub

Sub DmRaiseEvent()
    If SubExists(mCallback, mEvent & "_DmDoEvent") Then
        CallSub2(mCallback, mEvent & "_DmDoEvent", "")     ' <--- This bit of code never gets called!
    End If
End Sub

Once again thanks for the help so far.

Dave
 
Upvote 0

ilan

Expert
Licensed User
Longtime User
is there a way to show the possible events with my own class/b4x lib when i type:

Sub (TAB) ....


i would like to show the available events for my class/codemodule/b4x generated libs

is this possible?

thank you
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
It would have been easier for us to help you if you had posted your test project as a zip file.

The attached project works.

Calling EventTest.DmRaiseEvent in Activity_Create doesn't work!
This is wrong too: CallSub2(mCallback, mEvent & "_DmDoEvent", "")
Or the event routine in Main should be Sub EventTest_DmDoEvent(Val As String), you need to add the parameter.

And the code:
Main:
B4X:
Sub Globals
    Dim EventTest As clsSpecialEvent
End Sub

Sub Activity_Create(FirstTime As Boolean)
'    Activity.LoadLayout("Layout1")
    EventTest.Initialize(Me, "EventTest")
End Sub

Sub Activity_Resume
    EventTest.DmRaiseEvent
End Sub

Sub EventTest_DmDoEvent
    ' do something - To test I put a breakpoint here and it don't trip
    Log("Event")
End Sub

Class:
B4X:
#Event: DmDoEvent

Sub Class_Globals
    Private mCallback As Object
    Private mEvent As String
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(callback As Object, eventName As String)
    mCallback = callback
    mEvent = eventName
End Sub

Public Sub DmRaiseEvent()
    If SubExists(mCallback, mEvent & "_DmDoEvent") Then
        CallSub(mCallback, mEvent & "_DmDoEvent") ' <--- This bit of code never gets called!
    End If
End Sub
 

Attachments

  • TestEvent.zip
    7.2 KB · Views: 161
Last edited:
Upvote 0

davemorris

Active Member
Licensed User
Longtime User
@DonManfred is correct, I missed that (I blame insufficient quantities of coffee so far today). :D

Hi
I tried the change suggested by @DonManfred and no luck, the breakpoint in main.EventTest_DmDoEvent does not trip. Any suggestions?

It may mean nothing but the sub DmRaiseEvent()in the clsSpecialEvent class never calls CallSub2() - but I can't see what is wrong the the sub SubExits() used condition expression.

Regards
Dave
 
Upvote 0

davemorris

Active Member
Licensed User
Longtime User
@klaus gave you a working example above. I would compare his example to yours (line-by-line) to see if you spot any differences.

Hi - you are correct (I missed @klaus reply) and it does work.

It appears moving the call to EventTest.DmRaiseEvents out of the Activity_Create() to Activity_Resume() is important and the using CallSub() instead of CallSub2() was required.

Thanks for the help (it now works)

I posted the working version - it may help somebody

Regards
Dave
 

Attachments

  • EventInClass.zip
    8.3 KB · Views: 149
Upvote 0
Top