B4J Question [SOLVED] Loading window over the others (like modal)

jroriz

Active Member
Licensed User
Longtime User
I would like to show a window "loading" while the system is validated for use.
But the window does not appear over the others, certainly because of operations involving a remote database.
Any idea?

loading.PNG


B4X:
Sub AppStart (Form1 As Form, Args() As String)
    
    fWait.Initialize("sp", 100, 100)
    fWait.SetFormStyle("UNDECORATED")
    fWait.SetFormStyle("TRANSPARENT")
    fWait.BackColor = fx.Colors.Transparent
    CSSUtils.SetBackgroundImage(fWait.RootPane, File.DirAssets, "loading.gif")

    fWait.Show    ' DOES NOT POPS UP THE FORM DUE TO DATABASE STUFF BELOW
    
    MainForm = Form1
    
    If File.DirApp.ToLowerCase.Contains(desenv) Then
        Principal
        Return
    End If
    
    Try
        pool.Initialize(DriverClass, JdbcURL, DBUsername, DBPassword)
    Catch
        fx.Msgbox(MainForm, LastException, msgErroBanco)
        ExitApplication
    End Try
    
    If File.Exists(File.DirApp, arqchave) = False Then
        chave.Show
    Else

        schave = File.ReadString(File.DirApp, arqchave)
        
        banco = pool.GetConnection
            
        ' apagar sessoes que podem ter ficado "presas"
        banco.BeginTransaction
        banco.ExecNonQuery(qDeleteOld & Plic(getmac.MacAddressFromClient))
        banco.TransactionSuccessful
        
        If chave.ChaveValida(schave) Then

            banco.BeginTransaction
            Log(getmac.MacAddressFromClient)
            banco.ExecNonQuery2(InserirChave, Array(schave, getmac.MacAddressFromClient))
            banco.TransactionSuccessful

            banco.Close
            pool.ClosePool
            Principal    ' main sub
        Else
            banco.Close
            chave.Show
        End If
    End If
        
End Sub
 

Jorge M A

Well-Known Member
Licensed User
Longtime User
Maybe (and only maybe) you can take the concept of the Splash Screen and adapt it to your needs with a Wait For (your process..)
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
1) Use B4xDialog from XUI Views Lib with a custom dialog, and use it in place of fx.MsgBox as well.
2) Put a Sleep(0) statement after the fWait.Show call
 
Upvote 0

jroriz

Active Member
Licensed User
Longtime User
Well, I created a project that reproduces the scenario that I need and that is not working as expected:

1 - Show an animated GIF so that it is clear that the user has to wait.

2 - Perform system startup operations. Meanwhile, the GIF from step 1 must be on the screen, ANIMATED.

3 - After everything is ready, the animated GIF disappears and the main form is shown.

In the attached project the animated GIF does not appear.
Code below.

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
    #AdditionalJar: mysql-connector-java-5.1.48.jar
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form

#Region Database Location
    ' do not worry: created just for test
    Private DBUsername As String = "us13022020"
    Private DBPassword As String = "12345678"
    Private DriverClass As String = "com.mysql.jdbc.Driver"
    Private JdbcURL As String = "jdbc:mysql://db4free.net/db13022020?characterEncoding=utf8"
    
    Private pool As ConnectionPool, db As SQL
    Private sp As Form
#End Region

End Sub

Sub AppStart (Form1 As Form, Args() As String)

    MainForm = Form1

    ShowWait    ' transparent form wiht a wait animated gif
    ' Its not showing up
    
    PreparingSystem    ' initial database stuff

    ' should stay visible until PreparingSystem finishs
    sp.Close    ' closes the wait form
    
    MainForm.Show

    fx.Msgbox(MainForm, "SYSTEM READY!", "")

End Sub

Sub ShowWait
    
    sp.Initialize("sp", 300, 300)
    sp.WindowLeft = 0
    sp.WindowTop = 0
    sp.SetFormStyle("TRANSPARENT")
    sp.BackColor = fx.Colors.Transparent
    'change image here
    CSSUtils.SetBackgroundImage(sp.RootPane, File.DirAssets, "wait.gif")
    sp.Show

End Sub

Sub PreparingSystem
    
    Log("Preparing system...")

    Try
        Log("Connecting...")
        pool.Initialize(DriverClass, JdbcURL, DBUsername, DBPassword)
    Catch
        fx.Msgbox(MainForm, LastException, "Connection error")
        ExitApplication
    End Try

    db = pool.GetConnection
    
    db.BeginTransaction
    
    For i = 1 To 2
        Log("R/W " & i)
        Dim nrec As Int = db.ExecQuerySingleResult("SELECT count(*)+1 FROM table1")
        Log(db.ExecQuerySingleResult("SELECT text FROM table1 WHERE id = " & Rnd(1, nrec)))
        db.ExecNonQuery($"INSERT INTO table1 (text) values (${DateTime.Now})"$)
    Next
    
    db.TransactionSuccessful
    
    db.Close
    pool.ClosePool

End Sub

'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub
 

Attachments

  • test.zip
    150.9 KB · Views: 172
Upvote 0

stevel05

Expert
Licensed User
Longtime User
If you add a Sleep(50) statement immediately after the ShowWait call and set the sp form AlwaysOnTop it will show up, but its not animating.

You will probably need to run the queries ASync and use Wait For for the result and for the call to the PreparingSystem Sub to get it to do what you want.
 
Last edited:
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
Could you not just make PreparingSystem a ResumableSub and call it with
B4X:
...
ShowWait    ' transparent form with a wait animated gif
Wait For (PreparingSystem) Complete
...

This was the full code I used (removed db stuff as I don't have correct drivers)
B4X:
Sub Process_Globals
    Private fx As JFX
    Private sp As Form
End Sub

Sub AppStart (MainForm As Form, Args() As String)
    ShowWait    ' transparent form with a wait animated gif
    Wait For (PreparingSystem) Complete 
    sp.Close    ' closes the wait form
    MainForm.Show
    fx.Msgbox(MainForm, "SYSTEM READY!", "")
End Sub

Sub ShowWait
    sp.Initialize("sp", 300, 300)
    sp.WindowLeft = 0
    sp.WindowTop = 0
    sp.SetFormStyle("TRANSPARENT")
    sp.BackColor = fx.Colors.Transparent
    'change image here
    CSSUtils.SetBackgroundImage(sp.RootPane, File.DirAssets, "wait.gif")
    sp.Show
End Sub

Sub PreparingSystem As ResumableSub
    Log("Preparing system...")
    For a = 0 To 250000 ' for loop delay
        Log(a)
        Sleep(0) ' need this in the loop
    Next
End Sub
 
Last edited:
Upvote 0

jroriz

Active Member
Licensed User
Longtime User
Could you not just make PreparingSystem a ResumableSub and call it with
B4X:
...
ShowWait    ' transparent form with a wait animated gif
Wait For (PreparingSystem) Complete
...

This was the full code I used (removed db stuff as I don't have correct drivers)
B4X:
Sub Process_Globals
    Private fx As JFX
    Private sp As Form
End Sub

Sub AppStart (MainForm As Form, Args() As String)
    ShowWait    ' transparent form with a wait animated gif
    Wait For (PreparingSystem) Complete
    sp.Close    ' closes the wait form
    MainForm.Show
    fx.Msgbox(MainForm, "SYSTEM READY!", "")
End Sub

Sub ShowWait
    sp.Initialize("sp", 300, 300)
    sp.WindowLeft = 0
    sp.WindowTop = 0
    sp.SetFormStyle("TRANSPARENT")
    sp.BackColor = fx.Colors.Transparent
    'change image here
    CSSUtils.SetBackgroundImage(sp.RootPane, File.DirAssets, "wait.gif")
    sp.Show
End Sub

Sub PreparingSystem As ResumableSub
    Log("Preparing system...")
    For a = 0 To 250000 ' for loop delay
        Log(a)
        Sleep(0) ' need this in the loop
    Next
End Sub

But the database stuff is what make GIF freeze.
Putting sleep (50) after the ShoWait and using the Wait For (PreparingSystem) Complete, the GIF appears, but is not animated.
 
Upvote 0

Jorge M A

Well-Known Member
Licensed User
Longtime User
With or without the database connection, the behavior is the same.
Here is the code that has been suggested to you, and connecting it to my database works as described.

Note that I made some small changes, like first showing the MainForm and then assigning it as the parent to the sp, just for the gif to appear above the main form.

B4X:
Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.Show
    ShowWait    ' transparent form with a wait animated gif
    Wait For (PreparingSystem) Complete
    sp.Close    ' closes the wait form
    fx.Msgbox(MainForm, "SYSTEM READY!", "")
End Sub

Sub ShowWait
    Dim sp As Form
    sp.Initialize("sp", MainForm.Width, MainForm.Height)
    sp.AlwaysOnTop=True
    sp.SetFormStyle("TRANSPARENT")
    sp.BackColor = fx.Colors.Transparent
    
    'change image here
    CSSUtils.SetBackgroundImage(sp.RootPane, File.DirAssets, "wait.gif")
    
    sp.SetOwner(MainForm)            'Will appear above MainForm
    sp.Show
    
End Sub
 

Attachments

  • test.zip
    130.1 KB · Views: 181
Upvote 0

jroriz

Active Member
Licensed User
Longtime User
Using my database, GIF freezes.
You can try with my database. I created it only for this test.
I put some sleep (50) but the result was strange.

Thats my PreparingSystem sub:
Sub PreparingSystem:
Sub PreparingSystem As ResumableSub
    
    Log("Preparing system...")

    Try
        Log("Connecting...")
        pool.Initialize(DriverClass, JdbcURL, DBUsername, DBPassword)
        Sleep(50)
        
        db = pool.GetConnection
        Sleep(50)

        db.BeginTransaction
        Sleep(50)
    
        For i = 1 To 2
            Log("R/W " & i)

            Dim nrec As Int = db.ExecQuerySingleResult("SELECT count(*)+1 FROM table1")
            Sleep(50)
            Log(db.ExecQuerySingleResult("SELECT text FROM table1 WHERE id = " & Rnd(1, nrec)))
            Sleep(50)
            db.ExecNonQuery($"INSERT INTO table1 (text) values (${DateTime.Now})"$)
            Sleep(50)
        Next
    
        db.TransactionSuccessful
        Sleep(50)

    Catch
        fx.Msgbox(MainForm, LastException, "Connection error")
    End Try

    
    db.Close
    Sleep(50)
    pool.ClosePool
    Sleep(50)

    Return Null
End Sub
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Using sleep in a sub that us using Synchronious calls will have no effect, you will need to change the db calls to use db.ExecQueryAsync and wait for the results. Then you won't need the sleeps in the sub
 
Last edited:
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Something like this

B4X:
Sub PreparingSystem As ResumableSub

  

    Log("Preparing system...")



    Try

        Log("Connecting...")

        pool.Initialize(DriverClass, JdbcURL, DBUsername, DBPassword)

      

        pool.GetConnectionAsync("GetConnection")

        Wait For GetConnection_ConnectionReady (Success As Boolean, tdb As SQL)

        db = tdb



        db.BeginTransaction

  

        For i = 1 To 2

            Log("R/W " & i)



            Dim RS As Object = db.ExecQueryAsync("Task1","SELECT count(*)+1 FROM table1",Null)

            Wait For Task1_QueryComplete (Success As Boolean, Crsr As ResultSet)

          

            Do While Crsr.NextRow

                Dim nrec As Int = Crsr.GetInt2(0)

                Log("Nrecs " & nrec)

            Loop

          

          

'            Log(db.ExecQuerySingleResult("SELECT text FROM table1 WHERE id = " & Rnd(1, nrec)))





            db.AddNonQueryToBatch($"INSERT INTO table1 (text) values (${DateTime.Now})"$,Null)

            Dim RS As Object = db.ExecNonQueryBatch("Task2")

            Wait for (RS) Task2_NonQueryComplete (Success As Boolean)

          

        Next

  

        db.TransactionSuccessful



    Catch

        fx.Msgbox(MainForm, LastException, "Connection error")

    End Try



  

    db.Close

    pool.ClosePool

    Log("Done")

    Return True

End Sub
 
Upvote 0

jroriz

Active Member
Licensed User
Longtime User
Something like this

B4X:
Sub PreparingSystem As ResumableSub



    Log("Preparing system...")



    Try

        Log("Connecting...")

        pool.Initialize(DriverClass, JdbcURL, DBUsername, DBPassword)

    

        pool.GetConnectionAsync("GetConnection")

        Wait For GetConnection_ConnectionReady (Success As Boolean, tdb As SQL)

        db = tdb



        db.BeginTransaction



        For i = 1 To 2

            Log("R/W " & i)



            Dim RS As Object = db.ExecQueryAsync("Task1","SELECT count(*)+1 FROM table1",Null)

            Wait For Task1_QueryComplete (Success As Boolean, Crsr As ResultSet)

        

            Do While Crsr.NextRow

                Dim nrec As Int = Crsr.GetInt2(0)

                Log("Nrecs " & nrec)

            Loop

        

        

'            Log(db.ExecQuerySingleResult("SELECT text FROM table1 WHERE id = " & Rnd(1, nrec)))





            db.AddNonQueryToBatch($"INSERT INTO table1 (text) values (${DateTime.Now})"$,Null)

            Dim RS As Object = db.ExecNonQueryBatch("Task2")

            Wait for (RS) Task2_NonQueryComplete (Success As Boolean)

        

        Next



        db.TransactionSuccessful



    Catch

        fx.Msgbox(MainForm, LastException, "Connection error")

    End Try





    db.Close

    pool.ClosePool

    Log("Done")

    Return True

End Sub
That's it!
Case closed...
 
Upvote 0
Top