Editor de texto utilizando TextPane JAVA

12 respostas
F

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

12 Respostas

V

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

F

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

F

Opa

Consegui implementar baseando em um padrao do java:

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

Brigado

F

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.

F

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.

V

Talvez a classe TextUtils te ajude:

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 &lt; 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(&quot;\\\\&quot;, &quot;\\\\\\\\&quot;);
        text = text.replaceAll(&quot;\\.&quot;, &quot;\\\\.&quot;);
        text = text.replaceAll(&quot;\\*&quot;, &quot;\\\\*&quot;);
        text = text.replaceAll(&quot;\\?&quot;, &quot;\\\\?&quot;);
        text = text.replaceAll(&quot;\\(&quot;, &quot;\\\\(&quot;);
        text = text.replaceAll(&quot;\\)&quot;, &quot;\\\\)&quot;);
        text = text.replaceAll(&quot;\\[&quot;, &quot;\\\\[&quot;);
        text = text.replaceAll(&quot;\\]&quot;, &quot;\\\\]&quot;);
        text = text.replaceAll(&quot;\\{&quot;, &quot;\\\\{&quot;);
        text = text.replaceAll(&quot;\\}&quot;, &quot;\\\\}&quot;);
        text = text.replaceAll(&quot;\\^&quot;, &quot;\\\\^&quot;);
        text = text.replaceAll(&quot;\\$&quot;, &quot;\\\\\\$&quot;);
        text = text.replaceAll(&quot;\\+&quot;, &quot;\\\\+&quot;);
        text = text.replaceAll(&quot;\\|&quot;, &quot;\\\\|&quot;);
        return text;
    }
}

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.

F

Resumindo:

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

F

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.

V

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

F

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

Grato

V

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

F

Ok esta certo

Criado 22 de outubro de 2010
Ultima resposta 28 de out. de 2010
Respostas 12
Participantes 2