Primeri koda:
File:PythonOnSymbianBookExampleCode TouchOnFullscreen.zip
File:PythonOnSymbianBookExampleCode TouchWithinRectangle.zip
File:PythonOnSymbianBookExampleCode TouchArbitaryRegions.zip
File:PythonOnSymbianBookExampleCode TouchyPaint.zip
File:PythonOnSymbianBookExampleCode TicTacToe.zip
Korisnički interfejsi (Touch UI) koji su omogućeni za dodir (touch-enabled) su prirodniji od interfejsa koji se oslanjaju samo na hardverske tastere ili tastature. Dok neke aplikacije rade dobro sa obe vrste ovih interfejsa, neke aplikacije su poboljšane ili su dostupne jedino ako imaju touch interfejs.
Symbian platforma podržava uređaje sa i bez touch interfejsa.
Ovo poglavlje objašnjava kako detektovati da li je dodir podržan do strane uređaja, kako rukovati sa touch događajima iz različitih regiona ekrana u našem canvas-u, i kako će Python postupiti u slučaju gde se deklarisani preklapajući rukovatelji događajima (event handlers) touch ekrana.
Python aplikacije koje koriste samo osnovne elemente korisničkog interfejsa (npr. obaveštenja i sl.) ne bi trebale zahtevati nikakve promene kako bi radile na touch-enabled uređajima. To je zato što se događaji generisani kada korisni dodirne UI element mapiraju za iste događaje koje aplikacija primi od fizičkog tastera pritisnutog na non-touch uređaju.
Python on Symbian v2.0 obezbeđuje eksplicitnu podršku za događaje sa touch pokazivačem (pointer) u appuifw modulu Canvas objekta. Aplikacije koje koriste canvas za crtanje mogu lako biti napravljene da rade osetljivo i na touch i non-touch uređajima koristeći on-scree virtual directional keypad za simulaciju akcije fizičke tastature.
Sledeći primer pokazuje kako virtualna tastatura može biti omogućena samo za touch uređaje.
import appuifw |
Navedeni kod koristi touch_enabled() funkciju da odredi da li je uređaj touch omogućen i vraća True ukoliko je touch UI omogućen i False u suprotnom.
Python može detektovati četiri različita touch događaja, koji se referencirani koristeći sledeće key codes (iz key_codes.py):
Kako bi detektovao touch događaje, Canvas veže (binds) event handler za zahtevane key codes, koji se pozivaju kada se određeni događaj desi. Pristup je vrlo sličan kao i ona koji se koristi da se vežu pritisci tastera na Canvas.
Sledeći isečak koda pokazuje aplikaciju koja će prikazati obaveštenje svaki put kada se ekran dodirne. Canvas se veže za EButton1Down događaj, ali možemo se vezati i za druge touch događaje, tako što ćemo zameniti EButton1Down sa EButton1Up , EDrag ili ESwitchOn.
import appuifw |
U navedenom isečku koda, Ebutton1Down događaj je vezan za down_event() funkciju. Callback funkcija se može zameniti pozivanje bind() funkcije opet sa drugim handler-om, ili može biti 'očišćena' zadavanjem None kao što je prikazano.
canvas.bind(key_codes.EButton1Down, None) |
U prethodnom poglavlju, pokazali smo kako touch događaji mogu biti detektovani na punom ekranu (canvas-u). Detektovanje događaja na određenom području ekrana se postiže prosleđivanjem gornje leve i donje desne koordinate traženog prostora kao dodatnih parametara bind() pozivu.
PyS60 ne pruža posvećene UI kontrole za tastere, ali oni se mogu obezbediti kao oblici nacrtani na canvas-u, i mogu biti zakrivljeni ili čak kružni. bind() pristup nam omogućuje da odredimo samo pravougaone oblasti.
Kako bismo detektovali touch down događaj u pravougaoniku sa koordinatama levog gornjeg ugla (x1, y1) i koordinatama donjeg desnog ugla (x2, y2), koristimo:
canvas.bind(key_codes.EButton1Down, down_event, ((x1,y1),(x2,y2))) |
Sledeći isečak koda pokazuje kako detektujemo svaki od touch događaja u drugoj oblasti canvas-a/ekrana:
'''Detecting touch over a specific area of screen''' |
Kada se pokrene, ova aplikacija izgleda kao na sledećoj slici (Slika 30). Svaka oblast ekrana reaguje na njen određeni tip događaja prikazujući informacionu belešku.
*Napomena: Ako događaj vučenja ode van ograničene oblasti, neće biti primljen događaj vučenja.
Slika 30 – Detekcija događaja na četiri različita područja canvas-a/ekrana
Oblasti ekrana koje se vezuju za bilo koji pojedinačni event keycode se mogu preklapati. Unutar preklapajuće oblasti, samo callback funkcija koja je registrovana zadnja će biti pozvana kao odgovor na događaj. Međutim, oblasti koje se vezuju za različite event keycode se mogu preklapati bez problema, i obe callback funkcije se pozovu ako se oba događaja dogode u preklapajućoj oblasti.
Pogledajmo sledeći primer(Slika 31 ):
Slika 31 – Preklapajuće oblasti
Za Overlapping (preklapanje) 1:
Za Overlapping (preklapanje) 2:
Ovo je dalje ilustrovano sa primerom touch klavira (Slika 32 ):
Slika 32 – Touch klavir
Crne dirke preklapaju bele dirke. Da bismo osigurali da će dodir preklapajuće oblasti (crne dirke) okinuti callback funkciju registrovanu na crne dirke, vežemo (bind) njihove event handlers poslednje.
import appuifw |
Funkcija bind() nam dopušta da primimo dodirne događaje (touch events) u pravougaonoj oblasti. Ali šta da radimo kada želimo da koristimo druge oblike, na primer, dugmad koja imaju zaobljene ivice, ili neki drugi proizvoljni oblik?
Postoje tri osnovna pristupa koja možemo koristiti:
Sledeći isečak koda demonstrira treći pristup, koristeći primer cirkularne (okrugle) oblasti u kojoj želimo detektovati dodirni događaj (touch event).
import appuifw |
Funkcija blue_down(pos) je pozvana ako je događaj dodira (touch event) pozvan bilo gde unutar okružujućeg pravougaonika našeg kruga, i koristi poziciju dodira i prečnik kruga da odredi da li se dodir dogodio unutar kruga. Ukoliko jeste, ispisuje obaveštenje. Naredna slika prikazuje kod u akciji (Slika 33):
Slika 33 – Kružne oblasti dodira
Koristeći ono što smo naučili u prethodnom i u ranijim poglavljima, napravimo jednostavnu aplikaciju sličnu 'Paint'-u na Windows-u.
Prvo pripremamo prazno platno (canvas). Onda crtamo tačku gde detektujemo bilo koji događaj dodira na platnu. S obzirom da moramo da detektujemo više od jednog tipa događaja na istoj oblasti (čitavom platnu) – koristimo default event_callback() funkciju na platnu umesto pozivanja bind() za vezivanje pojedinačnog događaja.
canvas = appuifw.Canvas(event_callback=handle_event, redraw_callback=handle_redraw) |
Kada god je platno dodirnuto, handle_event() je pozvan, i prima informacije o događaju prosleđene kao argument. Informacije o događaju (event informations) su dictionary koji sadrži detalje vezane za događaj pokazivača (pointer event). Ima sledeći format (koji ostaje nepromenjen za non-touch uređaje):
U handle_event() funkciji detektujemo događaj dodira i crtamo tačku:
def handle_event(event): |
Ova prva implementacija Paint aplikacije nije radila baš kao što bi se očekivalo. S obzirom da nismo dobili događaj za svaku tačku, nismo iscrtali kontinualnu liniju, kao što se vidi na sledećoj slici (Slika 34 ):
Slika 34 – Touchy Paint
Kako bismo popravili ovo, modifikujemo handle_event() funkciju, kao što se vidi u narednom kodu. Ovo jednostavno obezbeđuje da za Edrag događaj mi crtamo liniju od prethodno dodirnute koordinate do primljene vučene koordinate. Takođe crtamo dve tačke kada detektujemo dodir da poboljšamo rezoluciju crtanja na ekranu.
def handle_event(event): |
Kompletni kod Paint aplikacije izgleda ovako, sa screenshot-om u narednoj slici (Slika 35 ):
import appuifw |
Slika 35 – Touchy Paint 2.
Završavamo ovo poglavlje sa brzom i jednostavnom igrom IKS-OKS (pravila se mogu pogledati na http://en.wikipedia.org/wiki/Tic-tac-toe). Nakon koda, vidimo i sliku našeg primera u akciji(Slika 36).
import appuifw
|
Slika 36 – Toucy X-O
Prođimo kroz kod po delovima. Nakon import-ovanja potrebnih modula, konstante boja i flag-ovi korišteni u igri se inicijalizuju.
# definiši konstante boja RGB_RED = (255, 0, 0) RGB_GREEN = (0, 255, 0) RGB_BLUE = (0, 0, 255) RGB_BLACK=(0,0,0) # definiši boju table board_colour=RGB_BLUE # definiši flag promenljive turn_flag="Cross" flag_rect1=None flag_rect2=None flag_rect3=None flag_rect4=None flag_rect5=None flag_rect6=None flag_rect7=None flag_rect8=None flag_rect9=None |
U ovom primeru, moramo crtati dva oblika: krug i krstić. Krug je poprilično jednostavan i može se iscrtati pomoću jedne linije koda. Crtanje krstića (X) je malo kompleksnije, pa definišemo funkciju da ovo uradi kad god je potrebno – draw_cross(pos, cross_colour).
def draw_cross(pos, cross_colour): '''Function to draw a cross - on the co-ordinates passed as arguments''' cross_length=30 cross_width=15 a=pos[0]-cross_length b=pos[1]-cross_length while a<=pos[0]+cross_length: canvas.point((a,b), width=cross_width, outline=cross_colour) a+=1 b+=1 a=pos[0]+cross_length b=pos[1]-cross_length while a>=pos[0]-cross_length and b<=pos[1]+cross_length: canvas.point((a,b), width=cross_width, outline=cross_colour) a-=1 b+=1 |
down(pos) je callback funkcija koju vežemo za down touch događaj. Ovde proveramo da li je poslednji oblik koji je iscrtan bio krug ili krst i prikladno tome crtamo onaj drugi (s obzirom da igrači naizmenice biraju polje). Krug se iscrtava prvi put kada se kod izvrši.
def down(pos): |
Nakon iscrtavanja svakog oblika (krstića ili nule tj. Cross ili Zero), pozivamo funkciju. Ovo proverava da li postoje tri ispravno poravnate nule ili krstića, i ukoliko ima, proglašava pobednika koristeći note.
def check_winner(): '''Function to check the winner after each turn''' global flag_rect1,flag_rect2,flag_rect3,flag_rect4,flag_rect5,flag_rect6,flag_rect7, flag_rect8,flag_rect9 if flag_rect1=="Cross" and flag_rect2=="Cross" and flag_rect3=="Cross": appuifw.note(u"Cross wins!") elif flag_rect1=="Zero" and flag_rect2=="Zero" and flag_rect3=="Zero": appuifw.note(u"Zero wins!") elif flag_rect1=="Cross" and flag_rect4=="Cross" and flag_rect7=="Cross": appuifw.note(u"Cross wins!") elif flag_rect1=="Zero" and flag_rect4=="Zero" and flag_rect7=="Zero": appuifw.note(u"Zero wins!") elif flag_rect1=="Cross" and flag_rect5=="Cross" and flag_rect9=="Cross": appuifw.note(u"Cross wins!") elif flag_rect1=="Zero" and flag_rect5=="Zero" and flag_rect9=="Zero": appuifw.note(u"Zero wins!") elif flag_rect2=="Cross" and flag_rect5=="Cross" and flag_rect8=="Cross": appuifw.note(u"Cross wins!") elif flag_rect2=="Zero" and flag_rect5=="Zero" and flag_rect8=="Zero": appuifw.note(u"Zero wins!") elif flag_rect3=="Cross" and flag_rect6=="Cross" and flag_rect9=="Cross": appuifw.note(u"Cross wins!") elif flag_rect3=="Zero" and flag_rect6=="Zero" and flag_rect9=="Zero": appuifw.note(u"Zero wins!") elif flag_rect3=="Cross" and flag_rect5=="Cross" and flag_rect7=="Cross": appuifw.note(u"Cross wins!") elif flag_rect3=="Zero" and flag_rect5=="Zero" and flag_rect7=="Zero": appuifw.note(u"Zero wins!") elif flag_rect1=="Cross" and flag_rect2=="Cross" and flag_rect3=="Cross": appuifw.note(u"Cross wins!") elif flag_rect1=="Zero" and flag_rect2=="Zero" and flag_rect3=="Zero": appuifw.note(u"Zero wins!") elif flag_rect4=="Cross" and flag_rect5=="Cross" and flag_rect6=="Cross": appuifw.note(u"Cross wins!") elif flag_rect4=="Zero" and flag_rect5=="Zero" and flag_rect6=="Zero": appuifw.note(u"Zero wins!") elif flag_rect7=="Cross" and flag_rect8=="Cross" and flag_rect9=="Cross": appuifw.note(u"Cross wins!") elif flag_rect7=="Zero" and flag_rect8=="Zero" and flag_rect9=="Zero": appuifw.note(u"Zero wins!") |