Italian Ormai sono cotto DoUntil /Loop e company

antonio.murtino

Member
Licensed User
Longtime User
ho fuso, mi sono scervellato per trovare una soluzione che di fatto non doveva essere cercata, perché?, nello sviluppo di una app, mi sono imbattuto in una condizione che non mi aspettavo. In sostanza si tratta di un classico ciclo Do Until/loop, da cui si esce quando il valore di una variabile cambia, non capisco, ma si punta in modo strano, nei vari linguaggi adottati nel tempo, dove questi cicli comuni si utilizzano normalmente, qui bloccano tutta l'attività, anche se ho dei vaghi ricordi, ovvero di averli già utilizzati in B4A e di averli visti funzionare regolarmente, posto un codice semplificato:


B4X:
Sub Start
    Do Until ucc=1
    DoEvents
    Loop
End Sub

Sub Button1_Click
    ucc=1
    DoEvents
    Msgbox (ucc,"Valore")
End Sub

in sostanza , viene chiamata la sub Start, questa deve 'loopare' sino a che il valore della variabile ucc non muti, tale variabile dovrebbe modificarsi semplicemente cliccando sul button, il cui evento Click ne esegue l'azione, quindi si dovrebbe uscire dal loop e ritornare al punto successivo alla chiamata della Sub Start.

Bene, non ne esce piuuuuuù, nonostante si denoti la pressione del button. In qualsiasi linguaggio che si rispetti ho utilizzato questa forma per assicurarmi che una determinata condizione si fosse verificata per poi riprendere dal successivo.

Che idea avete sulla questione?
 

imgsimonebiliato

Well-Known Member
Licensed User
Longtime User
Dov'è che richiami la sub "Start"?

Mi sarei aspettato:


B4X:
Sub Button1_Click
    ucc=1
    Start
    Msgbox (ucc,"Valore")
End Sub
 

LordZenzo

Well-Known Member
Licensed User
Longtime User
viene da pensare che la variabile ucc non sia globale
se la dichiari in Globals e' globale solo nel modulo corrente
se in Process_Globals allora in tutta la app, anche nei service
no imgsimonebiliato lui vuole uscire dal loop premendo un button non entrare nel loop
io avvolte ho usato un espediente diverso
ossia usando il colore di un "semaforo" che indica allo stesso tempo inizio e fine di una azione
 

Picena Informatica

Active Member
Licensed User
Longtime User
Java esegue una funzione alla volta. la variabile la devi controllare con un evento (timer)
 

antonio.murtino

Member
Licensed User
Longtime User
No la variabile ucc è globale, il codice che ho postato è molto semplificato, ma in sostanza la chiamata alla sub Start è posta all'interno di un ciclo for next
B4X:
For i = 0 to 5
'faccio delle cose
Start
'Sono uscito proseguo
next
ritengo che la cosa sia strana, inserisco anche dei DoEvents per far si che tutti gli altri processi possano essere eseguiti, ma niente da li non ne esce.
 

antonio.murtino

Member
Licensed User
Longtime User
La cosa bella è che questo tipo di istruzione è presente in ogni linguaggio, l'ho testato è funziona alla perfezione, tra l'altro sono quasi certo di averla già utilizzata in B4A, ma tra la marea di codice che ho in archivio è come cercare un ago nel pagliaio.
L'unica cosa che non ho provato e ad eseguirla su un altro modello di smartphone, ma quello lo posso fare subito.
 

antonio.murtino

Member
Licensed User
Longtime User
Niente da fare, sono in palla, ho trovato soluzioni a problemi ben più complessi e mi areno in questa boiata
 

sirjo66

Well-Known Member
Licensed User
Longtime User
non puoi fare il Loop come hai fatto tu su Android, su altri linguaggi sì, ma qui no perché va in palla

devi mettere un timer, anche a 10 ms, che continua a chiamare Start, controlla la variabile ucc, esegue quello che deve eseguire, e poi esce, e il timer lo richiama.

A volte il DoEvents non fa quello che ci si aspetta, poi se il sistema operativo sente che la routine ci mette troppo tempo a terminare automaticamente la blocca perchè pensa sia andata in palla.
Su Android devi lavorare di più sugli eventi e di meno sulla programmazione lineare (cioè come stai facendo tu)

Sergio
 

antonio.murtino

Member
Licensed User
Longtime User
Mi spiego meglio, anzi vi posto il codice originale cosi magari comprendiamo meglio la questione e il perché non è possibile usare il timer, ho anche lavorato sugli eventi in fase primaria, perché pensavo che la semaforica fosse più precisa, ma capitava che dopo un po avveniva una "ExitApplication" senza volerla, come se si sovraccaricasse qualche cosa, ho fatto il debug di tutto il processo, ma non viene rilevato nulla, tutto normale.
Ho deciso allora di procedere con il modo di cui ora si discute:
B4X:
Sub SuReset

    Dim i As Int

    ErrorStatus=False '{Variabile Globale}

    For i =0 To 5

        SelectButton(i)
           
        DoEvents
   
        If dex.Tag="1"  Then '{dex è una variabile oggetto 'jolly' di tipo globale che assume temporaneamente le proprietà  e i metodi di altri oggetti}
            RD.Initialize("rd")
            dreq.InitializeGet("http://" & glob.Cnf(18) &":" & Port(i))
            RD.ExecuteCredentials(dreq,1,User,Password)
             dreq.InitializeGet("http://" & glob.Cnf(18) &":" & Port(i) &"/relays.cgi?relay=" & Rele(i))
            RD.Execute(dreq,1)
        End If
   
        Start '{Devo attendere finche non si sia verificato il ResponseSuccess o ResponseError da parte dell'oggetto RD}
    
    Next

    For i = 0 To 5
       SelectButton(i)
          dex.Tag="0"
          If Port(i)> 8000 Then
           dex.SetBackgroundImage(LoadBitmap(File.DirAssets,"button.png"))
          End If
    Next
    ProgressDialogHide

    If ErrorStatus=False Then
       Msgbox("Il reset delle periferiche è avvenuto correttamente.","Reset")
     Else
       Msgbox("Si sono verificati degli errori durante il reset.","Reset")
    End If

    Activity.Finish

End Sub

Sub rd_ResponseSuccess (Response As HttpResponse, TaskId As Int)
    Ucc=True
    DoEvents
End Sub

Sub rd_ResponseError (Response As HttpResponse, Reason As String, StatusCode As Int, TaskId As Int)
    Ucc=True
    ErrorStatus =True
End Sub

Sub Start
    Do Until Ucc=true
     DoEvents
    Loop
End Sub
si parte dal presupposto che tutti gli oggetti sono regolarmente dichiarati e che le procedure sono perfettamente funzionanti, infatti se al posto di Start ci metto una Msgbox per fermare temporaneamente il ciclo iterativo, tutto funziona a dovere.

La Sub SunReset viene regolarmente lanciata da una voce di menù.
 
Last edited:

antonio.murtino

Member
Licensed User
Longtime User
Se la cosa vi può interessare, nell'area "questions" in lingua inglese, Erel ha appena postato una sua disquisizione in merito, sostanzialmente dice di evitare i loop chiusi in questo modo in B4A perché prende un enorme tempo macchina intasando tutto il processo e che DoEvents serve ad un piffero.

Troveremo un'altro metodo, grazie a tutti per la partecipazione.
 

LucaMs

Expert
Licensed User
Longtime User
Beh, colui (a me da oggi non è permesso nominarlo e se lo faccio sarò anche bannato... quindi ne approfitto e vi saluto subito, perché sarò bannato sicuramente, visto che qualcosa qui comincia a starmi sul cazzo ) suggerisce di non usare nemmeno mai il DoEvents.

Ti assicuro che non solo anch'io ho usato spesso una "struttura" analoga, se non uguale, alla tua con altri linguaggi ed ambienti, ma che l'ho usata anche in b4a mi ha funzionato. E' però possibile che dipenda forse dalla velocità del dispositivo usato; forse mi ha funzionato su un dispositivo lento (si potrebbe pensare il contrario).
Il DoEvents dovrebbe far sì che anche l'intercettazione della pressione del Button venga eseguita e quindi la routine che ne gestice l'evento anche; non ho ben capito se a te risulta che la Button1_Click venga eseguita, ma suppongo di no, altrimenti dovresti ottenere l'uscita dal Loop.

Cmq, in questi casi, l'innominabile suggerisce sempre di usare dei timer (il che è una bella scocciatura, perché il "flusso" diventa sempre un bel casino)
 
Last edited:

LordZenzo

Well-Known Member
Licensed User
Longtime User
secondo me i timer sono una cagata pazzesca
come se invece di avere un cicalino al citofono, mi alzo dal divano ogni secondo e chiedo chi è presumendo che forse qualcuno citofona

comunque ti consiglio di usare gli eventi response e fare le azioni necessarie li
 

LucaMs

Expert
Licensed User
Longtime User

Hanno bannato (a proposito, hehehe) il famigerato GOTO e poi ti fanno fare i salti mortali coi timer!
 

antonio.murtino

Member
Licensed User
Longtime User

Be non è che ha detto di non usarli, l'indicazione era che l'uso di tali metodi non è "politicamente corretto", io in ogni caso li uso e continuerò ad usarli nei linguaggi in cui sono previsti, perché ne vedo l'utilità. In ogni caso nel mio codice non è possibile utilizzare i timer perché "desincronizzano" tutto il processo. Cercherò di utilizzare il codice basato sugli eventi come la prima versione e cercherò di capire il problema della fasulla "ExitApplication" che si verifica.
 

sirjo66

Well-Known Member
Licensed User
Longtime User
praticamente tu chiami la routine Start per attendere la risposta dal comando dreq.InitializeGet e l'errore più grave è qui, poichè l'http response lavora con eventi e non devi aspettare tu.

Praticamente inizializzi una variabile globale dove ti segni cosa stai facendo, ad esempio
Fase = "PrimoGet"
e poi nell'evento di ricezione dei dati, testando la variabile Fase sai cosa stai facendo,
quindi la inizializzi a Fase = "SecondoGet", esegui il secondo Get ed esci dalla routine, aspettando che l'evento venga di nuovo chiamato, e così via.

Sembra un po' difficile, ma ti assicuro che la strada è questa, io ho fatto parecchi programmi che devono gestire dati inviati/ricevuti da rete lan/internet e funzionano senza problemi

Sergio
 

luciano deri

Active Member
Licensed User
Longtime User
Il DoEvents fa notoriamente dei casini, va usato solo se hai bisogno di mostrare a l'utente un risultato parziale di una operazione lunga oppure un noise tipo progress bar. Non è adatto per gestire dei delay. Il timer è una soluzione un po' stupida ma talvolta efficace. Del resto lavoriamo con un sistema asincrono a eventi e non c'è un corpo di programma sempre in esecuzione.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…