Aprende Java Aprende Php Aprende C++ Aprende HTML 5 Aprende JavaScript Aprende JSON Aprende MySQL Aprende SQLServer Aprende Visual Basic 6 Aprende PostgreSQL Aprende SQLite Aprende Redis Aprende Kotlin Aprende XML Aprende Linux VSC Aprende Wordpress Aprende Laravel Aprende VueJS Aprende JQuery Aprende Bootstrap Aprende Netbeans Aprende Android
Sigueme en Facebook Sigueme en Twitter Sigueme en Instagram Sigueme en Youtube Sigueme en TikTok Sigueme en Whatsapp
Home / Java / Crea un efecto Flip en java swing

Crea un efecto Flip en java swing

Por jc mouse lunes, octubre 5, 2015

Entre los correos y mensajes en facebook y whatsapp que me llegan (y de entrada pido perdón a quienes no puedo responder o me olvide responder) me preguntaron como hacer un efecto flip (dar la vuelta) para un botón en java.

Bueno java cuenta con clases y métodos que nos permiten manipular imágenes, no son los mejores pero es lo que hay y con un poco de imaginación podemos hacer casi cualquier cosa. En el siguiente tutorial crearemos un componente swing que nos permita implementar el efecto flip con imágenes

Necesitamos

  • IDE Netbeans

Tiempo 30 minutos

Nivel: Intermedio

TUTORIAL EFECTO FLIP

Paso 1. El Proyecto

File -> New project… -> Java Class Library, en nombre de proyecto ponemos JFlip y presionamos el boton finish para terminar la creación del proyecto.

A continuación creamos la estructura del proyecto como se ve a continuación:

jflip

  • JFlip.java es una clase y es nuestro componente en si, es donde colocaremos el código necesario para el efecto flip
  • DemoFrame.java es un JFrame y nos servirá para probar nuestro swing
  • resource/ es un paquete, ahí colocaremos las imágenes que usemos en el proyecto

Paso 2. Flip

Abre la clase JFlip:

package com.bolivia.flip;

public class JFlip {
    
}

La clase JFlip se extenderá de la clase JComponent, esta clase es la base de todas los componentes swing exceptuando algunos casos. Al extender de la clase JComponent tenemos la base perfecta para desarrollar nuestro swing.

Así también necesitamos controlar eventos del mouse por lo que implementaremos un MouseListener, nuestra clase queda de la siguiente forma:

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;

public class JFlip extends JComponent implements MouseListener{

    /**Constructor de clase*/
    public JFlip(){}
    
    @Override
    public void mouseClicked(MouseEvent e) {/*...*/}

    @Override
    public void mousePressed(MouseEvent e) {/*...*/}

    @Override
    public void mouseReleased(MouseEvent e) {/*...*/}

    @Override
    public void mouseEntered(MouseEvent e) {/*...*/}

    @Override
    public void mouseExited(MouseEvent e) {/*...*/}
    
}

Antes de continuar con la codificación, debemos analizar como emular en dos dimensiones el «efecto flip» siendo que en la realidad ese efecto se produce en tres dimensiones. El problema se reduce a un efecto de perspectiva es decir cuando el plano da vuelta a nuestros ojos un lado se hace más pequeño a medida que gira hasta desaparecer y reaparecer del otro lado pero esta vez aumentando de tamaño hasta alcanzar su tamaño original, en las imágenes siguientes podemos ver gráficamente a que me refiero:

flip perspective

dar la vuelta

Nuestro plano que es un polígono tiene 4 esquinas (A,B,C y D) , los puntos Ax, Cx, Bx y Dx tienen un desplazamiento horizontal uniforme hacia la mitad del plano, los puntos Ay y Cy son constantes, en cambio los puntos By y Dy tienen un movimiento vertical uniforme menor al desplazamiento horizontal, es menor porque no queremos que los puntos By y Dy se intercepten lo que arruinaría el efecto flip. Cuando los puntos Ax, Cx, Bx y Dx llegan hasta la mitad del plano, se debe invertir el procedimiento, es decir, los puntos Ax, Cx, Bx y Dx tienen ahora un desplazamiento negativo y el desplazamiento vertical también lo es, pero, las variables By y Dy se vuelven constantes y Ay y Cy son los que se desplazan en sentido vertical . Es decir:

java swing flip

Otro punto importante a considerar es que java nos permite recortar pedazos de una imagen pero esos pedazos deben ser rectangulares, por lo que no podremos hacer uso de esos métodos en este proyecto, sin embargo si podemos usar un objeto Shape para pintar secciones irregulares de una imagen usando las coordenadas del polígono descrito más arriba y así simular el efecto en perspectiva, no es lo ideal pero gracias al movimiento constante nuestros ojos no notaran la diferencia.

dog

Continuemos con la programación

Los imports que usamos en la clase flip son:

import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.GeneralPath;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.Timer;

Declaramos las variables:

    private Timer timer                     =       null;    
    private boolean inTransition            =       false;
    private int speed                       =       12;//velocidad de flip en milisegundos
    private int displacement                =       2;//desplazamiento en pixeles
    private boolean isFront                 =       true;
    private boolean inward                  =       true;//sentido del desplazamiento
    //iconos por defecto
    private Icon iconBack                   =       new ImageIcon(getClass().getResource("/com/bolivia/resource/photo1.jpg"));
    private Icon iconFront                  =       new ImageIcon(getClass().getResource("/com/bolivia/resource/photo2.jpg"));
    private Image image                     =       ((ImageIcon)iconFront).getImage();
    //variables de desplazamiento
    private int displacementHorizontal      =       0;    
    private float displacementLeft          =       0;       
    private float displacementRight         =       0;    
    //tamaño por defecto
    private Dimension dimension             =       new Dimension(160,160);

OJO: Utilizaremos dos imágenes de 160×160 pixeles que colocaremos en el paquete /resource/

A continuación declaramos el constructor de clase, sobreescribimos el método paintComponent() y definimos el método flipAnimate() para los cambios de variable de desplazamiento

    /**Constructor de clase*/
    public JFlip(){
        super();
        setSize(dimension);
        setPreferredSize(dimension);        
        setVisible(true);        
        addMouseListener(JFlip.this);        
    }
    
    @Override
    public void paintComponent(Graphics g){         
        Graphics2D g2 =(Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);            
        g2.setStroke(new BasicStroke( 0f ));
        //coordenas de imagen
        GeneralPath p = new GeneralPath();
            p.moveTo(displacementHorizontal, displacementLeft);//esquina A
            p.lineTo(getWidth()-displacementHorizontal-1, displacementRight);//esquina B
            p.lineTo(getWidth()-displacementHorizontal-1, getHeight()-displacementRight-1);//esquina D
            p.lineTo( displacementHorizontal, getHeight()-displacementLeft-1  );//esquina C
            p.closePath();
        Shape shp = p;
        g2.setClip(shp);
        g2.drawImage(image, 0, 0,getWidth() - displacementHorizontal,getHeight(), null);        
        g2.setClip(null);
        g2.draw(shp);
        g.dispose(); 
    }

    /**
     * Metodo que realiza los cambios en las variables de desplazamiento
     * @return Void
     */
    private void flipAnimate(){
        inTransition = !inTransition;
        //declaramos un evento para modificar el desplazamiento vertical y horizontal
        ActionListener animation = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                
                if(inward){   
                    displacementHorizontal += displacement;   
                    displacementRight += (displacementRight>=getHeight()/2)?0:displacement/(getSize().getWidth()/getSize().getHeight()+1f);                                        
                }else{
                    displacementHorizontal -= displacement;                                        
                    displacementLeft -=displacement/(getSize().getWidth()/getSize().getHeight()+1f);                                        
                }
                //repinta graficos
                repaint();
                
                //si se llego al medio del componente -> cambia de sentido
                if(displacementHorizontal >= getWidth()/2){ 
                    inward = false;
                    displacementLeft = displacementRight;                    
                    displacementRight=0;                    
                    //
                    if( isFront ){//mostrar imagen de atras
                        isFront=false;
                        image=((ImageIcon)iconBack).getImage();                        
                    }else{//mostrar imagen de adelante
                        isFront =true;
                        image=((ImageIcon)iconFront).getImage();                        
                    }                    
                } 
                //volvio a su posicion inicial -> detener animacion
                if( inward == false && displacementHorizontal == 0 ){
                    inTransition=false;   
                    timer.stop();
                    displacementLeft=0;
                    displacementRight=0;
                    displacementHorizontal=0;
                    inward = true;                                 
                }
            }
        }; 
        //
        if( inTransition )
        {
            if(timer != null)timer.stop();
            timer = new Timer( speed, animation);
            timer.start(); //inicia animacion      
        }
    }

El efecto flip se llevara a cabo cuando el usuario de un clic sobre el swing, por lo que debemos invocar al metodo flipAnimate() en el evento mouseClicked, nuestra clase final queda de la siguiente forma:

package com.bolivia.flip;
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.GeneralPath;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.Timer;
/**
 * @web https://www.jc-mouse.net/
 * @author Mouse
 */
public class JFlip extends JComponent implements MouseListener {
    
    private Timer timer                     =       null;    
    private boolean inTransition            =       false;
    private int speed                       =       4;//velocidad de flip en milisegundos
    private int displacement                =       2;//desplazamiento en pixeles
    private boolean isFront                 =       true;
    private boolean inward                  =       true;//sentido del desplazamiento
    //iconos por defecto
    private Icon iconBack                   =       new ImageIcon(getClass().getResource("/com/bolivia/resource/photo1.jpg"));
    private Icon iconFront                  =       new ImageIcon(getClass().getResource("/com/bolivia/resource/photo2.jpg"));
    private Image image                     =       ((ImageIcon)iconFront).getImage();
    //variables de desplazamiento
    private int displacementHorizontal      =       0;    
    private float displacementLeft          =       0;       
    private float displacementRight         =       0;    
    //tamaño por defecto
    private Dimension dimension             =       new Dimension(160,160);
    
    /**Constructor de clase*/
    public JFlip(){
        super();
        setSize(dimension);
        setPreferredSize(dimension);        
        setVisible(true);        
        addMouseListener(JFlip.this);        
    }
    
    @Override
    public void paintComponent(Graphics g){         
        Graphics2D g2 =(Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);            
        g2.setStroke(new BasicStroke( 0f ));
        //coordenas de imagen
        GeneralPath p = new GeneralPath();
            p.moveTo(displacementHorizontal, displacementLeft);//esquina A
            p.lineTo(getWidth()-displacementHorizontal-1, displacementRight);//esquina B
            p.lineTo(getWidth()-displacementHorizontal-1, getHeight()-displacementRight-1);//esquina D
            p.lineTo( displacementHorizontal, getHeight()-displacementLeft-1  );//esquina C
            p.closePath();
        Shape shp = p;
        g2.setClip(shp);
        g2.drawImage(image, 0, 0,getWidth() - displacementHorizontal,getHeight(), null);        
        g2.setClip(null);
        g2.draw(shp);
        g.dispose(); 
    }

    /**
     * Metodo que realiza los cambios en las variables de desplazamiento
     * @return Void
     */
    private void flipAnimate(){
        inTransition = !inTransition;
        //declaramos un evento para modificar el desplazamiento vertical y horizontal
        ActionListener animation = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                
                if(inward){   
                    displacementHorizontal += displacement;   
                    displacementRight += (displacementRight>=getHeight()/2)?0:displacement/(getSize().getWidth()/getSize().getHeight()+1f);                                        
                }else{
                    displacementHorizontal -= displacement;                                        
                    displacementLeft -=displacement/(getSize().getWidth()/getSize().getHeight()+1f);                                        
                }
                //repinta graficos
                repaint();
                
                //si se llego al medio del componente -> cambia de sentido
                if(displacementHorizontal >= getWidth()/2){ 
                    inward = false;
                    displacementLeft = displacementRight;                    
                    displacementRight=0;                    
                    //
                    if( isFront ){//mostrar imagen de atras
                        isFront=false;
                        image=((ImageIcon)iconBack).getImage();                        
                    }else{//mostrar imagen de adelante
                        isFront =true;
                        image=((ImageIcon)iconFront).getImage();                        
                    }                    
                } 
                //volvio a su posicion inicial -> detener animacion
                if( inward == false && displacementHorizontal == 0 ){
                    inTransition=false;   
                    timer.stop();
                    displacementLeft=0;
                    displacementRight=0;
                    displacementHorizontal=0;
                    inward = true;                                 
                }
            }
        }; 
        //
        if( inTransition )
        {
            if(timer != null)timer.stop();
            timer = new Timer( speed, animation);
            timer.start(); //inicia animacion      
        }
    }
    
    @Override
    public void mouseClicked(MouseEvent e) {
        flipAnimate();
    }

    @Override
    public void mousePressed(MouseEvent e) {/*...*/}

    @Override
    public void mouseReleased(MouseEvent e) {/*...*/}

    @Override
    public void mouseEntered(MouseEvent e) {/*...*/}

    @Override
    public void mouseExited(MouseEvent e) {/*...*/}

    public Icon getIconBack() {
        return iconBack;
    }

    public void setIconBack(Icon iconBack) {
        this.iconBack = iconBack;
    }

    public Icon getIconFront() {
        return iconFront;
    }

    public void setIconFront(Icon iconFront) {
        this.iconFront = iconFront;
    }

    public int getDisplacement() {
        return displacement;
    }

    public void setDisplacement(int displacement) {
        this.displacement = displacement;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }
    
}//JFlip:end

Compilamos el proyecto, para usar el componente solo lo arrastramos al jframe y también podemos modificar la velocidad de animación, la cantidad de desplazamiento en pixeles y cargar nuevas imagenes desde su menú de propiedades, ejecutamos y probamos el efecto flip.

Descargar proyecto FLIP aquí 🙂

enjoy!!!

Tags

Artículos similares

Anima tus fotografias con esta IA (Gratis)

En este post te enseño a usar una herramienta de Inteligencia Artificial para animar tus fotografias y esto completament[...]

Crear PopupMenu (Ventana Emergente)

En este tutorial crearemos una aplicación android que nos permitirá abrir un PopupMenu de donde podremos seleccionar una[...]

Ejemplo de operaciones CRUD con MyBatis 3

«MyBatis es una herramienta de persistencia Java que se encarga de mapear sentencias SQL y procedimientos almacenados co[...]

Pruebas funcionales con AssertJ Swing

AssertJ Swing es una biblioteca para Java que proporciona una interfaz fluida para la realización automatizada de prueba[...]

Crear imagen dinamicamente y agregar a un objeto swing

Si bien se puede hacer uso de archivos de imagen (jpg, png, bmp, etc) en las aplicaciones java, también este te permite[...]

Default Methods

Uno de los cambios principales introducidos a las interfaces en  Java 8 fue que estos puedan tener métodos concretos, es[...]