home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1997 #3 / amigamamagazinepolishissue03-1 / ma_1995 / 11 / ami041.txt < prev    next >
Text File  |  1997-04-07  |  10KB  |  217 lines

  1.  
  2. Kurs jëzyka C (cz. 6.)
  3. ----------------------
  4.  
  5. MALOWANIE PO EKRANIE 
  6.  
  7. <a>Kamil Iskra, Dariusz Ûbik
  8.  
  9. <txt>Odcinek ten zawiera dokoïczenie omówienia listingu 9., który
  10. zamieôciliômy w poprzednim numerze Magazynu AMIGA.
  11.  
  12. W naszym programie wystëpuje oczywiste powiâzanie pomiëdzy trybem
  13. pracy programu, klawiszem powodujâcym jego wywoîanie i opisujâcym
  14. go tekstem.  Stworzyliômy wiëc wîasnâ strukturë o nazwie
  15. "operacja", która îâczy te trzy elementy: pole "name" zawiera
  16. opis trybu, a "key" literë wywoîujâcâ dany tryb. Trzecie pole --
  17. "fun" -- moûe byê czymô nowym dla niezbyt doôwiadczonych
  18. programistów. Jest to wskaúnik na funkcjë pobierajâcâ argumenty
  19. "wskaúnik na strukturë IntuiMessage" oraz "wskaúnik na strukturë
  20. Window", a nie zwracajâcâ niczego (void). Peîniejsze wiadomoôci
  21. znajdziesz w ksiâûce "Jëzyk ANSI C". W programie definiowana jest
  22. tablica takich struktur: "op_tab", w pola "fun" jest wpisywany
  23. adres funkcji obsîugujâcych dany tryb programu, a to, w jakim
  24. trybie program znajduje sië w danym momencie, jest odnotowane w
  25. zmiennej "op_pos", której wartoôê jest po prostu indeksem tablicy
  26. "op_tab". Aby wywoîaê funkcjë, której adres znajduje sië w polu
  27. "fun", naleûy postâpiê tak samo, jakby sië wywoîywaîo normalnâ
  28. funkcjë. My w programie robimy po prostu:
  29.  
  30. <l>op_tab[op_pos].fun(&msg, window);
  31.  
  32. <txt>Deklaracjë zmiennych mamy juû za sobâ, nastëpnie otwieramy
  33. biblioteki i okna, potem przychodzi czas na pëtlë "for",
  34. wykonujâcâ sië do koïca programu, oraz "rutynkë", czyli
  35. oczekiwanie na informacje z portu okna, a póúniej jeszcze jakieô
  36. "cuda": "__STDC__" i inne.
  37.  
  38. Zastosowaliômy wyraûenie, które nie jest znane wszystkim
  39. kompilatorom, a mianowicie skopiowanie jednej struktury do
  40. drugiej za pomocâ pojedynczego przypisania. Taki zapis jest
  41. zgodny z normâ ANSI jëzyka C, ale niektóre starsze kompilatory
  42. mogâ mieê z nim problemy. Z tego powodu uûyliômy dyrektyw
  43. preprocesora, powodujâcych warunkowâ kompilacjë: jeûeli jest
  44. zdefiniowana staîa "__STDC__" i jest ona róûna od 0 (#if
  45. __STDC__), co oznacza, ûe dany kompilator jest zgodny z normâ
  46. ANSI, to uûywamy wyûej opisanej instrukcji, w przeciwnym wypadku
  47. (#else) jawnie kopiujemy jednâ strukturë do drugiej. Warto moûe w
  48. tym momencie wspomnieê o kilku innych standardowo zdefiniowanych
  49. staîych, np. __SASC i AMIGA dla SAS/C, AZTEC_C i MCH_AMIGA dla
  50. Aztec C, __GNUC__ i AMIGA dla GNU CC. Dziëki nim moûna tworzyê
  51. programy, dziaîajâce na kilku platformach sprzëtowych oraz
  52. moûliwe do skompilowania na róûnych kompilatorach.
  53.  
  54. Wprawdzie nie wszyscy bëdâ zmuszeni do wywoîania funkcji
  55. CopyMem() z biblioteki Exec, jednak wszyscy powinni jâ znaê:
  56.  
  57. <l>void CopyMem( APTR source, APTR dest, unsigned long size );
  58.  
  59. <txt>Zadaniem funkcji jest skopiowanie obszaru pamiëci,
  60. wskazywanego przez wskaúnik "source", do obszaru wskazywanego
  61. przez "dest", rozmiar kopiowanego "kawaîka" podany w bajtach jest
  62. trzecim argumentem. UWAGA! Kolejnoôê parametrów "source" i "dest"
  63. jest ODWROTNA niû w standardowych funkcjach kopiujâcych jëzyka
  64. C, takich jak "strcpy", "memcpy" itd.
  65.  
  66. Po wykonaniu kopii przybyîej wiadomoôci i zwrocie oryginaîu
  67. "rozpakowujemy prezent" od Intuition.
  68.  
  69. Klasa wiadomoôci IDCMP_VANILLAKEY:
  70.  
  71. Flaga ta powoduje dostarczanie do programu informacji o uûyciu
  72. klawiatury. Informacja tego typu zawiera w polu "Code" kod znaku,
  73. jaki znajdowaî sië pod naciôniëtym przyciskiem, obsîugiwane jest
  74. aktualne obîoûenie klawiatury, ustawione przez uûytkownika za
  75. pomocâ systemowego programu "Input". VANILLAKEY dostarcza tylko
  76. pojedyncze znaki, nie jest moûliwe odczytanie ciâgów
  77. zdefiniowanych pod przyciskami, nie moûna dowiedzieê sië o
  78. przycisku HELP, kursorach... Moûliwe jest jednak odczytanie
  79. wciôniëcia klawisza [Esc], poniewaû jest on pojedynczym znakiem o
  80. kodzie 27.
  81.  
  82. W programie, po otrzymaniu informacji o naciôniëciu przycisku,
  83. sprawdzamy, czy jest to [Esc]. Jeôli tak, to opuszczamy program,
  84. w przeciwnym wypadku przeglâdamy tablicë operacji, sprawdzajâc,
  85. czy któraô z nich nie ma skrótu z klawiatury identycznego z
  86. naciôniëtym przyciskiem. Ten przydîugawy warunek w pëtli "for"
  87. pozwala przejrzeê wszystkie elementy tablicy "op_tab". Poniewaû
  88. operator "sizeof" zwraca rozmiar obiektu w bajtach, naleûy
  89. wielkoôê të podzieliê przez rozmiar pojedynczego elementu.
  90. Operator "sizeof" podaje rozmiar obiektu podczas kompilacji
  91. programu, w zwiâzku z tym wyraûenie w warunku pëtli "for" otrzyma
  92. staîâ wartoôê.
  93.  
  94. Po otrzymaniu informacji IDCMP_CLOSEWINDOW wywoîujemy funkcjë:
  95.  
  96. <l>BOOL DoubleClick( ULONG sSeconds, ULONG sMicros, ULONG cSeconds, ULONG cMicros);
  97.  
  98. <txt>Jej zadaniem jest sprawdzenie, czy podane dwie wartoôci
  99. czasu mieszczâ sië w tzw. double clicku. Jeôli róûnica miëdzy
  100. tymi wartoôciami jest mniejsza od "double clicku", to zostanie
  101. zwrócona wartoôê TRUE, w przeciwnym wypadku FALSE. Czas do
  102. funkcji podaje sië w postaci sekund i mikrosekund pierwszego i
  103. drugiego wydarzenia. Moûna je znaleúê w strukturze
  104. "IntuiMessage".
  105.  
  106. Dziëki funkcji DoubleClick() program opuszcza sië dopiero po
  107. dwukrotnym klikniëciu na gadûecie zamykania. W wypadku
  108. pojedynczego naciôniëcia zostanie zmieniony tryb pracy programu
  109. (tak, wiemy, to nie jest intuicyjne).
  110.  
  111. W wypadku, gdy system dostarczy informacji o przyciskach myszy
  112. (IDCMP_MOUSEBUTTONS), zostanie wywoîana bieûâca funkcja z tablicy
  113. "op_tab".
  114.  
  115. Wewnâtrz instrukcji "switch" pojawiîa sië kolejna, nie omówiona
  116. dotychczas, klasa informacji IDCMP, a mianowicie IDCMP_MOUSEMOVE.
  117. Klasa ta powoduje przekazywanie do portu okna aktywnego
  118. informacji o kaûdym ruchu myszy (trzeba je obsîugiwaê szybko, bo
  119. przy nagîych ruchach myszâ przybywa naprawdë sporo informacji!).
  120. Do jej funkcjonowania konieczne jest umieszczenie w polu "Flags"
  121. okna flagi WFLG_REPORTMOUSE. Program w prezentowanej wersji nie
  122. robi nic w wypadku stwierdzenia takiej klasy wiadomoôci.
  123. Umieôciliômy jâ jednak, aby umoûliwiê rozbudowë programu, która
  124. bez znajomoôci tej klasy informacji mogîaby byê kîopotliwa.
  125.  
  126. Poniewaû w funkcji "main" nie znajdziemy juû nic ciekawego, omówië
  127. funkcje zawarte w tablicy "op_tab":
  128.  
  129. linia() -- zawiera funkcjë z biblioteki "graphics.library":
  130.  
  131. <l>void Draw( struct RastPort *rp, long x, long y );
  132.  
  133. <txt>Jej zadaniem jest narysowanie linii pomiëdzy obecnym
  134. poîoûeniem kursora a podanymi wspóîrzëdnymi, zmieniane jest
  135. poîoûenie kursora graficznego na wartoôci x i y.
  136.  
  137. punkt() -- zawiera dwie funkcje biblioteczne:
  138.  
  139. <l>LONG WritePixel( struct RastPort *rp, long x, long y );
  140.  
  141. <txt>Zmienia kolor punktu o wspóîrzëdnych (x, y) na kolor
  142. ustawiony jako APen. Rezultatem dziaîania funkcji jest zero, gdy
  143. wszystko jest OK, lub -1, gdy podany punkt jest poza rastportem.
  144. Funkcja, jako jedna z niewielu, nie zmienia poîoûenia kursora
  145. graficznego.
  146.  
  147. <l>void Move( struct RastPort *rp, long x, long y );
  148.  
  149. <txt>Przesuwa kursor graficzny w podane miejsce, bez
  150. jakiegokolwiek efektu wizualnego.
  151.  
  152. Funkcja napis() -- odwoîuje sië do funkcji systemowej:
  153.  
  154. <l>LONG Text( struct RastPort *rp, STRPTR string, unsigned long count );
  155.  
  156. <txt>Umieszcza ona tekst, wskazywany przez "string", w
  157. rastporcie. Napis jest umieszczany w bieûâcym miejscu (cp_x,
  158. cp_y) i rysowany bieûâcâ czcionkâ. Pisany jest zarówno poniûej,
  159. jak i powyûej poîoûenia kursora (dlaczego tak jest, powiemy w
  160. kolejnej czëôci). Po zakoïczeniu dziaîania funkcji kursor
  161. graficzny znajduje sië na koïcu tekstu. Funkcja ta wymaga podania
  162. liczby znaków do wypisania -- sîuûy do tego ostatni argument.
  163.  
  164. drmd() -- funkcja ta zmienia tryb rysowania po naciôniëciu lewego
  165. przycisku myszy. Systemowe narzëdzia, sîuûâce do tego celu,
  166. opisaliômy wczeôniej. Wystëpujâca tu przydîuga i skomplikowana
  167. konstrukcja, bëdâca drugim argumentem funkcji SetDrMd(),
  168. powoduje, ûe tryb rysowania zostanie ustalony na kolejny lub
  169. odliczanie rozpocznie sië od poczâtku. Postëpujâc zgodnie z
  170. kolejnoôciâ operatorów, najpierw zostanie wykonana konstrukcja
  171. warunkowa, zwracajâca numer obecnego trybu (jej zadanie byîo
  172. omówione wczeôniej) -- po jego zwiëkszeniu o jeden otrzymamy
  173. numer kolejnego trybu. Poniewaû argument funkcji SetDrMd(),
  174. bëdâcy równoczeônie indeksem tablicy names[], powinien byê
  175. istniejâcym trybem, naleûy zadbaê o to, aby wartoôê ta nie
  176. przekraczaîa 7, poniewaû po zsumowaniu masek bitowych wszystkich
  177. trybów rysowania otrzymamy takâ wîaônie wartoôê (patrz
  178. "graphics/rastport.h"). Do zapisania liczby z przedziaîu 0..7
  179. wystarczâ trzy najmîodsze bity -- wîaônie w tym celu wykonujemy
  180. bitowâ operacjë I (AND) z flagâ 7 (bitowo 0111). Dziëki temu
  181. przetrwajâ jedynie najmîodsze bity i zapisanie liczby wiëkszej od
  182. 7 nie bëdzie moûliwe, uzyskamy wiëc cyklicznie zmieniajâcy sië
  183. tryb graficzny. Niektórzy z Was zapewne zastanawiajâ sië,
  184. dlaczego nie zastosowaliômy tu prostszej i bardziej ogólnej
  185. metody z wyraûeniem warunkowym "if" -- po prostu tak, jak jest,
  186. jest szybciej i krócej.
  187.  
  188. color() -- zmienia kolor tîa po przyciôniëciu prawego przycisku
  189. oraz atramentu po przyciôniëciu lewego.
  190.  
  191. kwadrat() -- rysuje wypeîniony prostokât od poîoûenia kursora
  192. graficznego do poîoûenia myszy w momencie klikniëcia. Zwie sië
  193. niezbyt zgodnie z prawdâ, poniewaû kolega Darek nie odróûnia
  194. prostokâtów od kwadratów. Funkcja ta korzysta z funkcji
  195. biblioteki graficznej:
  196.  
  197. <l>void RectFill( struct RastPort *rp, long xMin, long yMin, long xMax, long yMax );
  198.  
  199. <txt>Jej zadaniem jest wypeînienie prostokâtnego obszaru za
  200. pomocâ aktualnego koloru APen. Wspóîrzëdne lewego górnego rogu
  201. prostokâta (xMin, yMin) MUSZ byê mniejsze od wspóîrzëdnych
  202. prawego dolnego rogu (xMax, yMax) lub im równe.
  203.  
  204. elipsa() -- funkcja rysuje elipsë, dîugoôci póîosi sâ równe
  205. wspóîrzëdnym wektora îâczâcego punkt (cp_x, cp_y) z punktem, nad
  206. którym "przyciôniëto" mysz. Biblioteczna funkcja do rysowania
  207. elipsy wyglâda nastëpujâco:
  208.  
  209. <l>void DrawEllipse( struct RastPort *rp, long xCenter, long yCenter, long a, long b );
  210.  
  211. <txt>xCenter i yCenter to wspóîrzëdne ôrodka elipsy, a i b to
  212. póîosie elipsy (muszâ byê wiëksze od zera). Wspóîrzëdne cp_x i
  213. cp_y nie sâ zmieniane.
  214.  
  215. Za miesiâc pokaûemy, jak uûywaê róûnych czcionek oraz jak tworzyê
  216. górne menu.
  217.