Ponto V!

Home Java Informações gerais Conhecendo o JFrame
Vinícius Godoy de Mendonça
Conhecendo o JFrameImprimir
Escrito por Vinícius Godoy de Mendonça

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:

public void paint(Graphics g)

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:

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

  1. paintBorder(Graphics): Que pinta uma borda ao redor do componente;
  2. paintComponent(Graphics): Em componentes, esse método é equivalente ao paint. Se você estiver escrevendo um componente, sobrescreva paintComponent() no lugar de paint().
  3. 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.


Comentários (42)
  • Davi S. Pereira  - Parabéns
    avatar

    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

  • Vinícius Godoy de Mendonça  - Obrigado!
    avatar

    Obrigado! :)

  • alberto
    avatar

    cara mto bom mesmo
    parabens

  • Tiago
    avatar

    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!

  • Vinícius Godoy de Mendonça
    avatar

    Obrigado. :)

  • vinicius hisao suzuki  - ótimo
    avatar

    sou professor de jogos em java e adorei o artigo. certamente vou usar seu guia como referência em minhas aulas.

  • Vinícius Godoy de Mendonça
    avatar

    Oi chará. Que ótimo, sinta-se livre para usar esse ou qualquer outro conteúdo do site. Só pedimos que você nos cite, ok?

  • Franklin Carlos Soares  - Parabéns
    avatar

    Muito bom seu tutorial. Sou super fã da linguagem JAVA, e curto games, no entanto ainda sou um mero aprendiz dessa linguagem.

  • Vinícius Godoy de Mendonça
    avatar

    Obrigado! :)

  • Neudo Cordovil Araujo  - Parabens!
    avatar

    Godoy, parabéns, os livros dessa área não estão com nada.

  • Neudo Cordovil Araujo
    avatar

    Parabéns, os aqui no BR dessa área não estão com nada.

  • Emerson neves da silva  - Muito bom
    avatar

    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!!!

  • Vinícius Godoy de Mendonça
    avatar

    Obrigado. Pretendo escrever mais artigos de Java quando terminar a parte de OpenGL.

  • Jhonatan  - Me ajude
    avatar

    Como faço para acessar um JLabel, que esta em um outro frame?

  • Vinícius Godoy de Mendonça
    avatar

    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.

  • Elisson Andrade  - Método update()
    avatar

    Cara, legal, só me tira uma dúvida: qual a diferença do método paint(Graphics) pro método update(Graphics)??

  • Vinícius Godoy de Mendonça
    avatar

    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.

  • Elisson Andrade  - Método update()
    avatar

    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?

  • Vinícius Godoy de Mendonça
    avatar

    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-rendering

    Assim vc mesmo controla quando e como a pintura ocorre.

  • Jessé
    avatar

    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?

  • Stélio Corrêa  - Excelente artigo
    avatar

    Parabenizo-te pelos excelentes artigos e que continue ajudando a comunidade Java. Abrs.

  • Anônimo
    avatar

    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.

  • Vinícius Godoy de Mendonça
    avatar

    Oi. Poste sua dúvida no GUJ.
    E aproveite e ponha lá seu código também.

  • joao  - JFrameFormatedTexttedField
    avatar

    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.

  • Vinícius Godoy de Mendonça
    avatar

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

    E o Javadoc:
    http://download.oracle.com/javase/6/docs/api/javax/swing/JFormattedTex tField.html

    E tire suas dúvidas no GUJ (sou moderador lá):
    http://www.guj.com.br

  • Anônimo
    avatar

    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.

  • Vinícius Godoy de Mendonça
    avatar

    Me ajudaria MUITO se você deixasse aqui o link do seu tópico no GUJ.

  • Anônimo
    avatar

    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.

  • Aleff Henrique
    avatar

    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! :side:
    Site muito bom, continuem assim.

  • Paulo Chaves  - JFrame
    avatar

    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!!!

  • Vinícius Godoy de Mendonça
    avatar

    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.

  • Paulo Chaves  - JFrame
    avatar

    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.

  • Luis Albuquerque
    avatar

    Muito bom cara!
    Meus parabéns!

    Estou começando programação e isso me ajudará e muito!

    Abraço ;)

  • Vinícius Godoy de Mendonça
    avatar

    Valeu. :)

  • Paulo Chaves  - Java
    avatar

    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!!!!

  • Vinícius Godoy de Mendonça
    avatar

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

  • Paulo Chaves  - Java
    avatar

    Estudo na Faculdade Católica do Tocantins.... quase PUC..mas por enquanto só facul mesmo...flw..tudo de bom...tô vendo tratamento de eventos....!

  • Igor  - Agradecimento
    avatar

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

  • Jair
    avatar

    Cara... Parabéns! Ainda vou ficar bom nessa coisa.. Muito bom. Vou ficar de olho nos seus Artigos :) .

  • Vinícius Godoy de Mendonça
    avatar

    Obrigado!

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2  

Busca

Linguagens

Twitter