Form.showmodal

  1. 3 weeks ago

    Ragazzi, ho un altro problemino. Nell'esecuzione di una stampa o nel caricamento di dati ho utilizzato un form.show con la scritta "elaborazione in corso", perché in Windows non compare la rotella dell'esecutivo e in corso come con Mac.Ora ovviamente la form si chiude se clicco da un'altra parte e se la faccio modale non elabora. Come posso risolvere.
    Grazie Umberto

  2. Antonio R

    Apr 10 Pre-Release Testers, Xojo Pro Europe (Italy)

    Fai in modo che il lancio della stampa, o il caricamento avvenga da dentro la modale, in questo modo puoi anche indicare alla modale quando chiudersi

  3. 2 weeks ago

    Grazie Antonio,
    avevo pensato di fare così ma ho 10 stampe devo poi fare una modale per ognuna di esse? Ho pensato anche in alternativa di usare una progresswheel, ma ho visto degli esempi e sinceramente non ho capito come utilizzarla. Ho trovato sul forum inglese uno che ha realizzato una progresswheel più grande (ovviamente disegnato da lui) con un timer, ma non riesco a farlo scattare nella mia form mi apple sempre frizzata, non ruota. Come devo fare?
    Grazie

  4. Antonio R

    Apr 15 Pre-Release Testers, Xojo Pro Answer Europe (Italy)

    Non mi sono spiegato.
    Il metodo più semplice è creare una modal che eseguirà il tuo codice. Ovviamente una classe non una per ogni stampa...

    Per non bloccare il programma vediamo una versione più lunga a descrivere, ma molto più efficiente.

    Crei una finestra (diciamo di tipo sheet, così su macOS sarà attaccata alla finestra e su win sarà una modal) chiamiamola wMetodoLungo
    dentro ci metti la progresswheel, on un canvas in cui animerai qualcosa se vuoi, e una label per dire cosa sta facendo (tipo "sto stampando questo..., sto stampando quello....")

    Crei una sottoclasse di Thread. (Chiamiamola ThAutomatico)
    A questa aggiungi un delegate codiceDaEseguire (pubblico) senza parametri
    Aggiungi una proprietà cb (pubblica) as codiceDaEseguire

    Un delegate è la firma di un metodo. per cui puoi assegnare alla proprietà cb qualsiasi metodo che non accetti parametri.

    Aggiungi un evento hoTerminato (per poter capire quando il thread è finito)
    Aggiungi un metodo hoFinito che semplicemente attiva l'evento:

    raiseEvent hoTerminato

    Implementi il metodo Run con:

    if cb<>nil then cb.invoke
    Xojo.Core.Timer.callLater(10, weakAddressOf HoFinito)

    In pratica se esiste un metodo assegnato a cb questo viene eseguito nel thread, poi il tread richiama, fuori dal suo codice in modo da non bloccarsi, il metodo HoFinito che scatena l'evento HoTerminato.

    Nella finestra che hai creato aggiungi questa classe (ThAutomatico1) e implementi l'unico evento presente: hoTerminato
    self.close

    In pratica alla termine dell'esecuzione fai chiudere in automatico la finestra.

    Aggiungi un metodo Constructor(messaggio as text, codice as ThAutomatico.codiceDaEseguire)

    thAutomatico1.cb = codice
    super.Constructor
    Label1.text = messaggio

    In pratica assegni al cb del thread il metodo presente in codice e dopo aver chiamato il super.constructor, che viene inserito automaticamente, assegni alla label il cosa stai facendo.

    Ora per lanciare la tua stampa (o il tuo metodo molto lungo) fai:
    dim w as new wMetodoLungo("Cosa sto facendo…", weakAddressOf ilMioMetodoLungo)
    w.showModalWithin self

    Dove "Cosa sto facendo…" è il messaggio da far apparire all'utente e ilMioMetodoLungo è il metodo che vuoi eseguire.

    In questo modo non blocchi l'interfaccia, la progress wheel viene eseguita animata, ma essendo una modal l'utente non può interagire cambiando i parametri.

    Ricordati però che essendo eseguito in un thread il tuo metodo non può in nessun modo interagire con l'interfaccia, per cui raccogli prima tutti i dati.

    Il tutto è complicato a spiegare, ma molto semplice da eseguire.

  5. Ciao Antonio,
    ho seguito, spero, le tue istruzioni, ho inserito nella mia form, quando premo il pulsante, l'istruzione
    dim w as new wMetodoLungo("Eseguo report budget ", weakAddressOf esegui)
    w.showModalWithin self
    "esegui" è il mio metodo dove preparo tutti i dati ed eseguo le stampe. Ma praticamente il metodo non viene richiamato ( ho messo un break al suo interno) e la form wMetodoLungo resta frizzata. Forse ho sbagliato a creare il Constructor , ho fatto un metodo sotto la finestra wMetodoLungo chiamandolo Constructor e passando i parametri messaggio as text, codice as ThAutomatico.codiceDaEseguire, poi nel metodo il codice
    thAutomatico1.cb = codice
    super.Constructor
    Label1.text = messaggio
    Ho fatto bene? Dove ho sbagliato?
    Grazie

  6. Antonio R

    Apr 18 Pre-Release Testers, Xojo Pro Europe (Italy)

    Quando crei il constructor dovresti trovare già scritto super.Constructor, così come dovresti trovare il nome del metodo nella lista dei nomi possibili per i metodi (stai facendo un override)

    Nella finestra che si frizza vedi la label con il testo della label? La progress wheel è attiva?
    Questo per vedere che tutto sia settato correttamente

    Manca il comando di avvio.
    Ancora una volta usiamo un timer one shot (tipo quello del run)
    Quindi nuovo metodo avvia

    thAutomatico1.run

    ma per lanciarlo aggiungi al termine del constructor

    xojo.Core.Timer.CallLater(10, WeakAddressOf avvia)

    Con questo metodo hai una finestra modale, che quindi impedisce ulteriori interazioni, ma che non blocca il programma in quanto il suo codice viene eseguito in un thread. L'uso dei delegate ti permette di rendere il tutto indipendente dal codice (che appunto è in un delegate che passi come parametro). Puoi estendere la cosa per avere anche una visualizzazione del progresso del processo.

    Tieni conto che usi thread per cui nessuna interazione con l'interfaccia è possibile nel codice che stai eseguendo.

  7. Edited 2 weeks ago by Umberto

    Ho aggiunto il metodo avvia nella finestra wMetodoLungo e nel constructor il comando che mi hai detto, ora il metodo esegui parte regolarmente ma fa in crash in questa istruzione

    if ckbriepilogo.State = Checkbox.CheckedStates.Checked then

    ho provato ad eliminarlo ma va in errore in quello successivo :

    leggidatimese(ComboAnno.RowTag(ComboAnno.ListIndex),ComboMese.RowTag(ComboMese.ListIndex),ComboFiliale.RowTag(ComboFiliale.ListIndex),ComboVersione.RowTag(ComboVersione.ListIndex),"budget","G")

    Ho pensato che il metodo forse non può leggere i dati provenienti dalla form è possibile? Se è così posso passarli direttamente al metodo esegui in questa istruzione dim w as new wMetodoLungo("Eseguo report budget ", weakAddressOf esegui)?

  8. Antonio R

    Apr 18 Pre-Release Testers, Xojo Pro Europe (Italy)

    No

    Come ti ho detto il thread non può accedere ad elementi dell'interfaccia altrimenti vedi gli errori che stai vedendo.

    Il metodo migliore è raccogliere le informazioni prima e metterle in proprietà o in un oggetto apposito PRIMA di avviare il thread/modal poi nel codice che viene eseguito nel thread accedi solo a queste proprietà o proprietà di una oggetto.

    Mi spiego:
    Sembra un approccio "strano" ma ha i suoi notevoli vantaggi, ad esempio puoi salvare i parametri (ad esempio se li metti in un oggetto puoi in qualche modo serializzarlo per utilizzi successivi), rendi il codice principale indipendente dall'interfaccia (che puoi quindi inseguito modificare cambiando solo come la nuova interfaccia interagisce con l'oggetto che ne raccoglie i valori)

    Quando possibile, o imposto, è meglio separare il più possibile il codice dall'interfaccia per renderlo riutilizzabile (ad esempio se vedi la modale è indipendente dal codice, la puoi usare per qualsiasi processo)

    D'altronde il vantaggio di questo approccio è che il codice risiede nella finestra da cui sei partito, per cui creare un oggetto qui che magari poi elimini al termine (dopo il showModal) senza quindi lasciare cose in giro.

  9. Edited 2 weeks ago by Umberto

    Ho raccolto le informazioni come mi hai detto, finalmente il metodo viene eseguito perfettamente e con la progresswhell tutto funziona, però è piccola volevo utilizzare una canvas con una progresswheel disegnata. Ho trovato un esempio ma non riesco a farla girare con il tuo esempio. L'esempio usa un customtimer con l'istruzione
    if frmwindows.wheelos1.Enabled = True then frmwindows.wheelos1.invalidate end if nell'action

  10. Antonio R

    Apr 18 Pre-Release Testers, Xojo Pro Europe (Italy)

    per una canvas animata, basta che aggiungi un timer alla finestra modale che ogni tot (non esagerare con la frequenza) aggiorna l'immagine (invalidate)
    Poi sarà il codice del paint del canvas a decidere l'animazione.

    Lo puoi far partire nell'open direttamente (magari solo sotto win)

    Come vedi il metodo è espandibile (puoi anche aggiungere una funzione da richiamare per gli aggiornamenti di una progress bar).
    Una volta impostato non devi fare molto e il codice alla fine ti risulta molto più pulito.

  11. Grazie infinite è perfetto, un'ultima domanda , se voglio utilizzarlo per il caricamento di un file devo passare il metodo che legge il file e siccome apro il file con un open dialog lo passo come un parametro indipendente dall'interfaccia come mi hai detto sopra?

  12. Antonio R

    Apr 19 Pre-Release Testers, Xojo Pro Europe (Italy)

    Per il caricamento di un file (solo se lo interpreti per cui occorre un certo tempo)
    Apri il file con la dialog, poi quando la chiudi memorizzi il riferimento al file da aprire (potrebbe essere nil perché l'utente ha annullato) poi lancia la routine di "interpretazione" con la stessa tecnica

  13. Edited 2 weeks ago by Umberto

    Tutto ok anche con il file, ma ho scoperto che se durante il caricamento vado ad esempio su di un punto fuori dalla finestra modale e clicco scompare tutto anche se resta in esecuzione il programma, non è modale? Forse ho sbagliato qualcosa?
    Inoltre ho un problema all'interno del file posso trovare errori da segnalare all'utente, prima utilizzava il msgbox ma con questo sistema va in crash tutto come posso risolvere?
    Grazie

  14. Antonio R

    Apr 20 Pre-Release Testers, Xojo Pro Europe (Italy)

    Come ho detto puoi aggiungere altre funzionalità per mostrare il progresso (un timer nella finestra che legge dei valori e che viene attivato e spento all'avvio del thread, fai attenzione a chi possiede code ovvero alle regole di scopo: devi rendere il tutto indipendente da dove si trova il codice che utilizzi)
    Lo stesso per mostrare gli errori, in questo caso interrompi il codice del tread facendo mostrare l'errore all'utente

    La msgbox è un elemento della UI per cui non puoi lanciarla dal codice del thread, ma nel codice puoi impostare una variabile di errore e far terminare il thread, all'uscita se è impostata la condizione di errore la mostri, e fai chiudere la finestra dopo un tempo maggiore e/o mostri un pulsante per la chiusura

  15. last week

    Grazie infinite, tutto risolto e perfettamente funzionante.

or Sign Up to reply!