Imagens de fundo (backgrounds) são extremamente essenciais para certos layouts. Um simples gradient ou uma marca d’água representam um grande diferencial e tornam a aplicação mais agradável.

Infelizmente, o componente JFrame, até a versão 6.0 do JDK, não possui uma propriedade específica que possibilite configurar uma imagem como plano de fundo. Nesse caso é necessário implementar uma maneira, das várias possíveis, para disponibilizar esse recurso.

Definindo uma imagem de fundo

Para o exemplo do artigo, será usada uma imagem simples representando um gradient com dimensões 1024x768, que é a resolução mais utilizada atualmente nos desktops e armazenada no “C:\” como indica a figura a seguir:

ascjfiffig01.jpg

O caminho da imagem que será utilizado pelo Java nesse caso será: “C:\bg_gradient.jpg”.

O método paintComponent

Como citado anteriormente, para se criar a possibilidade de definição de uma imagem de fundo, é necessário implementá-la manualmente.

Os JFrames possuem uma propriedade chamada contentPane que é o componente padrão onde são adicionados todos os componentes específicos como botões, labels, áreas de texto, etc.

Este contentPane possui um método chamado paintComponent que é o método responsável por desenhá-lo (o que é exibido para o usuário). E é ele quem será implementado.

A Listagem 01 exibe uma private class que será utilizada mais adiante no artigo. Primeiramente é interessante focar na implementação de paintComponent.

private class NewContentPane extends JPanel{
//método implementado de JPanel
protected void paintComponent(final Graphics g) {
               super.paintComponent(g);
               g.drawImage(bImage, 0, 0, this);
        }
}

Listagem 01 – Classe interna que implementa paintComponent

A classe interna NewContentPane é uma classe filha de JPanel e será o novo contentPane de JFrame.

Super.paintComponent(g) chama o respectivo método, porém, de JPanel, para que não sejam perdidas as visualizações-padrão de um JPanel. Em seguida, o método drawImage “desenha” bImage (imagem utilizada como background – descrita na próxima etapa do artigo).

Com isso tem-se uma classe filha de JPanel, porém com uma imagem desenhada ao invés de uma cor padrão.

O JFrame com o novo contentPane

Será desenvolvido agora o JFrame adaptado com o novo contentPane.

A Listagem 02 representa o código-fonte da classe JFrameWithBackground com a classe interna criada anteriormente.

package br.com.jm.jframes;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class JFrameWithBackground extends JFrameFactory{

        Image bImage;

        public JFrameWithBackground(String path){
               this.bImage = this.createImage(path);
               this.initComponents();
        }

        public void initComponents(){
               super.setContentPane(new NewContentPane());
               super.setExtendedState(JFrame.MAXIMIZED_BOTH);
        }

        private Image createImage(String path){
               return Toolkit.getDefaultToolkit().createImage(path);
        }

        private class NewContentPane extends JPanel{
               protected void paintComponent(final Graphics g) {
                       super.paintComponent(g);
                       g.drawImage(bImage, 0, 0, this);
               }
        }
}

Listagem 02 – JFrameWithBackground

O construtor da classe recebe uma String que representa o caminho da imagem e em seguida chama o método createImage. Esse método chama a função createImage da classe Toolkit (java.awt.Toolkit) que retorna uma imagem de acordo com esse caminho. A variável, anteriormente citada, bImage agora representa a imagem de fundo do JFrame.

É dentro do método initComponents que se faz a alteração do contentPane que agora será uma instância de NewContentPane (classe interna criada no início do artigo e que implementa paintComponent).

Como isso tem-se um JFrame que possui um contentPane diferente do padrão; que possui uma imagem de fundo.

Testando o novo JFrame

Falta apenas testar o novo JFrame e sua nova capacidade (possuir uma imagem de fundo). A Listagem 03 exibe uma classe simples com um panel adicionado.

import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;

import br.com.jm.jframes.JFrameWithBackground;

public class TesteJFrameWithBackground {
        public static void main(String[] args) {
               try{
                       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
               } catch(Exception exception){

               }

               JPanel jPanel3 = new JPanel(new BorderLayout());
               jPanel3.add(new JLabel("teste-background"), BorderLayout.NORTH);
               jPanel3.add(new JLabel("texto:"), BorderLayout.WEST);
               jPanel3.add(new JScrollPane(new JTextArea()), BorderLayout.CENTER);
               jPanel3.add(new JLabel("teste-background-fim"), BorderLayout.SOUTH);
               jPanel3.setPreferredSize(new Dimension(400,500));
               jPanel3.setBorder(BorderFactory.createTitledBorder("jPanel3"));
               jPanel3.setOpaque(false);

               JFrameWithBackground jFrame = new JFrameWithBackground("C:\\bg_gradient.jpg");
               jFrame.setLayout(new BorderLayout());
               jFrame.getContentPane().add(jPanel3, BorderLayout.NORTH);
               jFrame.setVisible(true);
        }
}

Listagem 03 – Classe de testes

A imagem passada como parâmetro para JFrameWithBackground é a citada no início do artigo.

Conclusão

Implementando paintComponent de JPanel e armazenando essa implementação como novo contentPane de um JFrame foi possível criar um frame com uma imagem de fundo. À medida que essa nova classe vai sendo desenvolvida, pode-se criar métodos set e get que permitam atualizar, em tempo de execução, a imagem de fundo, tornando-a dinâmica.