B4J Question [SOLVED]Execute process e read output inside a TUI (Lanterna)

a.consorti

Member
Licensed User
Good morning lads,
I come back to you with yet another dilemma trying to understand how to execute a command and read its output from a terminal interface created using the lanterna library.
I understand that the problem is linked to the fact that the "Wait for" event of the command to be executed is not triggered. In practice the code does not error but nothing returns.
Below I show you all the code affected by the problem:

Full_Code:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

#AdditionalJar: lanterna-3.1.2.jar
#MergeLibraries: True

'GLI EVENTI FUNZIONANO SOLO IN RELEASE

Sub Process_Globals
    Private Terminal, Screen As JavaObject
    Private form, gui As JavaObject
    Private TextGraphics As JavaObject
    Private pannello As JavaObject
    Private lblRisultato As JavaObject
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    ' Setup terminal and screen layers
    Terminal = CreateTerminal
    Screen = CreateScreen(Terminal)
    Screen.RunMethod("startScreen", Null)
    Screen.RunMethod("clear", Null)
    TextGraphics = Screen.RunMethod("newTextGraphics", Null)
    
    ' Create panel to hold components
    pannello = CreatePanel
    pannello.RunMethod("setLayoutManager", Array As Object(CreateGridLayout(2)))
    

    Dim spazio_vuoto As JavaObject = CreateEmptySpace(CreateTerminalSize(0,0))
    lblRisultato = CreateLabel("Risultato:")
    
    Dim button2 As JavaObject = CreateButton("COMANDO", CreateRunnable("Button2"))

  
    pannello.RunMethod("addComponent", Array As Object(spazio_vuoto))
    pannello.RunMethod("addComponent", Array As Object(button2))
    pannello.RunMethod("addComponent", Array As Object(spazio_vuoto))
    pannello.RunMethod("addComponent", Array As Object(lblRisultato))

    ' Create window to hold the panel
    form = CreateBasicWindow
    form.RunMethod("setComponent", Array As Object(pannello))
        
    ' Create gui and start gui
    gui = MultiWindowTextGUI(Screen, CreateWindowManager, CreateEmptySpaceTextColor(CreateTextColor("RED")))
    gui.RunMethod("addWindowAndWait", Array As Object(form))

    ShowMessageDialog("WARNING", "PROGRAMMA TERMINATO")
End Sub

Sub Button2_Event (MethodName As String, Args() As Object)
    Log("Esecuzione binario e lettura output - Evento Button2 chiamato")
    Dim cmdArgs As List
    cmdArgs.Initialize
    cmdArgs.Add("Hello World") ' Usa un comando semplice per il debug
    Wait For (ExecuteCommand("echo", cmdArgs)) Complete (Result As String)
    Log("Risultato: " & Result)
    lblRisultato.RunMethod("setText", Array As Object((Result).As(String)))
End Sub

Sub DetectOS As String
    Dim os As String = GetSystemProperty("os.name", "").ToLowerCase
    If os.Contains("win") Then
        Return "windows"
    Else If os.Contains("mac") Then
        Return "mac"
    Else
        Return "linux"
    End If
End Sub

Sub JoinStrings(list As List, delimiter As String) As String
    Dim sb As StringBuilder
    sb.Initialize
    For Each item As String In list
        If sb.Length > 0 Then
            sb.Append(delimiter)
        End If
        sb.Append(item)
    Next
    Return sb.ToString
End Sub

Sub ExecuteCommand(command As String, Args As List) As ResumableSub
    Dim pb As JavaObject
    Dim params As List
    params.Initialize
    If DetectOS=="windows" Then
        params.Add("cmd")
        params.Add("/c")
    Else If  DetectOS=="linux" Then
        params.Add("/bin/bash")
        params.Add("-c")
    End If

    params.Add(command & " " & JoinStrings(Args, " "))
    pb.InitializeNewInstance("java.lang.ProcessBuilder", Array(params))
    
    Try
        Dim process As JavaObject = pb.RunMethod("start", Null)
        Dim exitCode As Int = process.RunMethod("waitFor", Null)
        
        ' Lettura dell'output standard
        Dim inputStream As JavaObject = process.RunMethod("getInputStream", Null)
        Dim inputStreamReader As JavaObject
        inputStreamReader.InitializeNewInstance("java.io.InputStreamReader", Array(inputStream))
        Dim bufferedReader As JavaObject
        bufferedReader.InitializeNewInstance("java.io.BufferedReader", Array(inputStreamReader))
        
        Dim stdOut As StringBuilder
        stdOut.Initialize
        Dim line As String
        Dim keepReading As Boolean = True
        Do While keepReading
            line = bufferedReader.RunMethod("readLine", Null)
            If line = Null Then
                keepReading = False
            Else
                stdOut.Append(line).Append(CRLF)
            End If
        Loop
        
        ' Lettura dell'output di errore
        Dim errorStream As JavaObject = process.RunMethod("getErrorStream", Null)
        Dim errorStreamReader As JavaObject
        errorStreamReader.InitializeNewInstance("java.io.InputStreamReader", Array(errorStream))
        Dim errorBufferedReader As JavaObject
        errorBufferedReader.InitializeNewInstance("java.io.BufferedReader", Array(errorStreamReader))
        
        Dim stdErr As StringBuilder
        stdErr.Initialize
        keepReading = True
        Do While keepReading
            line = errorBufferedReader.RunMethod("readLine", Null)
            If line = Null Then
                keepReading = False
            Else
                stdErr.Append(line).Append(CRLF)
            End If
        Loop

        If exitCode = 0 Then
            Log("Successo dell'esecuzione del comando")
            Log("Output: " & stdOut.ToString)
            Return stdOut.ToString
        Else
            Log("Errore nell'esecuzione del comando")
            Log("ExitCode: " & exitCode)
            Log("StdErr: " & stdErr.ToString)
            Return stdErr.ToString
        End If
    Catch
        Log("Errore durante l'esecuzione del comando: " & LastException)
        Return LastException
    End Try
End Sub

Sub ShowMessageDialog(title As String, message As String)
    Dim MessageDialogButton As JavaObject
    MessageDialogButton.InitializeStatic("com.googlecode.lanterna.gui2.dialogs.MessageDialogButton")
    Dim buttonOK As Object = MessageDialogButton.GetField("OK")
    Dim MessageDialog As JavaObject
    MessageDialog.InitializeStatic("com.googlecode.lanterna.gui2.dialogs.MessageDialog")
    Dim jo As JavaObject
    MessageDialog.RunMethod("showMessageDialog", Array As Object(gui, title, message, jo.InitializeArray("com.googlecode.lanterna.gui2.dialogs.MessageDialogButton", Array(buttonOK))))
End Sub

Sub CreateButton(par_title As String, runnable As JavaObject) As JavaObject
    Dim jo As JavaObject
    Return jo.InitializeNewInstance("com.googlecode.lanterna.gui2.Button", Array(par_title, runnable))
End Sub

Sub CreateRunnable (EventName As String) As Object
    Dim jo As JavaObject
    jo.InitializeNewInstance("java.lang.Object", Null)
    Return jo.CreateEvent("java.lang.Runnable", EventName, False)
End Sub

Sub CreateTerminalSize(colonne As Int, righe As Int) As JavaObject
    Dim componente As JavaObject
    Return componente.InitializeNewInstance("com.googlecode.lanterna.TerminalSize", Array As Object(colonne, righe))
End Sub

Sub CreateLabel(etichetta As String) As JavaObject
    Dim componente As JavaObject
    Return componente.InitializeNewInstance("com.googlecode.lanterna.gui2.Label", Array As Object(etichetta))
End Sub

Sub CreateGridLayout(colonne As Int) As JavaObject
    Dim gl As JavaObject
    Return gl.InitializeNewInstance("com.googlecode.lanterna.gui2.GridLayout", Array As Object(colonne))
End Sub

Sub CreatePanel As JavaObject
    Dim pnl As JavaObject
    Return pnl.InitializeNewInstance("com.googlecode.lanterna.gui2.Panel", Null)
End Sub

Sub CreateBasicWindow As JavaObject
    Dim window As JavaObject
    Return window.InitializeNewInstance("com.googlecode.lanterna.gui2.BasicWindow", Null)
End Sub

Sub CreateEmptySpace(par_terminal_size As JavaObject) As JavaObject
    Dim componente As JavaObject
    Return componente.InitializeNewInstance("com.googlecode.lanterna.gui2.EmptySpace", Array As Object(par_terminal_size))
End Sub

Sub CreateEmptySpaceTextColor(par_text_color As JavaObject) As JavaObject
    Dim componente As JavaObject
    Return componente.InitializeNewInstance("com.googlecode.lanterna.gui2.EmptySpace", Array As Object(par_text_color))
End Sub

Sub CreateTextColor(color As String) As JavaObject
    Dim textColorFactory As JavaObject
    textColorFactory.InitializeStatic("com.googlecode.lanterna.TextColor$Factory")
    Dim tc As JavaObject
    tc = textColorFactory.RunMethod("fromString", Array As Object(color))
    Return tc
End Sub



Sub MultiWindowTextGUI(scr As Object, windowmanager As Object, bg As Object) As JavaObject
    Dim gui As JavaObject
    Return gui.InitializeNewInstance("com.googlecode.lanterna.gui2.MultiWindowTextGUI", Array As Object(scr, windowmanager, bg))
End Sub



Sub CreateWindowManager As JavaObject
    Dim wm As JavaObject
    Return wm.InitializeNewInstance("com.googlecode.lanterna.gui2.DefaultWindowManager", Null)
End Sub

Sub CreateTerminal As JavaObject
    Dim factory As JavaObject
    Return factory.InitializeNewInstance("com.googlecode.lanterna.terminal.DefaultTerminalFactory", Null).RunMethod("createTerminal", Null)
End Sub

Sub CreateScreen(Term As Object) As JavaObject
    Dim s As JavaObject
    Return s.InitializeNewInstance("com.googlecode.lanterna.screen.TerminalScreen", Array(Term))
End Sub



Public Sub SetString (s As String, Column As Int, Row As Int)
    TextGraphics.RunMethod("putString", Array(Column, Row, s))
End Sub

I hope you can give me a hand. Thank you
 
Solution
I hope you can give me a hand. Thank you

Don't use shell. this code works

B4X:
Sub Button2_Event (MethodName As String, Args() As Object)
    Log("Esecuzione binario e lettura output - Evento Button2 chiamato")
    Dim cmdArgs As List
    cmdArgs.Initialize
    cmdArgs.Add("Hello world!") ' Usa un comando semplice per il debug
    lblRisultato.RunMethod("setText", Array As Object(ExecuteCommand("echo", cmdArgs)))
End Sub

Sub ExecuteCommand(command As String, Args As List) As String
    Dim pb As JavaObject
    Dim params As List
    params.Initialize
    If DetectOS=="windows" Then
        params.Add("cmd")
        params.Add("/c")
    Else If  DetectOS=="linux" Then
        params.Add("/bin/bash")
        params.Add("-c")...

a.consorti

Member
Licensed User
Today I updated with that code but the result waited to be shown until I close the program:


B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

#AdditionalJar: lanterna-3.2.0-alpha1.jar
#MergeLibraries: True

'GLI EVENTI FUNZIONANO SOLO IN RELEASE

Sub Process_Globals
    Private Terminal, Screen As JavaObject
    Private form, gui As JavaObject
    Private TextGraphics As JavaObject
    Private pannello As JavaObject
    Private lblRisultato As JavaObject
    
    Private output As String
    End Sub

Sub AppStart (Form1 As Form, Args() As String)
    ' Setup terminal and screen layers
    Terminal = CreateTerminal
    Screen = CreateScreen(Terminal)
    Screen.RunMethod("startScreen", Null)
    Screen.RunMethod("clear", Null)
    TextGraphics = Screen.RunMethod("newTextGraphics", Null)
    
    ' Create panel to hold components
    pannello = CreatePanel
    pannello.RunMethod("setLayoutManager", Array As Object(CreateGridLayout(2)))
    

    Dim spazio_vuoto As JavaObject = CreateEmptySpace(CreateTerminalSize(0,0))
    lblRisultato = CreateLabel("Risultato:")
    
    Dim button2 As JavaObject = CreateButton("COMANDO", CreateRunnable("Button2"))

 
    pannello.RunMethod("addComponent", Array As Object(spazio_vuoto))
    pannello.RunMethod("addComponent", Array As Object(button2))
    pannello.RunMethod("addComponent", Array As Object(spazio_vuoto))
    pannello.RunMethod("addComponent", Array As Object(lblRisultato))

    ' Create window to hold the panel
    form = CreateBasicWindow
    form.RunMethod("setComponent", Array As Object(pannello))
        
    ' Create gui and start gui
    gui = MultiWindowTextGUI(Screen, CreateWindowManager, CreateEmptySpaceTextColor(CreateTextColor("RED")))
    gui.RunMethod("addWindowAndWait", Array As Object(form))

    ShowMessageDialog("WARNING", "PROGRAMMA TERMINATO")
End Sub

Sub Button2_Event (MethodName As String, Args() As Object)
    Log("Esecuzione binario e lettura output - Evento Button2 chiamato")
    Private shl As Shell
    Dim params As List
    params.Initialize
    params.Add("/c")
    params.Add("dir")
    params.Add("c:\")
    shl.Initialize("shl","cmd.exe",params)
    shl.WorkingDirectory =  "C:\Windows\system32"

    shl.Run(-1)
 
    Wait For shl_ProcessCompleted (Success As Boolean, ExitCode As Int, StdOut As String, StdErr As String)
    If Success And ExitCode = 0 Then
        Log("Success")
        Log($" ${StdOut} "$)
        
    Else
      
        Log("Error: " & StdErr)
      
    End If


End Sub


Sub UpdateLabelWithOutput(outputvar As String)
    If lblRisultato.IsInitialized Then
        lblRisultato.RunMethod("setText", Array As Object(outputvar))
    End If
End Sub


Sub DetectOS As String
    Dim os As String = GetSystemProperty("os.name", "").ToLowerCase
    If os.Contains("win") Then
        Return "windows"
    Else If os.Contains("mac") Then
        Return "mac"
    Else
        Return "linux"
    End If
End Sub


Sub ShowMessageDialog(title As String, message As String)
    Dim MessageDialogButton As JavaObject
    MessageDialogButton.InitializeStatic("com.googlecode.lanterna.gui2.dialogs.MessageDialogButton")
    Dim buttonOK As Object = MessageDialogButton.GetField("OK")
    Dim MessageDialog As JavaObject
    MessageDialog.InitializeStatic("com.googlecode.lanterna.gui2.dialogs.MessageDialog")
    Dim jo As JavaObject
    MessageDialog.RunMethod("showMessageDialog", Array As Object(gui, title, message, jo.InitializeArray("com.googlecode.lanterna.gui2.dialogs.MessageDialogButton", Array(buttonOK))))
End Sub

Sub CreateButton(par_title As String, runnable As JavaObject) As JavaObject
    Dim jo As JavaObject
    Return jo.InitializeNewInstance("com.googlecode.lanterna.gui2.Button", Array(par_title, runnable))
End Sub

Sub CreateRunnable (EventName As String) As Object
    Dim jo As JavaObject
    jo.InitializeNewInstance("java.lang.Object", Null)
    Return jo.CreateEvent("java.lang.Runnable", EventName, False)
End Sub

Sub CreateTerminalSize(colonne As Int, righe As Int) As JavaObject
    Dim componente As JavaObject
    Return componente.InitializeNewInstance("com.googlecode.lanterna.TerminalSize", Array As Object(colonne, righe))
End Sub

Sub CreateLabel(etichetta As String) As JavaObject
    Dim componente As JavaObject
    Return componente.InitializeNewInstance("com.googlecode.lanterna.gui2.Label", Array As Object(etichetta))
End Sub

Sub CreateGridLayout(colonne As Int) As JavaObject
    Dim gl As JavaObject
    Return gl.InitializeNewInstance("com.googlecode.lanterna.gui2.GridLayout", Array As Object(colonne))
End Sub

Sub CreatePanel As JavaObject
    Dim pnl As JavaObject
    Return pnl.InitializeNewInstance("com.googlecode.lanterna.gui2.Panel", Null)
End Sub

Sub CreateBasicWindow As JavaObject
    Dim window As JavaObject
    Return window.InitializeNewInstance("com.googlecode.lanterna.gui2.BasicWindow", Null)
End Sub

Sub CreateEmptySpace(par_terminal_size As JavaObject) As JavaObject
    Dim componente As JavaObject
    Return componente.InitializeNewInstance("com.googlecode.lanterna.gui2.EmptySpace", Array As Object(par_terminal_size))
End Sub

Sub CreateEmptySpaceTextColor(par_text_color As JavaObject) As JavaObject
    Dim componente As JavaObject
    Return componente.InitializeNewInstance("com.googlecode.lanterna.gui2.EmptySpace", Array As Object(par_text_color))
End Sub

Sub CreateTextColor(color As String) As JavaObject
    Dim textColorFactory As JavaObject
    textColorFactory.InitializeStatic("com.googlecode.lanterna.TextColor$Factory")
    Dim tc As JavaObject
    tc = textColorFactory.RunMethod("fromString", Array As Object(color))
    Return tc
End Sub



Sub MultiWindowTextGUI(scr As Object, windowmanager As Object, bg As Object) As JavaObject
    Dim gui As JavaObject
    Return gui.InitializeNewInstance("com.googlecode.lanterna.gui2.MultiWindowTextGUI", Array As Object(scr, windowmanager, bg))
End Sub



Sub CreateWindowManager As JavaObject
    Dim wm As JavaObject
    Return wm.InitializeNewInstance("com.googlecode.lanterna.gui2.DefaultWindowManager", Null)
End Sub

Sub CreateTerminal As JavaObject
    Dim factory As JavaObject
    Return factory.InitializeNewInstance("com.googlecode.lanterna.terminal.DefaultTerminalFactory", Null).RunMethod("createTerminal", Null)
End Sub

Sub CreateScreen(Term As Object) As JavaObject
    Dim s As JavaObject
    Return s.InitializeNewInstance("com.googlecode.lanterna.screen.TerminalScreen", Array(Term))
End Sub



Public Sub SetString (s As String, Column As Int, Row As Int)
    TextGraphics.RunMethod("putString", Array(Column, Row, s))
End Sub
 
Last edited:
Upvote 0

teddybear

Well-Known Member
Licensed User
I hope you can give me a hand. Thank you

Don't use shell. this code works

B4X:
Sub Button2_Event (MethodName As String, Args() As Object)
    Log("Esecuzione binario e lettura output - Evento Button2 chiamato")
    Dim cmdArgs As List
    cmdArgs.Initialize
    cmdArgs.Add("Hello world!") ' Usa un comando semplice per il debug
    lblRisultato.RunMethod("setText", Array As Object(ExecuteCommand("echo", cmdArgs)))
End Sub

Sub ExecuteCommand(command As String, Args As List) As String
    Dim pb As JavaObject
    Dim params As List
    params.Initialize
    If DetectOS=="windows" Then
        params.Add("cmd")
        params.Add("/c")
    Else If  DetectOS=="linux" Then
        params.Add("/bin/bash")
        params.Add("-c")
    End If
    params.Add(command & " " & JoinStrings(Args, " "))
    pb.InitializeNewInstance("java.lang.ProcessBuilder", Array(params)) 
    Dim process As JavaObject = pb.RunMethod("start", Null)
    Dim exitCode As Int = process.RunMethod("waitFor", Null)
        
    ' Lettura dell'output standard
    Dim inputStream As JavaObject = process.RunMethod("getInputStream", Null)
    Dim b() As Byte
    b=inputStream.RunMethod("readAllBytes",Null)
    Dim bc As ByteConverter
    Dim stdout As String=bc.StringFromBytes(b,"utf8")
    If exitCode = 0 Then
        Log("Successo dell'esecuzione del comando")
        Return stdout
    End If
    Return "Cmd exec error"
End Sub
 
Upvote 0
Solution
Top