Crea formulario de login estilo Agents of Shield Marvel

Creado por jc mouse Miércoles, marzo 23, 2016

En esta oportunidad aprovechando el interés que tienen ahora los superheroes de Marvel, crearemos un formulario de logueo con ese aspecto futurista que tiene el software que se ven en las películas de los Vengadores.

hulk

Nuestro objetivo sera crear un formulario de forma irregular con una paleta de colores al estilo marvel, efectos y transparencia como se ve en la imagen siguiente:

formulario java

Necesitamos

  • IDE Nebeans 8.x y Java 8
  • Editor de imágenes (Gimp, Photoshop o cualquier otro)

Nivel: Intermedio – Avanzado

Tiempo: 30 minutos

Paso 1. Diseño 

Con un editor de imágenes creamos la forma que tendrá el formulario y marcaremos las coordenadas XY de cada esquina, en el ejemplo de este tutorial solo empleamos lineas rectas aunque pueden usarse curvas, claro que esto ocasionaría más cálculos y lineas de código a la hora de llevar las coordenadas a java.

plantilla XY

Nuestro formulario tendrá un tamaño fijo de 500×400 pixeles por lo cual las coordenadas de cada objeto que coloquemos en el, serán absolutas. Este formulario comprende de 2 etiquetas, 2 cajas de texto, 2 botones y 1 borde el cual sera pintado directamente en el jpanel. Para obtener las coordenadas de cada objeto usa el editor de imágenes de tu preferencia.

logueo shield

Cuando se presione el botón “Aceptar” se llevara internamente a cabo la autenticación del usuario y aparecerá un JDialog con un mensaje de respuesta informado del éxito o fracaso de la operación.

custom jdialog

Paso 2. Proyecto en netbeans

En Netbeans creamos un nuevo proyecto con el nombre de “MarvelAuthentication” y le agregamos los siguientes paquetes y archivos.

java marvel project

A continuación una breve explicación de cada uno de las clases java:

  • NetFrame. Este es el formulario principal donde se implementan todas las demás clases
  • NetPanel. Es un JPanel personalizado en donde se pintara un polígono de forma irregular que dará forma a nuestro formulario de logueo
  • NetTextField. JTextField personalizado para ingresar el nombre de usuario y contraseña.
  • NetButton. JButton personalizado
  • NetCustomDialog. JDialog personalizado

En el paquete “resource” tenemos dos imágenes que son:

patron

escudo agencia

Paso 3. Personalización de componentes

Pues eso, los componentes  swing que tiene java deben adecuarse al estilo que estamos buscando sin perder la funcionalidad que tienen, por tanto recurrimos a la herencia para personalizarlos a nuestro gusto.

Paso 3.1 NetButton

NetButton tiene modificaciones más de forma que de fondo por lo que es la clase más sencilla de personalizar en este tutorial, todo se reduce a modificar las propiedades del JButton, el código es el siguiente:

package net.jc_mouse.authentication;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
/**
 * @web http://www-jc-mouse.net/
 * @author mouse
 */
public class NetButton extends JButton implements FocusListener, MouseListener{
    
    /**
     * Constructor de clase
     */
    public NetButton(){
        super();
        NetButton.this.setSize(new Dimension(100,42));
        NetButton.this.setForeground(new Color(162,183,188));
        NetButton.this.setBorderPainted(true);
        NetButton.this.setContentAreaFilled(false);
        NetButton.this.setOpaque(true);
        NetButton.this.setBackground( new Color(0,0,0));
        NetButton.this.setBorder(BorderFactory.createLineBorder(new Color(162,183,188),2));
        NetButton.this.setFocusPainted(false);
        NetButton.this.addFocusListener(NetButton.this);
        NetButton.this.addMouseListener(NetButton.this);
    }

    @Override
    public void focusGained(FocusEvent e) {
        setBorder(BorderFactory.createLineBorder(new Color(248,110,1),2));
    }

    @Override
    public void focusLost(FocusEvent e) {
        setBorder(BorderFactory.createLineBorder(new Color(162,183,188),2));
    }

    @Override
    public void mouseClicked(MouseEvent e) {}

    @Override
    public void mousePressed(MouseEvent e) {
        NetButton.this.setBackground( new Color(70,98,110));
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        NetButton.this.setBackground( new Color(0,0,0));
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        NetButton.this.setBackground( new Color(90,130,130));
    }

    @Override
    public void mouseExited(MouseEvent e) {
        NetButton.this.setBackground( new Color(0,0,0));
    }    
    
}

Paso 3.2 NetTextField

El JTextField personalizado tendrá la siguiente forma:

swing custom

Para lograr esta forma tan peculiar sobre escribiremos el método paintComponent y pintaremos un polígono irregular (Polygon) teniendo en cuenta que el grosor del borde tiene un valor de 3 y  el pequeño triangulo del lado inferior derecho tiene un valor de 15 por lado, podremos calcular las medidas que necesitamos.

El resto de la personalización se lleva a cabo en el constructor de clase, implementamos también un FocusListener para que el borde de la caja de texto cambie de color según gane foco o lo pierda. El tipo de fuente que usamos es “Agency FB

package net.jc_mouse.authentication;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
/**
 * @web http://www-jc-mouse.net/
 * @author mouse
 */
public class NetTextField extends JTextField implements FocusListener{
    
    private Color borderColor = new Color(162,183,188);
    
    /**
     * Constructor de clase
     */
    public NetTextField(){
        super();
        NetTextField.this.setText("");
        NetTextField.this.setForeground(new Color(162,183,188));
        NetTextField.this.setPreferredSize(new Dimension(200,36));
        NetTextField.this.setVisible(true);
        NetTextField.this.setFont(new Font("Agency FB", Font.PLAIN, 18 ));        
        NetTextField.this.setBorder(new EmptyBorder(0, 12, 0, 12));
        NetTextField.this.setCaretColor(new Color(248,110,1));
        NetTextField.this.setSelectionColor(new Color(248,110,1));
        NetTextField.this.setSelectedTextColor( new Color(162,183,188) );
        NetTextField.this.putClientProperty("caretWidth", 4);
        NetTextField.this.setOpaque(false);
        NetTextField.this.addFocusListener(NetTextField.this);
    }
    
    
    @Override
    public void paintComponent(Graphics g){
        
        Graphics2D g2 =(Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);            
        
        Polygon fig = new Polygon();
        fig.addPoint( 0,0 );
        fig.addPoint( getWidth()-3,0 );
        fig.addPoint( getWidth()-3,getHeight()-18 );
        fig.addPoint( getWidth()-18,getHeight()-3 );
        fig.addPoint( 0,getHeight()-3 );
        
        g2.setColor( new Color(8,43,49,200) ); 
        g2.fill( fig );
        
        g2.setColor( borderColor );        
        g2.setStroke(new BasicStroke( 3 ));
        g2.draw( fig );
        
        super.paintComponent(g);
    }

    @Override
    public void focusGained(FocusEvent e) {
        borderColor = new Color(248,110,1);
        repaint();
    }

    @Override
    public void focusLost(FocusEvent e) {
        borderColor = new Color(162,183,188);
        repaint();
    }
    
}

Paso 3.3 NetCustomDialog

Para mostrar el resultado de la autenticación de usuario se usara un JDialog, pero para que este vaya a tono con el aspecto de marvel que le damos al formulario, debemos personalizarlo. Podríamos darle un aspecto similar al que le damos al formulario login, pero eso se lo dejo para que ustedes experimenten, en esta oportunidad nos limitaremos a darle un fondo negro , un borde y cambiar el aspecto de los botones usando el NetButton creado en el paso 3.1; también implementamos un método getAnswer() para que al cerrar el dialog, podamos capturar la respuesta del usuario, como en este caso solo tenemos un botón, la respuesta siempre sera TRUE.

package net.jc_mouse.authentication;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JDialog; 
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import javax.swing.BorderFactory;
/**
 * @web http://www-jc-mouse.net/
 * @author mouse
 */
public class NetCustomDialog extends JDialog implements ActionListener {
    
    private NetButton okButton = null;    
    private boolean answer = false;
    
    /**
     * Constructor de clase
     * @param frame
     * @param modal
     * @param message
     */
    public NetCustomDialog(JFrame frame, boolean modal, String message) {        
        super(frame, modal);
        NetCustomDialog.this.setPreferredSize( new Dimension(400,60));
        NetCustomDialog.this.setUndecorated(true);
        GridBagConstraints gridBagConstraints;
        
        JPanel myPanel = new JPanel();
        myPanel.setPreferredSize(new Dimension(500,100));
        myPanel.setBorder(BorderFactory.createLineBorder(new Color(119,232,228), 2));
        myPanel.setBackground(new Color(0,0,0));
        myPanel.setLayout(new GridBagLayout());
        
        NetCustomDialog.this.getContentPane().add(myPanel);        
        
        JLabel lbMsg = new JLabel(message);
        lbMsg.setForeground(new Color(255,255,255));
        lbMsg.setOpaque(false);
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 20);
        myPanel.add(lbMsg,gridBagConstraints);
        
        okButton = new NetButton();
        okButton.setText("OK");
        okButton.setPreferredSize(new Dimension(80,34));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        myPanel.add(okButton,gridBagConstraints);           
        
        //listener
        NetCustomDialog.this.okButton.addActionListener(NetCustomDialog.this);        
              
        NetCustomDialog.this.pack();
        NetCustomDialog.this.setLocationRelativeTo(frame);
        NetCustomDialog.this.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(okButton == e.getSource()) {
            answer = true;
            setVisible(false);
        }        
    }
    
    public boolean getAnswer() { return answer; }
}

Paso 4. NetPanel 

Finalmente el componente que nos falta personalizar y a la vez es el actor principal de este post, es el NetPanel, todo se reduce a pintar las coordenadas del polígono dado en el paso 1 dentro del método paintComponent,  se usa TexturePaint para colocar una imagen de fondo que se adecue a la forma irregular del formulario, para darle un poco de ese aspecto futurista, se aplica un 0.8f de transparencia al JPanel. Se pinta también el marco central donde irán el resto de los componentes personalizados, y para acabar se pinta el logo de shield en la esquina inferior derecha.

package net.jc_mouse.authentication;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.TexturePaint;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
/**
 * @web http://www-jc-mouse.net/
 * @author mouse
 */
public class NetPanel extends JPanel{
    
    private final Dimension dimension   =   new Dimension(500,400);    
    private final Image image           =   new ImageIcon(getClass().
                                            getResource("/net/jc_mouse/authentication/resource/boxnet.png")).getImage();
    private final Image logo            =   new ImageIcon(getClass().
                                            getResource("/net/jc_mouse/authentication/resource/shield.png")).getImage();
    private BufferedImage bufferedImage;    
    
    /**
     * Constructor de clase
     */
    public NetPanel(){
        super();        
        bufferedImage = imageToBI(image);              
        //tamaño del panel
        NetPanel.this.setSize(dimension);
        NetPanel.this.setPreferredSize(dimension);
    }
    
    @Override
    public void paintComponent(Graphics g){
        Graphics2D g2 =(Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);            
        
        //coordenadas de la figura principal
        int x1Points[] = {25,290,318,399,404,497,497,480,480,497,497,105,59,25,3,3,25,25,3,3};  
        int y1Points[] = {3,3,30,30,25,25,72,89,143,170,350,350,396,396,375,221,199,71,49,25};
        GeneralPath polygonPrincipal = new GeneralPath(GeneralPath.WIND_EVEN_ODD,x1Points.length);                 
        polygonPrincipal.moveTo(x1Points[0], y1Points[0]); 
        for(int i=0;i<x1Points.length;i++){
            polygonPrincipal.lineTo(x1Points[i], y1Points[i]);     
        }
        polygonPrincipal.closePath();
        
        //transparencia del jpanel
        g2.setComposite(AlphaComposite.getInstance(
            AlphaComposite.SRC_OVER, 0.8f));
        
        //se cargan las texturas
        TexturePaint paint = new TexturePaint( bufferedImage,
                new Rectangle2D.Double( 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight() ) );                
        
        //pinta cuerpo y borde del panel
        g2.setPaint(paint);
        g2.fill( polygonPrincipal );        
        g2.setColor( new Color(119,232,228) );
        g2.setStroke(new BasicStroke( 3 ));
        g2.draw( polygonPrincipal );
        
        //panel rectangular central
        Polygon panelCentral = new Polygon();
        panelCentral.addPoint( 40, 40 );
        panelCentral.addPoint( 460, 40 );
        panelCentral.addPoint( 460, 340 );
        panelCentral.addPoint( 40, 340 );        
        g2.setPaint(new GradientPaint(0, 0, new Color(18,62,69,240), 460, 0, new Color(0,2,6,220)));
        g2.fill( panelCentral );
        
        //bordes panel central
        g2.setStroke(new BasicStroke( 1 ));
        g2.setColor( new Color(221,0,1) );
        g2.draw(panelCentral );
        //esquinas
        g2.setStroke(new BasicStroke( 3 ));
        
        g2.drawLine(40, 40, 50, 40);
        g2.drawLine(40, 40, 40, 50);
        
        g2.drawLine(460, 40, 450, 40);
        g2.drawLine(460, 40, 460, 50);
        
        g2.drawLine(460, 340, 460, 330);
        g2.drawLine(460, 340, 450, 340);
        
        g2.drawLine(40, 340, 50, 340);
        g2.drawLine(40, 340, 40, 330);
        
        //logo jc mouse 🙂
        g2.drawImage(logo, 367, 256, 80, 80, null);    
    }
    
    /**
     * dado un image retorna un BufferedImage
     * @param img Image
     * @return BufferedImage
     */
    private BufferedImage imageToBI(Image img){          
        BufferedImage bi = new BufferedImage(img.getWidth(null), img.getHeight(null),BufferedImage.TYPE_INT_RGB);
        Graphics g = bi.createGraphics();
        g.drawImage(img, 0, 0, null);
        g.dispose();
        return bi;
    }
    
}//NetPanel

Paso 5. NetFrame

Para acabar el post se implementan todos los componentes personalizados en un JFrame, aprovechando que java 7 y 8 soportan transparencia se le da un fondo transparente al JFrame de esta forma lo único que se vera sera la forma irregular del NetPanel. Como le quitamos los bordes al JFrame, implementaremos que este pueda ser desplazado por pantalla usando el mouse.

package net.jc_mouse.authentication;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
/**
 * @web http://www-jc-mouse.net/
 * @author mouse
 */
public class NetFrame extends JFrame implements MouseListener,MouseMotionListener{
    
    private final Font LABEL_FONT   =   new Font("Agency FB", Font.PLAIN, 24 );
    private final Color LABEL_COLOR =   new Color(214,214,212);
    
    private Point initialClick;//para el movimiento
    
    /**
     * Constructor de clase
     */
    public NetFrame(){
      NetFrame.this.setUndecorated(true);
      initComponents();
      NetFrame.this.setLocationRelativeTo(null);      
      NetFrame.this.addMouseListener(NetFrame.this);
      NetFrame.this.addMouseMotionListener(NetFrame.this);
    }
     
    private void initComponents() {                
        setResizable(false);
        NetFrame.this.setBackground(new Color(0,0,0,0));//transparencia total
        
        NetPanel panel = new NetPanel();
        panel.setLayout(null);
        
        //objetos que forman la interfaz
        JLabel lbName = new JLabel("USUARIO");
        lbName.setFont(LABEL_FONT);
        lbName.setBounds(80, 80, 340, 32); 
        lbName.setForeground(LABEL_COLOR);
        
        NetTextField userText = new NetTextField();        
        userText.setBounds(80, 120, 340, 36); 
        
        JLabel lbPass = new JLabel("CONTRASEÑA");
        lbPass.setFont(LABEL_FONT);
        lbPass.setBounds(80, 170, 340, 32); 
        lbPass.setForeground(LABEL_COLOR);
        
        NetTextField passText = new NetTextField();        
        passText.setBounds(80, 210, 340, 36); 
        
        //botones
        NetButton btn1 = new NetButton();
        btn1.setText("ACEPTAR");
        btn1.setBounds(80, 260, 120, 36); 
        
        NetButton btn2 = new NetButton();
        btn2.setText("CANCELAR");
        btn2.setBounds(210, 260, 120, 36); 
        
        //listener        
        btn1.addActionListener((ActionEvent e) -> {
            if(userText.getText().equals("jc mouse") && passText.getText().equals("123456")){
                NetCustomDialog myDialog = new NetCustomDialog(NetFrame.this, true, "Exito: Los datos son correctos");
                 if(myDialog.getAnswer()){
                     /* accion a realizar */
                 }    
            }else{
                NetCustomDialog myDialog = new NetCustomDialog(NetFrame.this, true, "Error: Los datos son incorrectos!");
                 if(myDialog.getAnswer()){
                     /* accion a realizar */
                 }    
            }
        });//btn1
        
        btn2.addActionListener((ActionEvent e) -> {
            System.exit(0);
        });//btn2
        
        //se añade todo 
        panel.add(lbName);
        panel.add(userText);        
        panel.add(lbPass);
        panel.add(passText);        
        panel.add(btn1);
        panel.add(btn2);
        
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);        
        getContentPane().add(panel);
        pack();
    }
    
    public static void main(String args[]){
        EventQueue.invokeLater(() -> {
            new NetFrame().setVisible(true);
        });
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        //obtiene posicion de la ventana
        int thisX = getLocation().x;
        int thisY = getLocation().y;

        //determina el desplazamiento
        int xMoved = (thisX + e.getX()) - (thisX + initialClick.x);
        int yMoved = (thisY + e.getY()) - (thisY + initialClick.y);

        //mueve la ventana a su nueva posicion
        int X = thisX + xMoved;
        int Y = thisY + yMoved;
        this.setLocation(X, Y);
    }

    @Override
    public void mouseMoved(MouseEvent e) {}

    @Override
    public void mouseClicked(MouseEvent e) {}

    @Override
    public void mousePressed(MouseEvent e) {
        setCursor(new Cursor(Cursor.MOVE_CURSOR));
        initialClick = e.getPoint();
        getComponentAt(initialClick);
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    }

    @Override
    public void mouseEntered(MouseEvent e) {}

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

Si todo salio bien hasta aquí, ejecutamos y probamos el resultado. Usuario: jc mouse Contraseña: 123456

enjoy!!!

Si te ha gustado podrías compartirlo o dejar un comentario. ¡Muchas gracias!

Sobre el autor y el sitio web

Yo soy yo :) Mouse o como algunos de ustedes me llaman 'El Cochinote', Soy orgullosamente boliviano soy fundador y CEO de la web jc-Mouse.net uno de las pocas web en emprendimiento y tecnología en Bolivia.

Toda la información que encuentres en este sitio es y sera completamente gratis siempre, puedes copiar, descargar y re-publicar si así lo deseas en otros blogs o sitios web, solo te pido a cambio que dejes una referencia a esta web. Esto nos ayuda a crecer y seguir aportando. Bye

Enjoy! :)

ENTRADAS QUE TE PUEDEN INTERESAR

9 comentarios en “Crea formulario de login estilo Agents of Shield Marvel”

  1. neo dice:

    Error en la clase, NetTextField, el codigo es el mismo que la clase NetButton

    1. Mouse dice:

      gracias viejo 🙂 corregido

  2. Edwin dice:

    Muy buen Post, se ve excelente

  3. Angel dice:

    Hola mouse, buen tutorial, estoy intentando hacer lo mismo con un JTextArea, lo personlize y le di otra forma, pero no me funcionan las ScrollBars, el texto se escribe pero no puedo bajar para seguir viendo el contenido, ¿como puedo agregarle las scrollbars a un JTextArea modificado igual? por que no me funciona amigo, gracias y espero que me puedas ayudar.

    1. Mouse dice:

      cuando creas el textarea debes agregarle a un JSCrollPane, mas o menos asi:
      JTextArea textArea = new JTextArea();
      JScrollPane scrollPane = new JScrollPane(textArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

      y el scrollpane agregas a tu formulario

  4. Miguel dice:

    Excelente tutorial amigo, podrias con tiempo realizar alguno para personalizar una JTable o una progressbar, seria muy util, sigue asi, excelentes entradas.

  5. Luis carlos dice:

    Buen día, quisiese que me ayudaran, me genera error en la línea donde aparece este operador -> me podrían decir cómo funciona

    Gracias

    1. Mouse dice:

      actualiza java. Eso es parte de Lamba

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *


*

Comparte lo que sabes

Categorias

Android Bolivia

Bandera en Alto

Ultimas entradas

En este oportunidad comparto una pequeña aplicación hecha en java para recortar partes de una imagen seleccionado con el...

En este post crearemos un componente que solo hay en android y que no esta disponible en la paleta de controles de Netbe...

Radio.Garden es un proyecto interactivo desarrollado por el Instituto Holandés para el Sonido y la Visión en cooperación...

Una cola doblemente terminada o deque es una estructura de datos lineal que permite insertar y eliminar elementos por am...

Web amigas