Privacy Policy

Blog italiano

Clicca qui se vuoi andare al blog italiano su Lazarus e il pascal.

Forum ufficiale

Se non siete riusciti a reperire l'informazione che cercavate nei nostri articoli o sul nostro forum vi consiglio di visitare il
Forum ufficiale di Lazarus in lingua inglese.

Lazarus 1.0

TDD o Test-Driven Development
immagine docker per lavorare con lazarus e free pascal
Indice
Installare lazarus su mac osx sierra
Un dialog per la connessione al database:TfmSimpleDbConnectionDialog
Superclasse form base per programmi gestionali (e non) #4 - wait animation
Superclasse form base per programmi gestionali (e non) #3 - traduzione delle form
Superclasse form base per programmi gestionali (e non) #2 - log, exception call stack, application toolbox
Superclasse form base per programmi gestionali (e non)
Advanced Record Syntax: un esempio pratico
DB concetti fondamentali e TDBEdit, TDBMemo e TDBText
DB concetti fondamentali e DBGrid
Advanced Record Syntax
DB concetti fondamentali e ZeosLib
DB concetti fondamentali e connessioni standard
guida all'installazione di fpc trunk da subversion in linux gentoo
Creare un server multithread
Cifratura: breve guida all'uso dell'algoritmo BlowFish con lazarus e free pascal.
Free Pascal e Lazarus sul Raspberry Pi
fpcup: installazioni parallele di lazarus e fpc
Ubuntu - aggiornare free pascal e lazarus
Come interfacciare periferica twain
Lazarus 1.0
Aspetto retrò (Cmd Line)
Disporre le finestre in un blocco unico (come Delphi)
Zeos ... dietro le quinte (prima parte)
Lavorare con file in formato JSON con Lazarus
Overload di operatori
Dataset virtuale
Linux + Zeos + Firebird
Pascal Script
La gestione degli errori in Lazarus
Indy 10 - Invio email con allegati
Brute force
Le permutazioni
Da DataSource a Excel
StatusBar - aggirare l'errore variabile duplicata
Visualizzare un file Html esterno
Evidenziare voci TreeView
Toolbar
Direttiva $macro
Indy gestiore server FTP lato Client
TImage su Form e Panel
PopUpMenu sotto Pulsante (TSpeedButton)
Conversione numerica
Proprietà
Funzioni a parametri variabili
Overload di funzioni
Liste e puntatori
Conferma di chiusura di un applicazione
Il file: questo sconosciuto
UIB: Unified Interbase
System Tray con Lazarus
Intercettare tasti premuti
LazReport, PDF ed immagini
Lazarus e la crittografia
Ampliare Lazarus
Generare controlli RUN-TIME
TTreeview e Menu
TTreeView
Utilizzare Unità esterne
Lavorare con le directory
Realizzare programmi multilingua
Codice di attivazione
File INI
Esempio lista in pascal
Stabilire il sistema operativo
Recuperare codice HTML da pagina web
Trascinare un file nel programma
Mandare mail con Lazarus
Welcome to Italian community of Lazarus and Free Pascal. Please login or sign up.

Recenti

How To

Utenti
Stats
  • Messaggi totali: 20.582
  • Totale discussioni: 2.471
  • Online today: 25
  • Online ever: 5.949 (Luglio 30, 2026, 09:49:59 PM)
Utenti online
  • Users: 0
  • Guests: 22
  • Total: 22
22 Visitatori, 0 Utenti

eseguire una procedura di caricamento dati in background

Aperto da petrusic, Marzo 17, 2026, 10:05:30 AM

Discussione precedente - Discussione successiva

petrusic

Lo so, non sono stato più prtesente nel Forum per tanto tempo, ma sono stato assorbito dal mio solito nuovo programma che porto avanti molto lentamente ed ho trascurato molte cose, fra cui quello che mi ero ripromesso di fare, cioè partecipare in maniera diversa e più frequentemente alle discussioni aperte.

Mi trovo davanti ad una necessità, quella di attivare, all'avvio di una Form, basilare per l'inserimento dati, senza fare pesare all'utente l'attesa dovuta ai tempi di caricamento di dati dal DataBase.

Visto che i dati da caricare in memoria non occorrono per la digitazione all'interno del primo controllo attivo della Form, vorrei eseguire detto caricamento in maniera trasparente e sovrapposta all'attività di digitazione dell'utente (in background).

Inizialmente, avevo inserito detto caricamento nella FormCreate, ma dovevo aspettare il termine del caricamento per potere vedere apparire la Form chiamatra.

Poi ho pensato di sfruttare l'evento OnShow ed ho spostato le istruzioni all'interno della FormShow, ma anche così facendo il cursore di Pronto per la digitazione non compare se non dopo il completamento del caricamento dati.

A questo punto vorrei tentare di spostare quelle istruzioni dentro una routine procedurale da fare eseguire in background, ma non ho idea di come ottenere l'effetto desiderato.

Insomma, ho ancora bisogno del vostro preziozo aiuto.  :D
ciao ciao

xinyiman

Buongiorno, nessun problema, ognuno partecipa al forum come può. Per il tuo problema penso che la cosa più semplice sia mettere il caricamento dati in un timer.
Tu nell'oncreate metti l'avvio del timer dopo 2/3 secondi e così la form si vede.
Ieri è passato, domani è futuro, oggi è un dono...

DragoRosso

Ciao e benritornato.
Devo intanto darti alcune delucidazioni perchè tu apprenda dei particolari tecnologici, senza i quali qualunque soluzione pensata non potrà mai avere un buon esito.

Primo: perchè si attende (o meglio l'operatore attende), ovvero perchè il software sembra fermarsi ?

Ciò accade perchè tutte le attività di visualizzazion sono e devono essere serializzate, quindi ad esempio quando carichi i dati in un form questi vengono caricati (e devono essere caricati) senza intervento di "thread" diretti. In pratica questa operazione DEVE (e viene) eseguita all'interno del THREAD PRINCIPALE (Main Thread) che esegue tutte le operazioni sui controlli grafici (la UI) in maniera serializzata.

Quando scorri un database e riempi una griglia (TStringGrid a esempio), solo ed esclusivamente il "Main Thread" potrà disegnare e riepmipre la griglia.
E quando il "Main Thread" è troppo occupato a riempire una griglia da un database ad esempio ovviamente non si occupa di tutto il resto (come mouse, tastiera e altri controlli grafici) ... da cui il blocco apparente dell'interfaccia.

Tutto ciò dipende dalla potenza di elaborazione che hai a disposizione ...

Tutto ciò che ha a che fare con gli Eventi a design time o run time (in generale) e con le LCL (le librerie grafiche di Lazarus) usano il Main Thread e quindi vengono eseguite singolarmente una dietro l'altra, mai in parallelo.

Se per caricare una griglia ci si impiega dieci secondi, per dieci secondi l'interfaccia verrà congelata. Non ci sono alternative a ciò (a meno che non si voglia giocare al lotto e crearsi problemi futuribili poi difficilmente tracciabili e identificabili).

Ciò che chiedi quindi a prima vista non è così facilmente eseguibile.

Quando si ha a che fare con i database, generalmente si usano le "copie in memoria" (cioè una query già eseguita senza aggacnio con la parte grafica) per la visualizzazione.

In questo caso ciò che puoi fare banalmente è disattivare il controllo grafico (la tua StringGrid ad esempio con la sua proprietà Enabled := false), eseguire la query agganciata alla griglia e riattivare il controllo grafico una volta terminata la query.

La Query la puoi eseguire in un Thread separato dal principale (quindi non nel OnSHow, OnCreate o altro) e quindi tutto il tempo di esecuzione della query non bloccherà l'interfaccia (AMMESSO CHE I CONTROLLI GRAFICI AGGANCIATI ALLA QUERY SIANO DISATTIVATI).

Se il contenuto della StringGrid viene riempita a codice, allora tutto è più complesso e dipende dalla tecnica usata per la sua visualizzazione (o riempimento).

Ciò è indifferente al linguaggio usato, sia esso Pascal, C#, Rust o altro. I concetti sono esattamente gli stessi in tutti i linguaggi.
Poi ci sono gli ausili che i linguaggi o le RTL del linguaggi ti forniscono per aiuarti in ciò, e quindi il linguaggio per avere più o meno impatto sull'uso.

Puoi fare un semplice test disattivando i controlli grafici (una tua StringGrid) durante l'esecuzione della Query corrispondente per poi riattivarla alla fine e vedere che impatto ha sulla tua applicazione.

Intanto questo e dimmi se hai compreso il tutto e come è andato il test. Poi si passerà alle cose più complesse se non fosse soddisfacente il risultato.
:) Ogni alba è un regalo, ogni tramonto è una conquista :)

nomorelogic

Citazione di: petrusic il Marzo 17, 2026, 10:05:30 AM
A questo punto vorrei tentare di spostare quelle istruzioni dentro una routine procedurale da fare eseguire in background, ma non ho idea di come ottenere l'effetto desiderato.

potresti provare a vedere qualcosa del genere

il sorgente è scritto a mano (non l'ho provato) e prevede il passaggio di procedura anonima
che versione di FPC usi?


in alternativa devi usare un TThread


procedure TForm1.RunQuery; // metodo che esegue query pesante
begin
  // SELECT * FROM QUALCHE_TABELLA
end;

// in un bottone, nel button click o in OnCreate della Form1:
TThread.CreateAnonymousThread(
  procedure
  begin
    RunQuery;
  end
).Start;
Imagination is more important than knowledge (A.Einstein)

petrusic

Citazione di: nomorelogic il Marzo 17, 2026, 12:15:33 PM
che versione di FPC usi?

Effettivamente non è recente:
[quote]
Il mio Lazarus è la versione 3.8 - 20.lug.2025, mentre lka versione FPC è la 3.2.2 [/quote]
ciao ciao

petrusic

Citazione di: DragoRosso il Marzo 17, 2026, 11:59:58 AM
. . .
Quando si ha a che fare con i database, generalmente si usano le "copie in memoria" (cioè una query già eseguita senza aggacnio con la parte grafica) per la visualizzazione.

In questo caso ciò che puoi fare banalmente è disattivare il controllo grafico (la tua StringGrid ad esempio con la sua proprietà Enabled := false), eseguire la query agganciata alla griglia e riattivare il controllo grafico una volta terminata la query.

La Query la puoi eseguire in un Thread separato dal principale (quindi non nel OnSHow, OnCreate o altro) e quindi tutto il tempo di esecuzione della query non bloccherà l'interfaccia (AMMESSO CHE I CONTROLLI GRAFICI AGGANCIATI ALLA QUERY SIANO DISATTIVATI).
Se il contenuto della StringGrid viene riempita a codice, allora tutto è più complesso e dipende dalla tecnica usata per la sua visualizzazione (o riempimento).
. . .

Nel mio post d'apertura ho  fatto cenno ad un caricamento in memoria, non in controllo grafico come una griglia.
Ho capito che FormCreate e FormShow NON mi permettono di realizzare quello che mi propongo e per questo ho pensato ad una routine , routine che, però, devo richiamare da qualche parte. Attualmente la richiamo dentro la FormShow.

Comunque, proverò la procedura anonima che m i ha suggerito nomorelogic.
ciao ciao

nomorelogic

Citazione di: petrusic il Marzo 17, 2026, 12:40:05 PM
Citazione di: nomorelogic il Marzo 17, 2026, 12:15:33 PM
che versione di FPC usi?

Effettivamente non è recente:
[quote]
Il mio Lazarus è la versione 3.8 - 20.lug.2025, mentre lka versione FPC è la 3.2.2 [/quote]


lazarus è vecchiottello ma fpc dovrebbe andar bene
Imagination is more important than knowledge (A.Einstein)

petrusic

Citazione di: nomorelogic il Marzo 17, 2026, 12:15:33 PM
potresti provare a vedere qualcosa del genere

il sorgente è scritto a mano (non l'ho provato) e prevede il passaggio di procedura anonima

in alternativa devi usare un TThread

procedure TForm1.RunQuery; // metodo che esegue query pesante
begin
  // SELECT * FROM QUALCHE_TABELLA
end;

// in un bottone, nel button click o in OnCreate della Form1:
TThread.CreateAnonymousThread(
  procedure
  begin
    RunQuery;
  end
).Start;


Ho cercato di approfondire la conoscenza della tecnica TThread ed ho trovato Qui un argomento che sembrava potesse aiutarmi, ma alla fine mi sono convinto che non è la strada che cercavo, infatti ho capito che creare TThread anonimo corrisponderebbe a scrivere un programmino che può partire in parallelo su un altro core del pc e che svolge il suo lavoro in maniera assolutamente autonoma. Alla fine del suo lavoro, occorrendo, valorizzerebbe le variabili al suo interno, variabili che restano sue, quindi non accessibili dall'esterno.

Ma ciò non è ciò mi serve. Io devo raggiungere uno scopo esettamente opposto, prelevando e usando proprio le variabili ricavate dalla procedura TThread.

Penso perciò che opterò per lanciare un messaggio d'Attesa che eliminerò alla fine della memorizzazione dei miei dati prelevati dal DB e continuerò a quel pun to col mostrare la mia Form di inserimento movimenti.

Grazie per i suggerimenti. Ho conosciuto un altro strumento.
ciao ciao

DragoRosso

#8
Citazione di: petrusic il Marzo 17, 2026, 04:13:33 PM
infatti ho capito che creare TThread anonimo corrisponderebbe a scrivere un programmino che può partire in parallelo su un altro core del pc e che svolge il suo lavoro in maniera assolutamente autonoma. Alla fine del suo lavoro, occorrendo, valorizzerebbe le variabili al suo interno, variabili che restano sue, quindi non accessibili dall'esterno.
Ma ciò non è ciò mi serve. Io devo raggiungere uno scopo esettamente opposto, prelevando e usando proprio le variabili ricavate dalla procedura TThread.

Funziona così solo se lo programmi così. Il thread può agire banalmente su oggetti globali o pubbliche di altre entità (classi, interfacce, record, etc ...), in modo tale che il risultato rimanga pubblico e/o globale (o all'interno della classe / record, genericamente nell'oggetto di appartenenza).
L'attenzione che devi porre è CHE NON SI DEVE MAI ACCEDERE ALLA STESSA RISORSA DA PIU' THREAD CONTEMPORANEAMENTE (CIOE' NON SINCRONIZZATI).

Significa che la tua Query può essere globale o una proprietà/procedura/funzione pubblica della form o del DataModule e dal tuo Thread (Anonimo o no) ci puoi accedere ed eseguirla.

Durante l'esecuzione del thread non DEVI IN ALCUN MODO CERCARE DI ACCEDERE ALLA STESSA RISORSA (QUERY / FUNZIONE / PROCEDURA / PROPRIETA' / ETC ...).

Inoltre sarebbe utile che il Thread comunicasse la fine elaborazione settando un evento / messaggio o ponendo a 1 una variabile globale (tramite Interlocked ad esempio).
Ricordiamoci magari anche la gestione degli errori (altra variabile globale) visto che un Thread Anonimo sarebbe utile (scusate la ripetizione) non generasse una eccezione.

N.B.: e ovviamente il tuo thread NON DEVE ACCEDERE A NULLA DI GRAFICO (OSSIA A NULLA DELLE LCL).

P.S.: il fatto che un thread (software) giri su un altro CORE/THREAD (HARDWARE) è ininfluente, lo scopo è non usare / usare il meno possibile il Main Thread (che è software).
:) Ogni alba è un regalo, ogni tramonto è una conquista :)

Disclaimer:

Questo blog non rappresenta una testata giornalistica poiché viene aggiornato senza alcuna periodicità. Non può pertanto considerarsi un prodotto editoriale ai sensi della legge n. 62/2001.