martes, 6 de septiembre de 2011

HOW TO: JDesktopPane Background Image, JInternalFrame Transparent Title Bar

Hey hola a todos :) mas de alguna vez hemos querido darle un aspecto un poco mas vistoso a nuestras aplicaciones Swing en Java, ademas de eso, como todos sabemos algunos Look and Feel nos ayudan bastante (como el caso de Nimbus), pero aun asi, no estamos conforme con el resultado final.
Entonces supongamos que nuestra aplicacion se mira asi:


ummmm... la verdad, por muy bueno que sea el funcionamiento de la aplicacion no deja de ser un poco "aburrida" para el usuario final (al cual casi siempre le gusta ver que las pantallas tengas fuegos artificiales).
Obviamente no puedo hacer que las pantallas tengas dichos efectos x) pero almenos vamos a mejorar su aspecto haciendo la barra de titulo transparentes y una imagen de fondo a la pantalla principal. quedando el resultado final:



Bueno ahora es el momento indicado para decir: "No es lo que estoy buscando!!! esto no me sirve" y hacer clic en el icono de la flecha de "go back" de tu navegador x).



Ok, si aun estas leyendo significa que tu piensas que el siguiente código puede ser de utilidad en alguna aplicación que estes desarrollando, asi que empecemos.

Voy empezar explicando como se logra la transparencia en los JInternalFrame. en verdad es muy sencillo y simple como crear una subclase de JInternalFrame y sobre-escribir el método paintComponent.
Entonces nuestras clase queda de la siguiente manera:
package NEW.newpackage;

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.Icon;
import javax.swing.JInternalFrame;

/**
 *
 * @author McCubo
 * @version 1.0
 * @website http://www.gnuteam.blogspot.com
 */
public class CustomInternalFrame extends JInternalFrame{

    public CustomInternalFrame(String title) {
        super(title, true, true, true, true);
    }

    public void setIcon(Icon anIcon){
        setFrameIcon(anIcon);
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        g.setColor(new Color(100, 0, 4, 85));
        g.fillRoundRect(0, 0, getWidth(), getHeight(), 15, 15);
    }

}

Como dije anteriormente, bastante sencillo, ahora lo único que debemos hacer es crear clases que extiendan de CustomInternalFrame y agregarlas el JDesktopPane de nuestra aplicación ^^.

Ahora crearemos una clase que implemente la interfaz Border, dicha clase le indicamos la ruta del archivo a cargar como fondo e implementamos los metodos que la interfaz requiere. quedando dicha clase de la siguente manera:

package NEW.newpackage;

import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.border.Border;

/**
 *
 * @author McCubo
 */
public class BackgroundImage implements Border{
    public BufferedImage back;

    public BackgroundImage(){
        try {
            URL imagePath = new URL(getClass().getResource("../resources/logo_backup.png").toString());
            back = ImageIO.read(imagePath);
        } catch (Exception ex) {
            
        }
    }

    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        g.drawImage(back, (x + (width - back.getWidth())/2),(y + (height - back.getHeight())/2), null);
    }

    public Insets getBorderInsets(Component c) {
        return new Insets(0,0,0,0);
    }

    public boolean isBorderOpaque() {
        return false;
    }

}
Ahora un ejemplo de la clase principal podria ser:

package NEW.newpackage;

import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.UIManager;

/**
 *
 * @author McCubo
 * @version 1.0
 * @website http://www.gnuteam.blogspot.com
 */
public class MainFrame extends JFrame {

    private JDesktopPane jdesktopPane = new JDesktopPane();

    public MainFrame() {
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            setSize(new Dimension(500, 300));
            setIconImage(new ImageIcon("src/NEW/newpackage/icon.png").getImage());
            setLayout(new BorderLayout());
            CustomJInternalFrame1 customInternalFrame = new CustomJInternalFrame1();
            jdesktopPane.add(customInternalFrame);
            CustomJInternalFrame1 customInternalFrame1 = new CustomJInternalFrame1();
            jdesktopPane.add(customInternalFrame1);            
            add(jdesktopPane, BorderLayout.CENTER);
            customInternalFrame1.setVisible(true);
            customInternalFrame.setVisible(true);
            //Aca indicamos la clase con la imagen de fondo
            jdesktopPane.setBorder(new BackgroundImage());
            setVisible(true);
            setDefaultCloseOperation(EXIT_ON_CLOSE);
        } catch (Exception ex) {
            System.out.println(ex);
        }
    }

    public static void main(String[] args) {
        new MainFrame();
    }
}

Implementando esas clases el resultado final seria parecido al de la segunda imagen de esta entrada.
Solamente unos puntos que debo aclarar: la barra transparente solo la he probado con el Look and Feel de Nimbus y con el de Java de defecto, y resulta todo bien con Nimbus :D.

Por alguna duda en el código, dejo el proyecto completo en este enlace: Descargar Proyecto

Espero te sirva aunque sea una linea de todo el código acá presentado, no olvides de suscribirte o hacerte seguidor del blog/twitter para saber cuando se publiquen nuevas entradas.
Hasta la próxima, Saludos!!!

26 comentarios:

  1. @Yuan_007: me alegra que te parezca util la entrada, Saludos!

    ResponderEliminar
  2. UUU espero que me sirva gracias!

    ResponderEliminar
  3. @Anónimo
    Espero que te haya servido que si te funciones :) Saludos y Gracias por comentar

    ResponderEliminar
  4. Espero me sirva como a los que me antecedieron... gracias de antemano y que gran idea de colocar un resultado final, para que el lector sepa si le servirá o no... = )

    Gracias macho!!!!

    ResponderEliminar
  5. @Anónimo
    Gracias por comentar hombre! y cualquier duda en esta u otra entrada no dudes en comentarla en el respectivo post y vamos a tratar de solucionarla. Saludos!!

    ResponderEliminar
  6. Gracias por lo del JInternal frame buena fapTality digo fatality jeeeeeee

    ResponderEliminar
  7. @Radamanthys17
    Si man ahí dale con todo vos sabes. y la fapTality solo en NAPB comenta de eso xD me van a censurar el blog jajajaja kasettt pero con todo ahi. Nos vemos!!

    ResponderEliminar
  8. oye me podrías explicar como crear un color usando esto [new Color(78,100,224,0,0);]

    ResponderEliminar
    Respuestas
    1. Hola Daniel. pues la verdad me parece que ese constructor no existe para la clase awt.Color, posiblemente te quiera referir a un constructor sin el ultimo parámetro, ósea:
      new Color(int, int, int, int);
      con cuatro parámetros tipo int, usando ese constructor en teoría es bastante fácil entender cómo se crean los colores, simplemente le pasas el nivel de RGBA (Red, Green, Blue, Alpha), solo tienes que ir jugando con las infinitas combinaciones de colores para cada parámetro, eso sí, los rangos aceptados son 0-255, entre mas alto el numero, mas saturado de ese color será el resultado.

      Eliminar
  9. oye el "CustomJInternalFrame1" me da un Error :( dice "cannot br resolved to a type", por que podria ser? pues queria probar tu publicación pero fue el unico error...

    ResponderEliminar
    Respuestas
    1. Hola :D... pues la verdad es extraño que no te corra el código. en fin subo el proyecto donde esta el ejemplo (por si el enlace de arriba tuviera un error)
      http://www.mediafire.com/?08ccb7zgg1t5pw0
      Es un proyecto Netbeans, tienes que abrir el proyecto con ese IDE y todo listo, espero te funcione, Saludos!

      Eliminar
  10. Buenísimo :)
    Si no les funciona [http://www.mediafire.com/?08ccb7zgg1t5pw0] descarguen. jajaja

    ResponderEliminar
  11. Hola, muy bueno el blog, les queria consultar dado que estuve buscando y no encuentro la manera de centrar en la ventana principal varios JInternalFrame sin la necesidad de ir a propiedades-code y cambiar por Generate Resize Code, dado que me tira el JInternalFrame abajo, nose si me pudieran explicar de como hacerlo con un codigo o de otra manera, desde ya muchas gracias. Patricio.

    ResponderEliminar
    Respuestas
    1. Hey hola :). te dejo un pequeño codigo (basado en el codigo de este post) como centrar el jinternalframe, primero hay que darle un valor por defecto al JDesktopPane asi:
      jdesktopPane.setSize(1000, 600); // JDesktopPane que usas para contener todos los JInternalframes
      Luego despues de crear el JInternalframe agrega estas lineas:
      Dimension desktopPaneSize = jdesktopPane.getSize(); // Dimensiones del JDesktopPane
      Dimension jInternalFrameSize = internalFrame.getSize(); // Dimensiones del JInternalframe a cargar
      // Esto centra el JInternalFrame en la pantalla (JFrame)
      internalFrame.setLocation((desktopPaneSize.width - jInternalFrameSize.width) / 2,
      (desktopPaneSize.height - jInternalFrameSize.height) / 2);

      Aveces es mejor buscar en Google es mejor buscar en Ingles, debido a que hay comunidades mas grandes en dicho idioma, te dejo el enlace de donde lo encontre para que le des una leida:
      http://stackoverflow.com/a/7502856

      Eliminar
    2. También perdón por la tardanza de la respuesta, Espero te aclare las dudas, sino pues por acá estamos para ayudar :)

      Eliminar
    3. Hola Miguel, muchas gracias por tu repuesta, utilize el codigo para darle un valor por defectos al JDesktopPane el cual me sirvio, luego cuando utilizo el codigo para centrar los JInternalFrame me sale error en el internalFrame.getSize(); y luego en internalFrame.setLocation, desde ya muchas gracias. Saludos.

      Eliminar
    4. Hola, que tipo de error? excepción en tiempo de ejecución o de compilación?. seria bastante bueno que explicaras un poco el tipo de error.
      Debes tener una instancia de JInternalFrame antes de querer utilizar los métodos de esa clase, osea, antes del internalFrame.getSize(); Tienes que tener algo como:

      JInternalFrame internalFrame = new JInternalFrame();

      Eso es lo primero que me viene a la mente, pero si es una excepción la que arroja, postea la excepción y veremos como podemos ayudarte.
      Saludos!

      Eliminar
  12. Lo probé y me funciono pero ahora como lo adapto a un JInternarlFrame que ya tengo es decir tengo una clase por cada uno de mis internalframe pero ahora quiero que se vean como el de tu ejemplo como seria??

    public class VistaSecretaria
    {
    private JMenuBar barraMenu;
    private JMenu menuNuevo,menuEliminar;
    private JMenuItem nuevoAlumno,nuevoGrupo,eliminaAlumno;
    public JInternalFrame internaSecretaria;
    VistaSecretaria(JDesktopPane padre)
    {
    internaSecretaria =new JInternalFrame();
    barraMenu =new JMenuBar();
    menuNuevo =new JMenu("Nuevo");
    menuEliminar =new JMenu("Eliminar");
    nuevoAlumno =new JMenuItem("Captura Alumno");
    nuevoGrupo =new JMenuItem("Crear Grupo");
    eliminaAlumno =new JMenuItem("Elimina Alumno");
    internaSecretaria .setJMenuBar(barraMenu);
    //internaSecretaria .setVisible(true);
    internaSecretaria .setSize(975, 485);
    barraMenu .add(menuNuevo);
    barraMenu .add(menuEliminar);
    menuNuevo .add(nuevoAlumno);
    menuNuevo .add(nuevoGrupo);
    menuEliminar .add(eliminaAlumno);

    padre .add(internaSecretaria);

    }
    }

    ResponderEliminar
    Respuestas
    1. Hey hola, mira pues fíjate que deberías de descargar el proyecto que pongo a disposición en el enlace. y cuando lo tengas ya, adaptarlo a tus necesidades, porque de otra forma me tendrías que explicar que quieres hacer, y donde tienes tu clase VistaSecretaria y que hace.
      Te recomiendo eso, descarga el codigo, entiéndelo y adaptalo a tus necesidades.
      Saludos!

      Eliminar
    2. jejeje no hubo necesidad de descargar el proyecto , era tan fácil la solución me vi muy novato , simple y sencillamente tenia que crear una instancia a la clase que pones de ejemplo de la siguiente forma
      public CustomInternalFrame internaSecretaria;
      VistaSecretaria(JDesktopPane padre)
      {
      internaSecretaria =new CustomInternalFrame (null);

      y asi de facil tengo un internal como el de tu ejemplo , gracias por el ejemplo y que bien quedan las ventanitas de esta forma, gracias por el apoyo. saludos y que estés bien

      Eliminar
    3. En verdad me alegra que lo hallas solucionado :D. y aveces pasa así, se nos va una linea, yo en lo personal aveces paso buen tiempo por una comillas mal puesta o una coma xD pero como decía forrest gump: shit happens xD.
      Saludos!

      Eliminar
  13. Hola miguel, buenas noches eh probado con el consejo que me diste para poder centrar los jinternalframe, me sale un error de compilación que la verdad nose si es porque lo eh revisado mucho y no encuentro la solución, te comento mas o menos lo que quiero hacer: Tengo un jframe en donde tengo varios jinternalframe uno de ellos se llama cli_clientes, primero le doy un valor por defecto al jframe que contiene a los jinternalframa asi:

    panel.setSize(1000, 600);

    Luego me voy al jinternalframe que se llama cli_clientes y escribo el siguiente codigo:
    (Les pongo lineas para que el ejemplo sea mas facil de explicar cual es el problema)

    Linea 1 cli_clientes internalFrame = new cli_clientes();
    Linea 2 Dimension desktopSize = desktopPane.getSize();
    Linea 3 Dimension jInternalFrameSize = internalFrame.getSize();
    Linea 4 internalFrame.setLocation((desktopSize.width - jInternalFrameSize.width) / 2,
    (desktopSize.height - jInternalFrameSize.height) / 2);

    El error de compilacion me sale en la Linea 2 mas presisamente en = desktopPane.getSize();
    me dice:

    cannot find symbol
    symbol: variable desktopPane
    location: class cli_clientes

    Seria de mucha ayuda si podrias ayudarme, desde ya muchas gracias. Saludos!!

    ResponderEliminar
    Respuestas
    1. Hola Buenas noches igual. sabes, la solución mas viable que puedo ofrecerte es: envíame el código fuente que estas tratando de ejecutar, yo le doy debug acá en mi pc, y te lo reenvió, porque la verdad tendría que ver como tienes estructurado los paquetes y en que clase estas escribiendo que código.
      si te parece la idea, mi correo es: cubiascaceres@gmail.com
      Saludos!

      Eliminar
    2. Hola Miguel buenos días, te quería agradecer muchísimo el tiempo que te tomaste para ver el proyecto que te envié por email, por el tiempo que te tomaste para explicar paso a paso como centrar los jinternalframe de manera entendible y ademas hacer ejemplos que reforzaran mas tu explicación, Muchas Gracias Viejo. 100% Recomendable!!

      Eliminar
    3. Me olvidaba que es lo mas importante, gracias a la ayuda y los ejemplos eh podido centrar todos los jinternalframe de manera rápida y sencilla. Problema solucionado!!

      Eliminar