B4J Question How ? Events On classes

behnam_tr

Active Member
Licensed User
Longtime User
hi

i have a class module named > class1

then i creat 10 instance from class1 ( c1 as class1,c2 as class1 ,.......)
Now I want call a sub in class1 and update data for all instance
What can be the fastest and most optimal solution?

The solution I am currently using is that I keep the list of instances and then execute the desired function for each instance as follows.
B4X:
dim c1 as class1
dim c2 as class1
.
.
.
.
Dim list1 As List
list1.Initialize
list1.AddAll(Array As object(c1,c2,.....))
 
For Each c As class1 In list1
      c.mysub
Next

I think it would be easier and more efficient to use events, but I couldn't do it inside the classes.

Clearly, I want to use events instead of lists (project attached).
In fact, whenever the database is updated, I understand and update the class
B4X:
'form1
'database updated
If SubExists(class1,"mysub") Then
  CallSubDelayed2(class1, mysub, myparams)
EndIf
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
B4X:
'class1
sub mysub(object param0)
'any code
end sub
 

Attachments

  • testproject.zip
    4.9 KB · Views: 95
Last edited:
Solution
then i creat 10 instance from class1 ( c1 as class1,c2 as class1 ,.......)
Now I want call a sub in class1 and update data for all instance
Another way you could solve this problem is to create a "managing" class. In this class, you register/deregister other classes upon which you want to call common procedures at any given time.

Manger class code
B4X:
Sub Class_Globals
    Private classList As List
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    classList.Initialize
End Sub

Public Sub Add(aClass As Object)
    If classList.IndexOf(aClass) < 0 Then
        classList.Add(aClass)
    Else
        Log("Class aldready added")
    End If
End Sub

Public Sub Remove(aClass...

Daestrum

Expert
Licensed User
Longtime User
(I don't fully understand what you are trying to do) but if you want the classes to be updated, could you not use a timer in the class and have them update themselves?
 
Upvote 0

behnam_tr

Active Member
Licensed User
Longtime User
(I don't fully understand what you are trying to do) but if you want the classes to be updated, could you not use a timer in the class and have them update themselves?
Me too, I do not understand what exactly you want to do.
Could you please explain more in details your concern.

sample project attached.
The goal is to execute the Updateclass function on all classes that have been opened.
Actually, I want to use events trigger instead of the method I am currently using(test project), is it possible??
 
Upvote 0

behnam_tr

Active Member
Licensed User
Longtime User
(I don't fully understand what you are trying to do) but if you want the classes to be updated, could you not use a timer in the class and have them update themselves?
I can't use the timer
1- Only some instances may be updated, not all together
2- The data must be received from the database, I don't want the database to be busy all the time!!
 
Upvote 0

behnam_tr

Active Member
Licensed User
Longtime User
Me too, I do not understand what exactly you want to do.
Could you please explain more in details your concern.

In my program, a report is opened for each customer (class1)
Including receiving and payments, invoices and....
A transaction may be done for this customer in another form (myform1), for example, receiving money
I want the customer report that has already been opened to be updated as soon as the transaction is completed
without manually updating it In fact, an event is executed in class1
 
Last edited:
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Had a little attempt - should give you a basic idea of how to do it.

Obviously you will need to change it to make it fit your requirements.
 

Attachments

  • test.zip
    5.9 KB · Views: 99
Upvote 0

behnam_tr

Active Member
Licensed User
Longtime User
Had a little attempt - should give you a basic idea of how to do it.

Obviously you will need to change it to make it fit your requirements.
Thank you, but that was not my goal

Clearly, I want to use events instead of lists (project attached).
In fact, whenever the database is updated, I understand and update the class

'form1
'database updated
If SubExists(class1,"mysub") Then
CallSubDelayed2(class1, mysub, myparams)
End If

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'class1
sub mysub(object param0)
'any code
end sub
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
'form1
'database updated
If SubExists(class1,"mysub") Then
CallSubDelayed2(class1, mysub, myparams)
End If

In this example, do you want to call the mysub routine in all class1 instances at once ?
I am afraid that this is not possible, you can access only each instance with its name but not all instances at once with the generic class name.
 
Upvote 0

behnam_tr

Active Member
Licensed User
Longtime User
'form1
'database updated
If SubExists(class1,"mysub") Then
CallSubDelayed2(class1, mysub, myparams)
End If

In this example, do you want to call the mysub routine in all class1 instances at once ?
I am afraid that this is not possible, you can access only each instance with its name but not all instances at once with the generic class name.

yes
call the mysub routine in all class1 instances

I don't want to save the list of all instances and then update each one of them with a loop, I think it's not optimal.
I thought there might be a better solution
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
then i creat 10 instance from class1 ( c1 as class1,c2 as class1 ,.......)
Now I want call a sub in class1 and update data for all instance
Another way you could solve this problem is to create a "managing" class. In this class, you register/deregister other classes upon which you want to call common procedures at any given time.

Manger class code
B4X:
Sub Class_Globals
    Private classList As List
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    classList.Initialize
End Sub

Public Sub Add(aClass As Object)
    If classList.IndexOf(aClass) < 0 Then
        classList.Add(aClass)
    Else
        Log("Class aldready added")
    End If
End Sub

Public Sub Remove(aClass As Object)
    If classList.IndexOf(aClass) >= 0 Then
        classList.RemoveAt(classList.IndexOf(aClass))
    Else
        Log("Class not in managed list")
    End If
End Sub

'Called method must accept an array of objects as parameters.
' Modify to fit need. This is just one way of making parameter
' count and type generic.
Public Sub CallMethod(method As String, params() As Object)
    If Not(method = "null" Or method.Trim = "") Then
        If classList.Size > 0 Then
            For Each aClass In classList
                If SubExists(aClass, method) Then
                    CallSubDelayed2(aClass, method, params)
                End If
            Next
        Else
            Log("Class list is empty. Not executing any methods")
        End If
    Else
        Log("Called with empty method name. Not executing any methods")
    End If
End Sub

Sample Class1 code
B4X:
Sub Class_Globals

End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    
End Sub

Sample Class2 code
B4X:
Sub Class_Globals
    
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    
End Sub

Public Sub Test(params() As Object)
    Log("Hi. I'm method Test from class Class2")
    Log($"I've been called with ${IIf(params <> Null And params.Length > 0, params.Length, 0)} parameter(s)"$)
End Sub

Some testing code:
B4X:
    Dim mgr As Manager
    mgr.Initialize
    Log("CallMethod on empty list")
    mgr.CallMethod("Test", Null)
    Log("Adding a Null object to list")
    mgr.Add(Null)
    Log("Calling a method on Null object")
    mgr.CallMethod("Test", Null)
    Log("Removing Null object from list")
    mgr.Remove(Null)
    Dim cls As Class1
    cls.Initialize
    mgr.Add(cls)
    Log("Calling NON-existing class1 object method")
    mgr.CallMethod("Test", Null)
    Log("Adding same class1 object")
    mgr.Add(cls)
    Log("Removing class1 object")
    mgr.Remove(cls)
    Log("Removing class1 object again")
    mgr.Remove(cls)
    Dim cls2 As Class2
    Log("Adding uninitialized class2 object")
    mgr.Add(cls2)
    Log("Calling existing class2 object method against uninitialized class2 object")
    mgr.CallMethod("Test", Null)
    Log("Initializing class2 object")
    cls2.Initialize
    Log("Calling existing class2 object method")
    mgr.CallMethod("Test", Null)
    Log("Removing class2 object")
    mgr.Remove(cls2)
    Log("Notice that class2 object method is called AFTER class2 object has been removed.")
    Log("In this particular case, welcome to event driven programming (the event queue is processed AFTER class removal)")

Output of above testing code
CallMethod on empty list
Class list is empty. Not executing any methods
Adding a Null object to list
Calling a method on Null object
Removing Null object from list
Calling NON-existing class1 object method
Adding same class1 object
Class aldready added
Removing class1 object
Removing class1 object again
Class not in managed list
Adding uninitialized class2 object
Calling existing class2 object method against uninitialized class2 object
Initializing class2 object
Calling existing class2 object method
Removing class2 object
Notice that class2 object method is called AFTER class2 object has been removed.
In this particular case, welcome to event driven programming (the event queue is processed AFTER class removal)
Hi. I'm method Test from class Class2
I've been called with 0 parameter(s)

Note: If method is not called as expected, make sure you're not inserting a Null object or an uninitialized object. If object is uninitialized, initialization CAN happen after list insertion (not recommended).
 
Upvote 1
Solution

OliverA

Expert
Licensed User
Longtime User
Is it enough or you "need".
In this case it should be enough. The other case (I think if I understand it correctly) is trying to compare two maps that happen to have identical values. The map objects themselves are actually different memory objects. In this case, the class object always remains the same.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Any type of object.
Understood. We don't need this here. The only other thing that can get someone in trouble is the following:

B4X:
    Dim clsA As Class1
    clsA.Initialize
    Log("Adding clsA to manager")
    mgr.Add(clsA)
    Dim clsB As Class1
    clsB.Initialize
    Log("Creating clsB and assigning clsB to clsA")
    clsA = clsB
    Log("Trying to remove clsA from manager")
    mgr.Remove(clsA)
    Log("In this case, you've lost the ability to remove the original clsA from the list")

Output:

Adding clsA to manager
Creating clsB and assigning clsB to clsA
Trying to remove clsA from manager
Class not in managed list
In this case, you've lost the ability to remove the original clsA from the list

Some sort of "ID" may help in this situation, but then you would have to keep a list of IDs. As always, above is an example and any expansions to it are welcome (and hopefully shared).
 
Last edited:
Upvote 0

OliverA

Expert
Licensed User
Longtime User
I was thinking of a Map, not a List, with IDs as keys and classes (objects) as values.
I guess when I wrote list, I more meant some sort of container, be it Map, List, custom Type, etc. not just List per se. Again, that is another way of implementing it and I use such mechanisms, for example, in client server applications where I use a String id to connect the client to a server object (I think the Web Chat example uses such a mechanism). See https://www.b4x.com/android/forum/t...ads-sessions-and-server-events.39969/#content
 
Upvote 0
Top