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.