Universidad Carlos III de Madrid

Grado en Ingeniería Telemática/Grado en Ingeniería de Sistemas de Comunicaciones

Enero-Mayo 2014

Interfaces Gráficas de Usuario

Lab Section1. Sesión 2 (laboratorio): Interfaces Gráficas de Usuario

Exercise Section1.1. Hola mundo en Swing

Ejecuta el siguiente programa:

import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class HelloWorld extends JFrame {

    public HelloWorld() {
        super("HelloWorld");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().add(new JLabel("Hello World!"));
        setMinimumSize(new Dimension(200,100));
        setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    HelloWorld gui = new HelloWorld();
                }
            });
    }
}

Apartado 1

Responde a las siguientes preguntas:

  1. ¿De qué clase hereda HelloWorld? Encuéntrala en la API de Java. Indica la cadena completa de herencia desde HelloWorld hasta Object.
  2. ¿A qué método se invoca cuando se ejecuta super("HelloWorld")? Encuentra la documentación de este método en la API de Java.
  3. ¿Qué hace setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)? Responde utilizando la API de Java.
  4. ¿Para qué sirve la línea setVisible(true)? Encuentra su documentación en la API de Java. ¿Por qué no aparece setVisible entre los métodos de JFrame?
Soluciones
  1. Hereda de JFrame. La cadena completa de herencia se puede ver en la API de JFrame: java.lang.Object, java.awt.Component, java.awt.Container, java.awt.Window, java.awt.Frame, javax.swing.JFrame, HelloWorld.
  2. Se invoca al constructor de JFrame que recibe un único parámetro, de tipo String.
  3. Configura la ventana para que, cuando el usuario solicite cerrarla, finalice el programa. Se puede obtener esta información en la API de Java.
  4. Las ventanas, cuando se crean, no son visibles en el escritorio del usuario. Cuando se invoca setVisible con parámetro true la ventana pasa a ser visible. Este método no está programado directamente en JFrame, pero dispone de él porque lo hereda de la clase java.awt.Window.

Apartado 2

En el programa anterior la clase HelloWorld hereda de JFrame. Otra alternativa habría sido que no herede de esta clase sino que cree internamente un objeto de tipo JFrame y lo utilice para construir la ventana. Crea una clase llamada HelloWorld2 que haga lo mismo que HelloWorld, pero sin heredar de JFrame.

Soluciones
import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class HelloWorld2 {

    public HelloWorld2() {
        JFrame frame = new JFrame("HelloWorld");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new JLabel("Hello World!"));
        frame.setMinimumSize(new Dimension(200,100));
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    HelloWorld2 gui = new HelloWorld2();
                }
            });
    }
}

Exercise Section1.2. Calculadora en Swing

Programa una aplicación que muestre una calculadora similar a la de la imagen siguiente:

De momento, no es necesario que la calculadora reaccione a las acciones del usuario, como por ejemplo pulsaciones de botones. Se limitará a mostrar siempre un 0 como resultado.

Para conseguir un aspecto similar puedes establecer en el nivel superior de la ventana un BorderLayout. Ahí puedes después añadir:

  • Arriba (BorderLayout.NORTH), una etiqueta que emule la pantalla de la calculadora, mostrando el texto "0". Alinea la etiqueta a la derecha utilizando el constructor adecuado.
  • En el centro (BorderLayout.CENTER),un panel gestionado por un GridLayout, que muestre en cada celda un botón de la calculadora.

Soluciones

import java.awt.BorderLayout;
import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

public class Calculator extends JFrame {

    public Calculator() {
        super("Calculator");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());
        JLabel display = new JLabel("0", SwingConstants.RIGHT);
        JPanel buttonsPanel = new JPanel(new GridLayout(6, 3));
        buttonsPanel.add(new JButton("AC"));
        buttonsPanel.add(new JButton("+"));
        buttonsPanel.add(new JButton("-"));
        buttonsPanel.add(new JButton("C"));
        buttonsPanel.add(new JButton("*"));
        buttonsPanel.add(new JButton("/"));
        buttonsPanel.add(new JButton("7"));
        buttonsPanel.add(new JButton("8"));
        buttonsPanel.add(new JButton("9"));
        buttonsPanel.add(new JButton("4"));
        buttonsPanel.add(new JButton("5"));
        buttonsPanel.add(new JButton("6"));
        buttonsPanel.add(new JButton("1"));
        buttonsPanel.add(new JButton("2"));
        buttonsPanel.add(new JButton("3"));
        buttonsPanel.add(new JButton("."));
        buttonsPanel.add(new JButton("0"));
        buttonsPanel.add(new JButton("="));
        getContentPane().add(display, BorderLayout.NORTH);
        getContentPane().add(buttonsPanel, BorderLayout.CENTER);
        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    Calculator gui = new Calculator();
                }
            });
    }
}

Exercise Section1.3. Área de dibujo

Además de utilizar componentes ya programados de Swing, una aplicación gráfica puede también pintar directamente líneas, círculos, texto, etc. sobre objetos de la clase JPanel. A continuación se muestra un ejemplo compuesto por dos clases. La primera de ellas hereda de JPanel y ejerce como lienzo de dibujo:

import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JPanel;


public class Canvas extends JPanel {
    private Dimension preferredSize;

    public Canvas(Dimension preferredSize) {
        this.preferredSize = preferredSize;
    }

    public Dimension getPreferredSize() {
        return preferredSize;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Dimension size = getSize();
        int width = (int) size.getWidth();
        int height = (int) size.getHeight();
        g.drawLine(0, 0, width - 1, height - 1);
        g.drawLine(width - 1, 0, 0, height - 1);
    }
}

La segunda es una ventana que contiene una instancia de la clase anterior:

import java.awt.Dimension;

import javax.swing.JFrame;

public class CanvasApplication extends JFrame {

    public CanvasApplication() {
        super("Canvas");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().add(new Canvas(new Dimension(640, 480)));
        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    CanvasApplication gui = new CanvasApplication();
                }
            });
    }
}

Ejecuta la aplicación para ver cómo funciona. Observa qué ocurre si cambias el tamaño de la ventana.

El método paintComponent de Canvas es invocado por Swing cada vez que sea necesario redibujar la aplicación (por ejemplo, cuando cambia el tamaño de la ventana). En este método se utiliza el objeto de la clase Graphics que se recibe para dibujar las líneas que conforman las diagonales del panel. Si observas la API de esta clase, verás que también es posible dibujar arcos, óvalos, polígonos, texto, imágenes, etc. También es posible establecer el color en que se dibuja o la tipografía utilizada para el texto.

Modifica el método paintComponent para que dibuje lo que tú quieras. Utiliza al menos polígonos y círculos (con sólo bordes o con relleno), texto y distintos colores, para practicar el uso de la clase Graphics. Accede a su API para averiguar cómo se dibuja cada uno de los tipos de objetos anteriores.

Soluciones

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JPanel;


public class Canvas2 extends JPanel {
    private Dimension preferredSize;

    public Canvas2(Dimension preferredSize) {
        this.preferredSize = preferredSize;
    }

    public Dimension getPreferredSize() {
        return preferredSize;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Dimension size = getSize();
        int width = (int) size.getWidth();
        int height = (int) size.getHeight();
        g.drawLine(0, 0, width - 1, height - 1);
        g.drawLine(width - 1, 0, 0, height - 1);
        g.setColor(Color.BLUE);
        g.fillOval(width / 2 - 32, height / 2 - 32, 64, 64);
        g.setColor(Color.RED);
        g.drawString("This is Swing!", 60, 60);
        g.drawPolygon(new int[]{50,  100,  40, 110, 75},
                      new int[]{200,  200,  260, 260, 290}, 5);
    }
}
import java.awt.Dimension;

import javax.swing.JFrame;

public class CanvasApplication2 extends JFrame {

    public CanvasApplication2() {
        super("Canvas");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().add(new Canvas2(new Dimension(640, 480)));
        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    CanvasApplication2 gui = new CanvasApplication2();
                }
            });
    }
}