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:
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.