W Windows obsługa zdarzeń opiera się na koncepcji pętli komunikatów (message loop). Taka pętla powinna nieustannie kręcić się w każdym wątku, w którym tworzone są okna, i na bieżąco pobierać pojawiające się komunikaty o zdarzeniach. Dzięki temu użytkownik może przeprowadzać interakcje z interfejsem programu. Dlatego też wszelkie dłuższe działania (np. złożone obliczenia lub odczyt/zapis, zwłaszcza przez sieć) mogą sprawić, że aplikacja wyda się zawieszona. Pętla komunikatów nie będzie bowiem pobierać i przetwarzać gromadzących się w kolejce zdarzeń.
Typowym rozwiązaniem jest umieszczenie takich czasochłonnych operacji w osobnym wątku. Czasem jest to oczywiście niezbędne, lecz wielowątkowość, jak wiadomo, oprócz korzyści wprowadza dodatkowe problemy, które należy uwzględnić – jak choćby synchronizacja dostępu do danych.
Jeśli jednak nasza długa operacja daje się podzielić na kilka mniejszych, to możemy wówczas zastosować inne rozwiązanie. Można mianowicie co jakiś (krótki) czas pobierać oczekujące w kolejce komunikaty i zajmować się nimi, dzięki czemu interfejs będzie miał szansę zareagować na akcje użytkownika. Zazwyczaj oznacza to odpowiednio częste wywoływanie funkcji w rodzaju System.Windows.Forms.Application.DoEvents
z .NET lub TApplication.ProcessMessages
z VCL (Delphi). Jeśli na przykład dokonujemy jakichś obliczeń w pętli, wspomniane funkcje można wywoływać w każdym jej cyklu.
Jest nieco gorzej, jeśli piszemy z użyciem samego Windows API. Podobną funkcję musimy wtedy napisać sami. Nie jest to na szczęście trudne – należy po prostu “na chwilę” uruchomić naszą pętlę komunikatów, aby przetworzyła oczekujące zdarzenia:
Korzystamy z PeekMessage
, która sprawdza, czy w kolejce nie ma już więcej zdarzeń i informuje nas o tym. Trzeba tylko pamiętać, że wśród tych zdarzeń może pojawić się WM_QUIT
, który to komunikat oznacza konieczność zamknięcia aplikacji. Sposobem na jego obsłużenie może być chociażby wartość zwrócona z naszej funkcji; wywołujący będzie wówczas wiedział, że powinien zakończyć to, co aktualnie robi, gdyż program ma zostać zamknięty.
Oczywiście postać powyższej pętli powinna tak naprawdę być identyczna jak tej głównej, w funkcji WinMain
– a więc niekoniecznie taka, jak powyżej. To się aczkolwiek zdarza wtedy, gdy korzystamy z okien dialogowych, akceleratorów menu i tym podobnych rzeczy. Samo to wymaga jednak na tyle dużej biegłości w Windows API, że odpowiednie przerobienie zaprezentowanej funkcji to przy tym naprawdę mały pikuś ;-)
Możesz powiedzieć jak się nazywa czcionka użyta w kodzie? :P
Hmm… Courier New? :)