Tutorial de Java

Paneles Desplazables

Anterior | Siguiente

En anteriores programas se ha utilizado la clase JScrollPane para proporcionar una forma automática de desplazar el contenido de una ventana por parte del sistema. Esta clase permite dejar las manos libres al programador para centrarse en el código de su aplicación, sin tener que estar pendiente de tener que controlar la visibilidad de todo o parte del contenido de la ventana. Pero los ejemplos que se han visto no se centraban ninguno en la clase JScrollPane, por lo que son muy simples, pero visto que es una clase muy usada y útil, el ejemplo java1424.java es para presentar una aplicación un poco más avanzada para mostrar cómo interactúa en un programa. Además, el ejemplo hace uso de la clase JSplitPane, que permite dividir la ventana en subventanas independientes.

El programa implementa un JFrame que contiene un panel dividido en dos zonas, cada una conteniendo una instancia de un componente Swing. La zona superior de la ventana contiene un campo de texto y la inferior un gráfico, para ilustrar el hecho de que el contenido de los paneles de desplazamiento puede ser cualquiera que se elija.

El código del ejemplo se muestra a continuación y debería resultar sencillo de entender al lector, aunque hay algunos trozos sobre los que merece la pena detenerse y se comentarán a continuación.

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
import com.sun.java.swing.event.*;

class java1424 extends JPanel implements ChangeListener {
  private JSplitPane panelVert;
  private JScrollPane panelScro1;
  private JScrollPane panelScro2;
  
  public java1424() {
    setLayout( new BorderLayout() );
    // Se crea una zona para presentar el texto correspondiente al fichero
    creaPanelSup();
    // Se crea una zona inferior para mostrar el gráfico
    creaPanelInf();
    // Se crea un panel dividido verticalmente
    panelVert = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
    add( panelVert,BorderLayout.CENTER );
    // Se incorporan las dos zonas que se habían creado a las dos
    // partes en que se ha dividido el panel principal
    panelVert.setLeftComponent( panelScro1 );
    panelVert.setRightComponent( panelScro2 );
  }
  
  
  public void stateChanged( ChangeEvent evt ) {
    // Si el evento proviene del panel principal, seguimos...
    if( evt.getSource() == panelScro1.getViewport() ) {
      // Cogemos la posición actual dentro de la vista correspondiente
      // al panel principal
      Point point = panelScro1.getViewport().getViewPosition();
      // Ahora determinamos la escala correcta para las vistas, para las
      // dos zonas del panel principal
      Dimension dim1 = panelScro1.getViewport().getViewSize();
      Dimension dim2 = panelScro2.getViewport().getViewSize();
      float escalaX = 1;
      float escalaY = 1;
      if( dim1.width > dim2.width ) {
	escalaX = (float)dim1.width / (float)dim2.width;
	escalaY = (float)dim1.height / (float)dim2.height;
	// Escalamos en función del movimiento
	point.x /= escalaX;
	point.y /= escalaY;
      }
      else {
	escalaX = (float)dim2.width / (float)dim1.width;
	escalaY = (float)dim2.height / (float)dim1.height;
	// Escalamos en función del movimiento
	point.x *= escalaX;
	point.y *= escalaY;
      }
      // Movemos la otra vista en función de lo que movamos la de texto
      panelScro2.getViewport().setViewPosition( point );
    }
  }
  
  
  private void creaPanelSup() {
    // Creamos el panel de la zona de texto
    JTextArea areaTexto = new JTextArea();
    // Se carga el fichero en el área de texto, cuidando de capturar
    // todas las excepciones que se puedan producir
    try {
      FileReader fileStream = new FileReader( "java1424.java" );
      areaTexto.read( fileStream, "java1424.java" );
    } catch( FileNotFoundException e ) {
      System.out.println( "Fichero no encontrado" );
    } catch( IOException e ) {
      System.out.println( "Error por IOException" );
    }
    // Creamos el panel desplazable para el área de texto
    panelScro1 = new JScrollPane();
    panelScro1.getViewport().add( areaTexto );
    panelScro1.getViewport().addChangeListener( this );
  }
  
  
  private void creaPanelInf() {
    // Cargamos el gráfico, o imagen , en la panatalla
    Icon imagenP2 = new ImageIcon( "main.gif" );
    JLabel etiqP2 = new JLabel( imagenP2 );
    
    // Creamos el panel para el gráfico
    panelScro2 = new JScrollPane();
    panelScro2.setVerticalScrollBarPolicy(
      ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER );
    panelScro2.setHorizontalScrollBarPolicy(
      ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
    panelScro2.getViewport().add( etiqP2 );
    panelScro2.getViewport().addChangeListener( this );
  }
  
  
  public static void main( String args[] ) {
    JFrame ventana = new JFrame( "Tutorial de Java, Swing" );
    
    ventana.addWindowListener( new WindowAdapter() {
      public void windowClosing( WindowEvent evt ){
	System.exit( 0 );
      }
    } );
    ventana.getContentPane().add( new java1424(),BorderLayout.CENTER );
    ventana.setSize( 460,300 );
    
    ventana.setVisible( true );
  }
}

Los métodos que se usan para crear el contenido de los subpaneles es complicado. El método creaPanelSup(), se limita a utilizar un componente JTextArea sobre el que carga el fichero que contiene el código fuente del ejemplo. y el método creaPanelInf() presenta una imagen que se desplazará en consonancia con el movimiento del panel superior.

Sin embargo, sí que hay un trozo de código interesante en el método stateChanged(), que controla los cambios producidos por acción del usuario, y es el cálculo de la escala que diferencia a los dos paneles de desplazamiento. En el programa, el cálculo de la escala no es demasiado preciso, debido a que no tiene en cuenta del todo el tamaño de los dos paneles. Si se mueve la barra horizontal en el panel superior se puede observar esta circunstancia. Con un poco más de matemáticas por parte del lector, seguro que podrá compensar el error, y a su ejercicio se deja esa corrección, simplemente indicando que hay que experimentar con los métodos getViewPosition() y getExtentSize() de la clase JViewport para conseguir que los cálculos sean correctos.

Cuando se ejecuta el programa y se agranda la ventana, se puede ver una imagen semejante a la que reproduce la imagen siguiente.

Ahora, los movimientos sobre la barra de desplazamiento vertical en el panel superior hacen que la imagen que esta en el panel inferior se desplace al mismo tiempo. Quiza esto no le parezca al lector demasiado práctico, pero muestra cómo se puede conseguir el desplazamiento de un panel con respecto a otro; y este tipo de funcionalidad sí que es de uso frecuente en muchas aplicaciones, y aquí se muestra una forma muy sencilla de poder implementarla.

Otro detalle importante es la ausencia de barras de desplazamiento en el panel inferior, a pesar de que la imagen es mucho más grande que el tamaño de la subventana. Las líneas de código siguientes:

    panelScro2.setVerticalScrollBarPolicy(
      ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER );
    panelScro2.setHorizontalScrollBarPolicy(
      ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );

son las que permiten fijar las características de las barras de desplazamiento, y en este caso se indica que no deben estar presentes.

Navegador

Home | Anterior | Siguiente | Indice | Correo