Editor de texto utilizando TextPane JAVA

Galera, to com uma grande dificuldade para a criação de um editor de texto.
A principio esse editor deve fazer as seguintes ações:
Pegar um texto selecionado e adicionar Negrito, Italico, Sublinhado e etc (já consegui)

Porém ainda preciso de editar um texto da seguinte forma.

Se o usuario for no meio do texto e aperta no JButton Negrito entao o texto [size=18][color=red]a ser digitado ali[/color][/size] deve seguir a formatação.

Exemplo:

Digitei o seguinte texto:

“Este é um editor de Texto!”

Se eu voltar e colocar na posição anterior a palavra “editor” e selecionar Negrito e começar a digitar deverá aparecer assim:

“Este é um esse texto deve aparecer em negrito editor de Texto!”



public class TextComponentDemo extends JFrame {

    JTextPane textPane;
    AbstractDocument doc;
    static final int MAX_CHARACTERS = 300;
    String newline = "\n";
    HashMap<Object, Action> actions;
    // undo helpers
    protected UndoAction undoAction;
    protected RedoAction redoAction;
    protected UndoManager undo = new UndoManager();

    public TextComponentDemo() {
        super("Editor de Laudo");

        // Create the text pane and configure it.
        textPane = new JTextPane();
        textPane.setCaretPosition(0);
        textPane.setMargin(new Insets(5, 5, 5, 5));
        StyledDocument styledDoc = textPane.getStyledDocument();
        if (styledDoc instanceof AbstractDocument) {
            doc = (AbstractDocument) styledDoc;
            //doc.setDocumentFilter(new DocumentSizeFilter(MAX_CHARACTERS));
        } else {
            System.err.println("Text pane's document isn't an AbstractDocument!");
            System.exit(-1);
        }
        JScrollPane scrollPane = new JScrollPane(textPane);
        scrollPane.setPreferredSize(new Dimension(200, 200));

        // Create the status area.
        JPanel statusPane = new JPanel(new GridLayout(1, 1));
        CaretListenerLabel caretListenerLabel = new CaretListenerLabel("Barra de Status");
        statusPane.add(caretListenerLabel);

        // Add the components.
        getContentPane().add(scrollPane, BorderLayout.CENTER);
        getContentPane().add(statusPane, BorderLayout.PAGE_END);

        // Set up the menu bar.
        createActionTable(textPane);
        JMenuBar mb = new JMenuBar();
        setJMenuBar(mb);

        // Add some key bindings.
        addBindings();


        // Start watching for undoable edits and caret changes.
        doc.addUndoableEditListener(new MyUndoableEditListener());
        textPane.addCaretListener(caretListenerLabel);

        //Criação do ToolBar
        createToolBar();

    }

    // This listens for and reports caret movements.
    protected class CaretListenerLabel extends JLabel implements CaretListener {

        public CaretListenerLabel(String label) {
            super(label);
        }
        // Might not be invoked from the event dispatching thread.

        public void caretUpdate(CaretEvent e) {
            displaySelectionInfo(e.getDot(), e.getMark());
        }

        protected void displaySelectionInfo(final int dot, final int mark) {
            SwingUtilities.invokeLater(new Runnable() {

                public void run() {
                    int quant = 0;
                    if (dot - mark > 0) {
                        quant = dot - mark;
                    } else {
                        quant = mark - dot;
                    }
                    if (dot == mark) { // no selection
                        try {
                            Rectangle caretCoords = textPane.modelToView(dot);
                            // Convert it to view coordinates.
                            //setText("Status: Posição do Cursor: " + dot + ", view location = [" + caretCoords.x + ", "
                            //        + caretCoords.y + "]" + newline);
                            setText("Status: Posição do Cursor: " + dot);
                        } catch (BadLocationException ble) {
                            // setText("Status: Posição do Texto: " + dot + newline);
                            setText(quant + " caracteres selecionados" + newline);
                        }
                    } else if (dot < mark) {
                        setText(quant + " caracteres selecionados" + newline);
                    } else {
                        setText(quant + " caracteres selecionados" + newline);
                    }
                }
            });
        }
    }

    private void createToolBar() {
        JPanel painel = new JPanel();
        JMenuBar menu = new JMenuBar();
        JToolBar barra = new JToolBar("Barra");
        JPanel painelBotoes = new JPanel();

        JMenu fonte = new JMenu("Fonte");
        JMenu tamanho = new JMenu("Tamanho");
        JMenu cor = new JMenu("Cor");


        fonte.add(new StyledEditorKit.FontFamilyAction("Serif", "Serif"));
        fonte.add(new StyledEditorKit.FontFamilyAction("SansSerif", "SansSerif"));
        fonte.add(new StyledEditorKit.FontFamilyAction("Monospaced", "Monospaced"));

        tamanho.add(new StyledEditorKit.FontSizeAction("8", 8));
        tamanho.add(new StyledEditorKit.FontSizeAction("10", 10));
        tamanho.add(new StyledEditorKit.FontSizeAction("12", 12));
        tamanho.add(new StyledEditorKit.FontSizeAction("14", 14));
        tamanho.add(new StyledEditorKit.FontSizeAction("16", 16));
        tamanho.add(new StyledEditorKit.FontSizeAction("24", 24));
        tamanho.add(new StyledEditorKit.FontSizeAction("36", 36));
        tamanho.add(new StyledEditorKit.FontSizeAction("48", 48));

        cor.add(new StyledEditorKit.ForegroundAction("Preto", Color.black));
        cor.add(new StyledEditorKit.ForegroundAction("Vermelho", Color.red));
        cor.add(new StyledEditorKit.ForegroundAction("Azul", Color.blue));
        cor.add(new StyledEditorKit.ForegroundAction("Amarelo", Color.yellow));
        cor.add(new StyledEditorKit.ForegroundAction("Amarelo(2)", Color.orange));
        cor.add(new StyledEditorKit.ForegroundAction("Branco", Color.white));
        cor.add(new StyledEditorKit.ForegroundAction("Cinza", Color.GRAY));
        cor.add(new StyledEditorKit.ForegroundAction("Cian", Color.CYAN));
        cor.add(new StyledEditorKit.ForegroundAction("Verde", Color.GREEN));
        cor.add(new StyledEditorKit.ForegroundAction("Rosa", Color.pink));
        cor.add(new StyledEditorKit.ForegroundAction("Rosa(2)", Color.MAGENTA));

        menu.add(fonte);
        menu.add(tamanho);
        menu.add(cor);

        Action action = new DefaultEditorKit.CopyAction();
        action.putValue(Action.NAME, "Copiar");
        barra.add(action);


        action = new DefaultEditorKit.CutAction();
        action.putValue(Action.NAME, "Recortar");
        barra.add(action);

        action = new DefaultEditorKit.PasteAction();
        action.putValue(Action.NAME, "Colar");
        barra.add(action);

        barra.addSeparator();

        action = new StyledEditorKit.BoldAction();
        action.putValue(Action.NAME, "B");
        barra.add(action);

        action = new StyledEditorKit.ItalicAction();
        action.putValue(Action.NAME, "I");
        barra.add(action);

        action = new StyledEditorKit.UnderlineAction();
        action.putValue(Action.NAME, "S");
        barra.add(action);

        barra.addSeparator();

        action = new StyledEditorKit.AlignmentAction("left-justify", StyleConstants.ALIGN_LEFT);
        action.putValue(Action.NAME, "Esquerda");
        barra.add(action);

        action = new StyledEditorKit.AlignmentAction("center-justify", StyleConstants.ALIGN_CENTER);
        action.putValue(Action.NAME, "Centro");
        barra.add(action);

        action = new StyledEditorKit.AlignmentAction("right-justify", StyleConstants.ALIGN_RIGHT);
        action.putValue(Action.NAME, "Direita");
        barra.add(action);

        barra.addSeparator();

/*----------------O PROBLEMA É DAQUI --------------*/
        action = new StyledEditorKit.AlignmentAction("FirstLineIndent", StyleConstants.FirstLineIndent);
        action.putValue(Action.NAME, "Paragrafo");
        barra.add(action);
/*----------------O PROBLEMA É ATÉ AQUI --------------*/

        getContentPane().add(painel, BorderLayout.NORTH);
        painel.add(menu, BorderLayout.CENTER);
        painel.add(barra, BorderLayout.SOUTH);

    }


// This one listens for edits that can be undone.
    /**
     *
     */
    protected class MyUndoableEditListener implements UndoableEditListener {

        public void undoableEditHappened(UndoableEditEvent e) {
            // Remember the edit and update the menus.
//            undo.addEdit(e.getEdit());
//            undoAction.updateUndoState();
//            redoAction.updateRedoState();
        }
    }

    // Atalhos de navegação
    protected void addBindings() {
        InputMap inputMap = textPane.getInputMap();

        // Ctrl-a to go backward one character
        KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK);
        inputMap.put(key, DefaultEditorKit.selectAllAction);

        key = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, Event.CTRL_MASK);
        inputMap.put(key, DefaultEditorKit.beepAction);

        // Ctrl-b to go backward one character
        key = KeyStroke.getKeyStroke(KeyEvent.VK_B, Event.CTRL_MASK);
        inputMap.put(key, DefaultEditorKit.backwardAction);

        // Ctrl-f to go forward one character
        key = KeyStroke.getKeyStroke(KeyEvent.VK_F, Event.CTRL_MASK);
        inputMap.put(key, DefaultEditorKit.forwardAction);

        // Ctrl-p to go up one line
        key = KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK);
        inputMap.put(key, DefaultEditorKit.upAction);

        // Ctrl-n to go down one line
        key = KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK);
        inputMap.put(key, DefaultEditorKit.downAction);
    }

    // The following two methods allow us to find an
    // action provided by the editor kit by its name.
    private void createActionTable(JTextComponent textComponent) {
        actions = new HashMap<Object, Action>();
        Action[] actionsArray = textComponent.getActions();


        for (int i = 0; i
                < actionsArray.length; i++) {
            Action a = actionsArray[i];
            actions.put(a.getValue(Action.NAME), a);
        }
    }

    private Action getActionByName(String name) {
       return actions.get(name);
    }

    class UndoAction extends AbstractAction {

        public UndoAction() {
            super("Undo");
            setEnabled(false);
        }

        public void actionPerformed(ActionEvent e) {
            undo.undo();
            try {
                undo.undo();
            } catch (CannotUndoException ex) {
                System.out.println("Unable to undo: " + ex);
                ex.printStackTrace();
            }
            updateUndoState();
            redoAction.updateRedoState();


        }

        protected void updateUndoState() {
            if (undo.canUndo()) {
                setEnabled(true);
                putValue(Action.NAME, undo.getUndoPresentationName());
            } else {
                setEnabled(false);
                putValue(Action.NAME, "Undo");
            }
        }
    }

    class RedoAction extends AbstractAction {

        public RedoAction() {
            super("Redo");
            setEnabled(false);
        }

        public void actionPerformed(ActionEvent e) {
            undo.redo();
            try {
                undo.redo();
            } catch (CannotRedoException ex) {
                System.out.println("Unable to redo: " + ex);
                ex.printStackTrace();
            }
            updateRedoState();
            undoAction.updateUndoState();
        }

        protected void updateRedoState() {
            if (undo.canRedo()) {
                setEnabled(true);
                putValue(Action.NAME, undo.getRedoPresentationName());
            } else {
                setEnabled(false);
                putValue(Action.NAME, "Redo");
            }
        }
    }
    /**
     * Create the GUI and show it. For thread safety, this method should be
     * invoked from the event-dispatching thread.
     */   
    private static void createAndShowGUI() {
        // Create and set up the window.
        final TextComponentDemo frame = new TextComponentDemo();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    // The standard main method.
    public static void main(String[] args) {
        // Schedule a job for the event-dispatching thread:
        // creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            public void run() {
               createAndShowGUI();
            }
        });

    }
}

Atenciosamente

Esse editor faz isso e faz syntax coloring. Sugiro que você dê uma olhada numa classe chamada TextUtils que tem dentro dele.

Nao encontrei essa classe.
Desculpa mas sou bem novo na área estou começando agora.

Opa

Consegui implementar baseando em um padrao do java:

http://www.java2s.com/Tutorial/Java/0240__Swing/UsesalistenerlabeltodisplaycaretandselectionstatusForJTextPane.htm

Brigado

Estou quase postando meu codigo aqui
mas resta alguns detalhes.

Um deles é o seguinte:

Tenho uma linha, quero guardar todo o conteúdo de uma linha em uma string sem que o usuario selecione a linha inteira, ou seja:

Exemplo:

“Esta é uma linha que será selecionada”

Quando o usuario selecionar PARTE da linha e clicar em um botão, todo o resto da linha seria guardado em uma string.

Espero Respostas.

blz
até aqui!!

Descobri que nao preciso fazer na mao igual estava tentando
basta utilizar o “StyleConstants.FirstLineIndent”
porém nao estou conseguindo talvez devido as restrições

tipo:
eu uso assim:
action = new StyledEditorKit.AlignmentAction(“right-justify”, StyleConstants.ALIGN_RIGHT);

preciso usar também outro action com o parametro “StyleConstants.FirstLineIndent” porém nao da certo

acredito que devo criar alguma coisa que “herde” da classe/metodo AlignmentAction ou Action[] e adicionar
new Alignment
new AlignmentAction(“firstlineIndent”, StyleConstants.FirstLineIndent),

mas nao sei fazer.
Alguem poderia me ajudar

as classes envolvidas sao

StyledEditorKit, StyleConstants e DefaultEditorKit,

como eu ja disse sou novo com a linguagem e tenho algumas dificuldades.

Talvez a classe TextUtils te ajude:

[code]import java.awt.FontMetrics;
import java.awt.Point;

import javax.swing.JScrollPane;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.View;

/**

  • Util static methods to becomes easy operation with Text Components. All

  • functionalities are available to JTextComponent as well as a Document.

  • @author Farina, Andre
    */
    public class TextUtils
    {

    /**

    • Returns the line number of the caret in a text component.
    • @param txtCmp Text Component
    • @return Line number
      */
      public static int getCaretLine(JTextComponent txtCmp)
      {
      return getLine(txtCmp.getDocument(), txtCmp.getCaretPosition());
      }

    /**

    • Given an offset, returns the line number of a text component.
    • @param txtCmp Text Component
    • @param offset Offset position
    • @return Line number starting in 0.
      */
      public static int getLine(JTextComponent txtCmp, int offset)
      {
      return getLine(txtCmp.getDocument(), offset);
      }

    /**

    • Given an offset, returns the line number in a text component.
    • @param doc JTextComponent document
    • @param offset Offset position
    • @return Line number starting in 0.
      */
      public static int getLine(Document doc, int offset)
      {
      Element root = doc.getDefaultRootElement();
      return root.getElementIndex(offset);
      }

    /**

    • Given an offset, returns the column number in a text component.
    • @param offset Offset position
    • @return Column number starting in 0.
      */
      public static int getCaretColumn(JTextComponent txtCmp)
      {
      return getColumn(txtCmp, txtCmp.getCaretPosition());

    }

    /**

    • Given an offset, returns the column number in a text component.
    • @param offset Offset position
    • @return Column number starting in 0.
      */
      public static int getColumn(JTextComponent txtCmp, int offset)
      {
      return txtCmp.getCaretPosition() - getOffsetStartLine(txtCmp, offset);
      }

    /**

    • Given an offset, returns the offset where the line begins.
    • @param offset Offset position.
    • @return Offset where the line begins.
      */
      public static int getOffsetStartLine(JTextComponent txtCmp, int offset)
      {
      return getOffsetStartLine(txtCmp.getDocument(), offset);
      }

    /**

    • Given an offset, returns the offset where the line begins.
    • @param doc JTextComponent document
    • @param offset Offset position.
    • @return Offset where the line begins.
      */
      public static int getOffsetStartLine(Document doc, int offset)
      {
      int line = getLine(doc, offset);
      return getWhereLineStarts(doc, line);
      }

    /**

    • Given an offset, returns the offset where the line ends.
    • @param offset Offset position.
    • @return Offset where the line ends.
      */
      public static int getOffsetEndLine(JTextComponent txtCmp, int offset)
      {
      return getOffsetEndLine(txtCmp.getDocument(), offset);
      }

    /**

    • Given an offset, returns the offset where the line ends.
    • @param doc JTextComponent document
    • @param offset Offset position.
    • @return Offset where the line ends.
      */
      public static int getOffsetEndLine(Document doc, int offset)
      {
      int line = getLine(doc, offset);
      return getWhereLineEnds(doc, line);
      }

    /**

    • Given a line returns the offset number where the line starts.
    • @param line Line number
    • @return Offset number
      */
      public static int getWhereLineStarts(JTextComponent txtCmp, int line)
      {
      return getWhereLineStarts(txtCmp.getDocument(), line);
      }

    /**

    • Given a line returns the offset number where the line starts.

    • @param doc JTextComponent document

    • @param line Line number

    • @return Offset number
      */
      public static int getWhereLineStarts(Document doc, int line)
      {
      Element el = doc.getDefaultRootElement().getElement(line);
      if (el != null)
      return el.getStartOffset();

      return doc.getStartPosition().getOffset();
      }

    /**

    • Given a line returns the offset number where the line ends.
    • @param line Line number
    • @return Offset number
      */
      public static int getWhereLineEnds(JTextComponent txtCmp, int line)
      {
      return getWhereLineEnds(txtCmp.getDocument(), line);
      }

    /**

    • Given a line returns the offset number where the line ends.

    • @param doc JTextComponent document

    • @param line Line number

    • @return Offset number
      */
      public static int getWhereLineEnds(Document doc, int line)
      {
      Element el = doc.getDefaultRootElement().getElement(line);
      if (el != null)
      return el.getEndOffset();

      return doc.getEndPosition().getOffset();
      }

    /**

    • Count the line number.
    • @return Amount of lines.
      */
      public static int countLines(JTextComponent txtCmp)
      {
      return countLines(txtCmp.getDocument());
      }

    /**

    • Count the line number.
    • @param doc JTextComponent document
    • @return Amount of lines.
      */
      public static int countLines(Document doc)
      {
      return doc.getDefaultRootElement().getElementCount();
      }

    /**

    • Get number of rows in the content being shown. Independent of the text’s

    • size.

    • @return Amount of rows.
      */
      public static int getRows(JTextComponent txtCmp)
      {
      FontMetrics fm = txtCmp.getFontMetrics(txtCmp.getFont());
      int fontHeight = fm.getHeight();

      int ybaseline = txtCmp.getY() + fm.getAscent();
      int yend = ybaseline + txtCmp.getHeight();

      int rows = 1;

      while (ybaseline < yend)
      {
      ybaseline += fontHeight;
      rows++;
      }

      return rows;
      }

    /**

    • Get first visible line of the text component in a JScrollPane.

    • @param txtCmp Text component.

    • @return The line.
      */
      public static int getTopLine(JTextComponent txtCmp)
      {
      FontMetrics fm = txtCmp.getFontMetrics(txtCmp.getFont());
      int fontHeight = fm.getHeight();

      return (Math.abs(txtCmp.getY()) + fm.getAscent()) / fontHeight + 1;
      }

    /**

    • Get last visible line of the text component in a JScrollPane.

    • @param txtCmp Text component.

    • @return The line.
      */
      public static int getBottomLine(JTextComponent txtCmp)
      {
      FontMetrics fm = txtCmp.getFontMetrics(txtCmp.getFont());
      int fontHeight = fm.getHeight();

      View view = txtCmp.getUI().getRootView(txtCmp).getView(0);
      int height = view.getContainer().getParent().getHeight();

      return (Math.abs(txtCmp.getY()) + fm.getAscent() + height) / fontHeight;
      }

    /**

    • Scroll the pane until offset becomes visible.

    • @param scroll

    • @param offset
      */
      public static void scrollToVisible(final JScrollPane scroll, int offset)
      {
      if (!(scroll.getViewport().getView() instanceof JTextComponent))
      return;

      JTextComponent txtCmp = (JTextComponent) scroll.getViewport().getView();
      Element root = txtCmp.getDocument().getDefaultRootElement();
      int line = root.getElementIndex(offset);

      scrollLineToVisible(scroll, line);
      }

    /**

    • Scroll the pane until line becomes visible.

    • @param scroll

    • @param line
      */
      public static void scrollLineToVisible(final JScrollPane scroll, int line)
      {
      if (!(scroll.getViewport().getView() instanceof JTextComponent))
      return;

      JTextComponent txtCmp = (JTextComponent) scroll.getViewport().getView();
      FontMetrics fm = txtCmp.getFontMetrics(txtCmp.getFont());
      int fontHeight = fm.getHeight();
      scroll.getViewport().setViewPosition(new Point(0, fontHeight*line));
      }

    public static String generateEscapeRegex(String text)
    {
    text = text.replaceAll("\\", "\\\\");
    text = text.replaceAll("\.", "\\.");
    text = text.replaceAll("\", "\\");
    text = text.replaceAll("\?", "\\?");
    text = text.replaceAll("\(", "\\(");
    text = text.replaceAll("\)", "\\)");
    text = text.replaceAll("\[", "\\[");
    text = text.replaceAll("\]", "\\]");
    text = text.replaceAll("\{", "\\{");
    text = text.replaceAll("\}", "\\}");
    text = text.replaceAll("\^", "\\^");
    text = text.replaceAll("\$", "\\\$");
    text = text.replaceAll("\+", "\\+");
    text = text.replaceAll("\|", "\\|");
    return text;
    }
    }
    [/code]

Mas isso que você quer não tem nada de trivial. Não adianta postar o código inteiro no fórum e pedir para resolverem. Dê uma lida sobre como funciona exatamente a interface Document e StyledDocument.

Resumindo:

Ja implementei alinhar pela direita, esquerda, centro
Agora quero recuar ou avancar uma linha.

Queria dizer que ao terminar o editor de texto eu postarei todo o sistema pronto
para os usuarios do forum.

Já procurei e nao achei nada tão completo e free, diante disso agradeço a ajuda e me comprometo a disponibilizar quando terminar, já que só falta esse paragrafo mesmo.

Sim, sim, estava me referindo ao código gigante ali em cima, que faz com que esse tópico demore a ser carregado.

ViniGodoy, se puder excluir esse topico
pois nao vai ajudar ninguem oq foi dito aqui
vou criar outro mais especifico.

Grato

Só excluímos tópicos em casos extremos. De qualquer forma, tá a classe TextUtils aqui, ela pode ajudar muita gente. :slight_smile:

Ok esta certo