Problème avec la classe DefaultStyledDocument et la méthode setCharacterAttributes
Bonjour
Après avoir épuisé toutes les pistes... je me remets à vous pour m'aider à trouver une solution !
J'ai créé un éditeur qui modifie la couleur des mots suivant le contexte dans lequel ils se trouvent.
Jusqu'à là, rien d'extraordinaire !
J'ai mon parseur, qui analyse le texte que tape le programmeur et ensuite, j'utilise la méthode setCharacterAttributes pour affecter la couleur. Pour cela, je passe par un thread.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
public class AtelierDocument extends DefaultStyledDocument {
public void setCharacterAttributes(List<Style> list) {
try {
writeLock();
List<Style> styles = StyleBuffer.retourneStyles();
while (!styles.isEmpty()) {
Style style = styles.get(0);
styles.remove(style);
int taille = style.getTaille();
if (taille == -1)
taille = getLength();
if (style.getPosition() > getLength())
continue;
if (taille != 0) {
setCharacterAttributes2(style.getPosition(), taille, style.getStyle(), true);
}
}
} finally {
writeUnlock();
}
}
private void setCharacterAttributes2(int offset, int length, AttributeSet s, boolean replace) {
if (length == 0) {
return;
}
DefaultDocumentEvent changes = new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.CHANGE);
// split elements that need it
buffer.change(offset, length, changes);
AttributeSet sCopy = s.copyAttributes();
// PENDING(prinz) - this isn't a very efficient way to iterate
int lastEnd = Integer.MAX_VALUE;
for (int pos = offset; pos < (offset + length); pos = lastEnd) {
Element run = getCharacterElement(pos);
lastEnd = run.getEndOffset();
if (pos == lastEnd) {
// offset + length beyond length of document, bail.
break;
}
MutableAttributeSet attr = (MutableAttributeSet) run.getAttributes();
changes.addEdit(new AttributeUndoableEdit(run, sCopy, replace));
if (replace) {
attr.removeAttributes(attr);
}
attr.addAttributes(s);
}
changes.end();
fireChangedUpdate(changes);
fireUndoableEditUpdate(new UndoableEditEvent(this, changes));
}
} |
Le code du thread :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public static void appliquer(final int nombre, final int decal) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
if (appliquer)
document.setCharacterAttributes(StyleBuffer.retourneStyles());
else
StyleBuffer.effacerStyle();
} catch (Exception e) {
System.out.println("Erreur application des styles");
}
}
});
} |
ça fonctionne presque normalement...
Mais dés que j'utilise un undoManager pour filtrer les changements de styles, rien ne va plus !
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
undoManager = new UndoManager()//;
{
public synchronized boolean addEdit(UndoableEdit anEdit) {
if (anEdit instanceof AbstractDocument.DefaultDocumentEvent) {
AbstractDocument.DefaultDocumentEvent de = (AbstractDocument.DefaultDocumentEvent) anEdit;
if (de.getType() == DocumentEvent.EventType.CHANGE) {
return false;
}
}
return super.addEdit(anEdit);
}
}; |
En utilisant le undo/redo, rapidement j'ai le curseur qui disparait et ensuite, l'affichage de la zone texte se bloque ou mon texte est décalé.
Après plusieurs tests, je ne pense pas que mon problème soit dû à l'utilisation des threads. C'est la méthode setcharacterAttributes qui semble se mélanger les pinceaux à un moment que je n'arrive pas à déterminer !
Voici le l'adresse de mon code.
https://linotte.dev.java.net/source/...linotte/frame/
Il n'est pas très beau... je sais...
J'espère qu'une personne trouvera une solution....
Ronan
Présentation du problème plus simplement !
Bonjour,
Voici un exemple que vous pouvez tester pour mieux comprendre mon problème :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
import java.awt.*;
import java.awt.event.*;
import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.undo.*;
public class Demo {
public static SimpleAttributeSet style_error = null;
@SuppressWarnings("serial")
public static void main(String[] args) {
style_error = new SimpleAttributeSet();
StyleConstants.setForeground(style_error, Color.RED);
StyleConstants.setBackground(style_error, Color.WHITE);
StyleConstants.setItalic(style_error, false);
final JTextPane textPane = new JTextPaneText();
textPane.setPreferredSize(new Dimension(200, 200));
textPane.setDocument(new DefaultStyledDocument());
final UndoManager undoManager = new UndoManager() {
public synchronized boolean addEdit(UndoableEdit anEdit) {
if (anEdit instanceof AbstractDocument.DefaultDocumentEvent) {
AbstractDocument.DefaultDocumentEvent de = (AbstractDocument.DefaultDocumentEvent) anEdit;
if (de.getType() == DocumentEvent.EventType.CHANGE) {
return false;
}
}
return super.addEdit(anEdit);
}
};
textPane.getStyledDocument().addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent e) {
undoManager.addEdit(e.getEdit());
}
});
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JScrollPane(textPane), BorderLayout.CENTER);
JPanel buttons = new JPanel();
panel.add(buttons, BorderLayout.SOUTH);
JButton undo = new JButton("Undo");
undo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
undoManager.undo();
textPane.requestFocus();
} catch (CannotUndoException ex) {
}
}
});
buttons.add(undo);
JButton redo = new JButton("Redo");
redo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
undoManager.redo();
textPane.requestFocus();
} catch (CannotRedoException ex) {
}
}
});
buttons.add(redo);
JButton style = new JButton("Style");
style.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Pattern p = Pattern.compile("texte");
String out = textPane.getText();
Matcher matcher = p.matcher(out);
while (matcher.find()) {
textPane.getStyledDocument().setCharacterAttributes(matcher.start(), matcher.end() - matcher.start(), style_error, true);
}
}
});
buttons.add(style);
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
} |
Lancez cette classe. Pour reproduire mon problème, entrez le texte suivant dans le petit éditeur :
Citation:
voici un texte
sur une nouvelle ligne ce texte
encore une ligne !
Ensuite, appuyez sur le bouton Style. il va utilise la méthode setCharacterAttributes pour changer la couleur de toutes les occurrences du mot 'texte'.
Ensuite, utilisez le bouton redo pour revenir en arrière.
Vous voyez, ma zone de texte ne fonctionne plus !
Help :roll: