Swi-Prologi graafikalaiend - XPCE

XPCE on objekt-orienteeeritud teek (library) graafiliste kasutajaliideste (GUI - Graphical User Interface) tegemiseks programeerimiskeeltele. XPCE ei ole klassikalises mõttes programeerimiskeel - objektidel ei ole tekstilist esitust, kuid XPCE-s on olemas kõik objekt-orienteeritud keelte vahendid: objektid, meetodid, instantsid, muutujad, pärimine jne; XPCE objektid luuakse, neile saadetakse sõnumeid nende omaduste modifitseerimiseks ja lõpuks nad hävitatakse .
Kuna XPCE on teek, peaks teda kasutav programm algama käsuga
use_module(library(pce)).
kuid Swi-Prolog laeb (tavaliselt) kõik teegid (ka XPCE) automaatselt, kui programmis esineb mõni selles teegis kirjeldatud predikaat/käsk, näiteks XPCE uue objekti loomise käsk new . Kahekohalise predikaadi new esimene argument on viit objektile; Swi-Prologi viidad algavad kõik sümboliga @ ja kui kasutaja ei anna viidamärgi @ järel oma objektinime (väikese algustähega, muidu tõlgendatakse see muutujaks), loob Prolog ise uue (numbrilise) objektinime. Predikaadi new teine argument on objekti tüüp koos mingi objekti kõige olulisema parameetriga: akna korral akna pealkiri (caption), punkti korral - selle koordinaadid (näiteks new(@punkt,point(100,200)) jne); dialog on aken, mis on spetsialiseeritud sisend/väljundobjektide näitamiseks (on olemas ka objekt window, s.t. oleks võinud öelda ka new(@aken,window('Demonstratsioon')) ). Tavaliselt algab graafika kasutamine uue graafikaakna avamisega:

?- new(@demo, dialog('Demo Window')).
Lisame aknale tekstiobjekti (text_item on tegelikult sildiga sisestusaken):
?- send(@demo, append(text_item('Sisesta'))).
ja lõpuks avame akna (muidu seda ei näe):
send(@demo, open).
Tavaliselt ei taheta neid käske anda käsurealt, vaid programmist, s.t. kirjutatakse predikaat. Viida aknale võib anda ka muutujana (sel juhul annab Swi-Prolog muutuja väärtuseks @number, kus number on unikaalne täisarv, s.t. viitab just sellele aknale); et avatud aknale saaks viidata ka teistest predikaatidest, salvestame viida sellele predikaadiga aken:
alga:-
new(Demo, dialog('Demo Window')),
send(Demo, append(text_item('Sisesta'))),
assert(aken(Demo)),
send(Demo, open).
Teeme akna suuremaks; selleks saadame sellele teate, mis muudab selle omadust size; uue väärtuse tüüp on samuti size:
suurenda:-
aken(Aken),
send(Aken, size(size(400,300))).
Küsime nüüd primitiiviga get uue akna suurust ja vormistame selle kohta (umbes akna keskel) punasega kirjutatud teate (tavalise teksti kirjutamiseks on primitiiv text):
teade:-
aken(Aken),
get(Aken,width,Width),
get(Aken,height,Height),
concat_atom(['Graafikaaken on ',Width,'x',Height,' pikselit'],Sõnum),
new(Text,text(Sõnum)),
send(Text,colour,'#ff0000'),
send(Aken,display(Text,point(100,150))).
Teeme ka predikaadi algul loodud teksti sisetusaknasse kasutaja poolt sisestatud teksti lugemiseks:
loe(Text):-
aken(Aken),
get(Aken, member(nimi), TextItem),
get(TextItem, selection, Text).
Loodud objekti hävitab primitiiv free:
?- aken(Aken), free(Aken).
Objektide omaduste määramise ja lugemise predikaatidel send ja get on kaks süntaksivormi, näiteks
send(Box, width(100))
asemel võib ka öelda
send(Box, width, 100)
ja
get(Point, distance(point(10,10)), D)
asemel võib öelda
get(Point, distance, point(10,10), D)

XPCE-s on mitmesuguseid objekte; kasutaja loodud objektid on alati hierarhilises struktuuris. Kõige ülemisel tasemel on alati aken (window). Aknaid on neli tüüpi :dialog kontrollerite jaoks (interaktsioon kasutajaga), view teksti esitamiseks, browser nimistute esitamiseks ja picture graafika esitamiseks; picture on mõlemas suunas lõpmatu ja vajadusel kerimisribadega. Eri tüüpi aknaid saab kombineerida raami (frame), nende omavaheline asend määratakse käskudega above, below, right, left. Järgnevas kirjeldatud predikaat failisirvija(Kataloog) avab ekraanil pildiloleva akna, kus kasutaja saab kataloogis Kataloog olevaid faile sirvida ja avada valitud (teksti)faili klikkamisega nupul Vaata:

failisirvija(Kataloog) :-
new(F, frame('Failisirvija')),
send(F, append(new(B, browser))),
send(new(D, dialog), below(B)),
send(D, append(button(näita, message(@prolog, vaata, Kataloog, B?selection?key)))),
send(D, append(button(quit, message(F, destroy)))),
send(B, members(directory(Kataloog)?files)),
send(F, open).

vaata(Kataloog,F) :-
send(new(V, view(F)), open),
atom_concat(Kataloog,F,Filenm), send(V, load(Filenm)).

Nupp näita (ekraanil näitab XPCE objekti nime suure algustähega) saadab Prologile (XPCE ja Prolog on eri süsteemid!) sõnumi: käivitada predikaat vaata argumentidega Kataloog ja B?selection?key, s.t. sirvijas B valitud real olev tekst. Et predikaat vaata saaks neist koostada korrektse, s.t. täieliku failinime koos valitud faili kataloogi näitamisega, tuleb predikaadi failisirvija käivitamisel anda kataloogi Kataloog lõpus ka kataloogieraldaja: kas DOS-is/Windows-is kasutatav '/' või Unix-i '\', kuid '\' kasutamisel tuleb see anda kahekordselt, sest märk '\' on aatomite süntaksis (kõik argumendid on aatomid ja nende süntaks vastab Prologi ISO-standardile) nn escape-märk (selle kasutamine on analoogiline '\' kasutamisega näit. C tekstikonstantides), mis annab järgnevale märgile eritähenduse (näit \n - uuele reale minek), seega näiteks kataloogisC:\ olevate failide sirvimiseks tuleb anda kas käsk:

?- failisirvija('C:/').
või
?- failisirvija('C:\\').
Vastusena avab Prolog pildil näidatud akna, kus faili valimisel ja nupu "Näita" klõpsamisel avatakse (eraldi aknas) valitud fail.

Ka XPCE-le on tehtud palju lisamooduleid (library), mis teevad paljude sageli esinevate ülesannete lahendamise väga lihtsaks. Näiteks järgnev programmike joonestab funktsiooni Y = 100*sin(X/5)*cos(X/3) 200x50 pikseli suuruse graafiku; kuna siin kasutatud klass auto_sized-picture on defineeritud teekides plot/plotter (Prologi oletuskataloogi all asuvas kataloogis) ja autowin, siis laeme programmi algul need teegid :

:- use_module(library('plot/plotter')).

:- use_module(library(autowin)).

plot_function :-
To is 50, % millise X väärtuseni graafik joonistada
PlotStep is 1, % millise sammuga arvutada funktsiooni väärtused
Step is 10, % millise vahemiku järel jaotused X teljele
new(W, auto_sized_picture('Plotter demo')),
send(W, display, new(P, plotter)),
send(P, axis, new(X, plot_axis(x, 0, To, Step, 200))),% X-telg: 0..50
send(P, axis, plot_axis(y, 0, 100, @default, 50)), %Y-telg: 0..100
send(X, format, '%i'),
send(P, graph, new(G, plot_graph)),
plot_function(1, To, PlotStep, Template, G), %see predikaat joonistabki graafiku
send(W, open).

plot_function(X, To, _, _, _) :- %eelmisest erinev predikaat - argumentidega!
X > To, !.% X ei ole enam graafiku joonistamise vahemikus, valmis!

plot_function(X, To, Step, Template, G) :-
funktsioon(X,Y),
send(G, append, X, Y), % lisame G-le punkti (X,Y)
NewX is X + Step,
plot_function(NewX, To, Step, Template, G). %järgmine punkt

funktsioon(X,Y):-
Y is 100*sin(X/5)*cos(X/3).


Ülesandeid:
1. Ylesande tekst


Küsimused, probleemid: ©2004 Jaak Henno