Straipsnį pateikė Marcusas Junglasas
Programuodami įvykių prižiūrėtoją Delfyje (pvz., Paspaudus TB mygtuko įvykis), ateina laikas, kai jūsų programa kurį laiką turi būti užimta, pvz. kodas turi parašyti didelį failą arba suspausti kai kuriuos duomenis.
Jei tai padarysite, pastebėsite tai jūsų programa atrodo užrakinta. Jūsų formos nebegalima perkelti, o mygtukai nerodo jokio gyvenimo ženklo. Atrodo, kad sudužo.
Priežastis ta, kad „Delpi“ programa yra vienguba. Jūsų rašomas kodas reiškia tik daugybę procedūrų, kurias iškviečia pagrindinė Delphi gija, įvykus įvykiui. Likusią laiko dalį pagrindinė gija yra sistemos pranešimų tvarkymas ir kiti dalykai, pavyzdžiui, formos ir komponentų tvarkymo funkcijos.
Taigi, jei neužbaigsite įvykių tvarkymo atlikdami ilgą darbą, užkirsite kelią programai tvarkyti tuos pranešimus.
Bendras tokio tipo problemų sprendimas yra „Taikymas. Proceso pranešimai “. „Taikymas“ yra visuotinis „TApplication“ klasės objektas.
Paraiška. Proceso pranešimai tvarko visus laukiančius pranešimus, tokius kaip lango judesiai, mygtuko paspaudimai ir pan. Paprastai jis naudojamas kaip paprastas sprendimas, kad jūsų programa veiktų.
Deja, „ProcessMessages“ mechanizmas turi savo ypatybes, kurios gali sukelti didelę painiavą!
Ką veikia „ProcessMessages“?
„PprocessMessages“ tvarko visus laukiančius sistemos pranešimus programų pranešimų eilėje. „Windows“ naudoja pranešimus „kalbėtis“ su visomis veikiančiomis programomis. Naudotojų sąveika į formą perduodama pranešimais, o „ProcessMessages“ tvarko juos.
Pavyzdžiui, jei pele krinta ant „TButton“, „ProgressMessages“ daro viską, kas turėtų nutikti šiame įvykyje, pavyzdžiui, mygtuko perdažymas į „paspaustą“ būseną ir, žinoma, kvietimas atlikti „OnClick“ () tvarkymo procedūrą, jei jūs ją priskyrėte.
Štai problema: bet kuriame „ProcessMessages“ skambutyje gali būti pakartotinis bet kurio įvykio tvarkytojo skambutis. Štai pavyzdys:
Mygtuko „OnClick“ tolygią tvarkyklę naudokite šį kodą („darbas“). „For-pareiškimas“ imituoja ilgą apdorojimo darbą, kai kas ir tada skambina „ProcessMessages“.
Tai yra supaprastinta, kad būtų lengviau perskaityti:
{„MyForm“:}
„WorkLevel“: sveikasis skaičius;
{„OnCreate“:}
„WorkLevel“: = 0;
procedūra TForm1.WorkBtnClick (Siuntėjas: TObject);
var
ciklas: sveikasis skaičius;
prasideda
inc („WorkLevel“);
dėl ciklas: = 1 į 5 daryti
prasideda
„Memo1.Lines“. Pridėti ('- Darbas' + IntToStr (WorkLevel) + ', Ciklas' + IntToStr (ciklas);
Taikymas. Proceso pranešimai;
miegas (1000); // ar koks kitas darbas
galas;
„Memo1.Lines“. Pridėti ('Darbas' + IntToStr (WorkLevel) + 'baigta.');
gruodis („WorkLevel“);
galas;
BE „ProcessMessages“ šios memorandume įrašomos šios eilutės, jei mygtuką trumpai paspaudėte per du kartus:
- 1 darbas, 1 ciklas
- 1 darbas, 2 ciklas
- 1 darbas, 3 ciklas
- 1 darbas, 4 ciklas
- 1 darbas, 5 ciklas
1 darbas baigėsi.
- 1 darbas, 1 ciklas
- 1 darbas, 2 ciklas
- 1 darbas, 3 ciklas
- 1 darbas, 4 ciklas
- 1 darbas, 5 ciklas
1 darbas baigėsi.
Kol procedūra užimta, forma nerodo jokios reakcijos, tačiau antrą paspaudimą „Windows“ įdėjo į pranešimų eilę. Iškart po „OnClick“ pabaigos jis vėl bus vadinamas.
ĮSKAITANT „Proceso pranešimus“, išvestis gali būti labai skirtinga:
- 1 darbas, 1 ciklas
- 1 darbas, 2 ciklas
- 1 darbas, 3 ciklas
- 2 darbas, 1 ciklas
- 2 darbas, 2 ciklas
- 2 darbas, 3 ciklas
- 2 darbas, 4 ciklas
- 2 darbas, 5 ciklas
2 darbas baigėsi.
- 1 darbas, 4 ciklas
- 1 darbas, 5 ciklas
1 darbas baigėsi.
Šį kartą forma vėl veikia ir priima bet kokią vartotojo sąveiką. Taigi mygtukas paspaudžiamas iki pusės per pirmąją jūsų „darbininko“ funkciją, kuri bus nedelsiant įvykdyta. Visi įeinantys įvykiai tvarkomi kaip ir bet kuris kitas funkcijos skambutis.
Teoriškai kiekvieno skambučio į „ProgressMessages“ metu bet koks paspaudimų ir vartotojo pranešimų kiekis gali įvykti „vietoje“.
Taigi būkite atsargūs su savo kodu!
Skirtingas pavyzdys (paprastu pseudo kodu!):
procedūra „OnClickFileWrite“ ();
var myfile: = TFileStream;
prasideda
myfile: = TFileStream.create ('myOutput.txt');
bandyti
kol „BytesReady“> 0 daryti
prasideda
myfile. Rašyti (DataBlock);
dec („BytesReady“, dydis („DataBlock“));
„DataBlock“ [2]: = # 13; {1 bandymo linija}
Taikymas. Proceso pranešimai;
„DataBlock“ [2]: = # 13; {2 bandymo linija}
galas;
pagaliau
myfile.free;
galas;
galas;
Ši funkcija įrašo didelį duomenų kiekį ir bando „atrakinti“ programą naudodama „ProcessMessages“ kiekvieną kartą, kai rašomas duomenų blokas.
Jei vartotojas dar kartą spustelės mygtuką, tas pats kodas bus vykdomas, kol failas vis dar rašomas. Taigi failo negalima atidaryti antrą kartą ir procedūra nepavyksta.
Galbūt jūsų programa atgaus tam tikras klaidas, pavyzdžiui, atlaisvins buferius.
Kaip galimas rezultatas „Datablock“ bus išlaisvintas, o pirmasis kodas „staiga“ padidins „Prieigos pažeidimą“, kai prie jo prieisite. Tokiu atveju: 1 bandymo linija veiks, 2 bandymo linija suduš.
Geresnis būdas:
Kad būtų lengviau, galite nustatyti visą formą „įjungta: = klaidinga“, kuri blokuoja visus vartotojo įvestus duomenis, tačiau vartotojui to nerodo (visi mygtukai nėra pilki).
Geriau būtų visus mygtukus nustatyti kaip „išjungtus“, tačiau tai gali būti sudėtinga, jei norite laikyti vieną mygtuką „Atšaukti“. Be to, jūs turite pereiti visus komponentus, kad juos išjungtumėte. Kai jie vėl įjungiami, turite patikrinti, ar kai kurie iš jų turi būti išjungti.
Tu galėtum išjungti konteinerį, kurį kontroliuoja vaikas, kai pasikeičia nuosavybė Įgalinta.
Kaip rodo klasės pavadinimas „TNotifyEvent“, jis turėtų būti naudojamas tik trumpalaikėms reakcijoms į įvykį. Laiko reikalaujantis kodas yra geriausias būdas „IMHO“ sudėti visą „lėtą“ kodą į savo giją.
Kalbant apie „PrecessMessages“ problemas ir (arba) įgalinant ir išjungiant komponentus, reikia naudoti antrasis siūlas atrodo, kad tai nėra per daug sudėtinga.
Atminkite, kad net paprastos ir greitos kodo eilutės gali kabėti sekundėmis, pvz. atidarius failą diskų įrenginyje, gali tekti palaukti, kol diskas sukasi. Nelabai gerai atrodo, jei atrodo, kad jūsų programa sugenda, nes diskas yra per lėtas.
Viskas. Kitą kartą pridėsite „Programa. Proceso pranešimai “, pagalvokite du kartus;)