home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1997 #3
/
amigamamagazinepolishissue03-1
/
ma_1995
/
12
/
ami043.txt
< prev
next >
Wrap
Text File
|
1997-04-07
|
10KB
|
213 lines
C dla kaûdego (cz. 7.)
----------------------
MALOWANIA CIÂG DALSZY
<lead>W dzisiejszym odcinku opiszemy to, co zaprezentowane
zostaîo w listingu z poprzedniej czëôci.
<a>Kamil Iskra, Dariusz Ûbik
<txt>Wystëpuje oczywiste powiâzanie pomiëdzy trybem pracy
programu, klawiszem powodujâcym jego wywoîanie i opisujâcym go
tekstem. Stworzyliômy wiëc wîasnâ strukturë o nazwie "operacja",
która îâczy te trzy elementy: pole "name" zawiera opis trybu, a
"key" literë, wywoîujâcâ dany tryb. Trzecie pole -- "fun" -- moûe
byê czymô nowym dla niezbyt doôwiadczonych programistów -- jest
to wskaúnik na funkcjë pobierajâcâ argumenty, "wskaúnik na
strukturë IntuiMessage" oraz "wskaúnik na strukturë Window", a
nie zwracajâcâ niczego (void) -- peîniejsze wiadomoôci znajdziesz
w ksiâûce "Jëzyk ANSI C". W programie definiowana jest tablica
takich struktur: "op_tab", w pola "fun" jest wpisywany adres
funkcji obsîugujâcych dany tryb programu, a to, w jakim trybie
program znajduje sië w danym momencie, jest odnotowane w zmiennej
"op_pos", której wartoôê jest po prostu indeksem tablicy
"op_tab". Aby wywoîaê funkcjë, której adres znajduje sië w polu
"fun", naleûy postâpiê tak samo, jakby sië wywoîywaîo normalnâ
funkcjë. My w programie robimy po prostu:
<l> op_tab[op_pos].fun(&msg, window);
<txt>Deklaracjë zmiennych mamy juû za sobâ, nastëpnie otwarcie
bibliotek i okna, pëtla "for", wykonujâca sië do koïca programu,
oraz "rutynka", czyli oczekiwanie na informacje z portu okna, a
póúniej jakieô "cuda": "__STDC__" i inne.
Zastosowaliômy wyraûenie, które nie jest znane wszystkim
kompilatorom, a mianowicie przypisanie jednej struktury do
drugiej za pomocâ pojedynczego przypisania. Taki zapis jest
zgodny z normâ ANSI jëzyka C, ale niektóre starsze kompilatory
mogâ mieê z nim problemy. Z tego powodu uûyliômy dyrektyw
preprocesora, powodujâcych warunkowâ kompilacjë: jeûeli jest
zdefiniowana staîa "__STDC__" i jest ona róûna od 0 (#if
__STDC__), co oznacza, ûe dany kompilator jest zgodny z normâ
ANSI, to uûywamy wyûej opisanej instrukcji, w przeciwnym wypadku
(#else) jawnie kopiujemy jednâ strukturë do drugiej. Warto moûe w
tym momencie wspomnieê o kilku innych standardowo zdefiniowanych
staîych, np. __SASC i AMIGA dla SAS/C, AZTEC_C i MCH_AMIGA dla
Aztec C, __GNUC__ i AMIGA dla GNU CC -- dziëki temu moûna tworzyê
programy, dziaîajâce na kilku platformach sprzëtowych oraz
moûliwe do skompilowania na róûnych kompilatorach.
Wprawdzie nie wszyscy bëdâ zmuszeni do woîania funkcji CopyMem() z
biblioteki Exec, jednak wszyscy znaê jâ powinni:
<l> void CopyMem( APTR source, APTR dest, unsigned long size );
<txt>Zadaniem funkcji jest skopiowanie obszaru pamiëci,
wskazywanego przez wskaúnik "source", do obszaru wskazywanego
przez "dest". Rozmiar kopiowanego "kawaîka", podany w bajtach,
jest trzecim argumentem. UWAGA! Kolejnoôê parametrów "source" i
"dest" jest ODWROTNA niû w standardowych funkcjach kopiujâcych
jëzyka "C", takich jak "strcpy", "memcpy" itd.
Po wykonaniu kopii przybyîej wiadomoôci i zwrocie oryginaîu
"rozpakowujemy prezent" od Intuition.
<sr>Klasa wiadomoôci IDCMP_VANILLAKEY:
<txt>Flaga ta powoduje dostarczanie do programu informacji o
uûyciu klawiatury. Informacja tego typu zawiera w polu "Code" kod
znaku, jaki znajdowaî sië pod przyciôniëtym przyciskiem.
Obsîugiwane jest aktualne obîoûenie klawiatury, ustawione przez
uûytkownika za pomocâ systemowego programu "Input". VANILLAKEY
dostarcza tylko pojedynczych znaków. Nie jest moûliwe odczytanie
ciâgów zdefiniowanych pod przyciskami, nie moûna dowiedzieê sië o
przycisku HELP, kursorach... Moûliwe jest jednak odczytanie
wciôniëcia klawisza [Esc], poniewaû jest on pojedynczym znakiem o
kodzie 27.
W programie po otrzymaniu informacji o naciôniëciu przycisku
sprawdzamy, czy jest to [Esc]. Jeôli tak, to opuszczamy program,
w przeciwnym wypadku przeglâdamy tablicë operacji, sprawdzajâc,
czy któraô z nich nie ma skrótu z klawiatury identycznego z
naciôniëtym przyciskiem. Ten przydîugawy warunek w pëtli "for"
pozwala przejrzeê wszystkie elementy tablicy "op_tab". Poniewaû
operator "sizeof" zwraca rozmiar obiektu w bajtach, naleûy
wielkoôê të podzieliê przez rozmiar pojedynczego elementu.
Operator "sizeof" podaje rozmiar obiektu podczas kompilacji
programu, w zwiâzku z tym wyraûenie w warunku pëtli "for" otrzyma
staîâ wartoôê.
Po otrzymaniu informacji IDCMP_CLOSEWINDOW woîamy funkcjë:
<l> BOOL DoubleClick( ULONG sSeconds, ULONG sMicros, ULONG cSeconds,
ULONG cMicros);
<txt>Jej zadaniem jest sprawdzenie, czy dwa podane czasy mieszczâ
sië w tzw. double-clicku. Jeôli róûnica pomiëdzy podanymi czasami
jest mniejsza od double-clicku, to zostanie zwrócona wartoôê
TRUE, w przeciwnym wypadku FALSE. Czas do funkcji podaje sië w
postaci sekund i mikrosekund pierwszego i drugiego wydarzenia.
Czas moûna znaleúê w strukturze "IntuiMessage".
Dziëki funkcji DoubleClick() opuszczenie programu nastâpi dopiero
po dwukrotnym klikniëciu na gadûecie zamykania. W wypadku
pojedynczego naciôniëcia zostanie zmieniony tryb pracy programu
(tak, wiemy, to nie jest intuicyjne).
W wypadku, gdy system dostarczy informacji o przyciskach myszy
(IDCMP_MOUSEBUTTONS), zostanie wywoîana bieûâca funkcja z tablicy
"op_tab".
Wewnâtrz instrukcji "switch" pojawiîa sië kolejna, nie omówiona
dotychczas, klasa informacji IDCMP, a mianowicie IDCMP_MOUSEMOVE.
Klasa ta powoduje przekazywanie do portu aktywnego okna
informacji o kaûdym ruchu myszy (trzeba je obsîugiwaê szybko, bo
przy nagîych ruchach myszâ przybywa naprawdë sporo informacji!).
Do jej funkcjonowania konieczne jest umieszczenie w polu "Flags"
okna flagi WFLG_REPORTMOUSE. Program w prezentowanej wersji nie
robi nic w wypadku stwierdzenia takiej klasy wiadomoôci,
umieôciliômy jâ jednak, aby umoûliwiê jego rozbudowë, która bez
znajomoôci tej klasy informacji mogîaby byê kîopotliwa.
Poniewaû w funkcji "main" nie znajdziemy juû nic ciekawego, omówië
jedynie funkcje zawarte w tablicy "op_tab":
linia() -- Zawiera funkcjë z biblioteki "graphics.library":
<l>void Draw( struct RastPort *rp, long x, long y );
<txt>Jej zadaniem jest narysowanie linii pomiëdzy obecnym poîoûeniem
kursora a podanymi wspóîrzëdnymi. Zmieniane jest poîoûenie kursora
graficznego na wartoôci x i y.
punkt() -- Zawiera dwie funkcje biblioteczne:
<l>LONG WritePixel( struct RastPort *rp, long x, long y );
<txt>Rysuje punkt o wspóîrzëdnych (x, y). Funkcja zwraca zero,
gdy wszystko byîo OK, lub -1, gdy podany punkt jest poza
RastPortem. Jako jedna z niewielu nie zmienia poîoûenia kursora
graficznego.
<l> void Move( struct RastPort *rp, long x, long y );
<txt>Przesuwa kursor graficzny w podane miejsce, bez
jakiegokolwiek efektu wizualnego.
napis() -- Odwoîuje sië do funkcji systemowej:
<l> LONG Text( struct RastPort *rp, STRPTR string, unsigned long count );
<txt>Umieszcza ona tekst, wskazywany przez "string", w
RastPorcie. Napis jest umieszczany w bieûâcym miejscu (cp_x,
cp_y) i rysowany bieûâcâ czcionkâ. Jest pisany zarówno poniûej,
jak i powyûej poîoûenia kursora (dlaczego tak jest, powiemy za
chwilë). Po zakoïczeniu dziaîania funkcji kursor graficzny
znajduje sië na koïcu tekstu. Funkcja ta wymaga podania liczby
znaków do wypisania. Sîuûy do tego ostatni argument.
drmd() -- Funkcja ta zmienia tryb rysowania po przyciôniëciu
lewego przycisku myszy. Systemowe narzëdzia, sîuûâce do tego
celu, opisaliômy wczeôniej. Wystëpujâca tu przydîugawa i
skomplikowana konstrukcja, która jest drugim argumentem funkcji
SetDrMd() powoduje, ûe tryb rysowania zostanie ustalony na
kolejny lub odliczanie rozpocznie sië od poczâtku. Postëpujâc
zgodnie z kolejnoôciâ operatorów najpierw zostanie wykonana
konstrukcja warunkowa, zwracajâca numer obecnego trybu (jej
zadanie byîo omówione wczeôniej) -- po jego zwiëkszeniu o jeden
otrzymamy numer kolejnego trybu. Poniewaû argument funkcji
SetDrMd(), bëdâcy równoczeônie indeksem tablicy names[], powinien
byê istniejâcym trybem, naleûy zadbaê o to, aby wartoôê ta nie
przekraczaîa 7, poniewaû po zsumowaniu masek bitowych wszystkich
trybów rysowania, otrzymamy takâ wîaônie wartoôê (patrz
"graphics/rastport.h"). Do zapisania liczby z przedziaîu 0..7
wystarczâ trzy najmîodsze bity -- wîaônie w tym celu wykonujemy
bitowâ operacjë I (AND) z flagâ 7 (bitowo 0111). Dziëki temu
przetrwajâ jedynie najmîodsze bity i zapisanie liczby wiëkszej od
7 nie bëdzie moûliwe. Uzyskamy wiëc cyklicznie zmieniajâcy sië
tryb graficzny.
color() -- Zmienia kolor tîa po przyciôniëciu prawego przycisku
oraz atramentu po przyciôniëciu lewego.
kwadrat() -- Rysuje wypeîniony prostokât od poîoûenia kursora
graficznego do poîoûenia myszy w momencie klikniëcia. Zwie sië
niezbyt zgodnie z prawdâ, poniewaû kolega Darek nie odróûnia
prostokâtów od kwadratów. Funkcja ta korzysta z funkcji
biblioteki graficznej:
<l>void RectFill( struct RastPort *rp, long xMin, long yMin, long
xMax, long yMax );
<txt>Jej zadaniem jest wypeînienie prostokâtnego obszaru. Uznaje
aktualne kolory i tryb rysowania. Wspóîrzëdne lewego górnego rogu
prostokâta (xMin, yMin) MUSZÂ byê mniejsze lub równe od
wspóîrzëdnych prawego dolnego rogu (xMax, yMax).
elipsa() -- Funkcja rysuje elipsë, dîugoôci póîosi sâ równe
wspóîrzëdnym wektora îâczâcego punkt (cp_x, cp_y) z punktem, nad
którym "przyciôniëto" mysz. Biblioteczna funkcja do rysowania
elipsy wyglâda nastëpujâco:
<l>void DrawEllipse( struct RastPort *rp, long xCenter, long yCenter,
long a, long b );
<txt>xCenter i yCenter to wspóîrzëdne ôrodka elipsy, a i b to póîosie
elipsy (muszâ byê wiëksze od zera). Wspóîrzëdne cp_x i cp_y nie sâ
zmieniane.
Za miesiâc zajmë sië czcionkami.