Temna stran uporabe. ProcessMessages

Članek predložil Marcus Junglas

Pri programiranju orodja za obdelavo dogodkov v Delphiju (npr OnClick primer TButton), pride čas, ko mora biti vaša aplikacija nekaj časa zasedena, npr. koda mora napisati veliko datoteko ali stisniti nekaj podatkov.

Če to storite, boste to opazili zdi se, da je vaša aplikacija zaklenjena. Obrazca ni mogoče več premikati, gumbi pa ne kažejo življenja. Zdi se, da je strmoglavil.

Razlog je v tem, da je aplikacija Delpi enojna. Koda, ki jo pišete, predstavlja le kup postopkov, ki jih pokliče glavna nit Delphija, kadar koli se zgodi dogodek. Preostali čas je glavna nit obdelava sistemskih sporočil in drugih stvari, kot so funkcije za obdelavo obrazcev in komponent.

Če torej ne dokončate urejanja dogodkov z dolgotrajnim delom, boste preprečili, da bi aplikacija ravnala s temi sporočili.

Skupna rešitev za tovrstne težave je poklicati "Application. Obdelave sporočila ". "Application" je globalni objekt razreda TApplication.

Prijava. Processmessages obravnava vsa čakalna sporočila, kot so premiki okna, kliki gumbov in tako naprej. Običajno se uporablja kot preprosta rešitev, s katero bo vaša aplikacija "delovala".

instagram viewer

Na žalost ima mehanizem "ProcessMessages" svoje značilnosti, ki lahko povzročijo velike zmede!

Kaj pomeni ProcessMessages?

PprocessMessages obravnava vsa čakalna sistemska sporočila v čakalni vrsti aplikacij. Windows uporablja sporočila za "pogovor" z vsemi delujočimi aplikacijami. Interakcija uporabnika se v obliki pripelje prek sporočil in "ProcessMessages" z njimi ravna.

Če miška pada na TButton, na primer ProgressMessages naredi vse, kar se mora zgoditi na tem dogodku, kot je ponovno prebarvanje gumba v "pritisnjeno" stanje in seveda klic v postopek ravnanja OnClick (), če ste ga dodelili.

To je težava: vsak klic v ProcessMessages lahko znova vsebuje rekurzivni klic kateremu koli upravljavcu dogodkov. Tu je primer:

S spodnjo kodo uporabite gumb za ravnanje z gumbom OnClick ("delo"). Stavek for-izjavo simulira dolgo opravilo obdelave z nekaj klici v ProcessMessages.

To je poenostavljeno za boljšo berljivost:

{v MyForm:}
WorkLevel: celo število;
{OnCreate:}
WorkLevel: = 0;
postopek TForm1.WorkBtnClick (Pošiljatelj: TObject);
var
cikel: celo število;
začeti
inc (WorkLevel);
za cikel: = 1 do 5 stori
začeti
Memo1.Lines. Dodaj ('- Delo' + IntToStr (WorkLevel) + ', cikel' + IntToStr (cikel);
Uporaba. ProcessMessages;
spanja (1000); // ali kakšno drugo delo
konec;
Memo1.Lines. Dodaj ('Delo' + IntToStr (WorkLevel) + 'končano.');
dec (WorkLevel);
konec;

BREZ "Obdelave sporočil" se v beležko zapišejo naslednje vrstice, če je gumb v kratkem času pritisnjen: Dvakrat:

 - 1. delo, 1. cikel
- delo 1, cikel 2
- delo 1, cikel 3
- delo 1, cikel 4
- delo 1, cikel 5
Delo 1 se je končalo.
- 1. delo, 1. cikel
- delo 1, cikel 2
- delo 1, cikel 3
- delo 1, cikel 4
- delo 1, cikel 5
Delo 1 se je končalo.

Medtem ko je postopek zaseden, obrazec ne kaže nobene reakcije, vendar je Windows drugi klik postavil v čakalno vrsto sporočil. Takoj po končanju funkcije "OnClick" bo poklicana znova.

VKLJUČNO s "ProcessMessages", je izhod lahko zelo drugačen:

 - 1. delo, 1. cikel
- delo 1, cikel 2
- delo 1, cikel 3
- 2. delo, 1. cikel
- 2. delo, cikel 2
- 2. delo, 3. cikel
- Delo 2, cikel 4
- Delo 2, cikel 5
Delo 2 se je končalo.
- delo 1, cikel 4
- delo 1, cikel 5
Delo 1 se je končalo.

Tokrat se zdi, da obrazec spet deluje in sprejema vsako uporabniško interakcijo. Torej gumb pritisnete na polovico med prvo funkcijo "delavec" PROTI, s katero se boste rokovali takoj. Vsi dohodni dogodki se obravnavajo kot kateri koli drugi klic funkcije.

Teoretično se lahko med vsakim klicem na "ProgressMessages" "na mestu" zgodi KOLIKO število klikov in sporočil uporabnikov.

Zato bodite previdni s svojo kodo!

Drugačen primer (v preprosti psevdo kodi!):

postopek OnClickFileWrite ();
var myfile: = TFileStream;
začeti
myfile: = TFileStream.create ('myOutput.txt');
poskusi
medtem Priporočanje bytes> 0 stori
začeti
myfile. Pišite (DataBlock);
dec (BytesReady, sizeof (DataBlock));
Podatkovni blok [2]: = # 13; {testna vrstica 1}
Uporaba. ProcessMessages;
Podatkovni blok [2]: = # 13; {testna vrstica 2}
konec;
končno
myfile.free;
konec;
konec;

Ta funkcija zapiše veliko količino podatkov in poskuša aplikacijo "odkleniti" z uporabo "ProcessMessages" vsakič, ko zapiše blok podatkov.

Če uporabnik ponovno pritisne na gumb, bo ista datoteka nastala med pisanjem datoteke. Torej datoteke ni mogoče odpreti drugič in postopek ne uspe.

Morda bo vaša aplikacija naredila nekaj obnovitve napak, kot je sprostitev medpomnilnikov.

Ker bo možen rezultat, bo "Datablock" sproščen in prva koda bo, ko bo do njega dostopala, nenadoma "sprožila kršitev dostopa". V tem primeru: testna linija 1 bo delovala, preskusna linija 2 se bo sesula.

Boljši način:

Če želite olajšati nastavitev, lahko celoten obrazec nastavite na "omogočeno: = napačno", ki blokira vse uporabniške vnose, vendar tega uporabniku NE prikaže (vsi gumbi niso sive).

Boljši način bi bil, da vse gumbe nastavite na "onemogočeno", vendar je to lahko zapleteno, če želite na primer obdržati en gumb "Prekliči". Pregledati morate tudi vse komponente, da jih onemogočite, in ko so ponovno omogočene, morate preveriti, ali naj ostanejo v stanju onesposobljenosti še nekaj.

Lahko bi onemogočite krmiljenje nadrejene posode, ko se spremeni lastnost Enabled.

Kot nakazuje ime razreda "TNotifyEvent", ga je treba uporabiti le za kratkotrajne reakcije na dogodek. Za zamudno kodo je najboljši način IMHO, da vstavite vso "počasno" kodo v lastno nit.

Glede na težave s "PrecessMessages" in / ali omogočanjem in onemogočanjem komponent, uporaba a druga nit zdi se, da sploh ni preveč zapleteno.

Ne pozabite, da tudi preproste in hitre vrstice kode lahko visijo nekaj sekund, npr. odpiranje datoteke na diskovnem pogonu bo morda moralo počakati, da se pogon vrne. Ne izgleda zelo dobro, če se zdi, da se vaša aplikacija zruši, ker je pogon prepočasen.

To je to. Ko naslednjič dodate »Program«. ProcessMessages ", dvakrat premislite;)