9. KORISNIČKI INTERFEJS NA DODIR

 

Primeri koda:

 

File:PythonOnSymbianBookExampleCode TouchOnFullscreen.zip

File:PythonOnSymbianBookExampleCode TouchWithinRectangle.zip

File:PythonOnSymbianBookExampleCode TouchArbitaryRegions.zip

File:PythonOnSymbianBookExampleCode TouchyPaint.zip

File:PythonOnSymbianBookExampleCode TicTacToe.zip

 

 

9.1. Uvod

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.

 

9.2. Podrška za touch i non-touch uređaje

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
...
if appuifw.touch_enabled():
   appuifw.app.directional_pad=True;
else:
   appuifw.app.directional_pad=False;
...

 

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.

 

 

9.3. Detekcija touch događaja u full-screen modu

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
import graphics
import e32
import key_codes #import key_codes – neophodno za detekciju touch događaja
 
# definiši konstantu bele boje
RGB_WHITE =(255, 255, 255)
 
# promeni veličinu aplikacije na 'full'
appuifw.app.screen = 'full'
 
def quit():
   '''Define quit function'''
   app_lock.signal()
 
def down_event(event):
   '''Pen DOWN event handler'''
   appuifw.note(u"Down Event")
 
#pripremi ’canvas’ za crtanje
canvas = appuifw.Canvas()   
appuifw.app.body = canvas
 
#definiši right soft key kao ’exit’ taster
appuifw.app.exit_key_handler = quit
 
#očisti ’canvas’ sa belom bojom
canvas.clear(RGB_WHITE)
 
'''bind canvas for touch event'''
canvas.bind(key_codes.EButton1Down, down_event) 
#EButton1Up, EDrag i ESwitchOn bi se mogli koristiti slično
 
#Čekaj da korisnik izađe
app_lock = e32.Ao_lock()
app_lock.wait()

 

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)

 

 

9.4. Detektovanje dodira na određenom području

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.

 

 

9.4.1. Detektovanje dodira na određenom pravougaonom području

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'''
 
import appuifw
import graphics
import e32
import key_codes #import key_codes – neophodno za deteckiju touch događaja
 
# definiši konstante boja
RGB_RED = (255, 0, 0)
RGB_GREEN = (0, 255, 0)
RGB_BLUE = (0, 0, 255)
RGB_PURPLE = (100,0,255)
RGB_BLACK = (0,0,0)
 
#onemogući direkcioni pad
appuifw.app.directional_pad = False
 
#pripremi ’canvas’ za crtanje
canvas = appuifw.Canvas()   
appuifw.app.body = canvas
 
#pribavi veličinu ’canvas’-a (Total_x i Total_y)
Total_x, Total_y = canvas.size
y1 = Total_y/4
 
def blue_down(event):
    ''' Blue DOWN event handler '''
    appuifw.note(u"Blue Down")
 
def green_up(event):
    ''' Green UP event handler '''
    appuifw.note(u"Green Up")
 
def red_drag(event):
    ''' Red DRAG event handler '''
    appuifw.note(u"Red Drag")
 
def purple_tap(event):
    ''' Purple TAP event handler '''
    appuifw.note(u"Purple Tap")
 
# Plavi pravougaonik - DOWN Event
'''Draw Blue rectangle and text'''
canvas.rectangle(((0,0), (Total_x,y1)), fill=RGB_BLUE, width=5)
canvas.text((Total_x/2,y1/2), u"DOWN", fill = RGB_BLACK,font=(u'Nokia Hindi S60',40,appuifw.STYLE_BOLD))
'''Bind DOWN to Blue rectangle'''
canvas.bind(key_codes.EButton1Down, blue_down, ((0,0), (Total_x,y1)))
 
# Zelepi pravougaonik - UP Event
'''Draw Green rectangle and text'''
canvas.rectangle(((0,y1), (Total_x,2*y1)), fill=RGB_GREEN, width=5)
canvas.text((Total_x/2,3*y1/2), u"UP", fill = RGB_BLACK,font=(u'Nokia Hindi S60',40,appuifw.STYLE_BOLD)) 
'''Bind UP to Blue rectangle'''
canvas.bind(key_codes.EButton1Up, green_up, ((0,y1), (Total_x,2*y1)))
 
# Crveni pravougaonik - DRAG Event
'''Draw Red rectangle and text'''
canvas.rectangle(((0,2*y1), (Total_x,3*y1)), fill=RGB_RED, width=5)
canvas.text((Total_x/2,5*y1/2), u"DRAG", fill = RGB_BLACK,font=(u'Nokia Hindi S60',40,appuifw.STYLE_BOLD)) 
'''Bind DRAG to Red rectangle'''
canvas.bind(key_codes.EDrag, red_drag, ((0,2*y1), (Total_x,3*y1)))
 
# Ljubičasti pravougaonik - TAP Event
'''Draw Purple rectangle and text'''
canvas.rectangle(((0,3*y1), (Total_x,4*y1)), fill=RGB_PURPLE, width=5)
canvas.text((Total_x/2,7*y1/2), u"TAP", fill = RGB_BLACK,font=(u'Nokia Hindi S60',40,appuifw.STYLE_BOLD)) 
'''Bind TAP to Red rectangle'''
canvas.bind(key_codes.ESwitchOn, purple_tap, ((0,3*y1), (Total_x,4*y1)))
 
#čekaj da korisnik izađe
app_lock = e32.Ao_lock()
app_lock.wait()

 

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

 

                                    337px-PythonOnSymbian_Eventdetection_specific.png

 

 

9.4.2. Primer klavira (preklapajući događaji)

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

 

800px-PythonOnSymbian_TouchUI_Overlapping.jpg

 

Za Overlapping (preklapanje) 1:

 

Za Overlapping (preklapanje) 2:

 

Ovo je dalje ilustrovano sa primerom touch klavira (Slika 32 ):

 

 

Slika 32 – Touch klavir

 

                                   337px-PythonOnSymbian_Touch_piano.png

 

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
import graphics
import e32
import key_codes #import key_codes – neophodno za detekciju touch događaja
import audio
 
# definiši konstantu bele boje
RGB_WHITE =(255, 255, 255)
RGB_BLACK =(0, 0, 0)
 
# definiši zvučne fajlove
white1_sound= u"C:\\Data\\Sounds\\Digital\\white1.mp3"
white2_sound= u"C:\\Data\\Sounds\\Digital\\white2.mp3"
white3_sound= u"C:\\Data\\Sounds\\Digital\\white3.mp3"
white4_sound= u"C:\\Data\\Sounds\\Digital\\white4.mp3"
white5_sound= u"C:\\Data\\Sounds\\Digital\\white5.mp3"
white6_sound= u"C:\\Data\\Sounds\\Digital\\white6.mp3"
black1_sound= u"C:\\Data\\Sounds\\Digital\\black1.mp3"
black2_sound= u"C:\\Data\\Sounds\\Digital\\black2.mp3"
black3_sound= u"C:\\Data\\Sounds\\Digital\\black3.mp3"
black4_sound= u"C:\\Data\\Sounds\\Digital\\black4.mp3"
 
# promeni ’screen size’ aplikacije na 'full'
appuifw.app.screen = 'full'
 
# onemogući directional pad
appuifw.app.directional_pad = False
 
def quit():
   '''Define quit function'''
   app_lock.signal()
appuifw.app.exit_key_handler = quit
 
def white1(event):
   '''White1 callback function'''
   #Putanja fajla koji će se reprodukovati kada se dodirne ’white1’
   s1 = audio.Sound.open(white2_sound)
   try: # Try to stop() – moguće je da se fajl već reprodukuje
        s1.stop()
        s1.play()
   except:
        s1.play()
 
def white2(event):
   '''White2 callback function'''
   # Putanja fajla koji će se reprodukovati kada se dodirne ’white2’
   s2 = audio.Sound.open(white2_sound)
   try: # Try to stop()– moguće je da se fajl već reprodukuje
        s2.stop()
        s2.play()
   except:
        s2.play()
 
def white3(event):
   '''White3 callback function'''
   #Putanja fajla koji će se reprodukovati kada se dodirne ’white3’
   s3 = audio.Sound.open(white3_sound)
   try: # Try to stop()– moguće je da se fajl već reprodukuje
        s3.stop()
        s3.play()
   except:
        s3.play()
 
def white4(event):
   '''White4 callback function'''
   #Putanja fajla koji će se reprodukovati kada se dodirne ’white4’
   s4 = audio.Sound.open(white4_sound)
   try: # Try to stop()– moguće je da se fajl već reprodukuje
        s4.stop()
        s4.play()
   except:
        s4.play()
 
def white5(event):
   '''White5 callback function'''
   #Putanja fajla koji će se reprodukovati kada se dodirne ’white5’
   s5 = audio.Sound.open(white5_sound)
   try: # Try to stop()– moguće je da se fajl već reprodukuje
        s5.stop()
        s5.play()
   except:
        s5.play()
 
def white6(event):
   '''White6 callback function'''
   #Putanja fajla koji će se reprodukovati kada se dodirne ’white6’
   s6 = audio.Sound.open(white6_sound)
   try: # Try to stop()– moguće je da se fajl već reprodukuje
        s6.stop()
        s6.play()
   except:
        s6.play()
 
def black1(event):
   '''Black1 callback function'''
   #Putanja fajla koji će se reprodukovati kada se dodirne ’black1’
   s7 = audio.Sound.open(black1_sound)
   try: # Try to stop()– moguće je da se fajl već reprodukuje
        s7.stop()
        s7.play()
   except:
        s7.play()
 
def black2(event):
   '''Black2 callback function'''
   #Putanja fajla koji će se reprodukovati kada se dodirne ’black2’
   s8 = audio.Sound.open(black2_sound)
   try: # Try to stop()– moguće je da se fajl već reprodukuje
        s8.stop()
        s8.play()
   except:
        s8.play()
 
def black3(event):
   '''Black3 callback function'''
   #Putanja fajla koji će se reprodukovati kada se dodirne ’black3’
   s9 = audio.Sound.open(black3_sound)
   try: # Try to stop()– moguće je da se fajl već reprodukuje
        s9.stop()
        s9.play()
   except:
        s9.play()
 
def black4(event):
   '''Black4 callback function'''
   #The path of the file that is to be played when white1 is touched
   s10 = audio.Sound.open(black4_sound)
   try: # Try to stop()– moguće je da se fajl već reprodukuje
        s10.stop()
        s10.play()
   except:
        s10.play()
 
#pripremi ’canvas’ za crtanje
canvas = appuifw.Canvas()   
appuifw.app.body = canvas
 
#definiši right soft key kao ’exit’ taster
appuifw.app.exit_key_handler = quit
 
Total_x, Total_y = canvas.size
y1 = Total_y/6
 
#očisti ’canvas’ belom bojom
canvas.clear(RGB_WHITE)
 
#White Key #1 – Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,0), (Total_x,y1)), outline=RGB_BLACK, fill=RGB_WHITE, width=3)
canvas.bind(key_codes.EButton1Down, white1, ((0,0), (Total_x,y1)))
 
#White Key #2 - Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,y1), (Total_x,2*y1)),outline=RGB_BLACK, fill=RGB_WHITE, width=3)
canvas.bind(key_codes.EButton1Down, white2, ((0,y1), (Total_x,2*y1)))
 
#White Key #3 - Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,2*y1), (Total_x,3*y1)), outline=RGB_BLACK, fill=RGB_WHITE, width=3)
canvas.bind(key_codes.EButton1Down, white3, ((0,y1), (Total_x,2*y1)))
 
#White Key #4 - Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,3*y1), (Total_x,4*y1)), outline=RGB_BLACK,fill=RGB_WHITE, width=3)
canvas.bind(key_codes.EButton1Down, white4, ((0,3*y1), (Total_x,4*y1)))
 
#White Key #5 - Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,4*y1), (Total_x,5*y1)), outline=RGB_BLACK,fill=RGB_WHITE, width=3)
canvas.bind(key_codes.EButton1Down, white5, ((0,4*y1), (Total_x,5*y1)))
 
#White Key #6 - Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,5*y1), (Total_x,6*y1)), outline=RGB_BLACK,fill=RGB_WHITE, width=3)
canvas.bind(key_codes.EButton1Down, white6, ((0,5*y1), (Total_x,6*y1)))
 
#Black Key #1 - Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,y1-30), (Total_x/2,y1+30)), fill=RGB_BLACK, width=3)
canvas.bind(key_codes.EButton1Down, black1, ((0,y1-30), (Total_x/2,y1+30)))
 
#Black Key #2 - Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,2*y1-30), (Total_x/2,2*y1+30)), fill=RGB_BLACK, width=3)
canvas.bind(key_codes.EButton1Down, black2, ((0,2*y1-30), (Total_x/2,2*y1+30)))
 
#Black Key #3 - Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,4*y1-30), (Total_x/2,4*y1+30)), fill=RGB_BLACK, width=3)
canvas.bind(key_codes.EButton1Down, black3, ((0,4*y1-30), (Total_x/2,4*y1+30)))
 
#Black Key #4 - Iscrtaj i veži (bind) touch Pen down event
canvas.rectangle(((0,5*y1-30), (Total_x/2,5*y1+30)), fill=RGB_BLACK, width=3)
canvas.bind(key_codes.EButton1Down, black4, ((0,5*y1-30), (Total_x/2,5*y1+30)))
 
#Čekaj da korisnik izađe
app_lock = e32.Ao_lock()
app_lock.wait()

 

 

9.4.3. Detektovanje touch događaja u proizvoljnim oblastima

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
import graphics
import e32
import key_codes #import key_codes – neophodno za detekciju touch događaja
import math
 
#definiši konstantu boje
RGB_BLUE = (0, 0, 255)
 
# onemogući directional pad
appuifw.app.directional_pad = False
 
#pripremi ’canvas’ za crtanje
canvas = appuifw.Canvas()
appuifw.app.body = canvas
 
#Pribavljanje veličine ’canvas’-a (Total_x i Total_y)
Total_x, Total_y = canvas.size
 
# definiši koordinate centra kružnice i poluprečnik
circle_x=Total_x/2
circle_y=Total_y/2
radius=100
 
def calculate(centre, radius):
   '''Function to calculate co-ordinates of the circle'''
   return ((centre[0]-radius, centre[1]-radius), (centre[0]+radius, centre[1]+radius))
 
def blue_down(pos):
    ''' Blue DOWN event handler '''
    global circle_x,circle_y, radius
      # Upotrebi 'distance formula' da proveriš da li je dodirnuta oblast unutar naše kružnice
    distance=math.hypot(pos[0]-circle_x, pos[1]-circle_y)
    if distance<=radius:
        appuifw.note(u"Circle touched")
 
# Plavi pravougaonik - DOWN Event
'''Draw Blue rectangle and text'''
canvas.ellipse((calculate((circle_x, circle_y), radius)), fill=RGB_BLUE)
canvas.bind(key_codes.EButton1Down, blue_down)
 
#Čekaj da korisnik izađe
app_lock = e32.Ao_lock()
app_lock.wait()

 

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

 

      337px-PythonOnSymbian_TouchUI_CircleButtons1.png                 337px-PythonOnSymbian_TouchUI_Circlebuttons2.png

 

 

 

8.5. Bojenje dodirom

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)
appuifw.app.body = canvas
appuifw.app.exit_key_handler = quit

 

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):
   if event['type'] not in (key_codes.EButton1Up, key_codes.EButton1Down,key_codes.EDrag):
        return
   canvas.point((event['pos'][0], event['pos'][1]),outline=RGB_RED,width=10)

 

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

 

                                     335px-PythonOnSymbian_Screenshot0004.jpg

 

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):
   if event['type'] not in (key_codes.EButton1Up, key_codes.EButton1Down,key_codes.EDrag):
        return
   if event['type'] in (key_codes.EButton1Down, key_codes.EButton1Up):
        canvas.point((event['pos'][0], event['pos'][1]),outline=RGB_RED,width=10)
        canvas.point((event['pos'][0], event['pos'][1]),outline=RGB_RED,width=10)
        prev_pos[0]=event['pos'][0]
        prev_pos[1]=event['pos'][1]
 
        #appuifw.note(u"Green Down")
   elif event['type'] ==key_codes.EDrag:
        rect=(prev_pos[0], prev_pos[1],event['pos'][0], event['pos'][1])
        canvas.line(rect, outline=RGB_RED, width=10,fill=RGB_RED)
        prev_pos[0]=event['pos'][0]
        prev_pos[1]=event['pos'][1]

 

Kompletni kod Paint aplikacije izgleda ovako, sa screenshot-om u narednoj slici (Slika 35 ):

 

import appuifw
import graphics
import e32
import key_codes

appuifw.app.directional_pad=False;
 
RGB_RED = (255, 0, 0)
RGB_GREEN = (0, 255, 0)
RGB_BLUE = (0, 0, 255)
RGB_WHITE =(255, 255, 255)
 
canvas=None
global prev_pos
prev_pos=[0,0]
 
appuifw.app.screen = 'large'
 
def handle_redraw(event):
'''Define redraw function'''
   pass
 
def handle_event(event):
'''Define event callback function'''
   if event['type'] not in (key_codes.EButton1Up, key_codes.EButton1Down,key_codes.EDrag):
        return
   if event['type'] in (key_codes.EButton1Down, key_codes.EButton1Up):
        canvas.point((event['pos'][0], event['pos'][1]),outline=RGB_RED,width=10)
        canvas.point((event['pos'][0], event['pos'][1]),outline=RGB_RED,width=10)
        prev_pos[0]=event['pos'][0]
        prev_pos[1]=event['pos'][1]
   if event['type'] ==key_codes.EDrag:
        rect=(prev_pos[0], prev_pos[1],event['pos'][0], event['pos'][1])
        canvas.line(rect, outline=RGB_RED, width=10,fill=RGB_RED)
        prev_pos[0]=event['pos'][0]
        prev_pos[1]=event['pos'][1]
 
canvas = appuifw.Canvas(event_callback=handle_event, redraw_callback=handle_redraw)   
appuifw.app.body = canvas
appuifw.app.exit_key_handler = quit
 
canvas.clear(RGB_WHITE)
 
app_lock = e32.Ao_lock()
app_lock.wait()

 

 

Slika 35 – Touchy Paint 2.

 

                                     337px-PythonOnSymbian_TouchUI_paint.png

 

 

 

9.6. Touchy X-O (iks-oks)

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
import graphics
import e32
import key_codes #import key_codes - required for touch event detection
 
# definiši konstante boja
RGB_RED = (255, 0, 0)
RGB_GREEN = (0, 255, 0)
RGB_BLUE = (0, 0, 255)
RGB_BLACK=(0,0,0)
 
# ddefiniš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
 
def handle_redraw(event):
   pass
 
# onemogući directional pad
appuifw.app.directional_pad = False
 
canvas = appuifw.Canvas(redraw_callback=handle_redraw)
appuifw.app.body = canvas
 
Total_x, Total_y = canvas.size
 
RectWidth=Total_x/3
RectHeight=Total_y/3
print RectWidth,RectHeight
 
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
 
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!")
 
def down(pos):
    ''' Event handler '''
    global turn_flag,flag_rect1,flag_rect2,flag_rect3,flag_rect4,flag_rect5,flag_rect6,flag_rect7,flag_rect8,flag_rect9
    if 0<pos[0]<RectWidth and 0<pos[1]<RectHeight:
 
        if flag_rect1 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect1="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect1="Zero"
                      turn_flag="Cross"
               check_winner()
    elif RectWidth<pos[0]<2*RectWidth and 0<pos[1]<RectHeight:
 
        if flag_rect2 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect2="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect2="Zero"
                      turn_flag="Cross"
               check_winner()
    elif 2*RectWidth<pos[0]<3*RectWidth and 0<pos[1]<RectHeight:
 
        if flag_rect3 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect3="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect3="Zero"
                      turn_flag="Cross"
               check_winner()
    elif 0<pos[0]<RectWidth and RectHeight<pos[1]<2*RectHeight:
 
        if flag_rect4 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect4="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect4="Zero"
                      turn_flag="Cross"
               check_winner()
               print turn_flag, flag_rect4
    elif RectWidth<pos[0]<(2*RectWidth) and RectHeight<pos[1]<2*RectHeight:
 
        if flag_rect5 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect5="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect5="Zero"
                      turn_flag="Cross"
               check_winner()
    elif 2*RectWidth<pos[0]<3*RectWidth and RectWidth<pos[1]<2*RectHeight:
 
        if flag_rect6 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect6="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect6="Zero"
                      turn_flag="Cross"
               check_winner()
    elif 0<pos[0]<RectWidth and 2*RectHeight<pos[1]<3*RectHeight:
 
        if flag_rect7 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect7="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect7="Zero"
                      turn_flag="Cross"
               check_winner()
 
    elif RectWidth<pos[0]<2*RectWidth and 2*RectHeight<pos[1]<3*RectHeight:
 
        if flag_rect8 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect8="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect8="Zero"
                      turn_flag="Cross"
               check_winner()
 
    elif 2*RectWidth<pos[0]<3*RectWidth and 2*RectHeight<pos[1]<3*RectHeight:
 
        if flag_rect9 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect9="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect9="Zero"
                      turn_flag="Cross"
               check_winner()
 
# Crtaj pravougaonike #1 #2 i #3


canvas.bind(key_codes.EButton1Down, down, ((0,0), (RectWidth,RectHeight)))
canvas.bind(key_codes.EButton1Down, down, ((RectWidth,0), (2*RectWidth,RectHeight)))
canvas.bind(key_codes.EButton1Down, down, ((2*RectWidth,0), (3*RectWidth,RectHeight)))
canvas.rectangle(((0,0), (RectWidth,RectHeight)), fill=board_colour, width=5, outline=RGB_BLACK)
canvas.rectangle(((RectWidth,0), (2*RectWidth,RectHeight)), fill=board_colour, width=5, outline=RGB_BLACK)
canvas.rectangle(((2*RectWidth,0), (3*RectWidth,RectHeight)), fill=board_colour, width=5,outline=RGB_BLACK)
 
# Crtaj pravougaonike #4 #5 i #6


canvas.bind(key_codes.EButton1Down, down, ((0,RectHeight), (RectWidth,2*RectHeight)))
canvas.bind(key_codes.EButton1Down, down, ((RectWidth,RectHeight), (2*RectWidth,2*RectHeight)))
canvas.bind(key_codes.EButton1Down, down, ((2*RectWidth,RectHeight), (3*RectWidth,2*RectHeight)))
canvas.rectangle(((0,RectHeight), (RectWidth,2*RectHeight)), fill=board_colour, width=5,outline=RGB_BLACK)
canvas.rectangle(((RectWidth,RectHeight), (2*RectWidth,2*RectHeight)), fill=board_colour, width=5,outline=RGB_BLACK)
canvas.rectangle(((2*RectWidth,RectHeight), (3*RectWidth,2*RectHeight)), fill=board_colour, width=5,outline=RGB_BLACK)
 
# Crtaj pravougaonike #7 #8 i #9


canvas.bind(key_codes.EButton1Down, down, ((0,2*RectHeight), (RectWidth,3*RectHeight)))
canvas.bind(key_codes.EButton1Down, down, ((RectWidth,2*RectHeight), (2*RectWidth,3*RectHeight)))
canvas.bind(key_codes.EButton1Down, down, ((2*RectWidth,2*RectHeight), (3*RectWidth,3*RectHeight)))
canvas.rectangle(((0,2*RectHeight), (RectWidth,3*RectHeight)), fill=board_colour, width=5,outline=RGB_BLACK)
canvas.rectangle(((RectWidth,2*RectHeight), (2*RectWidth,3*RectHeight)), fill=board_colour, width=5,outline=RGB_BLACK)
canvas.rectangle(((2*RectWidth,2*RectHeight), (3*RectWidth,3*RectHeight)), fill=board_colour, width=5,outline=RGB_BLACK)
 
app_lock = e32.Ao_lock()
app_lock.wait()

 

 

Slika 36 – Toucy X-O

 

 

337px-PythonOnSymbian_TouchUI_TicTactoe1.jpg                           337px-PythonOnSymbian_TouchUI_TicTactoe2.jpg

 

 

337px-PythonOnSymbian_TouchUI_TicTactoe3.jpg                            337px-PythonOnSymbian_TouchUI_TicTactoe4.jpg

 

 

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):
    ''' Event handler '''
    global turn_flag, flag_rect1,flag_rect2,flag_rect3,flag_rect4,flag_rect5,flag_rect6,flag_rect7,flag_rect8,flag_rect9
    if 0<pos[0]<RectWidth and 0<pos[1]<RectHeight:
 
        if flag_rect1 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect1="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect1="Zero"
                      turn_flag="Cross"
               check_winner()
    elif RectWidth<pos[0]<2*RectWidth and 0<pos[1]<RectHeight:
 
        if flag_rect2 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect2="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect2="Zero"
                      turn_flag="Cross"
               check_winner()
    elif 2*RectWidth<pos[0]<3*RectWidth and 0<pos[1]<RectHeight:
 
        if flag_rect3 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect3="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect3="Zero"
                      turn_flag="Cross"
               check_winner()
    elif 0<pos[0]<RectWidth and RectHeight<pos[1]<2*RectHeight:
 
        if flag_rect4 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect4="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect4="Zero"
                      turn_flag="Cross"
               check_winner()
               print turn_flag, flag_rect4
    elif RectWidth<pos[0]<(2*RectWidth) and RectHeight<pos[1]<2*RectHeight:
 
        if flag_rect5 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect5="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect5="Zero"
                      turn_flag="Cross"
               check_winner()
    elif 2*RectWidth<pos[0]<3*RectWidth and RectWidth<pos[1]<2*RectHeight:
 
        if flag_rect6 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect6="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect6="Zero"
                      turn_flag="Cross"
               check_winner()
    elif 0<pos[0]<RectWidth and 2*RectHeight<pos[1]<3*RectHeight:
 
        if flag_rect7 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect7="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect7="Zero"
                      turn_flag="Cross"
               check_winner()
 
    elif RectWidth<pos[0]<2*RectWidth and 2*RectHeight<pos[1]<3*RectHeight:
 
        if flag_rect8 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect8="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect8="Zero"
                      turn_flag="Cross"
               check_winner()
 
    elif 2*RectWidth<pos[0]<3*RectWidth and 2*RectHeight<pos[1]<3*RectHeight:
 
        if flag_rect9 not in ("Cross", "Zero"):
               if turn_flag=="Cross":
                      draw_cross(pos, RGB_GREEN)
                      flag_rect9="Cross"
                      turn_flag="Zero"
               else:
                      canvas.point(pos,0x00ff00,width=50)
                      flag_rect9="Zero"
                      turn_flag="Cross"
               check_winner()

 

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!")

 

 

 

 

PyS60