Graficzny interfejs może (i powinien) ładnie wyglądać, ale jego najważniejszą cechą jest oczywiście interaktywność. GUI musi przede wszystkim umożliwiać reakcję na poczynania użytkownika, a to jest możliwe przez odpowiednią obsługę zdarzeń.
Informację o tym, że kliknięto gdzieś myszką lub wciśnięto klawisz, pozyskać jest oczywiście bardzo łatwo. W Windows wystarczy w tym celu obsługiwać komunikaty systemowe przychodzące do okna. O wiele większym wyzwaniem jest przetłumaczenie informacji “kliknięto w punkt (458,89) obszaru klienta” na “kliknięto w obrębie kontrolki TextBox o nazwie Text1
“. Komunikat należy bowiem przekazać do odpowiedniej kontrolki (-ek) – tej, której on dotyczy.
Jest pewnie wiele sposób na zrealizowanie takiego przekazywania, jednak najbardziej sensowne wydają mi się dwa. Pierwszym z nich jest propagacja zdarzenia na kolejne poziomy drzewa systemu GUI. Kliknięcie jest więc przekazywane do okna i od tej pory cała odpowiedzialność za jego obsłużenie spada na to właśnie okno. Ono sprawdza, czy myszka trafiła w którąś z kontrolek potomnych; jeśli tak, to znów zdarzenie jest przekazywane właśnie do tej kontrolki i okno się już nim nie zajmuje. Proces ten przebiega aż dojdziemy do najniższego możliwego poziomu, czyli kontrolki nie zawierającej już żadnych innych. Tam następuje właściwa obsługa zdarzenia.
Drugi sposób zakłada, że zdarzenie nie będzie “rozłazić” się po całym drzewie, tylko od razu trafiać do tej właściwej, docelowej kontrolki. Naturalnie nie zawsze da się tak zrobić. W przypadku wciśnięć klawiszy możemy pamiętać, która kontrolka ma tzw. fokus i do niej kierować komunikaty. Natomiast obsługa myszki wymaga wysłania swego rodzaju sondy wgłąb drzewa kontrolek w celu znalezienie tej najmniejszej, w którą trafił kursor (operacja ta jest znana jako hit test).
Generalnie zdarzenia z punktu widzenia ich obsługi można podzielić na dwie grupy: na zdarzenia myszki i na… wszystkie inne :) To właśnie te pierwsze przysparzają najwięcej kłopotów. Nie tylko wymagają rekurencyjnego przeszukiwania drzewa kontrolek, ale też mogą mieć globalne konsekwencje, jak np. zmiana fokusu. Zajmowanie się tymi konsekwencjami jest łatwiejsze, gdy wszystko odbywa się “na górze” – na poziomie głównych klas systemu GUI, a nie pojedynczych kontrolek. Jest to jeden z powodów przemawiających za wyborem drugiego sposobu przekazywania informacji o zdarzeniach.
Dawno, dawno temu, kiedy łącza były wolne a przeglądarki prymitywne, reklamy na stronach WWW miały postać statycznych lub co najwyżej animowanych banerów. Mało kto używał technologii w rodzaju Flash czy ActiveX, wymagających niestandardowych pluginów instalowanych po stronie użytkownika. A jeżeli już się na to decydował, to reklamy wykorzystujące te rozwiązania różniły się od zwykłych głównie stroną estetyczną: jakością i płynnością animacji.
Chciałoby się powiedzieć: stare dobre czasy, bo dawno odeszły już one do przeszłości. Teraz ze świecą można szukać nieflashowych banerów, a na stronach często można spotkać normalne telewizyjne, streamowane spoty reklamowe. Nie byłoby w tym nic niestosownego – w końcu reklamy są nieodłączną częścią każdego medium, a wykorzystanie najnowszych technologii z pewnością zwiększa ich atrakcyjność, a przez to skuteczność.
I wszystko byłoby w porządku, gdyby ich twórcy znali pojęcie umiaru i taktu. Problemem jest bowiem nie to, że dzisiejsze reklamy sieciowe to już nie tylko animacje, ale i filmy z dźwiękiem i muzyką, a nawet interaktywne gry. Sęk w tym, że one bardzo często przeszkadzają, a wręcz uniemożliwiają zapoznanie się z właściwą treścią strony, na której się znajdują.
Dzisiaj na przykład natrafiłem na baner jednego z operatorów komórkowych, wokół którego latały różnokolorowe motylki. Z pewnością wyglądały one efektownie, lecz czy oznacza to, że ich chmara powinna przesuwać się nad czytany przeze mnie tekst? A tak właśnie było, co oczywiście uniemożliwiało przeczytanie czegokolwiek. Rój uspokoił się dopiero wtedy, gdy przewinąłem się z powrotem na początek strony, gdzie widniał baner.
Zazwyczaj jestem przeciwny wszelkim zakazom – zwłaszcza w delikatnym obszarze Internetu – ale tym razem uważam, że ktoś powinien się zająć tą sprawą. Ktoś – czyli na przykład Komisja Europejska, która ostatnio całkiem dobrze spisała się w zakresie obrony praw użytkowników komórek i klientów linii lotniczych. Pół miliarda obywateli UE, z którego większość korzysta z Internetu, na pewno nie miałoby jej za złe wprowadzenie regulacji ograniczających ekspansję uciążliwych reklam.
Nie uważam przy tym, by musiałyby być one szczególnie restrykcyjne. Zasadniczo wystarczyłyby tylko dwa punkty:
Oczywiście można mieć wątpliwości, czy takie prawo nie byłoby trudne do egzekwowania, a przez to martwe. Dotyczyłoby ono jednak głównie dużych portali, czyli zarejestrowanych i powszechnie przedsiębiorstw, na które bez problemu można w razie czego nałożyć kary finansowe.
A co z mniejszymi serwisami? Naturalnie należałoby uniknąć absurdów w rodzaju wlepiania wirtualnych mandatów autorom stron domowych. W ich przypadku karą byłby po prostu spadek liczby odwiedzających i pogorszenie reputacji – czyli mechanizm, który w Internecie działa od zawsze.
Konstrukcje iteracyjne w C++ mają całkiem spore możliwości. Dotyczy to zwłaszcza instrukcji for
, która jest o wiele elastyczniejsza niż w innych językach. Mimo to w dziedzinie pętli C++ ma pewne niedostatki.
Zwykle najbardziej brakuje nam sposobu na przerwanie zagnieżdżonych pętli. W C# czy Javie jest to możliwe za pomocą specjalnych wariantów instrukcji break
. Lecz w C++ trzeba to robić albo z wykorzystaniem wyklętej (niezbyt zresztą słusznie) instrukcji goto
, albo poprzez zastosowanie zmiennych logicznych. Istnieje też sposób z wykorzystaniem wyjątków, ale można go traktować chyba tylko jako ciekawostkę.
Jest jeszcze jedno usprawnienie mechanizmu pętli, którego C++ nie posiada, ale dla odmiany ten brak nie jest aż tak dolegliwy. Chodzi tu o klauzulę else
występującą po pętli. Tę nietypową konstrukcję widziałem jak dotąd tylko w języku Python; wygląda ona następująco:
Fraza else
odnosi się tutaj do pętli, a nie do instrukcji if
. Jest ona wykonywana wtedy, gdy pętla kończy się normalnie, tzn. nie następuje wykonanie instrukcji break
. Jak widać oznacza to zwykle, że jakiś rodzaj przeszukiwania dotarł do końca wyznaczonego zakresu bez znalezienia pasującego elementu (w tym przypadku – dzielnika).
Większość języków nie posiada tej dziwnej konstrukcji, bo najczęściej można się bez niej obejść. Przeszukiwanie dokonywane w pętli jest bowiem często zamykane w funkcję, którą można zapisać bez użycia break
:
bool IsPrime(unsigned x)
{
for (unsigned i = 2; i < x; ++i)
if (x % i == 0) return false;
return true;
}[/cpp]
Pewne “nowoczesne” konstrukcje w nowszych językach programowania nie są więc zawsze lekarstwem na programistyczne bolączki. Czasami są zwykłym zawracaniem głowy.
Zawsze lubiłem teorię grafów. Niestety, ta sympatia jest w dużym stopniu nieodwzajemniona, gdyż z obejmującej tę teorię matematyki dyskretnej nie miałem zbyt dobrych ocen :) Mimo to chciałbym dzisiaj polecić pewną grę ściśle związaną z tą dziedziną.
Chodzi o Planarity. Polega ona na tym, by ułożyć wierzchołki danego grafu planarnego tak, by żadne jego krawędzie się nie przecinały. Dla małych grafów jest to oczywiście proste, lecz gdy liczba wierzchołków przekracza kilkanaście, na rysunku zaczyna być już gęsto…
Na forum Warsztatu pojawił się wątek z pytaniem o jakiś systematyczny sposób na odpowiednie ułożenie wierzchołków w tej grze. Z faktu, że o tej pory nie znaleziono tam żadnego pewnego rozwiązania wynika, że to całkiem interesująca gra ;)
Kiedy komukolwiek pokazuję fragment napisanego przez siebie kodu, reakcja jest zawsze dość podobna. Można ją streścić jako pytanie: “A dlaczego tu tak zielono?” :)
Faktycznie, dość intensywnie używam komentarzy. Rzeczywiście, nadużywam też stosowania przerw w postaci pustych wierszy. Zgadza się, że dwa wiersze “normalnego” kodu odpowiadają przeciętnie trzem wierszom napisanym przez mnie. Tak, to wszystko prawda. Co mam na swoje usprawiedliwienie?
Otóż… nic :P Wręcz przeciwnie, taki sposób pisania uważam za bardzo pożyteczny, a powodują mną takie oto motywy:
/********/
czy nagłówków opisujących pliki na pewno polepsza czytelność kodu.function1
, a klawisza Tab używa tylko w połączeniu z Altem :) Szkoda, że tego rodzaju kod widzi się stanowczo za często ;PTak więc, Wysoki Sądzie, z powodu swojego rozwlekłego stylu kodowania nie czuję najmniejszych wyrzutów sumienia i nie postanawiam nawet minimalnej poprawy ;P Co więcej, nie będę się krępował przed propagowaniem swoich poglądów na ten temat każdemu, kto będzie miał (nie)przyjemność oglądać napisany przeze mnie kod :)
Projektując klasy i kontrolki systemu GUI, wzoruję się na kilku istniejących rozwiązaniach. Większość wzorców czerpię jednak z Windows Forms, części platformy .NET. Tym, co ostatnio zwróciło w niej moją uwagę, to fakt, że wiele czynności można w niej wykonać na kilka sposób. Mówiąc ściślej, klasy wchodzące w skład WF posiadają często więcej niż jedną składową służącą osiągnięciu tego samego celu.
Przykład? Proszę bardzo. Do zmiany położenia i wymiarów kontrolki wystarczą dokładnie cztery właściwości. Mogą to być: Left (pozycja lewej krawędzi kontrolki), Top (górnej krawędzi), Width i Height. Tyle w zupełności wystarczy. Klasa Windows.Forms.Control ma też jednak inne:
Wszystkie je można oczywiście uzyskać z tych czterech, które wymieniłem na początku. Istnieje też rzecz jasna mnóstwo innych kombinacji z innymi właściwościami “pierwotnymi” i “pochodnymi”.
Można mieć jednak wątpliwości, czy istnienie różnych dróg dotarcia do podobnych danych jest konieczne i właściwe. Przy tak bogatym interfejsie (inny przykład: metoda Graphics.DrawImage() ma aż 30 (!) przeciążonych wersji) można bardzo długo zastanawiać się nad tym, którego sposobu mamy użyć w konkretnym przypadku.
To prawda, że interfejs zbyt ubogi jest zwykle o wiele większym problemem. Uważam jednak, że w programowaniu brzytwa Ockhama ma zastosowanie i że dróg prowadzących do tego samego celu nie należy mnożyć ponad potrzebę.
Wszyscy znają tę grę. Jedna z najpopularniejszych, najbardziej rozpowszechnionych i najlepszych produkcji w dziejach komputerowej rozgrywki. Mają prawie każdy i praktycznie każdy w nią grał. O jakiej grze mowa? O windowsowym Saperze, naturalnie :)
Dlatego wszystkich fanów z pewnością ucieszy fakt, że oto szykuje się ekranizacja tej niezwykłej produkcji. A już teraz można sobie obejrzeć zapowiadający trailer:
Trailer Minesweeper: The Movie
A teraz nieco poważniej… Większość tzw. śmiesznych filmików jest w rzeczywistości mało zabawna, ale trafiają się też perełki. O tym mogę śmiało powiedzieć, że mnie rozbroił :)