Aplicación MDI (JDesktopPanel) con imagen de fondo

24Nov08

Para conseguir colocar una imagen de fondo en una aplicación MDI (que utiliza JDesktopPane) realizamos un proceso similar al que realizamos para hacer lo mismo con un JPanel, es decir, sobrescribir el método paint, dibujando la imagen del tamaño del desktop panel, y luego sobre esta imagen el resto de las ventanas internas (JInternalFrame)

Código:

import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
//...

public class DesktopConFondo extends JDesktopPane {

    private Image imagen;

	//...

    @Override
    public void paint(Graphics g) {
		g.drawImage(imagen, 0, 0, getWidth(), getHeight(),
                         this);

		setOpaque(false);
        super.paint(g);
    }

	//...
}

Como podemos ver en el método paint hemos especificado tres lineas:

  • g.drawImage: dibujamos la imagen (guardada en el atributo “imagen”) en toda la extension del panel
  • setOpaque(false): le indicamos al panel que no dibuje su fondo por defecto (sino este taparía la imagen)
  • super.paint(g): le indicamos al panel que continúe dibujando el resto de los componentes
JDesktopPanel con imagen de fondo

JDesktopPanel con imagen de fondo

Redimensionado

Una cosa importante a la hora de dibujar la imagen es que lo hacemos desde el pixel [0,0] hasta el pixel [getWidth(), getHeight()], esto indica que cubrirá toda la extensión del panel en ese momento, permitiéndonos que la imagen acompañe una redimension del panel.

Redimensionando MDI

Redimensionando MDI

Algunas Variaciones

Una variación puede ser que el panel dibuje la imagen solo si está asignada a la variable “imagen”, en caso contrario (imagen == null) se dibujara el fondo por defecto:

	//...

    @Override
    public void paint(Graphics g) {
        if (imagen != null) {
            g.drawImage(imagen, 0, 0, getWidth(), getHeight(),
                     this);

            setOpaque(false);
        } else {
            setOpaque(true);
        }

        super.paint(g);
    }

	//...

La carga de la imagen la podemos realizar en el constructor:

	//...

    public DesktopConFondo(Image imagenInicial) {
        if (imagenInicial != null) {
            imagen = imagenInicial;
        }
    }

	//...

o que la misma pueda ir variando:

	//...

    public void setImagen(Image nuevaImagen) {
        imagen = nuevaImagen;

        repaint();
    }

	//...
Cambiando la imagen dinámicamente

Cambiando la imagen dinámicamente

De este método podemos observar dos cosas:

  • repaint(): Lo llamamos explícitamente para que cuando cambiemos la imagen esta se muestre inmediatamente.
  • Si el parámetro nuevaImagen es null, veremos el fondo por defecto.
Fondo por defecto (imagen == null)

Fondo por defecto (imagen == null)

Código

Este es el código del panel completo:

package ar.lefunes.mdiconimagen;

import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JDesktopPane;

public class DesktopConFondo extends JDesktopPane {

    private Image imagen;

    public DesktopConFondo() {
    }

    public DesktopConFondo(String nombreImagen) {
        if (nombreImagen != null) {
            imagen = new ImageIcon(
                         getClass().getResource(nombreImagen)
                         ).getImage();
        }
    }

    public DesktopConFondo(Image imagenInicial) {
        if (imagenInicial != null) {
            imagen = imagenInicial;
        }
    }

    public void setImagen(String nombreImagen) {
        if (nombreImagen != null) {
            imagen = new ImageIcon(
                         getClass().getResource(nombreImagen)
                         ).getImage();
        } else {

            imagen = null;
        }

        repaint();
    }

    public void setImagen(Image nuevaImagen) {
        imagen = nuevaImagen;

        repaint();
    }

    @Override
    public void paint(Graphics g) {
        if (imagen != null) {
            g.drawImage(imagen, 0, 0, getWidth(), getHeight(),
                     this);
            setOpaque(false);
        } else{
            setOpaque(true);
        }

        super.paint(g);
    }
}

Ejemplo Descargable

Puedes descargar el ejemplo completo desde (aprox. 38,3 KB): http://lefunes.googlecode.com/files/MDI_imagen_fondo.zip



15 Responses to “Aplicación MDI (JDesktopPanel) con imagen de fondo”

  1. Muchas gracias me sirvio mucho :d

  2. 2 Gocht

    No me funciona el codigo que descargue

  3. 3 foraneo

    Magnifico aporte muchas gracias!

  4. 4 kike

    Una duda, yo estoy utilizando jdestokpane, para mostrar internalframe que abro al pulsar en opciones de menu, el problema es que se ve el “marco “, con un fondo azul, del jdestokpane, y no quiero que se vea , ya que queda muy feo el marco con el fondo azul, sin tener nada seleccionado, haber si me podeis ayudar, gracias…

  5. 5 German

    Hola. Quería comentarles que me encontré de casualidad con este blog y me servido de mucha ayuda, se me complico un poquito con las direcciones de las imágenes pero logre encontrar la forma. He estado vichando sobre el manejo de fechas y usar parecido a lo que en Visual seria un DataTimePicker y no he encontrado mucha información que me sirva. Si tuvieran algún material que pueda ayudarme se los agradezco mucho.
    Muchas gracias el Blog esta muy bueno.Saludos!

  6. 6 Luispe

    Hola, una consulta:

    Es posible poder tener como fondo un objeto “JPanel” en lugar de una imagen ?
    Eso serviría por ejemplo para reproducir videos en los paneles y dar la sensación de “Picture in Picture” como en una TV.

    De no ser asi de que forma podría realizarlo ?

    Gracias y saludos !

  7. 7 suri

    Hola, cuando ejecuto tus ejemplos con el Netbeans 6.1 me sale un error al hacer click en los botones para establecer el fondo…

    Exception in thread “AWT-EventQueue-0” java.lang.NullPointerException
    at javax.swing.ImageIcon.(ImageIcon.java:138)
    at ar.lefunes.jpanelconfondo.JPanelConFondo.setImagen(JPanelConFondo.java:29)
    at ar.lefunes.jpanelconfondo.EjemploJPanelConFondo.btFondo1ActionPerformed(EjemploJPanelConFondo.java:92)
    at ar.lefunes.jpanelconfondo.EjemploJPanelConFondo.access$000(EjemploJPanelConFondo.java:3)
    at ar.lefunes.jpanelconfondo.EjemploJPanelConFondo$1.actionPerformed(EjemploJPanelConFondo.java:29)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
    at java.awt.Component.processMouseEvent(Component.java:6041)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
    at java.awt.Component.processEvent(Component.java:5806)
    at java.awt.Container.processEvent(Container.java:2058)
    at java.awt.Component.dispatchEventImpl(Component.java:4413)
    at java.awt.Container.dispatchEventImpl(Container.java:2116)
    at java.awt.Component.dispatchEvent(Component.java:4243)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4322)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3986)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3916)
    at java.awt.Container.dispatchEventImpl(Container.java:2102)
    at java.awt.Window.dispatchEventImpl(Window.java:2440)
    at java.awt.Component.dispatchEvent(Component.java:4243)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

  8. @Tadeo en la parte del GroupLayout es donde se especifica el tamaño del JDesktopPane, por lo que si no te funciona asignale mediante setSize() un nuevo tamaño al componente, ya que el JFrame se adapta a los componentes internos (y el único componente que tiene incluido, tiene un tamaño de 0,0)

    Saludos

  9. 9 Tadeo

    Hola, tu ejemplo me jalo muy bien, pero cuando quise implementarlo el desktopPane me sale reducido, solo se la barra de menu, y para que se vea la imagen tengo que redimensionar la ventana, ¿Que hago para que la ventana aparezca desde el principio mostrando la imagen completa?, aa por cierto en el codigo omiti la parte de GroupLayout porque al correr la aplicación me lanza una excepción de estar agragando el panel hijo esta agregando a su padre.

  10. @Ramiro el método getClass().getResource(nombreImagen) busca desde la clase que obtienes con getClass() la ruta relativa al recurso, por lo que si tu clase se encuentra en el directorio “gimnasio” de la forma “gimnasio/DesktopConFondo.java” y la imagen la colocas en “gimnasio/recursos/imagen.jpg” deberás pasarle como nombreImagen la cadena “recursos/imagen.jpg”

    Saludos

  11. 11 Ramiro

    Una consultita mas. Con respecto a direcciones relativas de los archivos. En este caso de la imagen. Vos lo pusiste como “recursos/imagen.jpg” yo hago lo mismo y la imagen es nula. Hay que establecer algo en las propiedades del proyecto? Porque pongo la direccion relativa de mi paquete, en el cual tengo la imagen al igual que en tu proyecto y no trae la imagen. Mi proyecto se llama “Gimnasio” y la imagen se encuentra en “gimnasio/recursos/imagen.jpg” y como direccion relativa le pongo en el metodo “recursos/imagen.jpg”

  12. 12 Ramiro

    Ahi lo solucione, muchas gracias. Era que habia dejado el initComponents() que Netbeans hace automaticamente asi nomas. No habia visto que tu habias modificado la linea de creacion.

    Muchas gracias y saludos!

  13. @Ramiro fijate donde creas el objeto con el cual inicializas la variable iPanel, ya que está almacenando en ella un objeto JDesktopPane (no un DesktopConFondo como estas esperando)

    Saludos

  14. 14 Ramiro

    Hola! Disculpa que moelste, pero he probado tu ejemplo y me anda perfecto, pero en mi proyecto no anda lo que hiciste. No me deja castear de un JDesktopPane a un DesktopConFondo. Pero vuelvo a repetir, tu ejemplo lo ejecuta satisfactoriamente.

    A mi Panel lo tengo como public static. Influye en algo eso?

    el Panel se encuentra dentro de un FrameView

    Mi error:

    Exception in thread “AWT-EventQueue-0” java.lang.ClassCastException: javax.swing.JDesktopPane cannot be cast to gimnasio.clases.utilidades.DesktopConFondo

    y el boton que lo origina

    private void btnFondoActionPerformed(java.awt.event.ActionEvent evt) {
    ((DesktopConFondo) iPanel).setImagen(“/amigo.jpg”);
    }

  15. 15 luis

    no se vale ese era mi truco ajja
    vale te salio mejor que a mi
    ya me avia salido antes pero lo usava con Jcomponent y yo que me preguntaba por que no se podia pintar bien en un Jpanel



A %d blogueros les gusta esto: