Java Swing StyledDocument get Element tree / SelectedText Styling like bold, italic

525 Views Asked by At

Hey i have some questions/problems.

I have to create a little program for text editing. The (selected) text should be style. Bold, Italic, Underline, Right- left- center alignment. It works great. I used the specific StyleEditorKit Actions.

My problem is now that this actions are fired through buttons in a jtoolbar and jmenuitems in a jmenu / jmenubar.

So there are two click elements to set a text bold, two elements to set a text italic and so on. If one element (e.g. the button in the toolbar) is clicked, the jmenuitem should be selected/activated too. But how can i realize this?

My idea is to check the selected text (CaretListener is implemented). If the text is bold => set the button and menuitem active. But how can i get if the selectedText is bold/italic etc?

I think there is a StyledDocument tree with leafs for this stuff. But how can i get this tree? how can i get the leafs?

This are my first steps:

jTextPane1.addCaretListener(new CaretListener() {

    @Override
    public void caretUpdate(CaretEvent e) {
        Highlight[] h = jTextPane1.getHighlighter().getHighlights();
        for(int i = 0; i < h.length; i++) {
            System.out.println(h[i].getStartOffset());
            System.out.println(h[i].getEndOffset());
            String selectedText = jTextPane1.getSelectedText();


            StyledDocument styleddoc = (StyledDocument) jTextPane1.getDocument();

            System.out.println(styleddoc);

        }

    }
});

But i only get javax.swing.text.DefaultStyledDocument@5098cb76

How can i iterate over the tree and get the leafs / bold or italic elements?

Thank you

4

There are 4 best solutions below

5
On

how can i get if the selectedText is bold/italic etc?

In your CaretListener you can use:

AttributeSet attributes = jTextPane1.getCharacterAttributes();
System.out.println( attributes.containsAttribute(StyleConstants.Bold, Boolean.TRUE) );

If one element (e.g. the button in the toolbar) is clicked, the jmenuitem should be selected/activated too.

You should be using an Action:

Action bold = new StyledEditorKit.BoldAction();
JButton boldButton = new JButton( bold );
JCheckBoxMenuItem boldMenuItem = new JCheckBoxMenuItem( bold );

When you set the state of an Action, the state of all components using the Action is changed. For example you can make the Action selected or enabled.

1
On

my code looks like this now

public void jToolBarInitButtons() {

    jTextPane1.addCaretListener(new CaretListener() {

    @Override
    public void caretUpdate(CaretEvent e) {

        StyledDocument styleddoc = (StyledDocument) jTextPane1.getDocument();

            AttributeSet attributes = jTextPane1.getCharacterAttributes();
            System.out.println("bold " +  attributes.containsAttribute(StyleConstants.Bold, Boolean.TRUE));
            System.out.println("italic " + attributes.containsAttribute(StyleConstants.Italic, Boolean.TRUE));

    }
2
On

Sorry. This is the whole code:

Update 2: here is the code

public class TestFrame extends javax.swing.JFrame {

    /**
     * Creates new form TestFrame
     */
    public TestFrame() {
        initComponents();
        initButtons();
    }

    Action boldAction = new StyledEditorKit.BoldAction();    
    Action italicAction = new StyledEditorKit.ItalicAction();
    Action underlineAction = new StyledEditorKit.UnderlineAction();

    public void initButtons() {
        JButton boldButton = new JButton(boldAction);
        boldButton.setText("bold");

        JButton italicButton = new JButton(italicAction);
        boldButton.setText("italic");

        JButton underlineButton = new JButton(underlineAction);
        boldButton.setText("underline");

        jToolBar1.add(boldButton);
        jToolBar1.add(italicButton);
        jToolBar1.add(underlineButton);

        jTextPane1.addCaretListener(new CaretListener() {

        @Override
        public void caretUpdate(CaretEvent e) {
            Highlighter.Highlight[] h = jTextPane1.getHighlighter().getHighlights();
            for(int i = 0; i < h.length; i++) {
                System.out.println("length " +  h.length);
                System.out.println(h[i].getStartOffset());
                System.out.println(h[i].getEndOffset());
                String selectedText = jTextPane1.getSelectedText();


                StyledDocument styleddoc = (StyledDocument) jTextPane1.getDocument();

                AttributeSet attributes = jTextPane1.getCharacterAttributes();
                System.out.println("Bold " + attributes.containsAttribute(StyleConstants.Bold, Boolean.TRUE));
                System.out.println("Italic " + attributes.containsAttribute("Italic " + StyleConstants.Italic, Boolean.TRUE));
                System.out.println("Underline " + attributes.containsAttribute(StyleConstants.Underline, Boolean.TRUE));
            }

        }
    });
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jTextPane1 = new javax.swing.JTextPane();
        jToolBar1 = new javax.swing.JToolBar();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jScrollPane1.setViewportView(jTextPane1);

        jToolBar1.setRollover(true);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(116, Short.MAX_VALUE)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 269, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(75, 75, 75))
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 192, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(23, 23, 23)
                .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(14, 14, 14)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(89, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new TestFrame().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextPane jTextPane1;
    private javax.swing.JToolBar jToolBar1;
    // End of variables declaration                   
}
6
On

So there are two click elements to set a text bold, two elements to set a text italic and so on. If one element (e.g. the button in the toolbar) is clicked, the jmenuitem should be selected/activated too. But how can i realize this?

Create both the menu item and the button by passing the same Action to their constructors.

It sounds like you intend show the bold state in the button and menu item, so you’ll probably want to create a JCheckBoxMenuItem and a JToggleButton. When you create the Action, set its SELECTED_KEY to a non-null value, so the buttons will keep it up to date:

action.putValue(Action.SELECTED_KEY, false);

From the Action documentation:

SELECTED_KEY

Components that honor this property only use the value if it is non-null. For example, if you set an Action that has a null value for SELECTED_KEY on a JToggleButton, the JToggleButton will not update it's selected state in any way. Similarly, any time the JToggleButton's selected state changes it will only set the value back on the Action if the Action has a non-null value for SELECTED_KEY. Components that honor this property keep their selected state in sync with this property. When the same Action is used with multiple components, all the components keep their selected state in sync with this property.

Your CaretListener should be as camickr described.