Atualização de componentes - Mudança de estado

E aí GUJ!

E aí pessoal, tudo bem com vocês? Estou tendo problema numa aplicação minha e estou precisando de uma ajuda de vocês.

Meu programa tem uma classe minha que é filha de um JPanel. Ela também é uma Thread e é iniciada normalmente sem problemas, ela funciona de forma perfeita. Mas existe um problema quando eu coloco ela em um JFrame, por exemplo.

Esse “painel” meu, vamos chamar assim, é iniciado sem nenhuma configuração (me refiro quanto as dimensões e a BufferedImage que tem nele). Tanto que quando ele é visto pela primeira vez, ele não aparece - Esse não é o problema! É exatamente para ele fazer isso pois, depois, quando o usuário clicar em um botão de procurar uma devida imagem, este painel então será novamente iniciado. Aí sim ele terá largura, altura e uma imagem para ser mostrada devidamente.

Eu acredito que sempre que o usuário clicar no botão para procurar a imagem, o painel deverá ser iniciado novamente para que apareça uma nova imagem pois, a BufferedImage desse painel, deve ser iniciada de novo (por causa das diferentes dimensões de cada imagem). Eu ainda tenho que após fazer isso, remover o painel do JFrame e adicioná-lo depois de modificado (não sei se isto está certo ou se existe outra maneira de fazer essa mudança nesse meu painel).

Tudo até aí, funciona perfeitamente. Veja a ordem:

1 - Painel iniciado e adicionado ao JFrame.
2 - Ocorre um clique em procurar imagem.
3 - Imagem encontrada, painel será removido de JFrame para modificação.
4 - Painel iniciado novamente com configurações da nova imagem.
5 - Painel adicionado novamente ao JFrame.

Meu painel está dentro de um JScrollPane para se caso as dimensões da imagem ultrapassem o limite do campo de visão, eu tenha a possibilidade de ainda assim ver a imagem por completo usando scroll. Então na verdade eu removo tanto o painel do JScrollPane e também o JScrollPane do JFrame. Reinicio os dois com o painel dentro do JScrollPane e adiciono o JScrollPane de volta ao JFrame.

É aí que eu vejo um problema! Após ter feito isso tudo direitinho, aparentemente nada acontece. O JFrame não é atualizado, no sentido de não haver nenhuma alteração visível no painel ou JScrollPane. Tipo, você fica - “Ei, cadê a imagem?”. Porém, quando eu redimensiono o JFrame ou minimizo e maximizo, a tela ou sei lá o que é, é atualizada e a imagem aparece dando o resultado que eu queria, mas não na hora e do jeito que eu queria. Ou seja, tenho que redimensionar a janela (o JFrame) manualmente depois de carregar a imagem para que o JScrollPane (pelo visto, aparenta ser ele) se atualize e demonstre o meu painel com a devida imagem escolhida.

Eu tentei, após selecionar a imagem e adicionar o JScrollPane de novo no JFrame, dar um repaint() no JFrame, mas não funcionou. Tentei repaint() do JScrollPane, nada também. Tentei repaint() do meu painel, e nada novamente.

Gostaria muito muito mesmo de saber por que meu painel, JScrollPane ou o próprio JFrame só é atualizado quando tento redimensionar o JFrame ou quando este some e reaparece. Também seria muito útil saber o que faz o meu JFrame ou sei lá o que é, ser atulizado. Tem alguma coisa ali ao redimensionar o JFrame? Se alguém tiver um jeito diferente, uma dica…

Não sei mais o que fazer.

Litium.

Opa.

Nossa, ninguém tem a menor noção disso? Ninguém sabe pelo menos como pegar um componente que já foi adicionado a um JFrame e modificar o seu estado? Isso me lembra um método da AbstractTableModel chamado fireTableStructureChanged, onde a estrutura da tabela é modificada visualmente dependendo da tabela que estejamos trabalhando.

Pessoal, preciso de ajuda! :frowning:

Litium.

Você está definindo o preferredSize do seu JPanel? É ele que diz ao Swing, e ao JScrollPane, que tamanho o painel deveria ter. Defina esse valor para o tamanho da imagem, ou os layout managers jogarão seu painel para tamanho 0.

Outra coisa, não deveria ser necessário remover e inserir o painel do JFrame toda a vez. O comando repaint se encarrega de redesenhar a janela, quando as dimensões do painel se alterarem.

Notei também que vc falou que o painel dispara uma thread. O que essa thread faz? Você sabe que o Swing não é thread-safe, e que para outras threads atualizarem seus componentes, é necessário usar um dos métodos da classe EventQueue, não sabe?

Oi Vini!

Eu na verdade tenho uma classe que é filha de JPanel, e esta mesma classe, implementa Runnable. Sigo esta forma devido ao exemplo do livro “Programação de Games com Java” do autor Jonathan S. Harbour. Essa classe tem dois métodos abstrator os quais atualizam lógica e graficos de tela. Eu confesso que não entendo como criar um main loop totalmente funcional (sim, segue o esquema de jogos).

Eu uso essa classe para adicionar e remover Sprites para usar em meus jogos depois. Com ela, adiciono Sprites em um ArrayList e posso movê-los com o mouse posicionando-os onde quero para que a animação não saia “torta”.

A razão para adicionar e remover componentes é algo como:

Tenho um programa, esse programa deve criar um novo projeto com as configurações do usuário. Mas antes de criar o projeto, o programa já tem seus componentes adicionados para visualização do usuário. Para que ele, usuário, veja que estão ali os componentes. Mas os componentes não estão configurados. Exemplo, tenho um JSpinner que representará a posição no eixo X de um Sprite. Só que esse JSpinner tá ali só para o usuário ver. Ele não é configurado antes do usuário criar um novo projeto, entende?

Com relação a Threads… Cara, eu li o capítulo todo de multithreading no livro do autor Deitel sexta edição e entendi coisas diferentes. Apreendi coisas, mas não muito falando sobre o pacote Swing não ser Thread-Safe. Vi pouca coisa e poucos exemplos com situações diferentes de como se tratar uma Thread em um ambiente swing. Então pra mim, que estudo só (é F@#! ter a vida que tenho aqui) é bem difícil deu ter a chance de ter conhecimento de algumas coisas.

Se tiver algum canto onde eu possa ler mais sobre Swing, com exemplos de Socket também (chat em swing) e como funciona mesmo uma Thread, o que uma classe que é uma Thread compartilha ou o que ela faz… sobre método invokeLater… sobre a palavra chave synchronized… nossa, será de grande ajuda mesmo. O livro que leio dá muita teoria e poucas situações. Ele dá situações BEM parecida, mas não são situações totalmente diferentes onde usam Thread, entende?

Vini, agradeço a sua ajuda. Sério mesmo, obrigado.

Litium.

Bom, é bom ler esse material, então:
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
http://java.sun.com/products/jfc/tsc/articles/threads/threads3.html
http://download.oracle.com/docs/cd/E17409_01/javase/tutorial/uiswing/concurrency/
http://java.sun.com/products/jfc/tsc/articles/painting/#swing

Não conheço o livro do Harbour, mas geralmente fazer um filho do JPanel não é uma boa alternativa para jogos. O ideal seria sobrescrever o JFrame diretamente, ou, se quiser fazer um componente, JComponent. Geralmente só sobrescrevemos o JPanel se queremos criar containeres, isso é, componentes que suportem outros componentes sobre eles. Para a questão de Java 2D, leia com atenção todos os tutoriais de Java do Ponto V!

Aliás, você sabe usar os layout managers? Entende como eles funcionam? Se você for projetar componentes, é importante entender a fundo como Swing trabalha com Layout Managers. Entender certinho o que os métodos de “Size” fazem. E seria bom entender a fundo também como o ScrollPane funciona:
http://download.oracle.com/javase/tutorial/uiswing/components/scrollpane.html

Bom, é bastante material. Mas fazer componentes que funcionam direito não é fácil. Se você não seguir as boas práticas, rapidamente sua tela fica com comportamento inconsistente.

Vini.

Obrigado pelo material de leitura. Hoje de noite vou começar a ler uma parte e terça ou quarta termino o resto. Vou fazer resumo e seguir seus conselhos. Se deus quiser, saio daqui apreendendo algo sobre o assunto.

Um abraço cara! :-o

Litium.