Em Java, a saída padrão é redirecionada usualmente para o console. Aqui vamos ver como fazer para que seja redirecionada de forma fácil para um componente gráfico, no caso um JTextArea.
Saída Padrão, Saída Padrão de Erro e Entrada Padrão – Uma Breve História
Tudo começou quando os sistemas operacionais ainda possuiam apenas interface de texto. Os programas não gráficos escrevem na saída padrão (normalmente o vídeo) e leem da entrada padrão (normalmente o teclado). A saída e entrada padrão podem ser redirecionadas pelo sistema operacional, por exemplo, se a saída for redirecionada para a impressora, ela é impressa, sem que se precisse modificar uma única linha de código. Também há a possibilidade de fazer com que a saída padrão de um programa, seja a entrada de outro, um mecanismo chamado pipe. Os fãs de Linux, aqueles que adoram a tela preta do console, escrevem linhas de comando enoooooormes, redirecionando a saída de um programa para a entrada de outro. Isso também pode ser feito no Windows, mas simplesmente não faz parte da cultura.
Qual a diferença da saída padrão da saída padrão de erro?
A saída padrão é a saída “normal” do programa e a saída de padrão de erro, bem, é a saída onde os erros são impressos. Isso permite que quando a saída padrão de um programa é redirecionada para outro, as mensagens de erros sejam impressas normalmente na tela.
Como é no Java?
Em Java, temos a classe java.lang.System, lá temos System.out, System.err e System.in, que são respectivamente: a saída padrão, a saída padrão de erro e a entrada padrão. A instrução System.out.println(“Olá mundo!”); é provavelmente uma das primeiras que qualquer um aprende. Nem todos sabem, no entanto, que também se pode escrever System.err.println(“Olá mundo tem erro!”); , e a segunda forma é preferível em caso de mensagens de erro, afinal, é a saída padrão de erro. Essas mensagens aparecem na tela preta do console, veremos a seguir como redirecioná-las para um componente gráfico.
MVC – Model-View-Controler – no JTextArea
Muitos compenentes gráficos Swing implementam o padrão MVC, isto é, possuem um modelo, um visualizador e um controlador. No caso de um JTextArea, na configuração padrão, o modelo é um documento texto, a visualização é a renderização do texto na tela e o controler é a interpretação dos comandos de edição do usuário. O que temos de mudar é o controlador, não serão eventos gerados pelo usuário e sim o texto escrito na saída padrão. Para isso temos:
- retirar o controle do usuário, setando a propriedade Editable do JTextArea para false. Muito Fácil.
- criar uma classe para atualizar o modelo, isto é, um controlador.
- redirecionar a saída padrão usando o método System.setOut()
Controlador: DocumentOutputStream
O código do controlador é simples. A classe é derivada de java.io.OutputStream porque para redirecionar a saída padrão ou a saída de erro é necessário um objeto do tipo java.io.PrintStream. Uma forma de criar é usar um objeto do tipo java.io.OutputStream. O construtor do controlador recebe como parâmetro o documento que irá armazenar os dados a serem mostrados pelo visualizador.
A classe java.io.OutputStream requer a implementação de um único método: public void write(int b) throws IOException. No entanto, os dois outros métodos write foram também implementados por razões de eficiência. Caso não fossem, cada caracter incluído no documento geraria um evento, implementando os outros métodos, o número de eventos gerados e consequentemente de objetos cai muito.
Abaixo está o código fonte da classe do controlador e aqui está o projeto completo do NetBeans.
package br.com.desenvolvendosoftware; import java.io.IOException; import java.io.OutputStream; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.SimpleAttributeSet; /** * Output Stream que escreve para um javax.swing.text. Document * Dessa forma pode servir de controler de uma JTextArea * @author Leila Algarve */ public class DocumentOutputStream extends OutputStream{ /** Documento do JTextArea */ private Document _document; /** Buffer com os bytes adicionados */ private StringBuffer _buffer; /** localização do último byte inserido no documento */ private int _offset; public DocumentOutputStream (Document document){ _document = document; } @Override public void write(int b) throws IOException { try { _document.insertString(_offset++, (char) b + "", new SimpleAttributeSet()); } catch (BadLocationException ex) { new IOException(ex); } } @Override public void write(byte[] bytes, int off, int len) throws IOException { StringBuffer buffer = new StringBuffer(); for (int indice=off; indice < len; indice ++) buffer.append((char)bytes[indice]); try { _document.insertString(_offset, buffer.toString() , new SimpleAttributeSet() ); _offset += buffer.length(); } catch (BadLocationException ex) { new IOException(ex); } } @Override public void write(byte[] bytes) throws IOException { StringBuffer buffer = new StringBuffer(); for (byte b : bytes) buffer.append((char)b); try { _document.insertString(_offset, buffer.toString() , new SimpleAttributeSet() ); _offset += buffer.length(); } catch (BadLocationException ex) { new IOException(ex); } } }
Post inspirado na pergunta de forum postada por rogerio3d.




![Verifique o meu feed [Valid RSS]](/images/valid-rss.png)
novembro 9th, 2009 at 16:32
Como é feito o System.setIn() utilizando este controlador?
novembro 11th, 2009 at 21:32
Eu criei esse controlador para receber os dados da saída padrão, não havia o desejo de se receber dados da entrada padrão. Redirecionar a entrada padrão seria como simular alguém digitando. No caso, seria necessário deixar a propriedade Editable em verdadeiro, para que o JTextArea também recebesse as comandos de entrada. O problema está no offset. Como eu suponho na minha classe, que apenas a saída padrão será considerada, não tem problema.