Vous êtes sur la page 1sur 62

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ

FACULTAD DE MATEMÁTICAS E INGENIERÍAS


INGENIERÍA DE SISTEMAS
SISTEMAS BASADOS EN EL CONOCIMIENTO I
GUIA PARA LA CONSTRUCCIÓN DE SISTEMAS BASADOS EN EL
CONOCIMIENTO A PARTIR DE UNA TABLA Y A PARTIR DE UN ÁRBOL DE
DECISIÓN.
Pervys Rengifo Rengifo

Esta guía se preparó como parte del apoyo didáctico que se ofrece a los estudiantes de
ingeniería de sistemas de la Fundación Universitaria Konrad Lorenz, dentro del curso de
Sistemas Basados en el Conocimiento I.
Los procedimientos básicos para la construcción de sistemas basados en el
conocimiento se hará alrededor de unos ejemplos que ilustran claramente cómo hacer
esta construcción para los casos en que el conocimiento esté representado o estructurado
como una tabla o como un árbol de decisión:

CASO 1: EL CONOCIMIENTO ESTÁ REPRESENTADO COMO UNA TABLA DE


DECISIÓN.
EJEMPLO: DE QUÉ ANIMAL SE TRATA?
A partir de la siguiente tabla de datos construya un sistema basado en el conocimiento
que permita determinar de qué animal se trata, a partir de la clase y la alimentación del
mismo. El conocimiento disponible está embebido en la siguiente tabla:

ANIMAL CLASE ALIMENTACION


'LEON' Mamífero carnivoro
'MUSARAÑA' Mamífero insectivoro
'CABALLO' Mamífero herbivoro
'COCODRILO' Reptil carnivoro
'CAMALEON' Reptil insectivoro
'TORTUGA DE TIERRA’ Reptil herbivoro
'AGUILA' Ave carnivoro
'GOLONDRINA' Ave insectivoro
'PERDIZ' Ave herbivoro

Paso 1: Construya la base de conocimiento en Prolog, utilizando lógica de predicados

animal('LEON'):-clase(mamifero),alimentacion(carnivoro).
Quiere decir: Un animal es un tigre si es mamífero y carnívoro.

animal('MUSARAÑA'):-clase(mamifero),alimentacion(insectivoro).
animal('CABALLO'):-clase(mamifero),alimentacion(herbivoro).
animal('COCODRILO'):-clase(reptil),alimentacion(carnivoro).
animal('CAMALEON'):-clase(reptil),alimentacion(insectivoro).
animal('TORTUGA DE TIERRA'):-clase(reptil),alimentacion(herbivoro).
animal('AGUILA'):-clase(ave),alimentacion(carnivoro).
animal('GOLONDRINA'):-clase(ave),alimentacion(insectivoro).
animal('PERDIZ'):-clase(ave),alimentacion(herbivoro).

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Predicados Prolog Análisis
animal('LEON'):- El león es un mamífero que se
clase(mamifero),alimentacion(carnivoro). alimenta de carne o de otros
animales
animal('MUSARAÑA'):- La musaraña es un mamífero que
clase(mamifero),alimentacion(insectivoro). se alimenta de insectos
animal('CABALLO'):- El caballo es un mamífero que se
clase(mamifero),alimentacion(herbivoro). alimenta de vegetales
animal('COCODRILO'):- El cocodrilo es un reptil que se
clase(reptil),alimentacion(carnivoro). alimenta de carne o de otros
animales
animal('CAMALEON'):- El camaleón es un reptil que se
clase(reptil),alimentacion(insectivoro). alimenta de insectos

animal('TORTUGA DE TIERRA'):- Este predicado indica que no hay


clase(reptil),alimentacion(herbivoro). un reptil que se alimente con sólo
vegetales
animal('AGUILA'):- El águila es un ave que se
clase(ave),alimentacion(carnivoro). alimenta de carne.

animal('GOLONDRINA'):- La golondrina es un ave que se


clase(ave),alimentacion(insectivoro). alimenta de insectos.

animal('PERDIZ'):- La perdiz es un ave que se


clase(ave),alimentacion(herbivoro). alimenta de vegetales.

Paso 2: Construya las preguntas en donde solicitará al usuario las características del
animal que desea clasificar:
pregunta1:-
write(' El grupo al que pertenece el animal es:'),nl,nl,
write('1. Mamifero.'),nl,
write('2. Reptil.'),nl,
write('3. Ave.'),nl,
read(N),
clasificar1(N).
Construya predicados para proceder de acuerdo con la respuesta a la pregunta 1:
clasificar1(1):-assert(clase(mamifero)),!.
clasificar1(2):-assert(clase(reptil)),!.
clasificar1(3):-assert(clase(ave)),!.
clasificar1(_):-pregunta1,!.

pregunta2:-

write(' Segun tipo de alimentacion puede ser:'),nl,nl,


write('1. Carnivoro.'),nl,
write('2. Insectivoro.'),nl,
write('3. Herbivoro.'),nl,
read(N2),

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


clasificar2(N2).
Construya predicados para proceder de acuerdo con la respuesta a la pregunta 2:
clasificar2(1):-assert(alimentacion(carnivoro)),!.
clasificar2(2):-assert(alimentacion(insectivoro)),!.
clasificar2(3):-assert(alimentacion(herbivoro)),!.
clasificar2(_):-pregunta2,!.

Paso 3: Defina un predicado que determine la clasificación de acuerdo con las


respuestas del usuario:

clasificar:-
animal(M),
write('El animal puede ser : '),nl,
write(' '),write(M),nl,nl.

Paso 4: Defina el predicado que permita ejecutar todo el programa:


empezar:-
pregunta1,
pregunta2,
consultar,!.

Ahora, que hacer si usted quiere proveer al usuario la posibilidad de hacer otra consulta:
Paso 1: Limpie todas las acciones del predicado assert, para esto puede definir un
predicado de nombre purgar

limpiar:-retract(clase(_)),
retract(alimentacion(_)),!.

Paso 2: Defina un predicado que permita continuar si el usuario responde


adecuadamente:
continue('s'):-empezar,!.
continue('S'):-empezar,!.
continue('n'):-continue('N').
continue('N'):-write(' NOS AGRADÓ AYUDARTE '),nl,
write('............HASTA PRONTO............').

Paso 3: Defina el predicado que pregunte al usuario si desea continuar.

pregunta:-nl,nl,
write('Desea continuar s/n : '),
read(X),
continue(X).

Paso 4: redefina el predicado consultar para que responda la clasificación y pregunte al


usuario si desea continuar:
clasificar:-
animal(M),
write('El animal puede ser : '),nl,
write(' '),write(M),nl,nl,

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


limpiar,
pregunta.

FINALMENTE EL PROGRAMA QUEDARÍA ASI:

animal('LEON'):-clase(mamifero),alimentacion(carnivoro).
animal('MUSARAÑA'):-clase(mamifero),alimentacion(insectivoro).
animal('CABALLO'):-clase(mamifero),alimentacion(herbivoro).
animal('COCODRILO'):-clase(reptil),alimentacion(carnivoro).
animal('CAMALEON'):-clase(reptil),alimentacion(insectivoro).
animal('TORTUGA DE TIERRA'):-clase(reptil),alimentacion(herbivoro).
animal('AGUILA'):-clase(ave),alimentacion(carnivoro).
animal('GOLONDRINA'):-clase(ave),alimentacion(insectivoro).
animal('PERDIZ'):-clase(ave),alimentacion(herbivoro).

empezar:-
pregunta1,
pregunta2,
clasificar,!.

pregunta1:-

write(' La clase a la que pertenece el animal es:'),nl,nl,


write('1. Mamifero.'),nl,
write('2. Reptil.'),nl,
write('3. Ave.'),nl,
read(N),
clasificar1(N).

clasificar1(1):-assert(clase(mamifero)),!.
clasificar1(2):-assert(clase(reptil)),!.
clasificar1(3):-assert(clase(ave)),!.
clasificar1(_):-pregunta1,!.

pregunta2:-

write(' Segun tipo de alimentacion puede ser:'),nl,nl,


write('1. Carnivoro.'),nl,
write('2. Insectivoro.'),nl,
write('3. Herbivoro.'),nl,
read(N2),
clasificar2(N2).

clasificar2(1):-assert(alimentacion(carnivoro)),!.
clasificar2(2):-assert(alimentacion(insectivoro)),!.
clasificar2(3):-assert(alimentacion(herbivoro)),!.
clasificar2(_):-pregunta2,!.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


limpiar:-retract(clase(_)),
retract(alimentacion(_)),!.

continue('s'):-empezar,!.
continue('S'):-empezar,!.
continue('n'):-continue('N').
continue('N'):-write(' NOS AGRADÓ AYUDARTE '),nl,
write('............HASTA PRONTO............').

clasificar:-
animal(M),
write('El animal puede ser : '),nl,
write(' '),write(M),nl,nl,
limpiar,
pregunta.

pregunta:-nl,nl,
write('Desea continuar s/n : '),
read(X),
continue(X).

1. El programa empieza cuando en la consola le digitamos


empezar. El símbolo :- se lee “si “ y corresponde a una
implicación de derecha a izquierda. Empieza a cargar las
preguntas 1 y 2:

empezar:-
pregunta1,
pregunta2,
clasificar,!.

2. El programa muestra al usuario la pregunta y las diferentes


opciones a escoger. En este caso, escribe en pantalla si el
animal pertenece al grupo de los mamíferos, reptiles o aves.
En cualquier caso, el número que se digite será leído y
guardado en una variable N.

pregunta1:-

write(' El grupo al que pertenece el animal es:'),nl,nl,


write('1. Mamifero.'),nl,
write('2. Reptil.'),nl,
write('3. Ave.'),nl,
read(N),
clasificar1(N).

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


3. El programa al leer el número digitado por el usuario lee si es
un 1 guarda la clase mamífero, si es 2 guarda la clase reptil, si
es 3 guarda la clase ave y si digita cualquier otro número
presenta de nuevo la pregunta 1:

clasificar1(1):-assert(clase(mamifero)),!.
clasificar1(2):-assert(clase(reptil)),!.
clasificar1(3):-assert(clase(ave)),!.
clasificar1(_):-pregunta1,!.

Se pueden incluir más cláusulas a la base de datos mediante el


predicado assert. Es decir, que para cada número que ingrese el
usuario se le asigna una clase.

4. El programa a continuación muestra al usuario las diferentes


opciones a escoger con la pregunta 2. En este caso, escribe en
pantalla si el animal según el tipo de alimentación puede ser
carnívoro, insectívoro o herbívoro. Igual al caso anterior, leerá
el número digitado y lo guardará en la variable N2.

pregunta2:-

write(' Segun tipo de alimentacion puede ser:'),nl,nl,


write('1. Carnivoro.'),nl,
write('2. Insectivoro.'),nl,
write('3. Herbivoro.'),nl,
read(N2),
clasificar2(N2).

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


6. El programa al leer el número digitado por el usuario lee si es un 1
guarda el tipo carnívoro, si es 2 guarda el tipo insectívoro, si es 3
guarda el tipo herbívoro y si digita cualquier otro numero presenta de
nuevo la pregunta 2

clasificar2(1):-assert(alimentacion(carnivoro)),!.
clasificar2(2):-assert(alimentacion(insectivoro)),!.
clasificar2(3):-assert(alimentacion(herbivoro)),!.
clasificar2(_):-pregunta2,!.

7. El programa empieza a hacer búsquedas de que animal cumple


con las características dadas por el usuario según la clase y la
alimentación y hace una eliminación de cláusulas de predicados.

limpiar:-retract(clase(_)),
retract(alimentacion(_)),!.

8. Encuentra el animal y lo guarda en la variable M y luego lo


muestra al usuario el animal encontrado.

clasificar:-
animal(M),
write('El animal puede ser : '),nl,
write(' '),write(M),nl,nl,
limpiar,
pregunta.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


9. El programa pregunta si desea continuar. Si el usuario le
dice que si se devuelve a hacer la pregunta No. 1 y así
sucesivamente hasta que a la pregunta Desea Continuar se
le dé que no.

pregunta:-nl,nl,
write('Desea continuar s/n : '),
read(X),
continue(X).

continue('s'):- continue('S').
continue('S'):-empezar,!.
continue('n'):-continue('N').
continue('N'):-write(' NOS AGRADÓ AYUDARTE'),nl,
write('............HASTA PRONTO............').

Funciones desconocida:

Añadiendo cláusulas

Para insertar cláusulas de un predicado dinámico existe una familia


de predicados ISO-standard, la familia assert, consistente en los
siguientes predicados:

asserta/ Inserta una nueva cláusula como si se hubiera escrito al


1 principio del programa.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


assertz/ Inserta una nueva cláusula como si se hubiera escrito al
1 final del programa.
assert/1 Idéntico a asserta/1.

Eliminando cláusulas

Análogamente, es posible eliminar cláusulas de predicados dinámicos


mediante la familia de predicados retract consistente en:

Elimina únicamente la primera cláusula que unifique con el


retract/1 argumento. Siempre se elimina por el principio del
programa.
rectractall/ Elimina todas las cláusulas que unifiquen con el
1 argumento.

AÑADIENDO INTERFACE GRÁFICA CON WINPROLOG 4.2

Win-Prolog, permite la creación de interfaces gráfica de usuario, tanto desde el código


como a través de una utilidad ayuda a construir de forma más sencilla estas interfaces. A
esta utilidad se puede acceder a través de la siguiente ruta:

Con lo cual aparecerá una ventana como la siguiente:

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


En la ventana de controles, se pueden seleccionar el tipo de control que se desea crear
y luego se ubica control en la ventana de la derecha, dimensionándolo con el ratón

Después de esto se obtendría una ventana con la siguiente apariencia

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Al hacer doble clic en el control (en este caso un botón), se abre una pantalla de
configuración básica (en este caso se le va a cambiar la leyenda que aparece en el
control, por Prueba 1.

Cuando ya se tenga listo el paquete de controles, se hace clic en export, obteniendo un


texto con un conjunto de instrucciones que se pegaría al código de Prolog que se esté
implementando y se adaptaría según las necesidades que se tengan.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Si desea un listado de los predicados usados en este tutorial puede consultar el apéndice
1, al final de este documento.

A continuación se muestra un ejemplo del programa anterior utilizando una interface


gráfica de usuario:
animal('LEON'):-clase(mamifero),
alimentacion(carnivoro),!.

animal('MUSARAÑA'):-clase(mamifero),
alimentacion(insectivoro),!.

animal('CABALLO'):-clase(mamifero),
alimentacion(herbivoro),!.

animal('COCODRILO'):-clase(reptil),
alimentacion(carnivoro),!.

animal('CAMALEÓN'):-clase(reptil),
alimentacion(insectivoro),!.

animal('NO EXISTE EN LA BASE DE CONOCIMIENTO'):-clase(reptil),


alimentacion(herbivoro),!.

animal('AGUILA'):-clase(ave),
alimentacion(carnivoro),!.

animal('GOLONDRINA'):-clase(ave),
alimentacion(insectivoro),!.

animal('PERDIZ'):-clase(ave),
alimentacion(herbivoro),!.

inicio:-retractall(clase(_)),
retractall(alimentacion(_)),

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


bienvenida,
empezar.

empezar:-pregunta1, % empezar ejecuta las funciones de pregunta1,


pregunta2
pregunta2, % y hacer la consulta.
consultar,!.

pregunta1:-combo_select(`El grupo al que pertenece el animal es:`,


[`Mamífero`,`Reptil`,`Ave`], S ),grupo(S),!. % y se llama una funcion
pregunta con parametro N, y segun el numero ingresado, se ejecuta alguna de las
siguientes
grupo(`Mamífero`):-assert(clase(mamifero)),!. % si N es 1, se ingresa a la base del
conocimiento, el predicado clase(mamifero)
grupo(`Reptil`):-assert(clase(reptil)),!. % igual para el 2, que ingresa clase(reptil),
grupo(`Ave`):-assert(clase(ave)),!. % y para 3.
grupo(_):-pregunta1,!.

pregunta2:-combo_select(`Segun tipo de alimentacion puede ser:`,


[`Carnívoro`,`Insectívoro`,`Herbivoro`], T ),tipo(T),!.

tipo(`Carnívoro`):-assert(alimentacion(carnivoro)),!. % si la opcion fue la 1, se


ingresa a la base de conocimiento alimentacion(carnivoro)
tipo(`Insectívoro`):-assert(alimentacion(insectivoro)),!. % con el 2,
alimentacion(carnivoro)
tipo(`Herbivoro`):-assert(alimentacion(herbivoro)),!. % y con el 3 se ingresa
alimentacion(herbivoro)
tipo(_):-pregunta2,!.

limpiar_base:-retract(clase(_)), % limpiar_base limpia la base de lo


ingresado por las opciones del usuario,
retract(alimentacion(_)),!. % para ejecutar una nueva consulta

continue('yes'):-empezar,!. % dependiendo del parametro, se sigue con


otra consulta o se sale.
continue('no'):-despedida.

consultar:- animal(M),
atom_string( M,Animal),
despliega_repuesta(Animal),
continuar.

despliega_repuesta(Animal) :-
_S1 = [dlg_ownedbydesktop,ws_sysmenu,ws_caption],
_S2 = [ws_child,ws_visible,ss_center],
_S3 = [ws_child,ws_visible,ws_tabstop,bs_pushbutton],
wdcreate( respuesta, `user_dialog`, 235, 43, 402, 160, _S1 ),

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


wccreate( (respuesta,10000), static, `EL ANIMAL PODRÍA SER`, 20, 10, 370, 20,
_S2 ),
wccreate( (respuesta,10001), static, Animal, 120, 40, 170, 30, _S2 ),
wccreate( (respuesta,1000), button, `ACEPTAR`, 130, 80, 150, 30, _S3 ),
wfcreate( foo1, arial, 18, 2 ),
wfont( (respuesta,10000), foo1 ),
wfont( (respuesta,10001), foo1 ),
window_handler( respuesta, bienvenida_handler ),
call_dialog( respuesta, R ),
wfclose(foo1),wclose(respuesta).

continuar:-message_box( yesno, 'Desea Continuar', A ), continue(A).

despedida:- _S1 = [ws_sysmenu,ws_popup,ws_caption,dlg_ownedbyprolog],


_S2 = [ws_child,ws_visible,ss_center],
_S3 = [ws_child,ws_visible,ws_tabstop,bs_pushbutton],
wdcreate( despedida, `user_dialog`,
235, 43, 533, 358, _S1 ),
wccreate( (despedida,10000), static, `Hasta pronto`,
146, 40, 240, 20, _S2 ),
wccreate( (despedida,10001), static, `Fue un placer Ayudarte`,
146, 60, 240, 20, _S2 ),
wccreate( (despedida,10002), static, `Sistemas Basados en el Conocimiento I`,
117, 90, 300, 20, _S2 ),
wccreate( (despedida,10003), static, `Facultad de Matemáticas e Ingenierías`,
117, 110, 300, 20, _S2 ),
wccreate( (despedida,10004), static, `FUNDACIÓN UNIVERSITARIA
KONRAD LORENZ-FUKL (http://www.fukl.edu)`, 16, 130, 500, 60, _S2 ),
wccreate( (despedida,1000), button, `OK`,
226, 190, 80, 20, _S3 ),
wcreate((despedida,2),grafix,``,0, 210, 533, 96,16'50000000),
wfcreate( foo, arial, 18, 0 ),
wfont( (despedida,10000), foo ),
wfont( (despedida,10001), foo ),
wfont( (despedida,10002), foo ),
wfont( (despedida,10003), foo ),
wfont( (despedida,10004), foo ),
wfont( (despedida,1000), foo ),
window_handler( despedida, bienvenida_handler ),
call_dialog( despedida, R ),
wfclose(foo),gfx_bitmap_close(fukl),gfx_bitmap_close(fukl1),wclose(despedida
).

bienvenida :- _S1 = [ws_sysmenu,ws_popup,ws_caption,dlg_ownedbyprolog],


_S2 = [ws_child,ws_visible,ss_center],
_S3 = [ws_child,ws_visible,ss_left],
_S4 = [ws_child,ws_visible,ws_tabstop,bs_pushbutton],

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


wdcreate( bienvenida, `user_dialog`,
235, 43, 532, 325, _S1 ),
wccreate( (bienvenida,10000), static, `FUNDACIÓN UNIVERSITARIA
KONRAD LORENZ-FUKL (http://www.fukl.edu)`, 70, 10, 390, 20, _S2 ),
wccreate( (bienvenida,10001), static, `FACULTAD DE MATEMÁTICAS E
INGENIERÍAS`, 110, 30, 320, 20, _S2 ),
wccreate( (bienvenida,10002), static, `SISTEMAS BASADOS EN EL
CONOCIMIENTO I`, 110, 50, 320, 20, _S2 ),
wccreate( (bienvenida,10003), static, `BIENVENIDOS AL PROGRAMA
"ANIMALES"`, 110, 70, 320, 20, _S2 ),
wccreate( (bienvenida,10004), static, `EL CUAL, CON UN EJEMPLO
SENCILLO, ILUSTRA EL PROCESO`, 60, 90, 420, 20, _S2 ),
wccreate( (bienvenida,10005), static, `DE CONSTRUCCIÓN DE UN
SISTEMA BASADO EN EL CONOCIMIENTO`, 60, 110, 420, 20, _S2 ),
wccreate( (bienvenida,10006), static, `SE TRATA DE DETERMINAR DE
QUE ANIMAL SE TRATA, A PARTIR DE`, 60, 130, 420, 20, _S3 ),
wccreate( (bienvenida,10007), static, `CIERTAS CARACTERÍSTICAS DEL
MISMO`, 60, 150, 420, 20, _S2 ),
wccreate( (bienvenida,1000), button, `CONTINUAR`,
210, 180, 130, 30, _S4 ),
wcreate((bienvenida,2),grafix,``,0, 210, 533, 96,16'50000000),
window_handler( bienvenida, bienvenida_handler ),
gfx_bitmap_load(fukl,'fukl.bmp'),
gfx_bitmap_load(fukl1,'fukl1.bmp'),
call_dialog( bienvenida, R ),
wclose(bienvenida).

bienvenida_handler( (Window,2), msg_paint, _, _ ) :- gfx_paint( (Window,2) ),


gfx(bitmap(0,0, 533, 96,0,0,fukl1)),
gfx_end( (Window,2)).
bienvenida_handler( (Window,1000), msg_button, _,
cancel ).

combo_select( Pregunta,Items, Selected ) :-_S1 =


[ws_sysmenu,ws_popup,ws_caption,dlg_ownedbyprolog],
_S2 = [ws_child,ws_visible,ws_tabstop,cbs_dropdown],
_S3 = [ws_child,ws_visible,ss_left],
_S4 = [ws_child,ws_visible,ws_tabstop,bs_pushbutton],
_S5 = [ws_child,ws_visible,ws_border],
wdcreate( combo, `user_dialog`, 272, 150, 390, 350,
_S1 ),
wccreate( (combo,500), combobox, `Combo1`, 100, 60,
170, 150, _S2 ),
wccreate( (combo,3), static, Pregunta, 50, 20, 280, 20,
_S3 ),
wccreate( (combo,1), button, `OK`, 140, 140, 100, 30,
_S4 ),
wcreate((combo,4),static,`iconbds`,10,10,70,54,16'50000003
),

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


wcreate((combo,2),grafix,``,25, 200, 343, 90,16'50000000),
fcreate( combo, [], -2, 0, 0 ),
wfcreate( foo, arial, 18, 0 ),
wfont( (combo,3), foo ),
wfont( (combo,500), foo ),
fill_combo( (combo,500), Items ),
window_handler( combo, combo_handler ),
call_dialog( combo, R ),
(R=cancel->Selected=R; (P is
R+1,enesimo(Selected,P,Items))),
fclose( combo ),wclose(combo),!.

combo_handler( (Window,2), msg_paint, _, _ ) :-


gfx_paint( (Window,2) ),
gfx(bitmap(0,0, 343, 90,0,0,fukl)), %tamaño de la imagen 343x90, iniciada en 0,0
gfx_end( (Window,2)).

% cuando ocurra un mensaje de cierre retorna "cancel"

combo_handler( _, msg_close, _, cancel ).

% cuando se presiona el boton "OK" retorna la seleccion

combo_handler( (Window,1), msg_button, _, Result ) :- get_selected_item(


(Window,500), Result ).

% llena el combobox con la lista de items, preseleccionando el primer item

fill_combo( Window, Items ) :-sndmsg( Window, cb_resetcontent, 0, 0, _ ),


forall( member( Item, Items ),sndmsg( Window, cb_addstring, 0,
Item, _ )),
sndmsg( Window, cb_setcursel, 0, 0, _ ).

% Se obtiene la posición-1 del ítem seleccionado

get_selected_item( Window, R ) :- sndmsg( Window, cb_getcursel, 0, 0, R ).

%obtiene el elemento enésimo de una lista


enesimo(X,1,[X|_]).
enesimo(X,N,[_|L]):-R is N-1, enesimo(X,R,L).

*****************************************************************

Para correr este programa debe descargar el archivo comprimido en la siguiente


dirección: http://in.solit.us/archives/download/152660

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Lo descomprime en una carpeta y luego lo abre con winprolog(se utilizó la versión 4.2).
Estos cuidados se requieren debido a los archivos de imágenes que se cargan al
programa: “fukl.bmp” y “fukl1.bmp”, los cuales deben estar en la carpeta local( aunque
si se quiere se puede cambiar esta ruta y colocar la ruta en donde se encuentren estos
archivos o eliminar el código que hace el llamado a estas imágenes), es decir en la
carpeta en donde se cargue el archivo SistemaExpertoFUKL.pl.

Después de abrir este abrir este archivo, proceda a compílarlo:

Corra el programa escribiendo en consola:


|?:- inicio.
Con lo que aparecerá la pantalla de bienvenida.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Al darle continuar, aparecerá la siguiente ventana:

Se escoge la elección que se desee, para este caso se escogerá reptil:

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Luego al hacer clic en OK, aparecerá la ventana de la siguiente pregunta, en la cual se
escogió la opción herbívoro:

Con estas respuestas, el programa produce el siguiente resultado:

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Al hacer clic en aceptar, el programa preguntará si se desea continuar:

Si se hace clic en “sí”, el programa volverá a presentar las dos preguntas, si le da clic
en “no”, el programa se despedirá y saldrá al darle ok.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


2. EJEMPLO: RECOMENDACIÓN DE LENTES DE CONTACTO
Suponga que se conocen datos sobre el tipo de lentes de contacto recomendadas en función
de ciertos variables: edad (3 valores), prescripción (2 valores), existencia de astigmatismo
(2 valores) y tasa de producción de lágrimas (2 valores). La tabla que recoge la información
disponible es la siguiente:

EDAD_DEL_PACIEN ASTIGMATISM TASA_DE_PRODUCCION_LAG


TE PRESCRIPCION O RIMAS LENTE_RECOMENDADO
JOVEN MIOPIA SI REDUCIDA NO_LENTE_CONTACTO
LENTE_CONTACTO_SUA
JOVEN MIOPIA SI NORMAL VE
JOVEN MIOPIA NO REDUCIDA NO_LENTE_CONTACTO
LENTE_CONTACTO_DU
JOVEN MIOPIA NO NORMAL RO
HIPERMETROPI
JOVEN A SI REDUCIDA NO_LENTE_CONTACTO
HIPERMETROPI LENTE_CONTACTO_SUA
JOVEN A SI NORMAL VE
HIPERMETROPI
JOVEN A NO REDUCIDA NO_LENTE_CONTACTO
HIPERMETROPI LENTE_CONTACTO_DU
JOVEN A NO NORMAL RO
PRE_PRESBIOPIC
O1 MIOPIA SI REDUCIDA NO_LENTE_CONTACTO
LENTE_CONTACTO_SUA
PRE_PRESBIOPICO MIOPIA SI NORMAL VE
PRE_PRESBIOPICO MIOPIA NO REDUCIDA NO_LENTE_CONTACTO
LENTE_CONTACTO_DU
PRE_PRESBIOPICO MIOPIA NO NORMAL RO
HIPERMETROPI
PRE_PRESBIOPICO A SI REDUCIDA NO_LENTE_CONTACTO
HIPERMETROPI LENTE_CONTACTO_SUA
PRE_PRESBIOPICO A SI NORMAL VE
PRE_PRESBIOPICO HIPERMETROPI NO REDUCIDA NO_LENTE_CONTACTO

1
PRESBIOPIA
que significa dificultad para enfocar objetos que están cerca y es común en los ancianos.Alteración de la visión asociada a la vejez.
En este trastorno existe una mayor rigidez del cristalino que produce dificultad para ver los objetos cercanos.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


A
HIPERMETROPI
PRE_PRESBIOPICO A NO NORMAL NO_LENTE_CONTACTO
PRESBIOPICO MIOPIA SI REDUCIDA NO_LENTE_CONTACTO
PRESBIOPICO MIOPIA SI NORMAL NO_LENTE_CONTACTO
PRESBIOPICO MIOPIA NO REDUCIDA NO_LENTE_CONTACTO
LENTE_CONTACTO_DU
PRESBIOPICO MIOPIA NO NORMAL RO
HIPERMETROPI
PRESBIOPICO A SI REDUCIDA NO_LENTE_CONTACTO
HIPERMETROPI LENTE_CONTACTO_SUA
PRESBIOPICO A SI NORMAL VE
HIPERMETROPI
PRESBIOPICO A NO REDUCIDA NO_LENTE_CONTACTO
HIPERMETROPI
PRESBIOPICO A NO NORMAL NO_LENTE_CONTACTO

El objetivo es generar un modelo que se ajuste a los ejemplos de entrenamiento y


posteriormente usar el modelo para clasificar un ejemplo nuevo.
Si se programa directamente la tabla anterior en Win-Prolog, se obtiene el siguiente código:

lente_recomendado('No formular Lente de Contacto'):-


tasa_de_produccion_de_lagrimas(reducida).
lente_recomendado('Lente de Contacto Suave'):-edad_del_paciemte(joven),
astigmatismo(si), tasa_de_produccion_de_lagrimas(normal).
lente_recomendado('Lente de Contacto Suave'):-
edad_del_paciemte(pre_presbyopic), astigmatismo(si),
tasa_de_produccion_de_lagrimas(normal).
lente_recomendado('No formular Lente de Contacto'):-
edad_del_paciemte(presbyopic), prescripcion(miopia), astigmatismo(si),
tasa_de_produccion_de_lagrimas(normal).
lente_recomendado('Lente de Contacto Suave'):-
edad_del_paciemte(presbyopic), prescripcion(hipermetropia), astigmatismo(si),
tasa_de_produccion_de_lagrimas(normal).
lente_recomendado('Lente de Contacto Suave'):-prescripcion(miopia),
astigmatismo(no), tasa_de_produccion_de_lagrimas(normal).
lente_recomendado('Lente de Contacto Duro'):-edad_del_paciemte(joven),
prescripcion(hipermetropia), astigmatismo(no),
tasa_de_produccion_de_lagrimas(normal).
lente_recomendado('No formular Lente de Contacto'):-
edad_del_paciemte(pre_presbyopic), prescripcion(hipermetropia),
astigmatismo(no), tasa_de_produccion_de_lagrimas(normal).
lente_recomendado('No formular Lente de Contacto'):-
edad_del_paciemte(presbyopic), prescripcion(hipermetropia),
astigmatismo(no), tasa_de_produccion_de_lagrimas(normal).
inicio:-write('Formulacion de lentes de contacto'),nl,nl, pregunta0, pregunta1,
pregunta2, pregunta3, conclusion, !.
pregunta0:-write('Seleccione las caracteristicas del paciente'),nl,write('Tasa de
produccion de Lagrimas'),nl,write(' 1. Normal.'),nl,write(' 2. Reducida.'),nl,
read(N), respuesta0(N).
respuesta0(1):- assert(tasa_de_produccion_de_lagrimas(normal)),!.
respuesta0(2):- assert(tasa_de_produccion_de_lagrimas(reducida)),!.
respuesta0(_):- write('Intente de nuevo'), nl, pregunta0.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


pregunta1:-write('Tiene astigmatismo?'),nl,write(' 1. Si.'),nl,write(' 2. No.'),nl,
read(N), respuesta1(N).
respuesta1(1):-assert(astigmatismo(si)), !.
respuesta1(2):-assert(astigmatismo(no)), !.
respuesta1(_):-write('Intente de nuevo'), nl, pregunta1,!.
pregunta2:-write('Seleccione la prescripcion del paciente'),
nl,
write(' 1. Miopia.'),
nl,
write(' 2. Hipermetropia.'),
nl,
read(N),
respuesta2(N).
respuesta2(1):-assert(prescripcion(miopia)),!.
respuesta2(2):-assert(prescripcion(hipermetropia)),!.
respuesta2(_):-write('Intente de nuevo'),
nl,
pregunta2,!.

pregunta3:-write('Edad del paciente'),


nl,
write(' 1. Joven.'),
nl,write(' 2. Presbiópico.'),
nl,
write(' 3. Pre - Presbiópico.'),
nl,
read(N),
respuesta3(N).
respuesta3(1):-assert(edad_del_paciente(joven)),!.
respuesta3(2):-assert(edad_del_paciente(presbiopico)),!.
respuesta3(3):-assert(edad_del_paciente(pre_presbiopico)),!.
respuesta3(_):-write('Intente de nuevo'),
nl,
pregunta3,!.
conclusion:-lente_recomendado(Lente),
write('Lo recomendado es: '), write(Lente),nl,
retract(edad_del_paciente(_)),
retract(prescripcion(_)),
retract(tasa_de_produccion_de_lagrimas(_)),
retract(astigmatismo(_)),
pregunta4.
pregunta4:-nl,nl,
write('Desea continuar s/n : '),
read(X),
continuar(X).
continuar('s'):-inicio,!.
continuar('S'):-inicio,!.
continuar('n'):-write('Hasta Pronto'),nl,nl,!.
continuar('N'):-write('Hasta Pronto'),nl,nl,!.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Sin embargo, este programa no explota las regularidades presentes en los
datos. Con este propósito se utilizan técnicas de minería de datos que buscan
extraer patrones o asociaciones relevantes que permitan hacer
representaciones simplificadas o muy sintéticas del conocimiento embebido en
la información.
Para este caso se utilizará el aprendizaje de árboles de decision para inducir
una representación más simplificada del problema. Como apoyo computacional
para esta tarea se utilizó el applet “Desición Tree Learning” 2
Este applet, tiene la siguiente apariencia:

Al hacer clic en “start applet”, aparece la siguiente pantalla:

2
http://www.c2i.ntu.edu.sg/Courses/AI/CIspace/Version4/dTree/index-2.html

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Luego se va a “edit”-“View Edit Text Representation” como se muestra en la siguiente
figura

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Resultando la siguiente ventana

Los datos de la tabla se preparan siguiendo el siguiente formato:

T:;EDAD_DEL_PACIENTE;PRESCRIPCION;ASTIGMATISMO;TASA_DE_PRODUCCION_LAGRIMAS;LENTE_RECOMEN
DADO
A:;JOVEN;MIOPIA;SI;REDUCIDA;NO_LENTE_COTACTO
A:;JOVEN;MIOPIA;SI;NORMAL;LENTE_CONTACTO_SUAVE
A:;JOVEN;MIOPIA;NO;REDUCIDA;NO_LENTE_COTACTO
A:;JOVEN;MIOPIA;NO;NORMAL;LENTE_CONTACTO_DURO
A:;JOVEN;HIPERMETROPIA;SI;REDUCIDA;NO_LENTE_COTACTO
A:;JOVEN;HIPERMETROPIA;SI;NORMAL;LENTE_CONTACTO_SUAVE
A:;JOVEN;HIPERMETROPIA;NO;REDUCIDA;NO_LENTE_COTACTO
A:;JOVEN;HIPERMETROPIA;NO;NORMAL;LENTE_CONTACTO_DURO
A:;PRE_PRESBYOPIC;MIOPIA;SI;REDUCIDA;NO_LENTE_COTACTO
A:;PRE_PRESBYOPIC;MIOPIA;SI;NORMAL;LENTE_CONTACTO_SUAVE
A:;PRE_PRESBYOPIC;MIOPIA;NO;REDUCIDA;NO_LENTE_COTACTO
A:;PRE_PRESBYOPIC;MIOPIA;NO;NORMAL;LENTE_CONTACTO_DURO
A:;PRE_PRESBYOPIC;HIPERMETROPIA;SI;REDUCIDA;NO_LENTE_COTACTO
A:;PRE_PRESBYOPIC;HIPERMETROPIA;SI;NORMAL;LENTE_CONTACTO_SUAVE
A:;PRE_PRESBYOPIC;HIPERMETROPIA;NO;REDUCIDA;NO_LENTE_COTACTO
A:;PRE_PRESBYOPIC;HIPERMETROPIA;NO;NORMAL;NO_LENTE_COTACTO
A:;PRESBYOPIC;MIOPIA;SI;REDUCIDA;NO_LENTE_COTACTO
A:;PRESBYOPIC;MIOPIA;SI;NORMAL;NO_LENTE_COTACTO
A:;PRESBYOPIC;MIOPIA;NO;REDUCIDA;NO_LENTE_COTACTO
A:;PRESBYOPIC;MIOPIA;NO;NORMAL;LENTE_CONTACTO_DURO
A:;PRESBYOPIC;HIPERMETROPIA;SI;REDUCIDA;NO_LENTE_COTACTO
A:;PRESBYOPIC;HIPERMETROPIA;SI;NORMAL;LENTE_CONTACTO_SUAVE
A:;PRESBYOPIC;HIPERMETROPIA;NO;REDUCIDA;NO_LENTE_COTACTO
A:;PRESBYOPIC;HIPERMETROPIA;NO;NORMAL;NO_LENTE_COTACTO

Donde T indica los nombres de las variables, A indica los patrones de entrenamiento y
B(aunque no aparece en este ejemplo) indica los patrones de validación.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Los datos en el formato anterior se pegan en la ventana anterior, con lo cual se obtiene
la siguiente apariencia:

Al presionar Update, se obtiene una pantalla como la siguiente:

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


A continuación se hace clic en la pestaña “solve”, como se muestra en la siguiente
figura

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Luego se elige el criterio para determinar el mejor atributo. En este caso se eligió
Ganancia de Información(Information Gain)

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


A continuación se hace clic en el icono “Auto Create”, para que genere el árbol
automáticamente con el criterio de Ganancia de Información

'

Con lo anterior se genera un árbol que tendra la siguiente apariencia:

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Si se accede a la ruta “View” + “Autoscale”, la gráfica del árbol se autoescala para que
quepa en la ventana de visualización.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


En View-Font Size se selecciona un tamaño de letra menor para un mayor ajuste de la
gráfica del árbol, la cual se reorganiza mediante el tradicional arrastre y suelte con el
ratón. Finalmente se obtiene el siguiente árbol de decisión.

Cada hoja del árbol(las que se presentan con recuadro verde) representa una regla de
decisión sintetizada a partir de los datos. Como se puede observar que los 24 patrones
originales, se pueden expresar mediante 9 reglas, lo cual revela una compresión de
24:9= 2.7.

Las reglas aprendidas fueron:

1. Si la “TASA DE PRODUCCIÓN DE LÁGRIMAS” es “REDUCIDA”, entonces


la recomendación es “NO USAR LENTES DE CONTACTO”.

2. Si la “TASA DE PRODUCCIÓN DE LÁGRIMAS” es “NORMAL” y SI


presenta astigmatismo y la edad del paciente es JOVEN, entonces la
recomendación es “USAR LENTES DE CONTACTO SUAVES”.

3. Si la “TASA DE PRODUCCIÓN DE LÁGRIMAS” es “NORMAL” y SI


presenta astigmatismo y la edad del paciente es “PRE_PRESBYOPIC”,
entonces la recomendación es “USAR LENTES DE CONTACTO SUAVES”.

4. Si la “TASA DE PRODUCCIÓN DE LÁGRIMAS” es “NORMAL” y SI


presenta astigmatismo y la edad del paciente es “PRESBYOPIC”, y la

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


prescripción es MIOPIA, entonces la recomendación es “NO USAR LENTES
DE CONTACTO”.
5. Si la “TASA DE PRODUCCIÓN DE LÁGRIMAS” es “NORMAL” y SI
presenta astigmatismo y la edad del paciente es “PRESBYOPIC”, y la
prescripción es HIPERMETROPÍA, entonces la recomendación es “USAR
LENTES DE CONTACTO SUAVES”.

6. Si la “TASA DE PRODUCCIÓN DE LÁGRIMAS” es “NORMAL” ” y NO


presenta astigmatismo y la prescripción es MIOPIA, entonces la recomendación
es “USAR LENTES DE CONTACTO DUROS”.

7. Si la “TASA DE PRODUCCIÓN DE LÁGRIMAS” es “NORMAL” ” y NO


presenta astigmatismo y la prescripción es HIPERMETROPÍA, y la edad del
paciente es “JOVEN”, entonces la recomendación es “USAR LENTES DE
CONTACTO DUROS”.

8. Si la “TASA DE PRODUCCIÓN DE LÁGRIMAS” es “NORMAL” ” y NO


presenta astigmatismo y la prescripción es HIPERMETROPÍA, y la edad del
paciente es “PRE_PRESBYOPIC”, entonces la recomendación es “NO USAR
LENTES DE CONTACTO”.

9. Si la “TASA DE PRODUCCIÓN DE LÁGRIMAS” es “NORMAL” ” y NO


presenta astigmatismo y la prescripción es HIPERMETROPÍA, y la edad del
paciente es “PRESBYOPIC”, entonces la recomendación es “NO USAR
LENTES DE CONTACTO”.

Una vez obtenido el árbol, se definen funciones para cada nodo del árbol. Para este
ejemplo se decidió la convención ilustrada en la siguiente gráfica, en la cual se observa
que el proceso 0, indaga por la tasa de producción de lágrimas; el proceso 1b, por el
astigmatismo; el proceso 2ba, por la edad del paciente; el proceso 2bb, por la
prescripción; el proceso 3bac, por prescripción, el cual es diferente al proceso 2bb, a
pesar de que ambos hacen la misma pregunta, las decisiones que se toman con la
respuesta son diferentes; el proceso 3bbb, por la edad del paciente, el cual es diferente
que el proceso 2ba, por las mismas razones esgrimidas antes.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


pregunta(1, Respuesta):-combo_select(`TASA DE PRODUCCIÓN DE LÁGRIMAS?`,
[`REDUCIDA`,`NORMAL`], Respuesta ).

pregunta(2, Respuesta):-combo_select(`TIENE ASTIGMATISMO?`, [`SI`,`NO`], Respuesta ).

pregunta(3, Respuesta):-combo_select(`QUE PRESCRIPCIÓN TIENE?`,


[`MIOPIA`,`HIPERMETROPIA`], Respuesta ).

pregunta(4, Respuesta):-combo_select(`CUAL ES LA EDAD DEL PACIENTE?`,


[`JOVEN`,`PRE-PRESBIOPICO`,`PRESBIOPICO`], Respuesta ).

recomendacion_lentes(Clase, Recomendacion):-(Clase=1->Recomendacion='Usar lente de


Contacto Suave';
Clase=2-> Recomendacion='Usar lente de Contacto Duro';
Clase=3->Recomendacion='No usar Lente de Contacto'),nl.

empezar:-bienvenida,proceso0.
proceso0:- pregunta(1, Respuesta ),
(Respuesta=`REDUCIDA`-> proceso_final(3);
Respuesta=`NORMAL` -> proceso('1b');inicio).
proceso('1b'):-pregunta(2, Respuesta ),
(Respuesta= `SI` ->proceso('2ba');
Respuesta= `NO` -> proceso('2bb'); proceso('1b')).
proceso('2ba'):-pregunta(4, Respuesta),
(Respuesta=`JOVEN`-> proceso_final(1);
Respuesta=`PRE-PRESBIOPICO`-> proceso_final(1);
Respuesta=`PRESBIOPICO`->proceso('3bac');proceso('2ba')).
proceso('2bb'):-pregunta(3, Respuesta ),
(Respuesta=`MIOPIA`->proceso_final(2);
Respuesta=`HIPERMETROPIA`->proceso('3bbb');proceso('2bb')).
proceso('3bac'):-pregunta(3, Respuesta ),
(Respuesta=`MIOPIA`->proceso_final(3);
Respuesta=`HIPERMETROPIA`->proceso_final(1);proceso('3bac')).
proceso('3bbb'):- pregunta(4, Respuesta),
(Respuesta=`JOVEN`-> proceso_final(2);
Respuesta=`PRE-PRESBIOPICO`-> proceso_final(3);
Respuesta=`PRESBIOPICO`-> proceso_final(3);proceso('3bbb')).

proceso_final(Clase):- recomendacion_lentes(Clase, M),atom_string( M,Recomendacion),


despliega_repuesta(Recomendacion) ,
continuar.

despliega_repuesta(Lente) :-
_S1 = [dlg_ownedbydesktop,ws_sysmenu,ws_caption],
_S2 = [ws_child,ws_visible,ss_center],
_S3 = [ws_child,ws_visible,ws_tabstop,bs_pushbutton],
wdcreate( respuesta, `user_dialog`, 235, 43, 402, 180, _S1 ),
wccreate( (respuesta,10000), static, `LA RECOMENDACIÓN ES`, 20, 10, 370, 20, _S2 ),
wccreate( (respuesta,10001), static, Lente, 120, 40, 170, 50, _S2 ),
wccreate( (respuesta,1000), button, `ACEPTAR`, 130, 100, 150, 30, _S3 ),
wfcreate( foo1, arial, 18, 2 ),
wfont( (respuesta,10000), foo1 ),
wfont( (respuesta,10001), foo1 ),

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


window_handler( respuesta, bienvenida_handler ),
call_dialog( respuesta, R ),
wfclose(foo1),wclose(respuesta).

continue('yes'):-proceso0,!. % dependiendo del parametro, se sigue con


otra consulta o se sale.
continue('no'):-despedida.
continuar:-message_box( yesno, 'Desea Continuar', A ), continue(A).

despedida:- _S1 = [ws_sysmenu,ws_popup,ws_caption,dlg_ownedbyprolog],


_S2 = [ws_child,ws_visible,ss_center],
_S3 = [ws_child,ws_visible,ws_tabstop,bs_pushbutton],
wdcreate( despedida, `user_dialog`, 235, 43,
533, 358, _S1 ),
wccreate( (despedida,10000), static, `Hasta pronto`,
146, 40, 240, 20, _S2 ),
wccreate( (despedida,10001), static, `Fue un placer Ayudarte`,
146, 60, 240, 20, _S2 ),
wccreate( (despedida,10002), static, `Sistemas Basados en el Conocimiento I`,
117, 90, 300, 20, _S2 ),
wccreate( (despedida,10003), static, `Facultad de Matemáticas e Ingenierías`,
117, 110, 300, 20, _S2 ),
wccreate( (despedida,10004), static, `FUNDACIÓN UNIVERSITARIA KONRAD
LORENZ-FUKL (http://www.fukl.edu)`, 16, 130, 500, 60, _S2 ),
wccreate( (despedida,1000), button, `OK`, 226,
190, 80, 20, _S3 ),
wcreate((despedida,2),grafix,``,0, 210, 533, 96,16'50000000),
wfcreate( foo, arial, 18, 0 ),
wfont( (despedida,10000), foo ),
wfont( (despedida,10001), foo ),
wfont( (despedida,10002), foo ),
wfont( (despedida,10003), foo ),
wfont( (despedida,10004), foo ),
wfont( (despedida,1000), foo ),
window_handler( despedida, bienvenida_handler ),
call_dialog( despedida, R ),
wfclose(foo),gfx_bitmap_close(fukl),gfx_bitmap_close(fukl1),wclose(despedida).

bienvenida :- _S1 = [ws_sysmenu,ws_popup,ws_caption,dlg_ownedbyprolog],


_S2 = [ws_child,ws_visible,ss_center],
_S3 = [ws_child,ws_visible,ss_left],
_S4 = [ws_child,ws_visible,ws_tabstop,bs_pushbutton],
wdcreate( bienvenida, `user_dialog`, 235,
43, 532, 325, _S1 ),
wccreate( (bienvenida,10000), static, `FUNDACIÓN UNIVERSITARIA KONRAD
LORENZ-FUKL (http://www.fukl.edu)`, 70, 10, 390, 20, _S2 ),
wccreate( (bienvenida,10001), static, `FACULTAD DE MATEMÁTICAS E
INGENIERÍAS`, 110, 30, 320, 20, _S2 ),
wccreate( (bienvenida,10002), static, `SISTEMAS BASADOS EN EL CONOCIMIENTO
I`, 110, 50, 320, 20, _S2 ),
wccreate( (bienvenida,10003), static, `BIENVENIDOS AL PROGRAMA " LENTES"`,
110, 70, 320, 20, _S2 ),
wccreate( (bienvenida,10004), static, `EL CUAL, CON UN EJEMPLO SENCILLO,
ILUSTRA EL PROCESO`, 60, 90, 420, 20, _S2 ),
wccreate( (bienvenida,10005), static, `DE CONSTRUCCIÓN DE UN SISTEMA
BASADO EN EL CONOCIMIENTO`, 60, 110, 420, 20, _S2 ),
wccreate( (bienvenida,10006), static, `SE TRATA DE RECOMENDAR UN TIPO DE
LENTE, A PARTIR DE`, 60, 130, 420, 20, _S3 ),

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


wccreate( (bienvenida,10007), static, `CIERTAS CARACTERÍSTICAS DEL
PACIENTE`, 60, 150, 420, 20, _S2 ),
wccreate( (bienvenida,1000), button, `CONTINUAR`,
210, 180, 130, 30, _S4 ),
wcreate((bienvenida,2),grafix,``,0, 210, 533, 96,16'50000000),
window_handler( bienvenida, bienvenida_handler ),
gfx_bitmap_load(fukl,'fukl.bmp'), %carga el archivo fukl.bmp del directorio local
gfx_bitmap_load(fukl1,'fukl1.bmp'), %carga el archivo fukl1.bmp del directorio local
call_dialog( bienvenida, R ),
wclose(bienvenida).

bienvenida_handler( (Window,2), msg_paint, _, _ ) :- gfx_paint( (Window,2) ),


gfx(bitmap(0,0, 533, 96,0,0,fukl1)),
gfx_end( (Window,2)).
bienvenida_handler( (Window,1000), msg_button, _, cancel ).

combo_select( Pregunta,Items, Selected ) :-_S1 =


[ws_sysmenu,ws_popup,ws_caption,dlg_ownedbyprolog],
_S2 = [ws_child,ws_visible,ws_tabstop,cbs_dropdown],
_S3 = [ws_child,ws_visible,ss_left],
_S4 = [ws_child,ws_visible,ws_tabstop,bs_pushbutton],
_S5 = [ws_child,ws_visible,ws_border],
wdcreate( combo, `user_dialog`, 272, 150, 400, 350, _S1 ),
wccreate( (combo,500), combobox, `Combo1`, 100, 60, 170, 150,
_S2 ),
wccreate( (combo,3), static, Pregunta, 50, 20, 350, 20, _S3 ),
wccreate( (combo,1), button, `OK`, 140, 140, 100, 30, _S4 ),
wcreate((combo,4),static,`iconbds`,10,10,70,54,16'50000003),
wcreate((combo,2),grafix,``,25, 200, 343, 90,16'50000000),
fcreate( combo, [], -2, 0, 0 ),
wfcreate( foo, arial, 18, 0 ),
wfont( (combo,3), foo ),
wfont( (combo,500), foo ),
fill_combo( (combo,500), Items ),
window_handler( combo, combo_handler ),
call_dialog( combo, R ),
(R=cancel->Selected=R; (P is R+1,enesimo(Selected,P,Items))),
fclose( combo ),wclose(combo),!.

combo_handler( (Window,2), msg_paint, _, _ ) :-


gfx_paint( (Window,2) ),
gfx(bitmap(0,0, 343, 90,0,0,fukl)), %tamaño de la imagen 343x90, iniciada en 0,0
gfx_end( (Window,2)).

% cuando ocurra un mensaje de cierre retorna "cancel"

combo_handler( _, msg_close, _, cancel ).

% cuando se presiona el boton "OK" retorna la seleccion

combo_handler( (Window,1), msg_button, _, Result ) :- get_selected_item( (Window,500),


Result ).

% llena el combobox con la lista de items, preseleccionando el primer item

fill_combo( Window, Items ) :-sndmsg( Window, cb_resetcontent, 0, 0, _ ),


forall( member( Item, Items ),sndmsg( Window, cb_addstring, 0, Item, _ )),
sndmsg( Window, cb_setcursel, 0, 0, _ ).

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


% Se obtiene la posición-1 del ítem seleccionado

get_selected_item( Window, R ) :- sndmsg( Window, cb_getcursel, 0, 0, R ).

%obtiene el elemento enésimo de una lista


enesimo(X,1,[X|_]).
enesimo(X,N,[_|L]):-R is N-1, enesimo(X,R,L).

Para correr este programa se debe descargar el archivo comprimido de la siguiente


dirección: http://in.solit.us/archives/download/153909, descomprimirlo en una carpeta
y luego abrirlo con winprolog(se utilizó la versión 4.2), igual que se hizo para el
ejemplo 1.
Aquí se muestra una secuencia de corrida del programa:
Al entrar el comando “empezar” se obtiene:

Al hacer clic en continuar…

Luego de seleccionar la opción “NORMAL”

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Luego de seleccionar la opción SI

Luego de elegir la opción JOVEN

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Al elegir la opción Aceptar

A elegir la opción NO

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


APÉNDICE 1
Este apéndice fue elaborado a partir del documento “WIN-PROLOG 4.2
Technical Reference” de Brian D. Steel3
PREDICADOS UTILIZADOS EN ESTE TUTORIAL PARA EL DESARROLLO
DE LA INTERFACE DE USUARIO
A continuación se hace una breve descripción de los predicados usados para la
construcción de las interfaces gráficas de usuario
• gfx_paint/1

obtiene el dispositivo de contexto recortado para comenzar gráficos


gfx_paint( Ventana )
+Ventana <window_handle>
Ejemplos
El siguiente programa crea una ventana "grafix", y le asocia un
manejador (handler), antes de mostrar la ventana
mostrar_ventana:-
wcreate( ventana, grafix, ``, 10, 10, 100, 100, 16'80800000 ),
window_handler( ventana, manejador ),
wshow(ventana, 1 ).

El manejador de ventana sólo tiene una cláusula, la cual reacciona a


mensajes "msg_paint", mediante la obtención del dispositivo de
recortado, dibujando un círculo gris, y luego liberando el dispositivo
de contexto:
manejador( ventana, msg_paint, _, _ ) :-
gfx_paint( ventana ), % obtención del contexto recortado del
dispositivo
gfx( (brush = stock(gray_brush) -> ellipse(10,10,90,90)) ), %
dibujando un círculo gris
gfx_end( ventana ). % liberando el dispositivo de contexto

3
Copyright (c) 1989-2001 Logic Programming Associates Ltda

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


• gfx_end/1
Libera el dispositivo de contexto para finalizar la graficación
gfx_end( Ventana )
+Window <window_handle> o <empty_list>
Commentarios
Esto libera el dispositivo de contexto de graficación actual, para la
Ventana con el fin de finalizar una secuencia de graficación, antes de
restaurar cualquier dispositivo de contexto guardado previamente
previamente. Si Ventana se especifica como una lista vacía, se libera
el dispositivo de contexto correspondiente a la impresora actual. Ver
ejemplo de gfx_paint/1
Notas:
Los dispositivos de contexto, tienen escasos recursos y siempre
deberían retornarse una vez se terminen de usar. Cada una de las
llamadas a gfx_begin/1 o a gfx_paint/1 debería estar acompañada
de una llamada a gfx_end/1, idealmente con una o más llamadas a
gfx/1entre ellos:
ideal_grafix( W ):-
gfx_begin( W ),
... realice una o más llamadas a gfx/1 aquí ...
gfx_end( W )
ideal_repaint( W) :-
gfx_paint( W ),
... realice una o más llamadas a gfx/1 aquí ...
gfx_end( W ).

El “subsistema GraFiX “ de WIN-PROLOG comprende un completo


conjunto de predicados, referidos genéricamente como "gfx*/n"
debido a que virtualmente todos sus nombres comienzan con las
letras "gfx". Muchos de ellos, incluyendo el predicado gfx_end/1,
están relacionados con el manejo de “dispositivos de contexto”: Ellos
constituyen el ambiente virtual en el cual se dibujan todas las gráficas
en las ventanas.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


• sndmsg/5
Envía un mensaje a una ventana
sndmsg( Ventana, Mensaje, Wparam, Lparam, Resultado )
+Ventana <window_handle>
+Mensaje <atom>
+Wparam <term>
+Lparam <term>
-Resultado <variable>
Comentarios
Esto envía el mensaje denominado Mensaje a la Ventana dada,
pasándole los parámetros Wparam y Lparam: El Resultado de la
llamada se retorna como un entero. Cada uno de los dos parámetros
puede ser de los siguientes tipos:
Tipo Significado
<integer> El entero se pasa directamente como un dato
<string> El texto de cadena se almacena en un buffer
temporal, y su dirección se pasa como un
apuntador
<atom> Este es un archivo de memoria creado con
fcreate/5: su dirección es pasada como un
apuntador

Ejemplo:
La siguiente llamada establece un archivo de memoria denominado
“buffer”, con un tamaño de 1024 bytes, con el fin de usarlo para con
sndmsg/5:
?- fcreate( buffer, [], -1, 1024, 0 ). <enter>
yes
Una vez se crea este buffer, se puede usar como un parámetro en la
llamada a sndmsg/5. La siguiente llamada envía un mensaje a la
ventana principal de WIN-PROLOG(“0”), la cual copia el título de la
ventana en el buffer, retornando el número de caracteres en el
nombre:
?- sndmsg( 0, wm_gettext, 1024, buffer, R ). <enter>
R = 10
Se puede hacer una llamada a wintxt/4 para recuperar el texto
contenido en buffer, antes de cerrarlo con fclose/1:
?- wintxt( buffer, 0, 0, T ), fclose( buffer ). <enter>
T = `W `
Notas:
Muchas operaciones en el ambiente Windows (Win32 API) son
manejados mediante el paso de mensajes a windows. Los cuales
pueden ser enviados por el mismo sistema operativo o por
aplicaciones. En tiempo de corrida, los mensajes y sus parámetros
son simplemente números, aunque la mayoría de compiladores de
Windows los proveen con nombres significativos y tipos de datos de
parámetros en tiempo de compilación. Debido a que Prolog es un
lenguaje dinámico, podría ser restrictivo limitar la denominación de
los mensajes al tiempo de compilación.

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


sndmsg/5 se ha proveído para facilitar específicamente la
programación del acceso a mensajes de windows.
El predicado sndmsg/5 , en efecto, no es nada más que un front end
para el predicado winapi/4, el cual permite que se pueda llamar
virtualmente a cualquier función el API win32( como también la
mayoría de aquellas en cualquier Librería de enlace dinámico(DLL) de
32 bits)
Este predicado soporta la mayoría de los mensajes de Windows,
incluyendo todos los documentados en la versión 2.0 del SDK de
Win32 de Microsoft.

• call_dialog/2
Llama a un diálogo modal y obtiene o verifica el resultado
call_dialog( Ventana, Resultado )
+Ventana <window_handle>
?Resultado <term>
Comentarios
Esto muestra la Ventana de diálogo dada, deshabilitando toas las
demás ventanas de nivel superior de WIN-PROLOG y espera a que el
usuario complete el diálogo: Resultado es unificado con cualquier
valor que haya sido retornado por el manejador de la ventana del
diálogo.
Ejemplo El siguiente predicado crea un diálogo muy simple con dos
botones,etiquetados con “Hola” y “Mundo”, respectivamente:

crear_dialogo :-
Dstyle = [ws_popup,ws_caption],
Bstyle = [ws_child,ws_visible,bs_pushbutton],
wdcreate( dialogo, `diálogo`, 100, 100, 170, 75, Dstyle ),
wccreate( (dialogo,1), button, `Hola`, 10, 10, 70, 30, Bstyle ),
wccreate( (dialogo,2), button, `Mundo`, 90, 10, 70, 30, Bstyle ).

Cuando se compila, y se entra el siguiente comando, se crea el


diálogo “dialogo”, pero no se depliega todavía
?- crear_dialogo. <enter>
Yes

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Para mostrar el diálogo, y retornar el texto del botón que fue
presionado, entre el siguiente comando:
?- call_dialog( dialogo, X ). <enter>
El diálogo aparecerá, deshabilitando todas las demás ventanas de
WIN-PROLOG, y si se presiona el botón "Hola", su texto en
minúsculas será retornado como sigue:
X = hola

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Notes
El ejemplo anterior usa el manejador de ventana por
defecto,window_handler/4, which simply unifica el texto en
minúsculas de cualquier botón cliqueado con Resultado. Esta acción
de unificar esta variable es lo que realmente completa el
diálogo. Los manejadores de ventanas (window handler) son
simplemente programas de aridad 4 que interceptan mensajes
destinados a una ventana(incluyendo diálogos y sus controles),
permitiendo que se puedan procesar acciones arbitrarias. Considere
el siguiente ejemplo:
manejador_boton( (dialogo,1), msg_button, _, Resultado ) :-
time( _, _, _, H, M, S, _ ),
Resultado= finished_at(H,M,S).
manejador_boton( Ventana, Mensaje, Datos, Resultado ) :-
window_handler(Ventana, Mensaje, Datos, Resultado ).
La primera cláusula detecta que un botón denominado “(boton,1)"
haya sido cliqueado y completa el diálogo retornando la estructura
“finished_at(H,M,S)" en lugar el átomo "hello". Los demás mensajes
son pasados al manejador de ventana por defecto.
El código completo sería:
crear_dialogo :-
Dstyle = [ws_popup,ws_caption],
Bstyle = [ws_child,ws_visible,bs_pushbutton],
wdcreate( dialogo, `diálogo`, 100, 100, 170, 75, Dstyle ),
wccreate( (dialogo,1), button, `Hola`, 10, 10, 70, 30, Bstyle ),
wccreate( (dialogo,2), button, `Mundo`, 90, 10, 70, 30,
Bstyle ).

manejador_boton( (dialogo,1), msg_button, _, Resultado ) :-


time( _, _, _, H, M, S, _ ),
Resultado= finished_at(H,M,S).
manejador_boton( Ventana, Mensaje, Datos, Resultado ) :-
window_handler(Ventana, Mensaje, Datos, Resultado ).

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Una vez compilado el nuevo manejador de ventana es asociado a la
ventana de diálogo con una llamada a window_handler/2, como se
muestra a continuación:

?- window_handler( dialogo, manejador_boton). <enter>


yes
Si el diálogo es invocado una vez más, y se presiona el botón
"(boton,1)" (etiquetado con "Hola"), se retorna el tiempo en lugar del
átomo "hola":
?- call_dialog( dialogo, X ). <enter>

X = finished_at(16,25,6)
Que indica la hora en que fue presionado el botón “Hola”. Si presiona
el botón “Mundo”, solo retornará R=mundo, ya que el nuevo
manejador(manejador_boton), no se definió para la ventana de ese
botón((dialogo,2)).

Si se deseara que los dos botones reaccionaran igual, se debía incluir


un predicado similar para el botón “Mundo” ((dialogo, 2)).
crear_dialogo :- Dstyle = [ws_popup,ws_caption],
Bstyle = [ws_child,ws_visible,bs_pushbutton],

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


wdcreate( dialogo, `diálogo`, 100, 100, 170,
75, Dstyle ),
wccreate( (dialogo,1), button, `Hola`, 10, 10,
70, 30, Bstyle ),
wccreate( (dialogo,2), button, `Mundo`, 90,
10, 70, 30, Bstyle ).
manejador_boton( (dialogo,1), msg_button, _,
Resultado ) :-
time( _, _, _, H, M, S, _ ),
Resultado= finished_at(H,M,S).
manejador_boton( (dialogo,2), msg_button, _, Resultado ) :-
time( _, _, _, H, M, S, _ ),
Resultado= finished_at(H,M,S).
manejador_boton( Ventana, Mensaje, Datos, Resultado ) :-
window_handler(Ventana, Mensaje, Datos, Resultado ).

Note que los diálogos “modales” y “no modales” tiene exactamente


los mismos manejadores de ventana: en efecto en WIN-PROLOG,
estos dos tipos de diálogos son lo mismo. Todo lo que determina si un
diálogo se comporta de forma modal o no modal en tiempo de
corrida, es si el diálogo es invocado por call_dialog/2 (modal) o
show_dialog/1 ( no modal).

• window_handler/2
Obtiene o establece el manejador para una ventana dada
window_handler( Ventana, Manejador )
+Ventana<atom> o <integer> en el dominio {0,1}
?Manejador <atom> o <variable>
Comentarios
Obtiene o establece el nombre de un predicado de aridad 4 que sera
usado como el Manejador para la Ventana de nivel superior(de
diálogo, de texto o de usuario). Si Manejador es una variable no
acotada, retorna el nombre del manejador existente, de otra forma,
establece que el manajador Manejador asociándolo a la Ventana.
Ejemplo
El siguiente programa usa wdcreate/7 y wccreate/8 para crear un
pequeño diálogo que contiene un pequeño botón de presionar por
defecto:
dialogo_ejemplo:-
Dstyle = [ws_visible,ws_popup,ws_caption],
Bstyle = [ws_visible,ws_child,bs_defpushbutton],
wdcreate( dialogo, `diálogo`, 10, 10, 100, 60, Dstyle ),
wccreate( (dialogo,1), button, `clic`, 10, 10, 80, 20, Bstyle ).

Una vez compilado, la siguiente llamada despliega el diálogo cerca a


la esquina superior izquierda de la pantalla(haciendo posteriormente
clic en el botón ocultará(aunque no cerrará) el diálogo)
?- dialogo_ejemplo. <enter>

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Yes

Este comportamiento es debido al manejador de ventana por defecto


para el diálogo, window_handler/4, como se puede apreciar mediante
la siguiente llamada, cuando se pregunta por el nombre del
manejador actual de la ventana “dialogo”:
?- window_handler( dialogo, H ). <enter>
H = window_handler
Ahora considere el siguiente manejador de ventana:
dialogo_manejador( (dialogo,1), msg_button, _, _ ) :-
time( _, _, _, H, M, S, _ ),
write( H-M-S ) ~> String,
wtext( (dialogo,1), String ).
dialogo_manejador( Ventana, Mensaje, Datos, Resultado ) :-
window_handler( Ventana, Mensaje, Datos, Resultado ).
La primera cláusula simplemente intercepta el mensaje "msg_button"
destinado al control del botón, "(dialogo,1)", y en vez de permitir al
botón, ocultar el diálogo, escribe el tiempo actual en una cadena,
usando esto para renombrar al botón. Todos los demás mensajes son
recogidos por la segunda cláusula, la cual simplemente se los pasa a
window_handler/4 para el procesamiento por defecto.
El código del programa completo sería:
dialogo_ejemplo:-
Dstyle = [ws_visible,ws_popup,ws_caption],
Bstyle = [ws_visible,ws_child,bs_defpushbutton],
wdcreate( dialogo, `diálogo`, 10, 10, 100, 60, Dstyle ),
wccreate( (dialogo,1), button, `clic`, 10, 10, 80, 20, Bstyle ).
dialogo_manejador( (dialogo,1), msg_button, _, _ ) :-
time( _, _, _, H, M, S, _ ),
write( H-M-S ) ~> String,
wtext( (dialogo,1), String ).
dialogo_manejador( Ventana, Mensaje, Datos, Resultado ) :-
window_handler( Ventana, Mensaje, Datos, Resultado ).

Una vez compilado este programa puede ser asociado al diálogo


“dialogo” con la siguiente llamada:
?- window_handler( dialogo, dialogo_manejador ). <enter>
yes

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Ahora, cuando se despliega el diálogo con una llamada a
dialogo_ejemplo /0, al hacer clic sobre el botón simplemente
cambiará su etiqueta desplegando el tiempo actual sin cerrar el
diálogo.
?- dialogo_ejemplo. <enter>
Yes

Notas
El window_handler/2 simplemente mantiene una base de datos local
de los nombre de las ventana de nivel superior y los nombres de sus
respectivos predicados “manejadores de ventana”: cuando un
mensaje llega a una ventana dada, se verifica esta base de datos
para buscar una coincidencia. Si se halla la ventana de nivel superior,
entonces se llama el correspondiente manejador con cuatro
argumentos:
<handler>( Ventana, Mensaje, Datos, Resultado )
Los primeros tres argumentos son acotados como sigue:
Ventana contiene el manejador de la ventana que recibe el mensaje
(<window_handle>),
Mensaje contiene el nombre del mensaje(<atom> if known, otherwise
<integer>), y Data contiene información suplementaria (dependiendo
del mensaje).
El último argumento, Resultado, es una variable no acotada. Si el
manejador de ventana une esto a algún valor, causará la terminación
de la ventana de nivel superior(generalmente un diálogo): si la
ventana fue invocada por call_dialog/2, este valor es pasado hacia
atrás como el segundo argumento del último predicado. Considere la
siguiente variante del manejador de ventana mostrado
anteriormente:

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


dialogo_manejador ( (dialogo,1), msg_button, _, (H,M,S) ) :-
time( _, _, _, H, M, S, _ ).
dialogo_manejador ( Ventana, Mensaje, Datos, Resultado ) :-
window_handler(Ventana, Mensaje, Datos, Resultado).
El dialogo completo sería:
dialogo_ejemplo:-
Dstyle = [ws_visible,ws_popup,ws_caption],
Bstyle = [ws_visible,ws_child,bs_defpushbutton],
wdcreate( dialogo, `diálogo`, 10, 10, 100, 60, Dstyle ),
wccreate( (dialogo,1), button, `clic`, 10, 10, 80, 20, Bstyle ).

dialogo_manejador( (dialogo,1), msg_button, _, (H,M,S) ) :-


time( _, _, _, H, M, S, _ ).
dialogo_manejador( Ventana, Mensaje, Datos, Resultado ) :-
window_handler(Ventana, Mensaje, Datos, Resultado).

Esta vez la primera cláusula retorna simplemente el tiempo. Una vez


compilado, el diálogo puede ser llamado “modalmente “ como se
muestra a continuación:
?-dialogo_ejemplo.<enter>

?- call_dialog( dialogo, R ).<enter>

Al hacer clic sobre el botón, se obtiene


R=(0,7,8)

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Que indica el tiempo: 0 horas, 7 minutos y 8 segundos (12:07:08 am,
hora a la que se corrió el programa.

Para remover la asociación entre una ventana y su manejador


definido por el usuario, window_handler/2 se llama para "re-asociar"
la ventana con el manejador por defecto, window_handler/4:
?- window_handler( dialogo, window_handler ). <enter>
Ahora cuando se llame el diálogo modalmente, simplemente retorna
el nombre del botón, cuando éste sea cliqueado.
?- dialogo_ejemplo.

?- call_dialog( dialogo, R ). <enter>

Al hacer clic sobre el botón, se obtiene


R=clic

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Que indica el nombre del botón.

Note que window_handler/2 asocia solamente ventanas de “nivel


superior"(ventanas de “Diálogo”, de “Texto” y de usuario, junto con la
“ventana principal” (“0”) y la “ventana de consola” (“1”): no es
posible asociar manejadores de ventanas a controles individuales
dentro de estas ventanas. Cuando se llama a un manejador de
ventana, su primer argumento especifica la ventana precisa (de nivel
superior o de control, según sea el caso) que ha recibido el mensaje,
y corresponde al programador decidir cómo usar esta información. En
el ejemplo anterior la primer cláusula especifica la ventana exacta
(“(diálogo, 1)”) y el mensaje ("msg_button") que está siendo
procesado, pero uno de estos parámetros o los dos se pueden
especificar total o parcialmente no instanciados. Por ejemplo, la
siguiente cláusula recogería los mensajes “msg_button” para
cualquier botón de cualquier diálogo para el cual se estableció
dialogo_handler/4 como su manejador, retornando el entero ID en vez
de su nombre
dialogo_handler ( (Dialogo,ID), msg_button, _, ID ).
Cualquier predicado puede servir a un número arbitrario de ventanas
de nivel superior (en particular, window_handler/4 sirve a todas las
ventanas hasta que es reemplazado por un manejador definido por el
usuario). Adicionalmente, es posible asociar ventanas y nombre de
manejadores, llamando a window_handler/2 incluso antes de que la
ventana y/o el manejador existan. Todo lo que se requiere es que el
predicado del manejador de aridad 4 está compilado y listo para
usarse en el momento en que se cree una ventana para la cual ese
predicado sea elegido como manejador
• gfx_bitmap_load/2
Carga un objeto bitmap de un archivo de disco dado.
• wdcreate/7
Crea una ventana de diálogo

wdcreate( Ventana, Texto, Izquierda, Superior, Ancho,


Profundidad, Estilo )
+Ventana <window_handle>
+Texto <string>

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


+Izquierda <integer>
+Superior <integer>
+Ancho <integer>
+Profundidad <integer>
+Estilo <list>

Comentarios
Esto crea una “ventana de diálogo” con el manejador Ventana, el
título Texto, en la posición (Izquierda, Superior), con el tamaño
(Ancho, Profundidad) y el estilo tipo lista Estilo.
Ejemplo
El siguiente programa usa wdcreate/7 wccreate/8 para crear un
pequeño diálogo que contiene un solo botón "pulsación por defecto”:
ejemplo_wdcreate :-
Dstyle = [ws_visible,ws_popup,ws_caption],
Bstyle = [ws_visible,ws_child,bs_defpushbutton],
wdcreate( prueba, `foo`, 10, 10, 100, 60, Dstyle ),
wccreate( (prueba,1), button, `fukl`, 10, 10, 80, 20, Bstyle ).
Una vez compilado, la siguiente llamada desplegará el diálogo cerca
de la esquina superior izquierda de la pantalla(al hacer clic sobre el
botón, la ventana se ocultará, pero no se cerrará):
?- ejemplo_wdcreate. <enter>
yes

• wclose/1
cierra una ventana
wclose( Ventana )
+Ventana <window_handle>
Commentarios:
Esto cierra la ventana denominada Ventana, liberando sus recursos.
Ejemplo:
La siguiente llamada crea una pequeña ventana de usuario(MDI
child):
?- wcreate( ventana, user, ``, 100, 100, 300, 200, 0 ). <enter>
Yes

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Después de hacer clic al mouse se retorna a la “ventana de consola”,
la ventana recientemente creada se puede cerrar con el siguiente
comando:
?- wclose( foo ). <enter>
yes
Notas
Cuando se cierra una ventana de “nivel superior”(tal como un diálogo
o una ventana de usuario), se cierran también todos los controles
constituyentes de esa ventana: de esta manera pueden hacerse
varias llamadas a wcreate/8 por cada subsecuente llamada a close/1.
El número de ventanas que se pueden abrir a la vez es una función de
los recursos spare en el ambiente Windows. Sin embargo, existe un
techo límite en WIN-PROLOG que limita el número de diálogos
abiertos a 64, pero, debido a que los diáologos pueden ser creados y
cerrados a voluntad cualquier número de veces, este límite, en
general, nunca es un problema.

• wcreate/8
crea una ventana
wcreate( Ventana, Clase, Texto, Izquierda, Superior, Ancho,
Profundidad, Estilo )
+Ventana <window_handle>
+Clase <atom>
+Texto <string>
+Izquierda <integer>
+Superior <integer>
+Ancho <integer>
+Profundidad <integer>
+Estilo <integer>
Comentarios:
Esto crea una ventana con un Manejador, Clase y Texto dados, en la
posición (Izquierda, Superior), con el tamaño (Ancho, Profundidad) y
el Estilo entero. Las siguientes clases de ventanas estándar que se
pueden crear por medio de este predicado:
Clase Significado de la clase
Button control de botón

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


ComboBox Control combobox
Edit control edit
ListBox control listbox
ScrollBar control scrollbar
Static Control static

Además de las clases anteriores , Win Prolog define las siguientes


clases:

Clase Significado de la clase


Text: Ventana de Texto de WIN-PROLOG
User: Ventana de usuario de WIN-PROLOG
Grafix: Control grafix de WIN-PROLOG

Una pseudo clase denominado, “Dialog”, se usa para crear ventana


de diálogo.
La siguiente instrucción crea una pequeña ventana de usuario(MDI
Child):
?- wcreate( ventana, user, ``, 100, 100, 300, 200, 0 ). <enter>
yes

Después de hacer clic al mouse se retorna a la “ventana de consola”,


la ventana recientemente creada se puede cerrar con el siguiente
comando;
?- wclose( ventana ). <enter>
yes
Notas: El predicado wcreate/8 proporciona soporte de bajo nivel
para los otros cuatro creadores de ventana: Los predicados
wccreate/8 y wdcreate/7 tratan a Estilo como una lista de nombres de
estilo, convirtiéndolos en un entero, mientras que wtcreate/6 y
wucreate/6 no tienen parámetro de estilo, y usan un entero por
defecto.
Este es uno de la pequeña familia de predicados de WIN-PROLOG para
manipular ventanas implementadas directamente en kernel
codificado en ensamblador, permitiendo funciones especiales de bajo
nivel que pueden ser manipuladas eficientemente. La mayor parte de
los demás predicados para manipular ventanas se implementan como
una “capa delgada” sobre la todo-poderosa winapi/4 para simplificar

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


las tareas comunes de programación en Windows. A pesar de que la
mayoría de aplicaciones pueden ser satisfechas con estos predicados
simples, siempre es probable que se presenten combinaciones de
funciones que no pueden ser realizadas fácilmente con ellas. En estas
ocasiones, se puede usar winapi/4 y su predicado ayudante wintxt/4,
para acceder virtualmente a cualquier función del API de Windows al
igual que las implementadas en DLL.

• wccreate/8
Crea una ventana de control
wccreate( Ventana, Clase, Texto, Izquierda, Superior, Ancho,
Profundidad, Estilo )
+Window <window_handle>
+Clase <atom>
+Texto <string>
+Izquierda <integer>
+Superior <integer>
+Ancho<integer>
+Profundidad <integer>
+Estilo <list>
Comentarios
Esto crea una ventana con un Manejador, Clase y Texto dados, en la
posición(Izquierda, Superior), con el tamaño (Ancho, Profundidad) y la
lista de Estilo. La lista de tipos de clases de estilo se describen en
wcreate/8.
Ejemplo
El siguiente programa usa wdcreate/7 y wccreate/8 para crear un
pequeño diálogo que contiene un pequeño diálogo con un botón.
ejemplo_dialogo :-
Dstyle = [ws_visible,ws_popup,ws_caption],
Bstyle = [ws_visible,ws_child,bs_defpushbutton],
wdcreate( ejemplo, `hola esta es una prueba`, 10, 10, 200,160,
Dstyle ),
wccreate( (ejemplo,1), button, `es es un ejemplo`, 30, 10, 120, 20,
Bstyle ).

Una vez compilado, la siguiente llamada desplegará el diálogo cerca


de la esquina superior izquierda de la pantalla(Si se ha clic en el
botón, el diálogo se ocultará, pero no se cerrará)
?- ejemplo_dialogo. <enter>
yes

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Notas:
Este es uno de una familia de predicados para la creación de
ventanas de WIN-PROLOG, implementada en términos de un
predicado de más bajo nivel, wcreate/8, el cual espera un valor de
estilo entero como su argumento final. Los predicados wccreate/8 and
wdcreate/7 esperan que el estilo sea especificado como una lista de
átomos, cada uno de los cuales denota el nombre de un estilo, los
cuales son convertidos en un estilo entero; wtcreate/6 y wucreate/6
no tienen parámetro Estilo, sino que simplemente usan un estilo
entero por defecto: Entonces, todos los cuatro predicados anteriores
llaman a wcreate/8 con su estilo por defecto o calculado.

• wfcreate/4
crea una fuente
wfcreate( Fuente, Apariencia, Tamaño, Estilo )
+Font <atom>
+Face <atom>
+Size <integer>
+Style <integer> in the range [0..3]
Comentarios
Esto crea la fuente llamada “Fuente”, usando la Apariencia dada, los
puntos Tamaño y estilo Estilo; cualquier fuente que existe con el
mismo nombre se cierra antes de que la nueva fuente sea creada. Los
Estilos son listados en la siguiente tabla:
Estilo Significado
0 normal
1 italic
2 bold
3 bolditalic

Ejemplo
La siguiente llamada creará una fuente llamada “fuente”,
especificando su apariencia como “Arial”, tamaño como 16 puntos y
estilo como normal ("0"), y asigna esta fuente a la ventana de
consola("(1,1)"):

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


?- wfcreate( fuente, arial, 16, 0 ), wfont( (1,1), fuente ).
<enter>
yes
La siguiente llamada restaura la fuente de consola por defecto("OEM
fixed font")
("0"), antes de cerrar la fuente creada anteriormente:
?- wfont( (1,1), 0 ), wfclose( foo ). <enter>
yes
Notas
Cuando se crean y usan Fuentes, es importante recordar que ellas son
recursos de bajo nivel de windows, que su uso inadecuado puede
resultar en comportamientos impredecibles. En particular una fuente
nunca puede ser cerrada o redefinida mientras esté seleccionada en
una ventana(ver ejemplo de arriba) o contexto de dispositivo gráfico.
Note que las fuentes creadas con wfcreate/4 son idénticas a las
creadas por gfx_font_create/4: los predicados orientados a ventanas
wf*/n son completamente intercambiables con los predicados "Grafix"
más recientes, gfx_font*/n

• wfont/2
obtiene o establece la fuente usada por un control de ventana
wfont( Ventana, Fuente )
+Ventana <window_handle>
?Fuente <variable>, <atom>, <integer> o <tuple>
Comentarios
Esto obtiene o establece la Fuente usada actualmente para desplegar
el texto de una Ventana de control determinada: Si Fuente es una
variable no acotada, retorna la fuente de ventana existente; de otra
forma, se usa para establecer la nueva fuente de ventana.
Ejemplo
Ver wfcreate/4
Notas
Este predicado puede ser usado únicamente para establecer la fuente
a ser usada por la ventana de control: no tiene efecto sobre la barra
de títulos de la ventana de nivel superior. Igualmente para manipular
fuentes preestablecidas, se puede usar wfont/2 para obtener o fijar un
stock de seis fuentes numéricas especiales, predefinidas, así como
también cualquier handle de fuente entera, donde handle está
contenida en una tupla de la forma “font(integer)”. El stock de
fuentes se lista a continuación:

Número Significado
0 OEM fixed font
1 system font
2 system fixed font
3 ANSI var font
4 ANSI fixed font
5 device default font

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


• wfclose/1
cierra una fuente
wfclose( Fuente )
+Fuente <atom>
Commentarios
Esto cierra la denominada Fuente, liberando sus recursos.
Ejemplos
Ver wfcreate/4

Nombre de estilos de ventanas


Cuando se crea una ventana, es a menudo necesario especificar su
“estilo”: esto determina la apariencia de la ventana y sus
características de comportamiento. Algunos estilos corresponden a la
mayoría de las ventanas: visibilidad , por ejemplo, o si la ventana es
una ventana “hija” o “emergente”. Otros estilos están relacionados
con clases específicas de ventanas: un control button puede aparecer
y comportarse como un checkbox, radio button o simple pushbutton.
Cada uno de los estilos está asociado con uno o más bits en un
entero de 32 bits: el conjunto requeridos de estilos debe ser
combinado usando la función “o inclusiva”, pasándolo antes a
wcreate/8 para crear una ventana. Por ejemplo, el siguiente programa
crea una ventan de diálogo con estilos combinados, "ws_visible",
"ws_popup" y "ws_caption", conteniendo un control "button" con los
estilos combinados, "ws_visible", "ws_child" and "bs_defpushbutton".
ejemplo :-
wcreate( prueba, dialog, `prueba`, 10, 10, 100, 60, 16'90C00000 ),
wcreate( (prueba,1), button, `bar`, 10, 10, 80, 20, 16'50000001 ).
Para hacer más fácil la especificación de la ventana, WIN-PROLOG
incluye dos predicados adicionales para la creación de ventanas,
wdcreate/7 y wccreate/8, en los cuales el argumento final “Estilo”
puede ser presentada como una lista de nombres de estilo, en vez de
un entero; el siguiente programa produce exactamente el mismo
diálogo que antes, pero usa lista de estilos en lugar de estilos enteros
precomputados:

ejemplo :-
Dstyle = [ws_visible,ws_popup,ws_caption],
Bstyle = [ws_visible,ws_child,bs_defpushbutton],
wdcreate( prueba, `prueba`, 10, 10, 100, 60, Dstyle ),
wccreate( (prueba,1), button, `bar`, 10, 10, 80, 20, Bstyle ).

Los dos predicados adicionales, wtcreate/6 y wucreate/6, crean


ventana de “texto” y de “usuario”(MDI Child) respectivamente: estas
dos tipos de ventanas tienen estilos predefinidos, por lo tanto estos
predicados omiten el parámetro estilo

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Notese que no todos los tipos de estilo pueden ser combinados: un
botón, por ejemplom no puede se simultáneamente un checkbox
("bs_checkbox"), radio button ("bs_radiobutton") y el pushbutton por
defecto("bs_defpushbutton").
El conjunto completo de nombres de estilo que pueden ser usadas en
wdcreate/7 y wccreate/8, junto con los tipos de ventana a las cuales
ellos pueden corresponder, son listados a continuación.
Estilos Genéricos
Estos son los estilos que pueden ser aplicados a más de una clase de
ventana.
Estilo Valor
ws_overlapped 16'00000000
ws_popup 16'80000000
ws_child 16'40000000
ws_minimize 16'20000000
ws_visible 16'10000000
ws_disabled 16'08000000
ws_clipsiblings 16'04000000
ws_clipchildren 16'02000000
ws_maximize 16'01000000
ws_caption 16'00C00000
ws_border 16'00800000
ws_dlgframe 16'00400000
ws_vscroll 16'00200000
ws_hscroll 16'00100000
ws_sysmenu 16'00080000
ws_thickframe 16'00040000
ws_minimizebox 16'00020000
ws_maximizebox 16'00010000
ws_group 16'00020000
ws_tabstop 16'00010000

Estilos de Edit
Estos son los estilos que pueden ser aplicados a los controles edit
Estilo Valor
es_left 16'00000000
es_center 16'00000001
es_right 16'00000002
es_multiline 16'00000004
es_uppercase 16'00000008
es_lowercase 16'00000010
es_password 16'00000020
es_autovscroll 16'00000040
es_autohscroll 16'00000080
es_nohidesel 16'00000100
es_oemconvert 16'00000400
es_readonly 16'00000800
es_wantreturn 16'00001000

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


Estilos de Listbox
Estos son los estilos que pueden aplicarse a los controles listbox
Estilo Valor
lbs_notify 16'00000001
lbs_sort 16'00000002
lbs_noredraw 16'00000004
lbs_multiplesel 16'00000008
lbs_ownerdrawfixed 16'00000010
lbs_ownerdrawvariable 16'00000020
lbs_hasstrings 16'00000040
lbs_usetabstops 16'00000080
lbs_nointegralheight 16'00000100
lbs_multicolumn 16'00000200
lbs_wantkeyboardinput 16'00000400
lbs_extendedsel 16'00000800
lbs_disablenoscroll 16'00001000

Estilos de Combobox
Estos son los estilos que pueden aplicarse a los controles combobox:
Estilo Valor
cbs_simple 16'00000001
cbs_dropdown 16'00000002
cbs_dropdownlist 16'00000003
cbs_ownerdrawfixed 16'00000010
cbs_ownerdrawvariable 16'00000020
cbs_autohscroll 16'00000040
cbs_oemconvert 16'00000080
cbs_sort 16'00000100
cbs_hasstrings 16'00000200
cbs_nointegralheight 16'00000400
cbs_disablenoscroll 16'00000800

Estilos Estaticos
Estos son los estilos que pueden aplicarse a los controles estáticos
Estilo Valor
ss_left 16'00000000
ss_center 16'00000001
ss_right 16'00000002
ss_icon 16'00000003
ss_blackrect 16'00000004
ss_grayrect 16'00000005
ss_whiterect 16'00000006
ss_blackframe 16'00000007
ss_grayframe 16'00000008
ss_whiteframe 16'00000009
ss_simple 16'0000000B

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS


ss_leftnowordwrap 16'0000000C
ss_noprefix 16'00000080

Estilos de Scrollbar
Estos son los estilos que pueden aplicarse a los controles scrollbar:

Estilo Valor
sbs_horz 16'00000000
sbs_vert 16'00000001
sbs_topalign 16'00000002
sbs_leftalign 16'00000002
sbs_bottomalign 16'00000004
sbs_rightalign 16'00000004
sbs_sizebox 16'00000008

FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS

Vous aimerez peut-être aussi