SWING
Para la implementación de un graficador de funciones de una variable real primero necesitamos definir una interfaz gráfica, es decir, los componentes necesarios y cómo acomodarlos. Después de crear un método de graficación, necesitamos definir el manejo de eventos de botón, de campo de texto y de ratón para interactuar de manera adecuada con el usuario.
Esta presentación se inicia describiendo la manera en se pueden crear y acomodar los componentes del graficador usando la interfaz gráfica de usuario (GUI) Swing. Luego se implementa un método que lee una función introducida por el usuario y construye su gráfico en el dominio de pantalla usando Java2D. Por último se maneja los eventos de mouse para interactuar con el gráfico.
Interfaz gráfica. Administradores de diseño.
Una primera vista de nuestro graficador se puede apreciar en la siguiente figura
Este graficador tiene una zona en la que aparecerá el gráfico, un panel para el logo, un panel de control donde aparecen los botones "Graficar" y "Ayuda" y un campo de texto para introducir la función. También hay un panel para poner dos barras de desplazamiento (sliders) para manejar la escala en los ejes.
Todos estos componentes están dentro de un 'Container' llamado aquí "Contenedor". Para manejar de una manera adecuada los bordes, algunos componentes se agrupan en un componente más grande, como se detalla en la figura que sigue
O sea, el "contenedor" incluye el panel "DisplayPanel1" donde estará el panel de graficación "ZG" y el panel "DisplayPanel2" donde estarán los paneles "LogoPanel", "ControlPanel" y "SliderPanel"
El código para generar este applet requiere importar algunas bibliotecas de Swing. Los comentarios del código están inmediatamente después.
Un 'parser' para leer la función
Para graficar una función necesitamos
Leer la función
Calcular los pares ordenados y unirlos con un segmento de recta
Para leer la función debemos usar un 'parser', es decir una clase que nos permita leer y evaluar la fórmula que define a la función. Aquí, en vez de implementar un 'parser' (que sería bastante laborioso), vamos a usar uno que está disponible de manera gratuita en internet: JEP (Java Expression Parser,http://sourceforge.net/projects/jep/). Al momento de esta publicación, la versión actual es la 2.3.1
Primero vamos a implementar un pequeño applet para ver como usar el evaluador
La manera fácil para poder usar JEP con el IDE JCreator (http://www.jcreator.com/) es descargar JEP y poner la carpeta 'org' (que viene en la subcarpeta 'build') en la subcarpeta 'classes' del proyecto.
Si usa otro IDE, deberá hacer los cambios adecuados para que Java pueda encontrar el archivo jep231.jar.
En nuestro programa, se deben importar dos bibliotecas
import org.nfunk.jep.*; import org.nfunk.jep.type.*;
La segunda biblioteca nos permite un buen manejo de los números complejos, para trabajar con funciones como 
|
|
Método de graficación.
Ahora que podemos leer funciones y evaluarlas, ya podemos implementar el método que construye el gráfico de la función.
> Coordenadas de pantalla y coordenadas reales
Primero debemos establecer un factor de escala para el eje X y el eje Y. Digamos 'escalaX = 30 pixeles' y 'escalaY=30 pixeles'.
Ahora debemos manejar la conversión entre coordenadas en números reales y coordenadas de pantalla. Supongamos que la variable 'aReal' corresponde al valor como número real de la coordenada de pantalla 'a'
- Conversión: números reales a coordenadas de pantalla
a = (int)Math.round(escalaX * (aReal ) );
- Conversión: coordenadas de pantalla a números reales
aReal = 1.0*a/escalaX;
Manejo de eventos
Bien, ya tenemos casi todos los ingredientes. Sólo falta agregar el manejo de eventos, es decir,
si el usuario presiona el botón graficar o da enter en el campo de texto de la función, se debe dibujar el gráfico
si el usuario arrastra el mouse sobre la zona gráfica, se debe arrastrar el gráfico
si el usuario usa los deslizadores (sliders) se ejecuta el cambio de escala en el eje respectivo
si el usuario entra al panel del logo (el mouse entra al panel) entonces el curso cambia a una "manita" indicando que, dando un clic o doble clic, irá al sitio web del CRV.
un frame de ayuda (acerca de la sintaxis de las fucniones)
Para hacer estas tareas debemos implementar los manejadores de eventos respectivos.
I. Manejador de eventos para campo de texto y para botón
Agregamos un auditor (listener) al campo de texto y al botón que "escucha" los eventos de 'dar enter' en el campo de texto o presionar el botón. Cuando esto sucede, solamente ejecutamos ZG.repaint(); con lo que se ejecuta el método gráfico en el panel ZG
... public void init() { ...
ManejadorDeEvento ManejadorDevt = new ManejadorDeEvento(); Tffun.addActionListener(ManejadorDevt); BtnGraficar.addActionListener(ManejadorDevt); }//
private class ManejadorDeEvento implements ActionListener { public void actionPerformed (ActionEvent evt) { Object source = evt.getSource (); // si se presiona el botón o se da 'enter' en algún campo de texto if ( source == BtnGraficar || source == Tffun) { ZG.repaint(); } } } |
II. Arrastre del mouse
Para implementar la respuesta al arrastre del mouse, debemos localizar el punto inicial de arrastre A y el punto final B y redefinir el origen (x0,y0) de acuerdo al vector B-A. Esto lo hacemos en la clase interna 'ZonaGrafica'

class ZonaGrafica extends JPanel implements MouseListener, MouseMotionListener { int offsetX, offsetY; boolean dragging;
ZonaGrafica() { offsetX=x0; offsetY=y0; addMouseListener(this); //auditores para eventos de mouse addMouseMotionListener(this); } //manejo de eventos de mouse public void mousePressed(MouseEvent evt) { if (dragging) return; int x = evt.getX(); // clic inicial int y = evt.getY(); offsetX = x - x0; offsetY = y - y0; dragging = true; }
public void mouseReleased(MouseEvent evt) { dragging = false; repaint(); }
public void mouseDragged(MouseEvent evt) { if (dragging == false) return; int x = evt.getX(); // posición del mouse int y = evt.getY(); x0 = x - offsetX; // mover origen usando suma vectorial y0 = y - offsetY; repaint(); }
//el resto hace nada public void mouseMoved(MouseEvent evt) {} public void mouseClicked(MouseEvent evt) { } public void mouseEntered(MouseEvent evt) { } public void mouseExited(MouseEvent evt) { }
public void paintComponent(Graphics g) { ... |
III. Deslizadores (sliders)
Agregar un par de deslizadores en el panel SP (instancia de SliderPanel) y un manejador de eventos que escuchan si hay algún cambio en cada deslizador. Si se escucha algún cambio, se redefine la variable escalaX o la variable escalaY, según corresponda y se ejecuta ZG.repaint() para actualizar en 'tiempo real'.
import javax.swing.event.*;...
class SliderPanel extends JPanel { JSlider xSlider,ySlider; // Manejo de escala
SliderPanel() { setLayout(new GridLayout(1,2)); SliderListener auditor = new SliderListener(); //escala X xSlider = new JSlider(JSlider.VERTICAL, 1, 200, 20); xSlider.addChangeListener(auditor); add(xSlider); //escalaY ySlider = new JSlider(JSlider.VERTICAL, 1, 200, 20); ySlider.addChangeListener(auditor); add(ySlider);
//xSlider.setLabelTable(xSlider.createStandardLabels(20)); //xSlider.setMajorTickSpacing(200); xSlider.setMinorTickSpacing(20); xSlider.setPaintTicks(true); xSlider.setPaintLabels(true);
//ySlider.setMajorTickSpacing(200); ySlider.setMinorTickSpacing(20); ySlider.setPaintTicks(true); ySlider.setPaintLabels(true); }//
class SliderListener implements ChangeListener { public void stateChanged(ChangeEvent e) { JSlider source = (JSlider)e.getSource(); ajusteEscala();
} }
public void ajusteEscala() { // se ejecuta si se 'oyó' algún cambio en algún Slider escalaX =(int) xSlider.getValue(); escalaY =(int) ySlider.getValue(); ZG.repaint(); }// } //fin class |
IV. Implementar LogoPanel
El manejo propuesto en LogoPanel no requiere mucho detalle, solo agregar una propiedad que defina comportamiento requerido. Esta propiedad se la podemos agregar en init().
... public void init() { ... //Logopanel LogoPanel = new JPanel(); LogoPanel.add(new JLabel(logocrv)); LogoPanel.addMouseListener (new MouseAdapter () { public void mouseClicked (MouseEvent e) { if(e.getClickCount() >0) { try{URL elURL= new URL("http://www.tec-digital.itcr.ac.cr/revistamatematica/crv/index.html"); getAppletContext().showDocument(elURL); }catch(MalformedURLException ae){} } } });
LogoPanel.setCursor(new Cursor(Cursor.HAND_CURSOR)); //fin logoPanel
... |
V. Ventana (JFrame) de ayuda
Para la ventana de ayuda creamos un JFrame con un JTextArea con algunas indicaciones acerca d ela sintaxis de las funciones en JEP. Debemos agregar un auditor al botón 'Ayuda' para que levante la ventana cuando es presionado.
...public void init() { ...
BtnAyuda.addActionListener(ManejadorDevt); }
...
private class ManejadorDeEvento implements ActionListener { public void actionPerformed (ActionEvent evt) { Object source = evt.getSource (); ... if(source == BtnAyuda) { fFrame.setVisible (true); }// } }//
class AyudaJFrame extends JFrame {
JTextArea p;
GraficadorClasico fApplet;
AyudaJFrame(GraficadorClasico applet) { super ("Ayuda"); fApplet=applet; Container content_pane = getContentPane ();
p = new JTextArea(30,40); p.setText(information()); p.setEditable(false);
JScrollPane sp = new JScrollPane(p); content_pane.add(sp,BorderLayout.CENTER);
pack (); setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE); }
public void actionPerformed (ActionEvent e) { //nada por hoy }
String information(){ String message = " :.\n" + " Mover ejes : arrastre el mouse\n\n" +" ------ ------ EJEMPLO\n" + " + suma x+2\n" + " - resta x-5\n" + " * multiplicación 3*x\n" + " / división -1/x\n" + " () agrupación (x+2)/(3*x)\n" + " ^ potenciación (-3*x)^2\n" + " % resto de la división x%5\n" + " RAIZ(x) raíz cuadrada RAIZ(x)\n" + " sqrt() raíz cuadrada sqrt(x)\n" + " mod() resto de la división mod(x,5)\n" + " sen() seno 4*sen(x^2)\n" + " cos() coseno 6*cos(-3*x)\n" + " tan() tangente 3*tan(x)\n" + " atan() arcotangente atan(x-3)\n" + " asin() arcoseno asen((x+5)/(3^x))\n" + " acos() arcocoseno 2-acos(-x+3)\n" + " sinh() seno hiperbólico sinh(x)\n" + " cosh() coseno hiperbólico -3*cosh(1/x)\n" + " tanh() tangente hiperbólica tanh(x)/2\n" + " asinh() arcoseno hiperbólico 2*asinh(x)/3\n" + " acosh() arcocoseno hiperbólico (2+acosh(x))/(1-x)\n" + " atanh() arcotangente hiperbólica atanh(x)*(3-x^(1/x))\n" + " ln() logaritmo natural ln(x)+1\n" + " log() logaritmo decimal -2*log(x)-1\n" + " abs() valor absoluto abs(x-2)\n" + " rand() valor aleatorio rand()\n" + " re() parte real de un Complejo re(2+9*i)\n" + " im() parte imaginaria im(-8+7*i)\n" + " angle() ángulo en pos. estándar angle(x,2)\n\n" + " pi 3,141592653589793 pi+cos(x)\n" + " e 2,718281828459045 e+1\n" + " Usa JEP,(Nathan Funk http://sourceforge.net/projects/jep/\n\n";
return message; }//información
} // class AyudaFrame |
|
|
|
No hay comentarios:
Publicar un comentario