Rakstu iesūtījis Marcus Junglas
Programmējot notikumu apstrādātāju Delfos (piemēram, OnClick TBTton notikums), pienāk laiks, kad jūsu lietojumprogrammai kādu laiku jābūt aizņemtai, piem. kods ir jāraksta liels fails vai jāsaspiež daži dati.
To darot, jūs to pamanīsit šķiet, ka jūsu lietojumprogramma ir bloķēta. Jūsu formu vairs nevar pārvietot, un pogām nav dzīvības pazīmju. Liekas, ka tas ir avarējis.
Iemesls ir tāds, ka Delpi lietojumprogrammai ir viena vītne. Jūsu rakstītais kods ir tikai virkne procedūru, kuras Delphi galvenais pavediens izsauc ikreiz, kad notiek kāds notikums. Pārējā laikā galvenais pavediens ir sistēmas ziņojumu apstrāde un citas lietas, piemēram, formas un komponentu apstrādes funkcijas.
Tātad, ja nepabeidzat notikumu apstrādi, veicot kādu ilgstošu darbu, jūs neļausit lietojumprogrammai apstrādāt šos ziņojumus.
Izplatīts šāda veida problēmu risinājums ir izsaukt “Lietojumprogramma. Procesa ziņojumi ". "Lietojumprogramma" ir TApplication klases globāls objekts.
Pieteikums. Procesa ziņojumi apstrādā visus gaidīšanas ziņojumus, piemēram, loga kustības, pogas klikšķus un tā tālāk. To parasti izmanto kā vienkāršu risinājumu, lai jūsu lietojumprogramma darbotos.
Diemžēl "ProcessMessages" mehānismam ir savas īpašības, kas var radīt lielu neskaidrību!
Ko nozīmē ProcessMessages?
PprocessMessages apstrādā visus gaidīšanas sistēmas ziņojumus lietojumprogrammu ziņojumu rindā. Windows izmanto ziņojumus, lai “runātu” ar visām darbojošajām lietojumprogrammām. Lietotāju mijiedarbība tiek veidota formā, izmantojot ziņojumus, un “ProcessMessages” apstrādā tos.
Piemēram, ja pele iet uz TBTton, ProgressMessages dara visu, kas tam jānotiek, piemēram, pogas pārkrāsošana uz “nospiestu” stāvokli un, protams, izsaukums OnClick () apstrādes procedūrai, ja tādu esat piešķīris.
Tā ir problēma: jebkurš processMessages zvans var ietvert rekursīvu zvanu jebkuram notikumu apstrādātājam. Šis ir piemērs:
Izmantojiet šo kodu, lai iegūtu pogas OnClick pat apstrādātāju (“darbs”). For-paziņojums imitē ilgu apstrādes darbu ar dažiem zvaniem uz ProcessMessages ik pa laikam.
Tas ir vienkāršots, lai nodrošinātu labāku lasāmību:
{MyForm:}
WorkLevel: vesels skaitlis;
{OnCreate:}
WorkLevel: = 0;
procedūra TForm1.WorkBtnClick (Sūtītājs: TObject);
var
cikls: vesels skaitlis;
sākt
inc (WorkLevel);
priekš cikls: = 1 uz 5 darīt
sākt
Memo1.Līnijas. Pievienot ('- Darbs' + IntToStr (WorkLevel) + ', Cikls' + IntToStr (cikls);
Pieteikums. Procesa ziņojumi;
gulēt (1000); // vai kāds cits darbs
beigas;
Memo1.Līnijas. Pievienot ('Darbs' + IntToStr (WorkLevel) + 'beidzies.');
decembris (WorkLevel);
beigas;
BEZ “ProcessMessages” piezīmei tiek rakstītas šādas rindas, ja poga tika divreiz nospiesta:
- 1. darbs, 1. cikls
- 1. darbs, 2. cikls
- 1. darbs, 3. cikls
- 1. darbs, 4. cikls
- 1. darbs, 5. cikls
1. darbs beidzās.
- 1. darbs, 1. cikls
- 1. darbs, 2. cikls
- 1. darbs, 3. cikls
- 1. darbs, 4. cikls
- 1. darbs, 5. cikls
1. darbs beidzās.
Kamēr procedūra ir aizņemta, veidlapa nerāda nekādu reakciju, bet otro klikšķi Windows ievietoja ziņojumu rindā. Pēc “OnClick” pabeigšanas tas atkal tiks izsaukts.
IESKAITOT “ProcesiZiņas”, izvade var būt ļoti atšķirīga:
- 1. darbs, 1. cikls
- 1. darbs, 2. cikls
- 1. darbs, 3. cikls
- 2. darbs, 1. cikls
- 2. darbs, 2. cikls
- 2. darbs, 3. cikls
- 2. darbs, 4. cikls
- 2. darbs, 5. cikls
2. darbs beidzās.
- 1. darbs, 4. cikls
- 1. darbs, 5. cikls
1. darbs beidzās.
Šoreiz šķiet, ka forma atkal darbojas un pieņem jebkādu lietotāja mijiedarbību. Tātad poga tiek nospiesta līdz pusei jūsu pirmās “darbinieka” funkcijas laikā, kas tiks apstrādāta uzreiz. Visi ienākošie notikumi tiek apstrādāti tāpat kā jebkurš cits funkciju izsaukums.
Teorētiski katra zvana laikā uz “ProgressMessages” Jebkurš klikšķu un lietotāju ziņojumu skaits var notikt “vietā”.
Tāpēc esiet piesardzīgs ar savu kodu!
Cits piemērs (vienkāršā pseidokodā!):
procedūra OnClickFileWrite ();
var myfile: = TFileStream;
sākt
myfile: = TFileStream.create ('myOutput.txt');
mēģiniet
kamēr BytesReady> 0 darīt
sākt
myfile. Rakstīt (DataBlock);
dec (BytesReady, izmērs (DataBlock));
DataBlock [2]: = # 13; {1. testa līnija}
Pieteikums. Procesa ziņojumi;
DataBlock [2]: = # 13; {2. testa līnija}
beigas;
beidzot
myfile.free;
beigas;
beigas;
Šī funkcija raksta lielu datu daudzumu un mēģina "atbloķēt" lietojumprogrammu, izmantojot "ProcessMessages" katru reizi, kad tiek uzrakstīts datu bloks.
Ja lietotājs vēlreiz noklikšķina uz pogas, tas pats kods tiks izpildīts, kamēr fails joprojām tiek rakstīts. Tātad failu nevar atvērt otro reizi, un procedūra neizdodas.
Varbūt jūsu lietojumprogramma veiks kādu kļūdu atkopšanu, piemēram, buferu atbrīvošanu.
Kā iespējams rezultāts "Datablock" tiks atbrīvots, un pirmais kods "pēkšņi" radīs "Piekļuves pārkāpums", kad tam piekļūs. Šajā gadījumā 1. testa līnija darbosies, 2. testa līnija sabruks.
Labāks veids:
Lai to padarītu vieglu, visu formu var iestatīt kā “iespējotu: = nepatiesa”, kas bloķē visu lietotāja ievadītos datus, bet to lietotājam NAV parādīt (visas pogas nav pelēkas).
Labāks veids būtu visu pogu iestatīšana uz “atspējota”, taču tas varētu būt sarežģīti, ja vēlaties paturēt vienu, piemēram, pogu “Atcelt”. Jums arī jāiet cauri visiem komponentiem, lai tos atspējotu, un kad tie atkal ir iespējoti, jums jāpārbauda, vai kāds no tiem ir palicis invalīdu stāvoklī.
Tu varētu atspējot konteinera bērnu vadīklas, kad mainās īpašums Iespējots.
Kā norāda klases nosaukums "TNotifyEvent", to vajadzētu izmantot tikai īslaicīgai reakcijai uz notikumu. Laikietilpīgs kods ir labākais veids, kā IMHO visu “lēno” kodu ievietot savā pavedienā.
Attiecībā uz "PrecessMessages" problēmām un / vai komponentu iespējošanu un atspējošanu, otrais pavediens šķiet, ka tas nemaz nav pārāk sarežģīts.
Atcerieties, ka pat vienkāršas un ātras koda līnijas var pakārt sekundes, piem. atverot failu diska diskdzinī, iespējams, būs jāgaida, līdz diska centrifugēšana ir pabeigta. Neizskatās ļoti labi, ja šķiet, ka jūsu lietojumprogramma avarē, jo disks ir pārāk lēns.
Tieši tā. Nākamreiz pievienojot “Pieteikums. ProcessMessages ", padomājiet divreiz;)