Az alkalmazás sötét oldala. ProcessMessages

A cikket Marcus Junglas nyújtotta be

Amikor egy eseménykezelőt programoznak Delphiben (mint például a Kattintásra egy TBgomb eseménye), akkor jön az az idő, amikor az alkalmazásnak egy ideig el kell foglalkoznia, pl. a kódnak nagy fájlt kell írni vagy adatot tömöríteni.

Ha megteszi, észre fogja venni úgy tűnik, hogy az alkalmazás zárolva van. Az űrlapot már nem lehet mozgatni, és a gombok nem mutatnak élet jelet. Úgy tűnik, hogy összeomlik.

Ennek oka az, hogy a Delpi alkalmazás egyetlen menetes. Az Ön által írt kód csak egy csomó eljárást képvisel, amelyeket Delphi főszála hív meg, amikor egy esemény bekövetkezik. A fennmaradó időben a fő szál a rendszerüzenetek kezelése és más dolgok, például az űrlapok és az alkatrészek kezelési funkciói.

Tehát, ha nem fejezi be az eseménykezelést hosszabb munkával, megakadályozhatja, hogy az alkalmazás kezelje ezeket az üzeneteket.

Az ilyen típusú problémák általános megoldása az "alkalmazás. ProcessMessages”. Az "alkalmazás" a TApplication osztály globális tárgya.

instagram viewer

Az alkalmazás. A Processmessages az összes várakozó üzenetet, például ablakmozgásokat, gomb kattintásokat és így tovább kezeli. Általában egyszerű megoldásként használják, hogy az alkalmazás "működőképes" maradjon.

Sajnos a "ProcessMessages" mögött található mechanizmusnak megvannak a maga sajátosságai, ami nagy zavart okozhat!

Mit jelent a ProcessMessages?

A PprocessMessages kezeli az alkalmazás üzenetsorában lévő összes várakozó rendszerüzenetet. A Windows üzeneteket használ az összes futó alkalmazás "beszélgetéséhez". A felhasználói interakció üzenetek útján kerül az űrlapra, és a "ProcessMessages" kezeli őket.

Ha például az egér egy TB gombra megy, a ProgressMessages mindent megtesz, aminek történnie kell ebben az eseményben, például a a gomb újbóli festése "megnyomott" állapotba, és természetesen hívás az OnClick () kezelési eljárásra, ha azt hozzárendelte.

Ez a probléma: a ProcessMessages hívásai visszatérő hívást tartalmazhatnak bármely eseménykezelőhöz. Íme egy példa:

Használja a következő kódot egy gomb OnClick páros kezelőjéhez ("munka"). A for-utasítás egy hosszú feldolgozási munkát szimulál, néha a ProcessMessages hívásával.

Ezt a jobb olvashatóság érdekében egyszerűsítettük:

{a MyFormban:}
WorkLevel: egész szám;
{OnCreate:}
WorkLevel: = 0;
eljárás TForm1.WorkBtnClick (Feladó: TObject);
var
ciklus: egész szám;
kezdődik
inc (WorkLevel);
mert ciklus: = 1 nak nek 5 csinál
kezdődik
Memo1.Lines. Add ('- Munka' + IntToStr (WorkLevel) + ', Ciklus' + IntToStr (ciklus);
Alkalmazás. ProcessMessages;
alvás (1000); // vagy más munka
vég;
Memo1.Lines. Add ('Munka' + IntToStr (WorkLevel) + 'véget ért.');
dec (WorkLevel);
vég;

A "ProcessMessages" NÉLKÜL a következő sorok kerülnek az emlékeztetőbe, ha a gombot kétszer megnyomták rövid idő alatt:

 - 1. munka, 1. ciklus
- 1. munka, 2. ciklus
- 1. munka, 3. ciklus
- 1. munka, 4. ciklus
- 1. munka, 5. ciklus
Az 1. munka véget ért.
- 1. munka, 1. ciklus
- 1. munka, 2. ciklus
- 1. munka, 3. ciklus
- 1. munka, 4. ciklus
- 1. munka, 5. ciklus
Az 1. munka véget ért.

Amíg az eljárás elfoglalt, az űrlap nem reagál, ám a második kattintást a Windows az üzenetsorba helyezte. Közvetlenül az „OnClick” befejezése után újra meghívják.

A "ProcessMessages" -T MEG beleszámítva, a kimenet nagyon eltérő lehet:

 - 1. munka, 1. ciklus
- 1. munka, 2. ciklus
- 1. munka, 3. ciklus
- 2. munka, 1. ciklus
- 2. munka, 2. ciklus
- 2. munka, 3. ciklus
- 2. munka, 4. ciklus
- 2. munka, 5. ciklus
A 2. munka befejeződött.
- 1. munka, 4. ciklus
- 1. munka, 5. ciklus
Az 1. munka véget ért.

Ezúttal úgy tűnik, hogy az űrlap újra működik, és minden felhasználói beavatkozást elfogad. Tehát a gombot félig lenyomva az első újrainduló "munkás" funkció alatt, amely azonnal kezelésre kerül. Minden bejövő eseményt úgy kezelünk, mint bármely más funkcióhívást.

Elméletileg minden, a „ProgressMessages” hívás során bármilyen kattintás és felhasználói üzenet előfordulhat, hogy „a helyén” van.

Tehát legyen óvatos a kóddal!

Különböző példa (egyszerű álkódban!):

eljárás OnClickFileWrite ();
var myfile: = TFileStream;
kezdődik
myfile: = TFileStream.create ('myOutput.txt');
próbáld ki
míg BytesReady> 0 csinál
kezdődik
myfile. Írás (DataBlock);
dec (BytesReady, méret (DataBlock));
DataBlock [2]: = # 13; {1. tesztvonal}
Alkalmazás. ProcessMessages;
DataBlock [2]: = # 13; {2. tesztvonal}
vég;
végül
myfile.free;
vég;
vég;

Ez a funkció nagy mennyiségű adatot ír, és megpróbálja "felszabadítani" az alkalmazást a "ProcessMessages" segítségével minden egyes adatblokk írásakor.

Ha a felhasználó ismét rákattint a gombra, ugyanaz a kód kerül végrehajtásra, amíg a fájlt még nem írják. Tehát a fájl nem nyitható meg második alkalommal, és az eljárás sikertelen.

Lehet, hogy az alkalmazás valamilyen hibát helyrehoz, például felszabadítja a puffereket.

Ennek eredményeként a "Datablock" felszabadul, és az első kód "hirtelen" felveti a "Hozzáférés megsértését", amikor hozzáfér. Ebben az esetben: az 1. tesztvonal működni fog, a 2. tesztvonal összeomlik.

A jobb módszer:

Az egyszerűség kedvéért beállíthatja a teljes űrlapot "engedélyezve: = hamis", amely blokkolja az összes felhasználói bemenetet, de ezt NEM jeleníti meg a felhasználónak (az összes gomb nem szürke).

Jobb mód lenne, ha az összes gombot "letiltva" állítja, de ez bonyolult lehet, ha például egy "Mégse" gombot akar tartani. Ezenkívül át kell mennie az összes összetevőn a letiltásuk érdekében, és amikor ismét engedélyezik őket, ellenőriznie kell, hogy maradtak-e valamilyen letiltott állapotban.

Te tudnál tiltsa le a tároló gyermekvezérlését, ha az Engedélyezett tulajdonság megváltozik.

Ahogyan a "TNotifyEvent" osztálynév sugallja, azt csak az esemény rövid távú reakcióira szabad használni. Időigényes kód esetén a legjobb módszer az IMHO, hogy az összes "lassú" kódot saját szálba tegye.

A "PrecessMessages" problémáival és / vagy az összetevők engedélyezésével és letiltásával kapcsolatban a második szál egyáltalán nem tűnik túl bonyolultnak.

Ne feledje, hogy még az egyszerű és gyors kódvonalak másodpercekre is lefagyhatnak, pl. Lehet, hogy egy fájl meghajtóra való megnyitásával meg kell várni, amíg a meghajtó becsavaródása befejeződik. Nem tűnik túl jól, ha az alkalmazás összeomlik, mert a meghajtó túl lassú.

Ez az. A következő alkalommal, amikor hozzáadja az "Alkalmazás. ProcessMessages ", gondoljon kétszer;)