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.
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:
Necesitamos
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.
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.
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.
Paso 2. Proyecto en netbeans
En Netbeans creamos un nuevo proyecto con el nombre de «MarvelAuthentication» y le agregamos los siguientes paquetes y archivos.
A continuación una breve explicación de cada uno de las clases java:
En el paquete «resource» tenemos dos imágenes que son:
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:
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!!!
En un post anterior conocimos una herramienta Open Source con un conjunto de herramientas para el trabajo con imágenes e[...]
¿Que es la facturación electrónica? Una factura es un documento que sirve para describir el costo de los servicios y des[...]
Para terminar el tutorial, debemos unir tanto la VISTA como el MODELO y para eso esta el CONTROLADOR. o.O El controlador[...]
Desde java 7 esta disponible la interface ExecutorService que se extiende de Executor y nos proporciona los métodos nece[...]
Lo que veremos en este post es la configuración del driver para PHP de SQL Server que ha creado Microsoft el cual permit[...]
En un post anterior vimos como utilizar GSON para serializar un objeto java en JSON, en esta oportunidad se vera el proc[...]