martes, 1 de abril de 2014

Pintar y Hacer que un JPanel escuche (Graphics)

Introducción
En java en ocasiones es necesario hacer una aplicación en la cual requerimos de obtener coordenadas del panel o bien simplemente mostrar algo desde un panel (no en un Frame que también se puede y es más sencillo).

Funcionamiento
El código esta dividido en tres clases; Principal.java, Ventana.java y Panel.java el funcionamiento es el siguiente: desde la clase principal se crea un objeto de la clase Ventana que es un JFrame para que está se visualice, en la clase Ventana se ponen las especificaciones de Ventana/Frame (Tamaño, Titulo, Menú, etc.), además se hace una llamada a la clase Panel y se agrega a la ventana para poderlo mostrar y en la clase Panel se pone todo lo que se requiera hacer sobre el panel es aquí donde podemos escuchar al panel y obtener valores.

Código
Clase Principal.java

package package1;

import javax.swing.UIManager;

public class Principal {
    
    public static void main(String [] args ){
        
        /* El siguiente codigo es para que la ventana se vea de mejor estilo*/
        for(UIManager.LookAndFeelInfo laf:UIManager.getInstalledLookAndFeels()){
                    if("Nimbus".equals(laf.getName()))
                     try {
                         UIManager.setLookAndFeel(laf.getClassName());
                     } catch (Exception ex) {
                          ex.printStackTrace();
                      }
                }
        
        //objeto clase Ventana
        Ventana con4 = new Ventana();
        con4.setLocationRelativeTo(null); //permite centrar la ventana
        con4.setVisible(true); //se muestre en pantalla
        con4.setDefaultCloseOperation(con4.EXIT_ON_CLOSE); //al cerrar se cierre el proceso
    }
}

Clase Ventana.java
package package1;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

public class Ventana extends JFrame implements ActionListener {   
    private JMenuBar menuBar = new JMenuBar();
    private JMenu menuFile = new JMenu();
    private JMenuItem menuFileExit = new JMenuItem();
    
    public Ventana() {
        try {
            jbInit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void jbInit() throws Exception {
        this.setJMenuBar( menuBar );
        this.getContentPane().setLayout( null );
        this.setSize(new Dimension(400, 401));
        this.setTitle( "Conecta 4" );
        this.setBackground(new Color(82, 255, 82));
        menuFile.setText( "File" );
        menuFileExit.setText( "Exit" );
        menuFileExit.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent ae ) { actionPerformed( ae ); } } );
        
        Panel panel = new Panel(); 
        panel.setBounds(new Rectangle(30, 50, 320, 260));
        panel.setBackground(new Color(82, 198, 255));
        menuFile.add( menuFileExit );
        menuBar.add( menuFile );
        this.getContentPane().add(panel);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.exit(0);
    }
}

Clase Panel.java
Es importante mecionar que para el panel escuche en el constructor debe llevar estas dos instrucciones:
-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|
        addMouseListener(this);
        addMouseMotionListener(this);
-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|

package package1;

import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Panel extends JPanel implements MouseListener, MouseMotionListener{
    
    Panel(){
        addMouseListener(this);
        addMouseMotionListener(this);
    }
    
    /*
     * Metodo necesario para pintar sobre el panel (mostrar graficos/imagenes)
     * */
    public void paintComponent(Graphics g2){
        super.paintComponent(g2);
        
        g2.drawOval(20, 20, 50, 50);
        g2.drawLine(40, 40, 50, 80);
        
    }
    
    @Override
    public void mouseClicked(MouseEvent e) {
        JOptionPane.showMessageDialog(null, "Esto es una prueba de que escuche: X= "+e.getX() +", Y="+e.getY());
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mouseDragged(MouseEvent e) {
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }
}

Las clases pueden ser modificadas dependiendo de que sea lo que se necesiten en este caso el objetivo es solo mostrar un simple ejemplo de como se puede trabajar sobre un panel y no sobre el Frame y también como escuchar al panel.

Al final se tiene una pantalla similar a la siguiente:

                                                                           Imagen 1

Pintar en el panel desde otro método
En ocasiones una vez que entramos a mouseClicked (o algún otro) y obtenemos las coordenadas X,Y se las pasamos a otro método como parámetro para que este método ejecute alguna acción, para que este cambio se muestre en el panel en caso de quererlo así solo se define un objeto de tipo Graphics y le asigna getGraphics() como se muestra en las siguientes lineas:

public void tira(int x, int y){
                   
                       ...

        Graphics g = getGraphics();
             
        Graphics2D g2d1 = (Graphics2D) g;
        g2d1.fillOval(fil, col, 35, 35);  //muestra esto sobre lo que ya esta


}