|
|
pl:prolog:prolog_lab:prolog_lab_xpce [2009/05/27 17:39] piw09 |
pl:prolog:prolog_lab:prolog_lab_xpce [2019/06/27 15:50] |
====== Prolog, graficzny interfejs użytkownika XPCE ====== | |
| |
XPCE jest zorientowanym obiektowo podsystemem wizualizacji dla środowiska SWI-Prolog. | |
Pełna dokumentacja XPCE znajduje się pod adresem: http://hcs.science.uva.nl/projects/xpce/UserGuide/ | |
| |
===== WPROWADZENIE ===== | |
| |
| |
| |
| |
==== Tworzenie obiektów ==== | |
| |
new/2 (new(?Reference, +NewTerm)) umożliwia tworzenie obiektów graficznych, pierwszy argument zwraca referencje do utworzonego obieku (unikalny identyfikator) z użyciem @/1, drugi argument jest rodzajem obiektu (klasą) do utworzenia. | |
| |
Referencje może być utworzona przez ''new'': | |
<code prolog> | |
?- new(P, point(10,20)). | |
P = @772024 | |
</code> | |
| |
Albo zadana (nazwana) tzw. //named reference//: | |
| |
<code prolog> | |
?- new(@demo, dialog('Demo Window')). | |
</code> | |
| |
free/1 (free(+Reference)) niszczy obiekty, argumentem jest identyfikator obiektu (pierwszy argument new/2). | |
| |
<code prolog> | |
?- free(@demo). | |
</code> | |
| |
**Uwaga:** Wszystkie obiekty utworzone z wykorzysaniem //named reference// (@demo w powyższym przykładzie) muszą być usunięte za pomocą free/2 w celu uniknięcia wycieków pamięci. | |
Jeżeli referenca obiektu nie jest nazwana (pierwszy argument new jest szukaną), obiekty takie są automatycznie usuwane. | |
| |
==== Modyfikacja stanu obiektów ==== | |
| |
Stan obiektu można zmodyfikować korzystając z predykatu: send/2. | |
Pierwszym argumentem jest referencja obiektu, drugim metoda do wykonania. | |
Poniższy przykład dodaje pole tekstowe do utworzonego wcześniej okna dialogowego. | |
| |
?- send(@demo, append(text_item(nazwa))). | |
| |
Aby wyświetlic tak utworzony obiekt należy użyc metody ''open'': | |
| |
?- send(@demo, open). | |
| |
send można również dekomponując term, zatem powyższy przykład można zapisać jako: | |
| |
?- send(@demo, append, text_item(nazwa)). | |
| |
zatem kolejne argumenty send licząc od 3-go będą argumentami metody append. | |
| |
XPCE definiuje kilka standardowych obiektów m.in. @display oraz @prolog. | |
@display reprezentuje ekran. | |
@prolog jest obiektem reprezentującym maszynę wnioskującą. | |
Dowolny predykat zdefiniowany w Prologu jest metodą, w nomenkleaturze XPCE. | |
Zatem za pomocą send można uruchomic np. write/1: | |
| |
?- send(@prolog, write('hello')). | |
| |
| |
| |
==== Odpytywanie obiektów ==== | |
| |
get/3 (get(+Receiver, +Selector(+Argument...), -Result)) umożliwia uzyskanie informacji o stanie obiektu. | |
Np. aby dowiedzieć się jaka jest szerokość obiektu: | |
| |
?- get(@demo,width,X) | |
| |
albo o wartości wpisanej do pola tekstowego (metoda ''member'' wyszuka wlaściwy obiekt, po nazwie, jaka była uzyta do jego utworzenia w tym przypadku ''nazwa''): | |
| |
?- get(@demo, member(nazwa), ObiektTekstowy), get(ObiektTekstowy, selection, ToCoUzytkownikWpisal). | |
| |
Biorąc pod uwagę poniższy program: | |
<code prolog> | |
:- new(@demo, dialog('Okno Testowe')), | |
new(@txt,text_item('to Jest tekst:')), | |
send(@demo,append(@txt)), | |
send(@demo,open). | |
</code> | |
| |
Zapytanie: | |
| |
?- get(@txt,selection,X). | |
| |
uzgodni z szukaną ''X'' wartość wprowadzoną przez użytkownika. | |
| |
Poniższe zapytanie uzgodni szerokość ekranu z szukaną X: | |
| |
?- get(@display,width,X). | |
| |
| |
==== Akcje ==== | |
| |
Aby zaprogramować zdarzenie związane z akcją użytkownika nalezy skorzystać z //uśpionego// send. | |
| |
Poniższy kod utworzy okno o nazwie 'dialogowe' oraz przycisk 'nacisnij'. | |
Po nacisnięciu przycisku na standardowym wyjściu pojawi się napiś 'au! nie naciskaj'. | |
| |
<code prolog> | |
?- new(@okno,dialog(dialogowe)), | |
new(@but,button(nacisnij,message(@prolog,write,'au! nie naciskaj!\n'))), | |
send(@okno,append,@but), | |
send(@okno,open). | |
</code> | |
| |
albo w krótszej wersji: | |
| |
<code prolog> | |
?- new(@okno,dialog(dialogowe)), | |
send(@okno,append(button(nacisnij,message(@prolog,write,'au! nie naciskaj!\n')))), | |
send(@okno,open). | |
</code> | |
| |
=== Selektor === | |
| |
<code prolog> | |
wypisz(X):- | |
new(Okno,dialog(wpisales)), | |
send(Okno,append(text(X))), | |
send(Okno,open). | |
| |
ui:- | |
new(Okno,dialog(dialogowe)), | |
send(Okno,append(new(Txt,text_item(pole_tekstowe)))), | |
send(Okno,append(button(nacisnij,message(@prolog,wypisz,Txt?selection)))), | |
send(Okno,open). | |
| |
:- ui. | |
</code> | |
| |
W 9 lini występuje tzw. selektor. Pozwala on na wybranie określonej własności obiektu, która ma być przekazana. | |
W tym przypadku jest to wartość ''selection'' pola tekstowego (szukana ''Txt''), czyli tekst wpisany w pole przez użytkownika. | |
| |
**Uwaga:** Wszystkie referencje do obiektów (rezultaty predykatu new/2) w powyższym przykładzie tworzone są automatycznie (nie są to //named references//), nie trzeba stosować free/2, niszczeniem obiektów zajmie się garbage collector. | |
| |
| |
| |
==== Okna modalne ==== | |
| |
Okno modalne jest to zwykle okno dialogowe, które blokuje wykonanie programu do czasu, aż użytkownik wprowadzi dane. | |
Aby skorzystać z mechanizmu blokowania należy użyć metod: ''confirm'' -- do wyświetlenia okna (zablokowania wykonania programu), oraz ''return'' do odblokowania. | |
| |
<code prolog> | |
zapytaj(Nazwa) :- | |
new(D, dialog('Podaj nazwe')), | |
send(D, append, | |
new(TI, text_item(nazwa, ''))), | |
send(D, append, | |
button(ok, message(D, return, | |
TI?selection))), % jeżeli przycisk nacisniety, odblokuj program | |
send(D, append, | |
button(porzuc, message(D, return, % jeżeli przycisk nacisniety, odblokuj program | |
@nil))), | |
send(D, default_button, ok), % Ok: domyslny przycisk | |
get(D, confirm, Odpowiedz), % wyswietlenie okna, zablokowanie wykonania programu | |
send(D, destroy), % analogiczne jak free(D) | |
Odpowiedz \== @nil, % uzytkonik nacisnal 'porzuc' | |
Nazwa = Odpowiedz. | |
</code> | |
| |
Zatem wykonując zapytanie: | |
| |
?- zapytaj(X). | |
| |
zostanie wyświetlone okno dialogowe, gdy użytkownik wprowadzi nazwę i potwierdzi naciśnięciem przycisku ''ok'' wprowadzona nazwa zostanie uzgodniona z szukaną X. | |
| |
| |
==== Obiekty graficzne ==== | |
| |
XPCE umożliwia wyświetlanie i manipulacje obiektów graficznych takich jak: strzałki, krzywe bezier, mapy bitowe, prostokąty, okręgi, elipsy, łuki, linie, łamane, oraz tekst. | |
| |
Do wyświetlania obiektów graficznych często wykorzystywana jest klasa ''window'' albo ''picture'' (dodaje suwaki). | |
Przykładowo: | |
<code prolog> | |
?- new(@p, picture('Demo Picture')), send(@p, open). | |
| |
?- send(@p, display, | |
new(@bo, box(100,100))). | |
?- send(@p, display, | |
new(@ci, circle(50)), point(25,25)). | |
?- send(@p, display, | |
new(@bm, bitmap('32x32/books.xpm')), point(100,100)). | |
?- send(@p, display, | |
new(@tx, text('Hello')), point(120, 50)). | |
?- send(@p, display, | |
new(@bz, bezier_curve(point(50,100), | |
point(120,132), | |
point(50, 160), | |
point(120, 200)))). | |
</code> | |
| |
Modyfikacje obiektów: | |
| |
<code prolog> | |
?- send(@bo, radius, 10). | |
?- send(@ci, fill_pattern, colour(orange)). | |
?- send(@tx, font, font(times, bold, 18)). | |
?- send(@bz, arrows, both). | |
</code> | |
| |
| |
| |
==== Obiekty złożone i połączone ==== | |
| |
Obiekty graficzne można ze sobą połączyć tworząc grupę obiektów (obiekt złożony) i wykonywać transformacje (zmiana koloru, położenia etc.) na całej grupie np: | |
| |
<code prolog> | |
?- new(@ic, device), | |
send(@ic, display, bitmap('happy.bm')), | |
send(@ic, display, text('Happy'), point(0, 64)), | |
send(@p, display, @ic, point(250, 20)). | |
</code> | |
| |
Następnie można przesunąć całą grupę: | |
| |
<code prolog> | |
?- send(@ic,x,100), send(@ic,y,120). | |
</code> | |
| |
Obiekty również można ze sobą połączyć, tak aby modyfikacja jednego obiektu pociągała za sobą modyfikację innego. Przykład znajduje się w następnej sekcji. | |
| |
==== Mysz: interakcja z obiektami graficznymi ==== | |
| |
Poniższy przykład umożliwia połączenie zdarzenia polegającego na przesunięciu obiektu mysza (przytrzymując lewy przycisk) z obiektem identyfikowanym przez @ic. | |
| |
<code prolog> | |
?- send(@ic, recogniser, move_gesture(left)). | |
</code> | |
| |
Albo co ma się stać po dwukrotnym kliknięciu obiektu @ci: | |
| |
<code prolog> | |
?- send(@ci, recogniser, | |
click_gesture(left, '', double, | |
message(@pce, write_ln, hello))). | |
</code> | |
| |
Poniższy przykład ilustruje tworzenie i manipulację obiektów połączonych. | |
| |
<code prolog> | |
:- pce_global(@in_out_link, make_in_out_link). | |
| |
make_in_out_link(L) :- | |
new(L, link(in, out, line(arrows := second))). | |
| |
linked_box_demo :- | |
new(P, picture('Linked Box demo')), | |
send(P, open), | |
send(P, display, new(B1, box(50,50)), point(20,20)), | |
send(P, display, new(B2, box(25,25)), point(100,100)), | |
send(B1, handle, handle(w, h/2, in)), | |
send(B2, handle, handle(w/2, 0, out)), | |
send_list([B1, B2], recogniser, new(move_gesture(left))), | |
send(B1, connect, B2, @in_out_link). | |
</code> | |
| |
===== ĆWICZENIA ===== | |
| |
| |
| |
| |
==== 1 Ćwiczenie: Okno dialogowe ==== | |
| |
Przetestuj poniższy program ((przykład zaczerpnięty z http://hcs.science.uva.nl/projects/xpce/UserGuide/sec-4.1.html)). ''send_list'' działa podobnie jak ''send'' przu czym uruchamia wskazaną metodę z argumentami będącymi kolejnymi elementami listy. Pojedynczy predykat ''send_list'' zastępuje wiele predykatów ''send''. | |
| |
<code prolog> | |
:-dynamic(employee/2). | |
| |
ask_employee :- | |
new(Dialog, dialog('Define employee')), | |
send_list(Dialog, append, | |
[ new(N1, text_item(first_name)), | |
new(N2, text_item(family_name)), | |
new(S, new(S, menu(sex))), | |
new(A, int_item(age, low := 18, high := 65)), | |
new(D, menu(department, cycle)), | |
button(cancel, message(Dialog, destroy)), | |
button(enter, and(message(@prolog, | |
assert_employee, | |
N1?selection, | |
N2?selection, | |
S?selection, | |
A?selection, | |
D?selection), | |
message(Dialog, destroy))) | |
]), | |
send_list(S, append, [male, female]), | |
send_list(D, append, [research, development, marketing]), | |
send(Dialog, default_button, enter), | |
send(Dialog, open). | |
| |
assert_employee(FirstName, FamilyName, Sex, Age, Dept) :- | |
assert(employee(FirstName, FamilyName, Sex, Age, Dept)). | |
</code> | |
| |
==== 2 Ćwiczenie: Okno dialogowe ==== | |
| |
Rozbuduj program z Ćwiczenia 1. | |
Dopisz redykat ''show_employees/0'' umożliwiający przeglądanie danych pochodzących z ''employee/5''. | |
W celu znalezienia odpowiednich obiektów wyświetlających dane tekstowe zobacz: [[http://hcs.science.uva.nl/projects/xpce/UserGuide/|Programming in XPCE]]. | |
| |
| |
==== 3 Ćwiczenie: Okna modalne ==== | |
| |
Dany jest następujący kod uzupełniający przykłady z rodziny wzięte: | |
| |
<code prolog> | |
go :- kobieta(X), wyswietl(X). | |
go. | |
</code> | |
| |
Zaprogramuj predykat wyświetl, tak aby wyświetlał w oknie dialogowym 1-szy argument oraz dwa przycski: ''Koniec'', ''Nastepny''. | |
Okno dilogowe powinno blokować wykonanie programu, aż do naciśnięcia jednego z przycisków. | |
Przy naciśnięciu ''Nastepny'' predykat zwraca fałsz wymuszając nawrót, dla ''Koniec'' zwraca prawdę. | |
| |
==== 4 Ćwiczenie: Wizualizacja drzewa genealogicznego potomków ==== | |
| |
Korzystając z predykatów określających koligacje rodzinne z [[prolog lab 1]] oraz z XPCE napisz predykat generujący graf będący drzewem genealogicznym określającym potomków wskazanej osoby: | |
| |
rysuj_potomek(+Kto,+Rodzic,+Kobieta,+Mezczyzna) | |
| |
gdzie Kto to osoba, dla której zostanie wygenerowane drzewo potomków, pozostałe argumenty są nazwami predykatów określającymi odpowiednio kto jest czyim rodzicem, kto jest kobietą, kto jest mężczyzną. | |
Przykładowe wywołanie: | |
| |
rysuj_potomek(franek,rodzic/2,kobieta/1,mezczyzna/1) | |
| |
Wygeneruje drzewo genealogiczne potomków dla osoby franek, przy czym rodzic/2, kobieta/1, mezczyzna/1 są zdefinowanymi predykatami, których klauzule przechowują informacje o koligacjach rodzinnych. | |
| |
Podpowiedź: najpierw napisz predykat znajdujący potomków, potem dodaj generację danych dla [[misc:GraphViz]], następnie wizualizację. | |
| |
==== 5 Ćwiczenie: Wizualizacja drzewa genealogicznego ==== | |
| |
Napisz predykat: | |
| |
rysuj_drzewo(+Kto,+Rodzic,+Kobieta,+Meżczyzna) | |
| |
rysujący kompletne drzewo dla wskazanej osoby. | |
| |
Przykład drzewa genealogicznego: | |
| |
{{:pl:prolog:prolog_lab:drzewo_gen_przyklad.png}} | |
| |
| |
==== Ćwiczenie 6: Obiekty graficzne ==== | |
| |
TBD | |
| |
====== Uwagi, komentarze, propozycje ====== | |
Tu studenci mogą wpisywać swoje uwagi. | |
| |
--- //[[gjn@agh.edu.pl|Grzegorz J. Nalepa]] 2009/05/06 09:13// | |
| |
Wg. mnie trochę za dużo materiału - mi się udało na zajęciach zrobić tylko 3 pierwsze ćwiczenia. | |
| |
--- //Tomek Kozera 2009/05/16 21:01// | |
| |
"Jeżeli referenca obiektu nie" Literówka - referencja powinno być | |
| |
"Referencje może być utworzona przez new:" - jak wyżej | |
| |
"działa podobnie jak send przu czym" - znowu literówka ;) | |
| |
---Anonim | |