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.
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.
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…
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.
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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
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);
}// </editor-fold>
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("<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;
}
}
Realmente não entendo por que não está funcionando…
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).
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