?? java7.htm
字號:
<HTML>
<HEAD>
<TITLE>Java desde Cero</TITLE>
</HEAD>
<BODY background=/iconos/1.gif TEXT=000000 LINK=FF0000 VLINK=A62A2A>
<H1>Java a través de la ventana<BR>
</H1>
<P>
Para hacer algo un poco más divertido, vamos a empezar
a trabajar con la biblioteca java.awt, que es la que contiene
todo un grupo de objetos para trabajar con ventanas y sus contenidos:
botones, listas, etc.<BR>
<H2>Nuestra primera ventana</H2>
<P>
En Java, la clase <B>Window</B> (descendiente de <B>Container</B>),
en la biblioteca <I>java.awt</I>, permite implementar ventanas
"peladas", es decir, sin bordes ni menús. Son
la base para cualquier tipo de ventanas (normales, pop-up, diálogos,
etc.). El otro descendiente de <B>Container</B>, <B>Panel</B>,
es más sencillo aún y sirve como espacio para que
una aplicación incorpore dentro suyo otros elementos (incluyendo
otros paneles).
<P>
La interface Java dirige tanto a uno como a otro todos los eventos
de teclado, mouse y foco que los afecten (en seguida veremos cómo
usar estos eventos).
<P>
De la clase <B>Window</B> descienden <B>Dialog</B> (para implementar
diálogos) y <B>Frame</B>, que es una ventana algo más
completa: ya tiene borde y menú, así como los botones
de cerrar, maximizar, etc.
<P>
El siguiente ejemplo crea una ventana que no hace nada pero contiene
varios elementos; se puede usar directamente (desde la ventana
DOS o Unix con <I>java Ejemplo7</I>) o como applet dentro de una
página HTML.
<P>
Si bien los elementos no disparan ninguna acción, se pueden
utilizar con toda su funcionalidad (por ejemplo, editar el texto
dentro de los cuadros de texto o presionar el botón).<BR>
<PRE>
<FONT SIZE=2>// grabar como "Ejemplo7.java"
// compilar con "javac Ejemplo7.java"
import java.awt.*;
public class Ejemplo7 extends Frame {
boolean inAnApplet = true;
public static void main(String args[]) {
Ejemplo7 window = new Ejemplo7();
window.inAnApplet = false;
window.setTitle("Ejemplo");
window.pack();
window.show();
}
public Ejemplo7() {
Panel panelAlto = new Panel();
panelAlto.add("West", new Label("Cartel", Label.CENTER));
panelAlto.add("East", new TextArea("Area de texto", 5, 20));
add("North", panelAlto);
Panel panelBajo = new Panel();
panelBajo.add(new TextField("Campo de Texto"));
panelBajo.add(new Button("Botón"));
add("South",panelBajo);
}
public boolean handleEvent(Event ev) {
if (ev.id == Event.WINDOW_DESTROY) {
if (inAnApplet) {
dispose();
} else {
System.exit(0);
}
}
return super.handleEvent(ev);
}
}<BR>
</FONT>
</PRE>
<H3>Un poco de detalle</H3>
<P>
La clase desciende de <B>Frame</B> (o sea que será una
ventana con borde, aunque no le vamos a poner menú).
<P>
Vamos a usar el flag <B>inAnApplet</B> para saber si se arrancó
como applet o como aplicación standalone (hay que cerrarla
en manera diferente en cada caso)
<PRE>
<FONT SIZE=2>public class Ejemplo7 extends Frame {
boolean inAnApplet = true;</FONT>
</PRE>
<P>
Si se llama como aplicación standalone, lo primero que
se ejecuta es <FONT FACE="Arial">main(...)</FONT>; en este caso
la aplicación crea una instancia de <FONT FACE="Arial">Ejemplo7</FONT>
(ejecutando el constructor <FONT FACE="Arial">Ejemplo7()</FONT>
a través de <I>new</I>), define que <B>no</B> es un applet,
y llama a tres métodos de la "abuela" window:
<UL>
<LI><FONT FACE="Arial">setTitle</FONT> que define cuál
va a ser el título que aparece en la ventana
<LI><FONT FACE="Arial">pack</FONT> que dimensiona los elementos
que componen la ventana a su tamaño preferido
<LI><FONT FACE="Arial">show</FONT> que muestra la ventana
</UL>
<P>
<PRE>
<FONT SIZE=2>public static void main(String args[]) {
Ejemplo7 window = new Ejemplo7();
window.inAnApplet = false;
window.setTitle("Ejemplo");
window.pack();
window.show();
}<BR>
</FONT>
</PRE>
<P>
Ojo! No confundir el objeto (instancia) <FONT FACE="Arial">window</FONT>
con la clase <B>Window</B>!
<P>
Si se carga como applet, entonces se ejecuta el constructor <FONT FACE="Arial">Ejemplo7()</FONT>
como en el caso anterior:<BR>
<PRE>
<FONT SIZE=2>public Ejemplo7() {
Panel panelAlto = new Panel();
panelAlto.add("West", new Label("Cartel", Label.CENTER));
panelAlto.add("East", new TextArea("Area de texto", 5, 20));
add("North", panelAlto);
Panel panelBajo = new Panel();
panelBajo.add(new TextField("Campo de Texto"));
panelBajo.add(new Button("Botón"));
add("South",panelBajo);
}<BR>
</FONT>
</PRE>
<P>
Este constructor define dos paneles que forman el contenido de
la ventana (panelAlto y panelBajo), los llena con un par de componentes
y los pone dentro de la ventana (recordar que <FONT FACE="Arial">Ejemplo7</FONT>
es una ventana!).
<P>
Para verlo más claro, se crea el panel (o espacio para
contener objetos) con:
<PRE>
<FONT SIZE=2> Panel panelAlto = new Panel();<BR>
</FONT>
</PRE>
<P>
Se agregan componentes al panel con el método <FONT FACE="Arial">add</FONT>:
<PRE>
<FONT SIZE=2> panelAlto.add("West", new Label("Cartel", Label.CENTER));
panelAlto.add("East", new TextArea("Area de texto", 5, 20));
<BR>
</FONT>
</PRE>
<P>
Se agregan el panel dentro de nuestro objeto con:
<PRE>
<FONT SIZE=2> add("North", panelAlto);</FONT>
</PRE>
<P>
que equivale a:
<PRE>
<FONT SIZE=2> this.add("North", panelAlto);</FONT>
</PRE>
<P>
lo que se puede ver (aunque es inválido porque la clase
no es static) como:
<PRE>
<FONT SIZE=2> Ejemplo7.add("North", panelAlto);</FONT>
</PRE>
<P>
Como nuestra clase <FONT FACE="Arial">Ejemplo7</FONT> desciende
de <FONT FACE="Arial">Frame</FONT>, ésta de <FONT FACE="Arial">Window</FONT>,
y ésta de <FONT FACE="Arial">Container</FONT>, el método
<I>add</I> lo está heredando de... su bisabuela! Por otra
parte, <FONT FACE="Arial">Panel</FONT> es hija de <FONT FACE="Arial">Container</FONT>,
y usa el mismo método para agregar sus componentes. Interesante,
no? Veamos la estructura:<BR>
<PRE>
<FONT SIZE=2>Object --- Component --- Container --+-- Panel
|
+-- Window --- Frame --- Ejemplo7
</FONT>
</PRE>
<P>
Noten que hemos usado dos métodos <FONT FACE="Arial">add</FONT>
con diferente <I>signature</I>:
<PRE>
<FONT SIZE=2> panelAlto.add("West", new Label("Cartel", Label.CENTER));
..........
panelBajo.add(new Button("Botón"));<BR>
</FONT>
</PRE>
<P>
El método <FONT FACE="Arial">add(Component)</FONT> agrega
un componente al final; el método <FONT FACE="Arial">add(String,Component)</FONT>
lo agrega en un lugar especificado por una palabra que depende
del <I>LayoutManager</I>, el objeto que se encarga de ordenar
los componentes dentro del contenedor.
<P>
<I>LayoutManager</I> es una <I>interface</I>, y como tal debe
implementarse a través de objetos no abstractos de los
que hay varios predefinidos en la librería java.awt: <FONT FACE="Arial">BorderLayout,
CardLayout, FlowLayout, GridBagLayout</FONT> y <FONT FACE="Arial">GridLayout</FONT>.
<P>
El Layout por defecto es BorderLayout, que define en el contenedor
las áreas "<FONT FACE="Arial">North</FONT>",
"<FONT FACE="Arial">South</FONT>", "<FONT FACE="Arial">West</FONT>",
"<FONT FACE="Arial">East</FONT>" y "<FONT FACE="Arial">Center</FONT>"
y es que usamos aquí. <FONT FACE="Arial">CardLayout</FONT>
permite "apilar" los componentes como cartas y ver uno
por vez, <FONT FACE="Arial">FlowLayout</FONT> los ordena de izquierda
a derecha como un texto, <FONT FACE="Arial">GridLayout</FONT>
los ordena en una cuadrícula donde cada componente tiene
un tamaño fijo y <FONT FACE="Arial">GridBagLayout</FONT>
los pone en una cuadrícula pero cada uno puede tener el
tamaño deseado.
<P>
Noten que no hace falta llamar, en el caso del applet, a <FONT FACE="Arial">Pack()</FONT>
y <FONT FACE="Arial">Show()</FONT>.
<H3>Y los eventos...</H3>
<P>
Ahora vamos a ver un método que viene de la clase tatarabuela!
Hace falta decir que me gusta esto de los objetos?
<P>
Vamos a redefinir <FONT FACE="Arial">handleEvent(Event)</FONT>,
que es el método que analiza los eventos dirigidos al componente
y toma las acciones adecuadas.
<P>
La clase <FONT FACE="Arial">Event</FONT> define básicamente
una serie de métodos que permiten saber si hay alguna tecla
de control presionada y muchas constantes que indican si se presionó
o movió el mouse, si se presionó alguna tecla en
particular, si se cambió el tamaño de la ventana,
etc. En particular hay algunos atributos interesantes:
<UL>
<LI>id que indica el tipo de evento
<LI>target que indica sobre qué componente se produjo el
evento
<LI>key qué tecla se presionó si fue un evento de
teclado
</UL>
<P>
etc.
<P>
En los descendientes de <FONT FACE="Arial">Component</FONT>, el
método handleEvent se llama automáticamente cada
vez que se produce un evento sobre el componente. En este caso,
simplemente vamos a mirar si el evento (sobre nuestro objeto de
clase <FONT FACE="Arial">Ejemplo7</FONT>) fue "cerrar la
ventana", que se identifica mediante <FONT FACE="Arial">event.id
= WINDOW_DESTROY</FONT> (una constante estática de la clase
<FONT FACE="Arial">Event</FONT>, y como tal la podemos usar con
el nombre de la clase como <FONT FACE="Arial">Event.WINDOW_DESTROY</FONT>):
<BR>
<PRE>
<FONT SIZE=2>public boolean handleEvent(Event ev) {
if (ev.id == Event.WINDOW_DESTROY) {
if (inAnApplet) {
dispose();
} else {
System.exit(0);
}
}
return super.handleEvent(event);
}
</FONT>
</PRE>
<P>
En ese caso, si nuestro ejemplo se disparó como aplicación
llamamos al método <FONT FACE="Arial">System.exit(0)</FONT>,
que cierra la aplicación; y si era un applet llamamos a
<FONT FACE="Arial">dispose()</FONT>, implementación de
un método de la interface <FONT FACE="Arial">ComponentPeer</FONT>
que se encarga de remover todos los componentes y la propia ventana.
<P>
Noten que cualquier otro tipo de evento deja seguir hasta <FONT FACE="Arial">return
super.handleEvent(event)</FONT>, que llama al método <FONT FACE="Arial">handleEvent</FONT>
de la clase madre: así como el prefijo <FONT FACE="Arial">this.</FONT>
se refiere a un método de la propia clase, el prefijo <FONT FACE="Arial">super.</FONT>
llama al método de la clase madre (aunque esté redefinido).
En este caso, la llamada se remonta hasta <FONT FACE="Arial">Component.handleEvent</FONT>,
que determina el tipo de evento y llama a uno de los métodos
<FONT FACE="Arial">action, gotFocus, lostFocus, keyDown, keyUp,
mouseEnter, mouseExit, mouseMove, mouseDrag, mouseDown</FONT>
o <FONT FACE="Arial">mouseUp</FONT> según sea apropiado
(y devuelve <FONT FACE="Arial">true</FONT>). Si ningún
método es aplicable, devuelve <FONT FACE="Arial">false</FONT>.
<P>
Es muy común, al redefinir un método, tener en cuenta
llamar antes o después al método de la clase antecesora
para inicializar o terminar alguna tarea.<BR>
<P>
Bueno, hasta aquí hay para jugar un poco. Pronto vamos
a ampliar este método para procesar todos los componentes
que pusimos dentro de la ventana. Jueguen mientras tanto que pronto
nos vemos!
<BR>
<HR>
<P>
Jorge Bourdette
<P>
<A HREF="mailto:jpb@amarillas.com">jpb@amarillas.com</A>
</BODY>
</HTML>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -