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 'LEON' 'MUSARAÑA' 'CABALLO' 'COCODRILO' 'CAMALEON' 'TORTUGA DE TIERRA’ 'AGUILA' 'GOLONDRINA' 'PERDIZ'
CLASE Mamífero Mamífero Mamífero Reptil Reptil Reptil Ave Ave Ave
ALIMENTACION carnivoro insectivoro herbivoro carnivoro insectivoro herbivoro carnivoro insectivoro 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 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).
Análisis El león es un mamífero que se alimenta de carne o de otros animales La musaraña es un mamífero que se alimenta de insectos El caballo es un mamífero que se alimenta de vegetales El cocodrilo es un reptil que se alimenta de carne o de otros animales El camaleón es un reptil que se alimenta de insectos
animal('AGUILA'):clase(ave),alimentacion(carnivoro).
Este predicado indica que no hay un reptil que se alimente con sólo vegetales El águila es un ave que se alimenta de carne.
animal('GOLONDRINA'):clase(ave),alimentacion(insectivoro).
La golondrina es un ave que se alimenta de insectos.
animal('PERDIZ'):clase(ave),alimentacion(herbivoro).
La perdiz es un ave que se alimenta de vegetales.
animal('TORTUGA DE TIERRA'):clase(reptil),alimentacion(herbivoro).
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 write('............HASTA PRONTO............').
'),nl,
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 argumento. Siempre se elimina por el principio del programa. rectractall/ Elimina todas las cláusulas que unifiquen con el 1 argumento. retract/1
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, pregunta2 pregunta2, consultar,!.
% empezar ejecuta las funciones de pregunta1, % y hacer la consulta.
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(_)), ingresado por las opciones del usuario, retract(alimentacion(_)),!. continue('yes'):-empezar,!. otra consulta o se sale. continue('no'):-despedida.
% limpiar_base limpia la base de lo % para ejecutar una nueva consulta % dependiendo del parametro, se sigue con
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 TE PRESCRIPCION JOVEN MIOPIA
ASTIGMATISM O SI
TASA_DE_PRODUCCION_LAG RIMAS REDUCIDA
JOVEN JOVEN
MIOPIA MIOPIA
SI NO
NORMAL REDUCIDA
JOVEN
MIOPIA HIPERMETROPI A HIPERMETROPI A HIPERMETROPI A HIPERMETROPI A
NO
NORMAL
SI
REDUCIDA
SI
NORMAL
NO
REDUCIDA
NO
NORMAL
MIOPIA
SI
REDUCIDA
PRE_PRESBIOPICO PRE_PRESBIOPICO
MIOPIA MIOPIA
SI NO
NORMAL REDUCIDA
PRE_PRESBIOPICO
MIOPIA HIPERMETROPI A HIPERMETROPI A HIPERMETROPI
NO
NORMAL
SI
REDUCIDA
SI NO
NORMAL REDUCIDA
JOVEN JOVEN JOVEN JOVEN PRE_PRESBIOPIC O1
PRE_PRESBIOPICO PRE_PRESBIOPICO PRE_PRESBIOPICO
LENTE_RECOMENDADO NO_LENTE_CONTACTO LENTE_CONTACTO_SUA VE NO_LENTE_CONTACTO LENTE_CONTACTO_DU RO NO_LENTE_CONTACTO LENTE_CONTACTO_SUA VE NO_LENTE_CONTACTO LENTE_CONTACTO_DU RO NO_LENTE_CONTACTO LENTE_CONTACTO_SUA VE NO_LENTE_CONTACTO LENTE_CONTACTO_DU RO NO_LENTE_CONTACTO LENTE_CONTACTO_SUA VE 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
PRE_PRESBIOPICO PRESBIOPICO PRESBIOPICO PRESBIOPICO PRESBIOPICO PRESBIOPICO PRESBIOPICO PRESBIOPICO PRESBIOPICO
A HIPERMETROPI A MIOPIA MIOPIA MIOPIA MIOPIA HIPERMETROPI A HIPERMETROPI A HIPERMETROPI A HIPERMETROPI A
NO SI SI NO
NORMAL REDUCIDA NORMAL REDUCIDA
NO_LENTE_CONTACTO NO_LENTE_CONTACTO NO_LENTE_CONTACTO NO_LENTE_CONTACTO LENTE_CONTACTO_DU RO
NO
NORMAL
SI
REDUCIDA
SI
NORMAL
NO_LENTE_CONTACTO LENTE_CONTACTO_SUA VE
NO
REDUCIDA
NO_LENTE_CONTACTO
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
+Wparam +Lparam -Resultado 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 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 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 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 o en el dominio {0,1} ?Manejador o 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: ( 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( if known, otherwise ), 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 +Superior +Ancho +Profundidad +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 +Texto <string> +Izquierda +Superior +Ancho +Profundidad +Estilo 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 Edit ListBox ScrollBar Static
Control combobox control edit control listbox control scrollbar Control static
Además de las clases anteriores , Win Prolog define las siguientes clases: Clase Text: User: Grafix:
Significado de la clase Ventana de Texto de WIN-PROLOG Ventana de usuario de WIN-PROLOG 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 +Texto <string> +Izquierda +Superior +Ancho +Profundidad +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 +Face +Size +Style 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 , , o 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 0 1 2 3 4 5
Significado OEM fixed font system font system fixed font ANSI var font ANSI fixed font device default font
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS
• wfclose/1 cierra una fuente wfclose( Fuente ) +Fuente 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 ss_noprefix
16'0000000C 16'00000080
Estilos de Scrollbar
Estos son los estilos que pueden aplicarse a los controles scrollbar: Estilo sbs_horz sbs_vert sbs_topalign sbs_leftalign sbs_bottomalign sbs_rightalign sbs_sizebox
Valor 16'00000000 16'00000001 16'00000002 16'00000002 16'00000004 16'00000004 16'00000008
FUNDACIÓN UNIVERSITARIA KONRAD LORENZ-INGENIERÍA DE SISTEMAS