JFrame não sincroniza informações

4 respostas
F

Caros,
Não domino o Swing. Tenho uma dúvida que não consegui resolver e gostaria da ajuda de vcs se possível.

Criei um aplicação baseada em JFrame que possui alguns componentes:

JFrame <- JPanel <- JScrollPane <- JTextArea.

Tenho um método (que se comunica via Socket com outra aplicação) a cada interação com meu canal de entrada eu envio uma string para meu "echo":

{
....
	entrada = new ObjectInputStream(cliente.getInputStream());
	String msg = null;
	do {
		msg = (String) entrada.readObject();
          echoMessage(msg);
	}while(!msg.equals(EOT));

... 
}

public void echoMessage(String msg){
        System.out.println(new Date()+" [ "+msg+" ]" + "\n");
        jTextAreaBaixo.append(msg+ "\n");
	jTextAreaBaixo.repaint();
	jTextAreaBaixo.revalidate();
	jTextAreaBaixo.requestFocus();
}

O Método se comporta perfeitamente no "console". O System.out é perfeitamente impressa no console do ecplise. A informação do jTextAreaBaixo só é apresentada muito (segunos quase) após o recebimento da menssagem de finalização("EOT"), em suma, dentro do laço o jTextAreaBaixo fica "cinza" e só recebe o focus após a finalização.
Podem me ajudar,
Agradeço,
FCorrea

4 Respostas

ViniGodoy

Em que thread esse código está rodando? Em que método está o while? Quando ele é chamado?

F

Fiz start na aplicação como runnbale:

public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				application = new CMSNavigator();
				application.getJFrame().setVisible(false);
				application.apresentaLogin();
			}
		});

	}

Após a validação do login, disponibilizo um botão de “ok” no JFrame que invoca o método TransferItem(). A comunutação com o servidor é estabelecida com sucesso existindo inclusive pseudo-sincronismo (delay muito pequeno) entre o sysout do servidor System.out.println no cliente (no caso a console do eclipse). Estou sem ideias de como resolver isso.

private JButton getJButton3() {
		if (jButton3 == null) {
			jButton3 = new JButton();
			jButton3.setText("Ok");
			jButton3.setBounds(new Rectangle(30, 100, 150, 30));
			jButton3.addMouseListener(new java.awt.event.MouseAdapter() {
				public void mouseClicked(java.awt.event.MouseEvent e) {
					jDialog.dispose();
					transferItem(atualDEV);
				}
			});
		}
		return jButton3;
	}

O resumo do metodo está abaixo:

public void transferItem(CMSNavigatorInfo navInfo){
			TransferProjectSerializable transfer = new TransferProjectSerializable();


			try {
			   transfer.setProjectId(navInfo.getBasicProject());
			   transfer.setUser(getUsername());
			   if (navInfo.isFileItem()) {
					   System.out.println(navInfo.getFile().getName());
					   System.out.println(navInfo.getFile().getManagementId());
                       transfer.setContentItem(navInfo.getFile().getManagementId());
			   } else if (navInfo.isTemplateItem()) {
				       System.out.println(navInfo.getTemplate().getName());
				       System.out.println(navInfo.getTemplate().getManagementId()) ;
				       transfer.setContentItem(navInfo.getTemplate().getManagementId());
			  }
				  transfer.setComando("transferproject");
			} catch (NullObjectException e) {
				e.printStackTrace();
			}

			transfer = transferencia(transfer);
			String msg = new String();
			msg += transfer.getResult()      +"\n";
			msg += transfer.getContentItem() +"\n";
			msg += transfer.getProjectId()   +"\n";
			msg += transfer.getUser()        +"\n";
			jTextAreaBaixo.append(msg);
		}


	   public TransferProjectSerializable transferencia (TransferProjectSerializable transfer) {

		   String address 	= SERVER_TRANSFER_HOST;
		   int porta 		= SERVER_TRANSFER_PORT;

	 		ObjectInputStream entrada = null;
	 		ObjectOutputStream saida = null;
	 		Socket cliente = null;
			echoMessage("Conectando ao servidor ...");

	 		try {

	 			cliente = new Socket(address,porta);
	 			cliente.setSoTimeout(SERVER_TIMEOUT);
				echoMessage("Conexao aceita de: "+cliente.getInetAddress().toString());
				echoMessage("Obtendo canal de saida");
	 			saida = new ObjectOutputStream(cliente.getOutputStream());
	 			saida.flush();

	 			saida.writeObject(transfer);

	 			echoMessage("Obtendo canal de entrada");
	 			entrada = new ObjectInputStream(cliente.getInputStream());

	 			String msg = null;

	 			do {

					msg = (String) entrada.readObject();
					echoMessage(msg);

				}while(!msg.equals(EOT));

	 			transfer = (TransferProjectSerializable) entrada.readObject();
	 			echoMessage("RCV: "+ transfer.getResult());

	 		} catch (Exception e) {
	 			echoMessage("Erro: "+e);
	 			apresentaMensagem("Navegador não disponível:  " + transfer.getResult() + ".Informe ao DesenvSuporte");
	 			System.exit(0);
	 		} finally{
	 				try {
	 					if (entrada != null) entrada.close();
	 					if (saida!=null) saida.close();
	 					if (cliente != null) {
	 						echoMessage("Encerrando a conexao");
	 						cliente.close();
	 						cliente = null;
	 						echoMessage("Conexao encerrada");
	 						return transfer;
	 					}
	 				} catch (IOException e1) {
	 					echoMessage("Erro ao encerrar a conexao - "+e1);
	 				}
	 				return transfer;
	 		}

		}
ViniGodoy

Aparentemente, você está com o classico problema de quem começa a trabalhar com Swing agora. Ou

seja, seu código de transferência está rodando na Thread do Swing. Acontece que ações de repaint() apenas empilham um evento de pintura na thread do swing, que está ocupada fazendo seu processamento. Só quando esse processamento terminar, é que esses eventos serão processados.

Para resolve-lo, dispare esse código a partir de uma nova thread. Assim, sua thread cuida de transferência, enquanto o swing fica livre única e exclusivamente para processar pintura.

F

Obrigado Amigos,

Apresento a minha solução para os leitores:

Uma classe de teste (Swing):

public class teste extends JFrame {

	private static final long serialVersionUID = 1L;
	private JPanel jContentPane = null;
	private JScrollPane jScrollPane = null;
	private JTextArea jTextArea = null;

	/**
	 * This is the default constructor
	 */
	public teste() {
		super();
		initialize();
	}

	/**
	 * This method initializes this
	 * 
	 * @return void
	 */
	private void initialize() {
		this.setSize(300, 200);
		this.setContentPane(getJContentPane());
		this.setTitle("JFrame");
	}

	/**
	 * This method initializes jContentPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJContentPane() {
		if (jContentPane == null) {
			jContentPane = new JPanel();
			jContentPane.setLayout(new BorderLayout());
			jContentPane.add(getJScrollPane(), BorderLayout.CENTER);
		}
		return jContentPane;
	}

	/**
	 * This method initializes jScrollPane	
	 * 	
	 * @return javax.swing.JScrollPane	
	 */
	private JScrollPane getJScrollPane() {
		if (jScrollPane == null) {
			jScrollPane = new JScrollPane();
			jScrollPane.setViewportView(getJTextArea());
		}
		return jScrollPane;
	}

	/**
	 * This method initializes jTextArea	
	 * 	
	 * @return javax.swing.JTextArea	
	 */
	private JTextArea getJTextArea() {
		if (jTextArea == null) {
			jTextArea = new JTextArea();

		}
		return jTextArea;
	}

	public void addLogArea (String msg) {
		jTextArea.append(msg);
		jTextArea.updateUI();
	
	}
	
	
}

Extendida por outra classe de teste(teste2) p/ execução execução:

[]

public class teste2 extends teste{

private static final int 	SERVER_TRANSFER_PORT 	= 41000;
private static final String SERVER_TRANSFER_HOST 	= "xxxxxx.yyyyy.com";  //  @jve:decl-index=0:
private static final int 	SERVER_PORT 			= 40000;
private static final int 	SERVER_TIMEOUT 			= 600000;	
private static final String SERVER_HOST 			= "xxxx.yyyyy.com";  
private static final String EOT 					= "EOT";

public static teste  appGui = null;

public static void echoMessage(String msg){
     System.out.println(new Date()+" [ "+msg+" ]" + "\n");
     appGui.addLogArea(msg+ "\n");
}


private static final long serialVersionUID = 1L;

	public static TransferProjectSerializable transferencia  (TransferProjectSerializable transfer) {
		
        String address 	= SERVER_TRANSFER_HOST;
        int porta 		= SERVER_TRANSFER_PORT;
   
		ObjectInputStream entrada = null;
		ObjectOutputStream saida = null;
		Socket cliente = null;
        echoMessage("Conectando ao servidor ...");
    
		try {
			
			cliente = new Socket(address,porta);
			cliente.setSoTimeout(SERVER_TIMEOUT);
        echoMessage("Conexao aceita de: "+cliente.getInetAddress().toString());
        echoMessage("Obtendo canal de saida");
			saida = new ObjectOutputStream(cliente.getOutputStream());
			saida.flush();
			
			saida.writeObject(transfer);
			
			echoMessage("Obtendo canal de entrada");
			entrada = new ObjectInputStream(cliente.getInputStream());
			
			String msg = null;
			
			do {
				
			msg = (String) entrada.readObject();
			echoMessage(msg);
 			
		}while(!msg.equals(EOT));
			
			transfer = (TransferProjectSerializable) entrada.readObject();
			echoMessage("RCV: "+ transfer.getResult());	

		} catch (Exception e) {
			echoMessage("Erro: "+e);
			echoMessage("Navegador não disponível:  " + transfer.getResult() + ".Informe ao DesenvSuporte");
			System.exit(0);
		} finally{
				try {
					if (entrada != null) entrada.close();
					if (saida!=null) saida.close();
					if (cliente != null) {
						echoMessage("Encerrando a conexao");
						cliente.close();
						cliente = null;
						echoMessage("Conexao encerrada");
						return transfer;
					}
				} catch (IOException e1) {
					echoMessage("Erro ao encerrar a conexao - "+e1);
				}
				return transfer;
		}
  
		
} 

public static void main(String[] args) {	
	
	TransferProjectSerializable transfer = new TransferProjectSerializable();
	appGui =  new teste();
	appGui.setVisible(true);
	transfer.setComando("teste");	
	transferencia(transfer);

}

}

[]

Simplifiquei a interface e o “log” foi bem apresentado. A atualização funcion bem.

Uma pergunta a mais, se possível.

Existe alguma maneira eficiente de executar o scroll do JTextArea? Eventos?
Um abraço,
FCorrea

Criado 22 de junho de 2009
Ultima resposta 24 de jun. de 2009
Respostas 4
Participantes 2