B4J Question [ABMaterial] How to catch ABMTable's event if it was placed in a class?

incendio

Well-Known Member
Licensed User
Longtime User
Hello guys,

I made a class of ABMTable

These are a few codes of my class declaration
B4X:
Sub Class_Globals
    Private Tbl As ABMTable
    Private RowTheme As String
    Private NoOfRows, NoOfCols As Int
    Type CellInfo(Val As String,Thm As String)
End Sub

Sub Initialize(page As ABMPage,Headers() As String, HeadThemes() As String, Vis() As Boolean,HTheme As String,RTheme As String)
    Tbl.Initialize(page, "tbl1", False, False, True, HTheme)
    Tbl.SetHeaders(Headers)
    Tbl.SetColumnDataFields(Headers)
    Tbl.SetHeaderThemes(HeadThemes)
    Tbl.SetColumnVisible(Vis)
    Tbl.IsBordered = True
    RowTheme       = RTheme
    Log("initialize")
End Sub

Sub tbl1_Clicked(PassedRowsAndColumns As List)
    Log("tbl clicked")
End Sub

Public Sub ReturnABMTable As ABMComponent
   Return Tbl
End Sub

Public Sub GetActiveRow
   Return Tbl.GetActiveRow
End Sub

Public Sub TtlRows
   Return NoOfRows
End Sub

Public Sub TtlCols
   Return NoOfCols
End Sub

Properties & methods worked fine, except for event. The Sub tbl1_Clicked never called when table clicked.

When table clicked, nothing happen, no errors, and table seems not active. Usually, when table clicked, row that clicked became active, indicated by different color from another rows. But this is not a case.

I changed initialization codes to this
B4X:
Sub Initialize(page As ABMPage,Row As Int,Col As Int,Headers() As String, HeadThemes() As String, Vis() As Boolean,HTheme As String,RTheme As String)
    Tbl.Initialize(page, "tbl1", False, False, True, HTheme)
    Tbl.SetHeaders(Headers)
    Tbl.SetColumnDataFields(Headers)
    Tbl.SetHeaderThemes(HeadThemes)
    Tbl.SetColumnVisible(Vis)
    Tbl.IsBordered = True
    page.Cell(Row,Col).SetFixedHeight(300, True)
    page.Cell(Row,Col).AddComponent(Tbl)

    RowTheme       = RTheme
    Log("initialize")
End Sub

This time, when clicked, table became active, it was indicated by different color row, called to Sub GetActiveRow returns OK, but Sub tbl1_Clicked still never called.

Where did I miss ?
Thanks in advance.
 
Last edited:

incendio

Well-Known Member
Licensed User
Longtime User
I made another class, this time using ABMInput
B4X:
Sub Class_Globals
    Private TxtInput As ABMInput
    Private ABM As ABMaterial
End Sub

Public Sub Initialize(Row As Int, Col As Int,page As ABMPage,Handler As String, Lbl As String,CharCount As Int,Theme As String)
    TxtInput.Initialize(page, "TxtInput", ABM.INPUT_TEXT, Lbl, False, Theme)
    TxtInput.CharacterCounter = CharCount
    TxtInput.RaiseChangedEvent = True
    page.Cell(Row,Col).AddComponent(TxtInput)
End Sub

Sub TxtInput_Changed(value As String)
    Log("new value : " & value)
End Sub

Sub TxtInput_EnterPressed(value As String)
    Log("enter pressed : " & value)
End Sub

Events never called. Here are the lines on Logs window when I type a in that class & then pressed ENTER :
Params.Size: 2
Params.Size: 4
Params.Size: 3
Param: a
Params.Size: 3
Param: a
Params.Size: 2
Params.Size: 3
Param: a

Can anyone confirm that events for ABMTable & ABMInput won't work if it placed in a class?
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Yes, none of the the ABMComponents will raise an event placed in such a class. They are all raised within the parent page class. When an event from your browser arrives in B4J the all have to pass through the Page_Parseevent event and are then delegated to the 'correct' method.

There is a case #545 in the feedback app about that, however I have not found a solution without breaking all existing projects.
 
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
The best workaround I found is to do a callsub in the parseevent...
I have done so with a modal sheet and making callsub calls for the buttons...
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Tbl.Initialize(page, "tbl1", False, False, True, HTheme)
One of the problems with such a construction is the uniqueness of an ID. Like in this example if you create two instances of this class, both will have the same ID and in html that is a big problem. And you need the ID to create the events like tbl1_Clicked() so you cannot make it variable. There is no easy solution for this I'm afraid.
 
Upvote 0

incendio

Well-Known Member
Licensed User
Longtime User
One of the problems with such a construction is the uniqueness of an ID. Like in this example if you create two instances of this class, both will have the same ID and in html that is a big problem. And you need the ID to create the events like tbl1_Clicked() so you cannot make it variable. There is no easy solution for this I'm afraid.
In that code, I didn't know why the event was not called in that class, so it was a silly attempt, perhaps, using a constant string will do the trick which was still a failure.

By the way, since you said, event catch on page level, I made a little modification on Class initialization
B4X:
Sub Initialize(page As ABMPage,Handler As String, Row As Int,Col As Int,Headers() As String, HeadThemes() As String, Vis() As Boolean,HTheme As String,RTheme As String)
    Tbl.Initialize(page, Handler, False, False, True, HTheme)
    Tbl.SetHeaders(Headers)
    Tbl.SetColumnDataFields(Headers)
    Tbl.SetHeaderThemes(HeadThemes)
    Tbl.SetColumnVisible(Vis)
    Tbl.IsBordered = True
    page.Cell(Row,Col).SetFixedHeight(300, True)
    page.Cell(Row,Col).AddComponent(Tbl)
    RowTheme       = RTheme
    Log("initialize")
End Sub

Add Handler parameter in Sub Initialize, and moved Sub tbl_clicked from class to parent page.
On parent page, made this code
B4X:
tbl1.Initialize(page,"tbl1",2,1, Array As String("ID","Group","Locked"), Array As String("tblheader","tblheader","tblheader"), Array As Boolean(False,True,True),"tbltheme","tblrow")

Sub tbl1_Clicked(PassedRowsAndColumns As List)
   Log("tbl clicked")
   Private tblCellInfo As ABMTableCell = PassedRowsAndColumns.Get(0)
   txtGrp.Text = tbl1.GetString(tblCellInfo.Row, tblCellInfo.Column)
   txtGrp.Refresh
   txtGrp.SetFocus
   page.ShowToast("0","toastred","Row : " & tblCellInfo.Row & " col : " & tblCellInfo.Column ,2000)
End Sub

Log("tbl clicked") on Sub tbl1_Clicked never showed in B4J's log window - strange, but the rest of the line executed fine.

So, I guest it will do the trick. On my class, there are properties & methods, while for events, since they are already catch by page, just make a Sub to handle it if necessary.
 
Upvote 0

incendio

Well-Known Member
Licensed User
Longtime User
I was wrong, events still won't work in class.

There are 2 weird things :
1) Run app without class, after event triggered, change codes in app to use class and run again, event still triggered even after pressed CTRL F5 & kill proses and clean project. But when PC restart, run app that use class, this time event won't work.

2) When using table in class, event was not catch by Page_Parseevent. When I clicked on table created by Class, B4J's Log window should log eventname, but it was nothing. Other component such as ABMInput registered their event on Log window but not ABMTable created with class

So, now back again to simple code module to create ABMTable.
 
Upvote 0
Top