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:

?- new(P, point(10,20)).
P = @772024

Albo zadana (nazwana) tzw. named reference:

?- new(@demo, dialog('Demo Window')).

free/1 (free(+Reference)) niszczy obiekty, argumentem jest identyfikator obiektu (pierwszy argument new/2).

?- free(@demo).

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:

:- new(@demo, dialog('Okno Testowe')),
   new(@txt,text_item('to Jest tekst:')),
   send(@demo,append(@txt)),
   send(@demo,open).

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'.

?- new(@okno,dialog(dialogowe)),
   new(@but,button(nacisnij,message(@prolog,write,'au! nie naciskaj!\n'))),
   send(@okno,append,@but),
   send(@okno,open).

albo w krótszej wersji:

?- new(@okno,dialog(dialogowe)),
   send(@okno,append(button(nacisnij,message(@prolog,write,'au! nie naciskaj!\n')))),
   send(@okno,open).

Selektor

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.

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.

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.

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:

?- 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)))).

Modyfikacje obiektów:

?- send(@bo, radius, 10).
?- send(@ci, fill_pattern, colour(orange)).
?- send(@tx, font, font(times, bold, 18)).
?- send(@bz, arrows, both).

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:

?- new(@ic, device),
     send(@ic, display, bitmap('happy.bm')),
     send(@ic, display, text('Happy'), point(0, 64)),
     send(@p, display, @ic, point(250, 20)).

Następnie można przesunąć całą grupę:

?-  send(@ic,x,100), send(@ic,y,120).

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.

?- send(@ic, recogniser, move_gesture(left)).

Albo co ma się stać po dwukrotnym kliknięciu obiektu @ci:

?- send(@ci, recogniser,
           click_gesture(left, '', double,
                         message(@pce, write_ln, hello))).

Poniższy przykład ilustruje tworzenie i manipulację obiektów połączonych.

:- 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).

ĆWICZENIA

1 Ćwiczenie: Okno dialogowe

Przetestuj poniższy program 1). 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.

:-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)).

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: Programming in XPCE.

3 Ćwiczenie: Okna modalne

Dany jest następujący kod uzupełniający przykłady z rodziny wzięte:

go :- kobieta(X), wyswietl(X).
go.

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 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:

Ćwiczenie 6: Obiekty graficzne

TBD

Uwagi, komentarze, propozycje

Tu studenci mogą wpisywać swoje uwagi.

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 „send można również dekomponując term, zatem powyższy przykład można zapisać jako:” – jakiś błąd logiczny, brakuje co najmniej jednego słowa („send można użyć(?)”) – Kamil Kuduk

pl/prolog/prolog_lab/prolog_lab_xpce.txt · ostatnio zmienione: 2019/06/27 15:50 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0