|
O JFrame é a classe do Swing que representa uma janela. Nesse artigo, vamos entender como ele funciona. Muito do que for visto aqui, será diretamente aplicável aos JApplets, portanto, mesmo que seu ideal no futuro seja trabalhar somente nos navegadores, será uma boa idéia ler esse tópico.
Do contrário da maioria dos tutoriais sobre janelas, esse não se destina a mostrar como inserir botões ou caixas de texto. Veremos o processo de pintura do Swing um pouco mais à fundo, já que desenhar uma janela é uma das atividades mais importantes num jogo.
Propriedades básicas
O JFrame é uma classe do pacote javax.swing. O primeiro passo para criar um JFrame é importar esse pacote. A criação de um JFrame é trivial, e resume-se a:
package br.com.pontov.frame;
import javax.swing.JFrame;
public class MeuPrimeiroFrame {
public static void main(String[] args) {
JFrame frame = new JFrame(“Minha primeira janela”);
frame.setVisible(true);
}
}
O que esse código faz? Basicamente, ele cria um objeto do tipo JFrame, com o título Minha primeira janela e o torna visível. Entretanto, executar esse código por ser um pouco frustrante. Primeiro, porque por padrão, a janela será criada com altura e largura 0. Depois, porque ela também será posicionada no canto superior esquerdo da tela. Finalmente, clicar no X no canto da janela irá torná-la oculta, mas não terminará o programa. Da forma como está, o programa nunca termina.
Como alterar essas propriedades? O JFrame possui uma série de atributos que podem ser modificados. Um deles já vimos no exemplo anterior, a propriedade visible, alterada através do método setVisible(). Para alterar os tamanho, por exemplo, podemos usar o método setSize(int width, int height).
Então, vamos alterar esse programa para que o nosso Frame tenha um tamanho, apareça no centro da tela e feche a aplicação, quando for o usuário clicar no x. Por questão de síntese, vou deixar aqui só o código que vai dentro do main. O resto permanece igual:
JFrame frame = new JFrame("Minha primeira janela");
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
A maior parte dos métodos é auto-explicativa. O método setLocationRelativeTo posiciona o JFrame em relação a outro componente qualquer. Ele é bastante útil se sua aplicação tem várias janelas, o que não é o caso dos jogos. Entretanto, caso nenhum componente seja passado para ele, o método automaticamente centraliza o JFrame. Você só deve tomar o cuidado para usá-lo após o comando setSize, uma vez que o código de centralização precisa conhecer o tamanho da janela. A lista completa de todos os métodos e sua descrição pode ser encontrada no javadoc da classe JFrame.
O que acontece debaixo dos panos
O método setVisible() mostra o JFrame, mas não bloqueia a aplicação naquele ponto. Ou seja, outros comandos, após o setVisible() continuarão a ser executados. Um programador Java mais atento pode estar se perguntando, “mas se isso ocorre, porque a aplicação não finalizou assim que o main terminou?”
O que acontece é que assim que a primeira janela é aberta, o Swing dispara uma thread, para as ações de pintura e é ela que mantém o programa vivo. É importante saber que essa é a única thread que realizará a pintura, em todo Swing. Cada comando de pintura é enfileirado, e essa thread executará uma ação dessa fila por vez.
Isso porque a Sun percebeu que arquiteturas thread-safe, que permitissem a atualização e pintura em várias threads simultâneas, tornariam o framework muito complexo, o que dificultaria para um programador criar seus próprios componentes já que eles também teriam que ser thread-safe. E permitir a criação de componentes personalizados é um importante fator de sucesso para qualquer arquitetura de janelas.
O Swing conhece todas as janelas criados pela aplicação. Ele então entrará em janela por janela, disparando o método:
Esse método também é disparado automaticamente caso uma janela se torne invisível e seja reexibida, total ou parcialmente. Isso pode ocorrer, por exemplo, se a janela for minimizada e restaurada, ou se algum aplicativo entrar na frente da janela momentaneamente, destruindo parte de seu conteúdo. Esse método também será invocado automaticamente caso o componente seja redimensionado.
O método também pode ser forçosamente disparado, através do comando repaint(). Isso colocará uma mensagem na fila de mensagens do Swing.
Existem dois erros comuns que os programadores novatos cometem, envolvendo o método paint:
- Desenham usando o objeto Graphics uma única vez, por exemplo, na construção do JFrame, e esperam que aquela pintura irá continuar lá. Como vimos, isso não acontecerá já que, se um trecho da janela for ocultado, quem terá que repinta-lo é o método paint, e ele só fará isso se for programado para tal.
- Fazem algum processamento pesado e pretendem mostrar mensagens em meio a esse processamento. Isso não funciona por que, como já vimos, o Swing possui uma única thread de pintura, que pinta de acordo com uma fila de mensagens.
Para entender melhor o item 2, vamos examinar passo-a-passo o que ocorre:
- A janela é pintada;
- O swing processa a primeira ação da fila, que é o processamento pesado do usuário;
- Logo no início, o programador tenta mostrar um status dizendo “Processando, aguarde”. Isso irá alterar o estado da janela, o que põe uma ação de repaint na fila;
- O processamento ocorre.
- O programador altera o status para “Pronto!”, o que enfileira um novo repaint.
- O Swing processa o primeiro repaint, pintando “Pronto!”
- O Swing descarta o segundo repaint, já que nenhum objeto mudou nesse meio tempo.
A solução para o este problema, é disparar o processamento pesado em outra thread e, nessa outra thread, enfileirar comandos de pintura no Swing. Realizamos esse enfileiramento através do comando EventQueue.ivokeLater(Runnable) ou EventQueue.invokeAndWait(Runnable). Na verdade, é uma boa prática só alterar estado de objetos Swing a partir de outras threads usando um desses comandos.
Reescrevendo nosso programa
Vamos agora deixar nosso programa mais adequado com os conceitos aprendidos. Para isso, vamos criar uma classe filha de JFrame e nela colocaremos todas as configurações de nossa janela. É uma boa prática não alterar a visibilidade do Frame em sua construção. Tipicamente, quem cria uma janela é quem deve dizer quando ela se torna visível, essa não é uma decisão que cabe a janela em si. Então, iremos fazer com que o main assuma essa tarefa. Como o main roda na thread principal e não na thread do Swing, ele deverá fazer isso usando a EventQueue. O código final, depois de pronto, fica assim:
public class MeuPrimeiroFrame extends JFrame {
public MeuPrimeiroFrame() {
super("Minha primeira janela");
setSize(400, 300);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
final MeuPrimeiroFrame mpf = new MeuPrimeiroFrame();
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
mpf.setVisible(true);
}
});
}
}
Usamos agora o super, para chamar o construtor da classe pai, JFrame, passando o título. Ajustamos o tamanho, localização e comando padrão de fechamento da janela, já no construtor. Por fim, nosso main cria um objeto da nossa janela, e em seguida o torna visível, usando para isso a EventQueue.
Mas, qual a vantagem dessa abordagem? A vantagem é que agora poderemos sobrescrever o método paint(). E exatamente é exatamente nesse ponto que iniciará o nosso tutorial de Java 2D.
Observações finais
Em jogos, iremos sobrescrever o método paint(). Entretanto, o Swing para aplicações comerciais já facilitou muito a tarefa de fazer janelas. Na classe JFrame, você encontrará o método add, que permite a adicionar um novo componente no interior do JFrame. Por padrão, o método paint() do JFrame irá percorrer todos os seus componentes, e chamar seus respectivos métodos paint. O método paint da classe JComponent então dispara 3 métodos:
- paintBorder(Graphics): Que pinta uma borda ao redor do componente;
- paintComponent(Graphics): Em componentes, esse método é equivalente ao paint. Se você estiver escrevendo um componente, sobrescreva paintComponent() no lugar de paint().
- paintChildren(Graphics): Pinta os componentes que forem colocados sobre o seu componente. No caso de um painel, por exemplo, pintaria todos os botões, caixas de textos, etc., dentro desse painel.
Vários componentes já estão presentes na enorme biblioteca do Swing, e muitos programadores sequer usarão os métodos de pintura diretamente na vida. Alguns deles são: Painéis (JPanel), botões (JButton, JCheckBox, JRadioButton), caixas de texto (JTextField, JTextArea, JFormattedTextField, JEditorPane), tabela (JTable), entre outros.
O Swing também possui três tipos de janela: O JFrame, que vimos até agora, o JDialog e o JInternalFrame. O JDialog é similar ao JFrame, mas representa uma caixa de diálogo. Por isso, ela pode ser tornada modal, ou seja, impedir que o usuário realize outras ações fora da janela, até que seja fechada. Outra diferença é que o método setVisible() de janelas modais é bloqueante. O JInternalFrame é uma janela desenhada dentro de outra, na verdade, dentro de um JDesktopPane. Ele não pode ser arrastado para fora do desktop pane que a possui.
Não entraremos em detalhes sobre como montar uma janela Swing padrão ou sobre como criar componentes personalizados. Para isso, a sun já disponibiliza extensa documentação em seu site, como a do trail: Creating GUI with JFC/Swing. Em jogos, geralmente sobrescreveremos totalmente a pintura e criaremos à mão todo cenário e seus atores.
Finalmente, vale relembrar que os conceitos de pintura vistos aqui também valem para o JApplet.
-
26/04/2010 23:17:01 |187.41.0.xxx| Tiago

Olá, Vinícius. Como profissional quero agradecer a você por está compartilhando o teu conhecimento de forma colaborativa para nós aprendizes. É raro encontrar hoje alguém que tenha tal conhecimento e queira disponibilizá-lo desta forma aos colegas de profissão. Mais uma vez, parabéns pela iniciativa e, acredite, é de pessoas assim que a nossa profissão precisa para ter um espaço reconhecido no nosso país. Grande abraço garoto, fica com Deus e sucesso!
-
22/08/2010 20:45:35 |200.188.228.xxx| vinicius hisao suzuki - ótimo

sou professor de jogos em java e adorei o artigo. certamente vou usar seu guia como referência em minhas aulas.
-
22/08/2010 21:44:28 | Vinícius Godoy de Mendonça

Oi chará. Que ótimo, sinta-se livre para usar esse ou qualquer outro conteúdo do site. Só pedimos que você nos cite, ok?
-
06/09/2010 12:28:13 |189.119.62.xxx| Franklin Carlos Soares - Parabéns

Muito bom seu tutorial. Sou super fã da linguagem JAVA, e curto games, no entanto ainda sou um mero aprendiz dessa linguagem.
-
02/10/2010 19:08:22 |189.93.160.xxx| Neudo Cordovil Araujo - Parabens!

Godoy, parabéns, os livros dessa área não estão com nada.
-
02/10/2010 19:09:59 |189.93.160.xxx| Neudo Cordovil Araujo

Parabéns, os aqui no BR dessa área não estão com nada.
-
14/10/2010 08:14:42 |187.82.74.xxx| Emerson neves da silva - Muito bom

Parabéns vinicius, show de bola esse seu tutorial sobre Jframe java, ele demonstra bem explicito todos os codigos e suas funcionalidades, vou encaminhar esse link para outros alunos de computação!!!
-
14/10/2010 08:32:29 | Vinícius Godoy de Mendonça

Obrigado. Pretendo escrever mais artigos de Java quando terminar a parte de OpenGL.
-
11/11/2010 20:06:50 |200.223.110.xxx| Jhonatan - Me ajude

Como faço para acessar um JLabel, que esta em um outro frame?
-
12/11/2010 07:35:09 | Vinícius Godoy de Mendonça

Passe o JLabel por parâmetro, ou o valor que você quer alterar como parâmetro.
Dê uma olhada nesse tópico do GUJ que pode te ajudar.
-
21/02/2011 12:44:48 |189.82.215.xxx| Elisson Andrade - Método update()

Cara, legal, só me tira uma dúvida: qual a diferença do método paint(Graphics) pro método update(Graphics)??
-
21/02/2011 13:03:43 | Vinícius Godoy de Mendonça

A diferença só é significativa em componentes não lightweight. O update responde a apenas ao repaint() e evita a limpeza do fundo. A implementação padrão dele em componentes swing é simplesmente fazer uma chamada à paint, o que torna os dois métodos muito parecidos.
De qualquer forma, na prática você não deve sobrescrever nem esse método, nem o paint. Só o paintComponent mesmo.
-
21/02/2011 14:28:49 |189.82.215.xxx| Elisson Andrade - Método update()

Mas, se não me engano, tu não disse em outro artigo que o paintComponent() só serviria para jogos em caso de jogos estáticos, como xadrez por exemplo? E se o game for dinamico, reescrevo que método?
-
21/02/2011 14:30:51 | Vinícius Godoy de Mendonça

Método nenhum. Você usa a técnica de Active Rendering (desenho direto):
http://www.pontov.com.br/site/index.php/java/48-java2d/124-desenho-dir eto-active-renderingAssim vc mesmo controla quando e como a pintura ocorre.
-
10/05/2011 23:48:13 |189.44.201.xxx| Jessé

Eu gostei mt desse tutorial.
eu gostaria de saber se isso é j2me, por que eu vi muita semelhança,
mas usou o método "static void main(String []args)" que eu costumo ver em j2se , eu não vi a classe principal sendo extendida da classe Midlet como eu costumo ver e fazer, alias eu nem conhecia essa classe
JFrame, vc pode postar um pouco mais sobre ela?
-
29/05/2011 09:53:40 |187.24.188.xxx| Stélio Corrêa - Excelente artigo

Parabenizo-te pelos excelentes artigos e que continue ajudando a comunidade Java. Abrs.
-
06/06/2011 17:14:42 |187.126.5.xxx| Anônimo

Oi, admiro seu conhecimento desde do GUJ.Preciso de ajuda:Tenho um JFrame e ela está um JContentPane composto de muitos jButtons(Mesas de um restaurante) que tem cores diferentes para cada estado.Ao clicar na mesa abre uma nova janela(JFrame).Eu altero o estado dessa mesa,altero o status no BD,mas a cor da mesa não muda em tempo de execução.Já tentei várias opçoes(repaint() revalidate( )e nada.Agradeço desde já se puder me ajudar.Meu email é rickdj2000@hotmail.com.
-
06/06/2011 19:00:39 | Vinícius Godoy de Mendonça

Oi. Poste sua dúvida no GUJ.
E aproveite e ponha lá seu código também.
-
17/06/2011 02:00:24 |201.10.99.xxx| joao - JFrameFormatedTexttedField

Ola professor td bem?
sou estudante de Sistemas para internet na utfpr e preciso apresentar uma trabalho sobre a classe JFrameFormattedTextField c vc puder montar um tutorial ai pra gente aprender um pouco mais sobre esta classe eu agradeço. adoro seus tutoriais são muito bons e bem explicativos... abraço.
-
17/06/2011 08:24:52 | Vinícius Godoy de Mendonça

Bem, acho que esse é o seu trabalho, não? De qualquer forma, esse é um portal sobre desenvolvimento de jogos, acho que não teria muito a ver falar com sobre o JFormattedTextField aqui.
Comoce lendo os tutoriais escritos pela Sun:
http://download.oracle.com/javase/tutorial/uiswing/components/formatte dtextfield.htmlE o Javadoc:
http://download.oracle.com/javase/6/docs/api/javax/swing/JFormattedTex tField.htmlE tire suas dúvidas no GUJ (sou moderador lá):
http://www.guj.com.br
-
17/06/2011 20:03:11 |187.126.200.xxx| Anônimo

Vinicius, desculpe insistir mas minha dúvida não foi respondida por ninguém lá no GUJ.E tenho muita urgência pois meu projeto final está pronto mas não posso apresentá-lo sem que minha JFrame atualize sem fechar e abrir(em tempo de execução).Dê uma olhada lá no GUJ ou me ajude aqui mesmo.Pelo que leio do seu conhecimento em Java, tenho certeza que você sabe a solução.Grato.Se precisar ver o código eu te envio por e-mail.
-
17/06/2011 20:32:32 | Vinícius Godoy de Mendonça

Me ajudaria MUITO se você deixasse aqui o link do seu tópico no GUJ.
-
18/06/2011 10:34:05 |187.126.52.xxx| Anônimo

Desculpe,Vinícius.O link é
http://www.guj.com.br/java/244410-atualizar-jframe#1269091.
Aproveitei para colocar o código também.
Acho que estou errando em algum pequeno detalhe.
Mais uma vez,grato pela atenção.
-
19/06/2011 00:36:24 |187.78.149.xxx| Aleff Henrique

Sou um programador de jogos amador em java, estava procurando algo para começar o desenvolvimento nesta linguagem. Agradeço muito por esta introdução!
Site muito bom, continuem assim.
-
04/08/2011 15:14:49 |200.219.121.xxx| Paulo Chaves - JFrame

Vinicius .....parabéns gostei do tutorial..bastante produtivo..sou iniciante no mundo da programação java...queria que vc publicasse aí como faço pra mudar a cor da janela..abraço e sucesso!!!
-
04/08/2011 16:40:13 | Vinícius Godoy de Mendonça

Como você irá sobrescrever o paintComponent para seus jogos, fica bem simples alterar o fundo do JFrame. Bastará pintar um retângulo da cor que quiser no fundo, ou mesmo pintar uma imagem inteira. Os tutoriais de Java 2D trarão essa questão.
Se você não está falando de jogos, uma rápida consulta ao javadoc já teria te respondido essa pergunta: dê uma olhada no método setBackground. Demais não relacionadas a jogos de Java, você pode perguntar diretamente no GUJ.
-
08/08/2011 01:47:03 |200.219.66.xxx| Paulo Chaves - JFrame

Valeu Vinicius....já tinha conseguido antes de vc publicar, mas muito obrigado!!! faço S.I ...tô vendo java.. e acho bacana essa linguagem...tudo de bom!! na verdade eu não tava falando de jogos.
-
08/08/2011 15:51:36 |200.211.82.xxx| Luis Albuquerque

Muito bom cara!
Meus parabéns!Estou começando programação e isso me ajudará e muito!
Abraço
-
01/09/2011 03:31:40 |200.219.69.xxx| Paulo Chaves - Java

Vinicius era pra vc tá dando aula na facul pra gente brother....vc parece dominar muito bem a Linguagem Java...parabéns, sucesso meu caro!!!!
-
01/09/2011 12:18:58 | Vinícius Godoy de Mendonça

Oi.
Basta você ir para a PUCPR, onde dou aula nos cursos de tecnologia em jogos digitais e na pós graduação de Desenvolvimento de Jogos Digitais.

-
04/09/2011 01:18:30 |200.219.114.xxx| Paulo Chaves - Java

Estudo na Faculdade Católica do Tocantins.... quase PUC..mas por enquanto só facul mesmo...flw..tudo de bom...tô vendo tratamento de eventos....!
-
13/11/2011 19:37:53 |177.40.172.xxx| Igor - Agradecimento

Fico muito grato por fornecer tais explicações. Gostei muito do seu modo de expor: claro e objetivo. Parabéns!











Parabéns, gostei muito do site. Sou desenvolvedor java e sempre tive o desejo de aprender a desenvolver jogos. Fico muito feliz em achar um site deste tipo. Sendo este muito completo, pois vejo que vocês dão o básicoo mesmooo!!
Espero compartilhar meus aprendizados com as pessoas deste site ( forum ).
grato