GUJ Discussões   :   últimos tópicos   |   categorias   |   GUJ Respostas

[RESOLVIDO]Mudar cor texto em JTexArea ou JTextPane

Boa tarde a todos

Gostaria de pedir uma luz a quem puder me ajudar. Gostaria de criar um editorzinho de texto, que muda a cor da palavra, conforme o usuário digita. Consigo alterar as cores do texto inteiro ou alterar as cores a partir de onde está o cursor, mas não consigo altera as cores de uma única palavra já digitada. A idéia é tentar fazer algo como um leitor de XML, porém com algumas tags específicas. Até agora todo o meu progresso se resume no seguinte código:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.Pattern;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;


public class EditorTexto extends JFrame implements KeyListener{

	private JTextPane tpTeste;
	private JScrollPane spTeste;
	private String ultimoTexto="";

	public static void main(String args[]){
		new EditorTexto();
	}
	
	public EditorTexto(){
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		DocumentoEstiloso doc = new DocumentoEstiloso();
		
		tpTeste = new JTextPane();
		tpTeste.setStyledDocument(doc);
		tpTeste.addKeyListener(this);
		
		spTeste = new JScrollPane(tpTeste);
		spTeste.setPreferredSize(new Dimension(400,400));
		
		getContentPane().add(spTeste);
		
		setVisible(true);
		pack();
		
	}
	
	
	private void redStile(){
		StyleContext sc = StyleContext.getDefaultStyleContext();  
        AttributeSet aSet = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.red);  
        tpTeste.setCharacterAttributes(aSet, false);
        
	}
	
	private void blueStile(){
		StyleContext sc = StyleContext.getDefaultStyleContext();  
        AttributeSet aSet = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.blue);
        //Já descobri que se mudar para "true" onde está "false", consigo mudar todas as palavras
        //e do jeito que está o java altera apenas as próxima palavras
        tpTeste.setCharacterAttributes(aSet, false);
        
	}

	//Monitoro o teclado
	public void keyPressed(KeyEvent arg0) {
		if(arg0.getKeyChar() == KeyEvent.VK_SPACE){
			//Capturo o último texto digitado
			ultimoTexto = tpTeste.getText().split(" ")[tpTeste.getText().split(" ").length-1];
			redStile();
			
		}else if(arg0.getKeyChar() == KeyEvent.VK_A){
			blueStile();
		}
	}

	public void keyReleased(KeyEvent arg0) {
		
	}

	public void keyTyped(KeyEvent arg0) {
		
	}
	
	
}

Pelo que li não tem maneira de fazer isto com o JTextArea, mas se alguém conhecer POR FAVOR me mostre. Resumindo consigo alterar a partir de uma parte do texto para frente e consigo trocar a cor de todo o texto, porém só não consigo fazer aquilo que preciso: achar uma palavra recém digitada e alterar a cor dela.

No aguardo de ajuda,

Inté…

Você pode tentar alterar o método keyTyped pra fazer a mudança da cor logo depois que a pessoa digita.

Obrigado luigstl pela dica, dei realmente o keyTyped não funcionava, tive de mudar para o keyReleased para funcionar (o keytyped faz com que seja pega o texto sem que se conte a última tecla digitada), mas voltando a dúvido do tópico consegui resolver com o código deste link http://stackoverflow.com/questions/9745792/java-change-color-of-element-on-jtextpane-using-styleddocument.

Mais uma vez obrigado a todos que pelo menos deram uma olhada no tópico.

Inté…

Esqueçam o que eu disse antes. O método que estava naquela URL consistia em uma excelente prática de POG (Programação Orientada a Gambiarra). O melhor jeito, pelo menos na minha opinião é através da criação de um DocumentFilter. Ex.:


package filtroTexto;

import java.awt.Color;

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;

public class FiltroTPValorPropriedade extends DocumentFilter{

	
	private StyleContext sc = StyleContext.getDefaultStyleContext();
	
	//Na hora de inserir um novo texto
	public void insertString(FilterBypass fb, int offset, String string,
			AttributeSet attr) throws BadLocationException {

		for(String texto : string.split("\n")){
			if(!texto.isEmpty())
			super.insertString(fb, offset, texto + "\n", getAtributos(texto));			
			
		}
	}


	//Na hora de trocar o texto
	public void replace(FilterBypass fb, int offset, int length, String text,
			AttributeSet attrs) throws BadLocationException {

		for(String texto : text.split("\n")){
			if(!texto.isEmpty())
			super.replace(fb, offset, length, texto + "\n", getAtributos(texto));			
			
		}
		
	}
	
	//Método em que a brincadeira toda acontece
	private AttributeSet getAtributos(String text){
		
		//Formatação do texto
		AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, getColor(text));
		aset = sc.addAttribute(aset, StyleConstants.FontFamily, "Lucida Console");
		aset = sc.addAttribute(aset, StyleConstants.Alignment, StyleConstants.ALIGN_JUSTIFIED);
		return aset;
	}
	
	//Método para selecionar as cores baseado no texto que é passado
	private Color getColor(String text){
		if(text.contains("<nome>")){
			return Color.blue;
		}else if(text.contains("<imports>")){
			return Color.RED;
		}else if(text.contains("<valor>")){
			return new Color(0,140,0);
		}else if(text.contains("<tipo>")){
			return new Color(0, 0, 150);
		}
		return Color.black;
	}
}

Para se ligar o JTextPane ao filtro é só usar o seguinte comando:

JTextPane tpComando = new JTextPane();
((AbstractDocument)tpComando.getDocument()).setDocumentFilter(new FiltroTPValorPropriedade());

Mais uma vez agradeço ao luigistl pela dica que me deu.

Inté…

Ola Jubarius,

Sei que este post já está marcado como resolvido mas eu estou com essa mesma necessidade que vc passou. Eu peguei o seu algoritmo estudei e tentei implementar e não deu certo, então eu queria saber se existe algo mais para configurar no TextPane ou mais algum parametro nele.

Estou tetando isso funcionar a muito tempo e estou desesperado já, se puder me ajudar eu agradeceria muito…

Blz Crisx,

Tipo… o único detalhe do código é que ele não funciona na JTextArea, somente no JTextPane e tem um outro componente de texto que eu não me lembro agora o nome. Qualquer coisa posta aí o teu código que eu dou uma olhada e vejo se consigo de dar uma ajuda.

Inté…

Bom, vamos lá então:

Essa é a minha classe principal que não tem nenhum segredo. É um frame com um JTextPane e logo abaixo do initComponents eu crio a ligação com o filtro

import javax.swing.JTextPane;
import javax.swing.text.AbstractDocument;


public class Editor extends javax.swing.JFrame {

    public Editor() {
        initComponents();
        TextPane = new JTextPane();  
       ((AbstractDocument)TextPane.getDocument()).setDocumentFilter(new Filter()); 
    }
    @SuppressWarnings("unchecked")
    // &lt;editor-fold defaultstate="collapsed" desc="Generated Code"&gt;
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        TextPane = new javax.swing.JTextPane();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jScrollPane1.setViewportView(TextPane);

        getContentPane().add(jScrollPane1, java.awt.BorderLayout.CENTER);

        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-416)/2, (screenSize.height-338)/2, 416, 338);
    }// &lt;/editor-fold&gt;

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Editor().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify
    private javax.swing.JTextPane TextPane;
    private javax.swing.JScrollPane jScrollPane1;
    // End of variables declaration
}

A classe de filtro como primeiro exemplo eu usei a sua classe, depois tentei criar uma minha e mudei algumas coisa no código mas nem a sua funcionou para mim.

import java.awt.Color;
import javax.swing.text.AttributeSet;  
import javax.swing.text.BadLocationException;  
import javax.swing.text.DocumentFilter;  
import javax.swing.text.SimpleAttributeSet;  
import javax.swing.text.StyleConstants;  
import javax.swing.text.StyleContext;  
  
public class Filter extends DocumentFilter{  
  
      
    private StyleContext sc = StyleContext.getDefaultStyleContext();  
      
    //Na hora de inserir um novo texto  
    public void insertString(FilterBypass fb, int offset, String string,  
            AttributeSet attr) throws BadLocationException {  
  
        for(String texto : string.split("\n")){  
            if(!texto.isEmpty())  
            super.insertString(fb, offset, texto + "\n", getAtributos(texto));            
              
        }  
    }  
  
  
    //Na hora de trocar o texto  
    public void replace(FilterBypass fb, int offset, int length, String text,  
            AttributeSet attrs) throws BadLocationException {  
  
        for(String texto : text.split("\n")){  
            if(!texto.isEmpty())  
            super.replace(fb, offset, length, texto + "\n", getAtributos(texto));             
              
        }  
          
    }  
      
    //Método em que a brincadeira toda acontece  
    private AttributeSet getAtributos(String text){  
          
        //Formatação do texto  
        AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, getColor(text));  
        aset = sc.addAttribute(aset, StyleConstants.FontFamily, "Lucida Console");  
        aset = sc.addAttribute(aset, StyleConstants.Alignment, StyleConstants.ALIGN_JUSTIFIED);  
        return aset;  
    }  
      
    //Método para selecionar as cores baseado no texto que é passado  
    private Color getColor(String text){  
        if(text.contains("&lt;nome&gt;")){  
            return Color.blue;  
        }else if(text.contains("&lt;imports&gt;")){  
            return Color.RED;  
        }else if(text.contains("&lt;valor&gt;")){  
            return new Color(0,140,0);  
        }else if(text.contains("&lt;tipo&gt;")){  
            return new Color(0, 0, 150);  
        }  
        return Color.black;  
    }  
}

Realmente não entendo por que não está funcionando…

Tudo bom Crisx,

Seguinte… É só mudar esta parte que começa a funcionar:

	public Editor() {
		initComponents();
		((AbstractDocument) TextPane.getDocument())
				.setDocumentFilter(new Filter());
	}

Só uma coisa, não sei qual é a tua necessidade de fato, mas este código foi criado para situações em que você tem uma string pronta e insere dentro da área de texto (JTextPane / JEditorPane). Para que o código funcione em tempo real, algo do tipo “enquanto o usuário digita…”, tem de mudar os métodos “insertString” e “replace” da classe Filter (Se eu não me engano dá para pegar o que já está escrito com o FilterBypass - o atributo fb destes dois métodos - utilizando algo tipo “fb.getDocument().getText(0,fb.getDocument().getLength())” ou coisa parecida).

Boa sorte

Inté…

Aee funcionou!!

Eu creio que eu já havia tentado desta maneira antes e não havia funcionado não sei porque mas pelo menos funcionou agora.
Realmente a minha intenção era pra ser enquanto o usuário digitava mas pelo menos agora já meio caminho andando, com um pouco de estudo eu acho que eu me viro agora, rsrsrsrsr

Muito obrigado pela ajuda Jubarius.

//