0

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

Torben G
  • 750
  • 2
  • 11
  • 33

4 Answers4

0

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.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Thanks. The thing with attributes works. But if i select my whole text it returns false... if i select everything without the last character it returns true... I used the BoldAction. Is it necessery to set the button to selected or enabled? – Torben G May 11 '16 at 15:53
  • System.out.println(attributes.containsAttribute(StyleConstants.Italic, Boolean.TRUE)); it returns false every time... – Torben G May 11 '16 at 15:57
  • `But if i select my whole text it returns false... ` - I guess you can iterate through each individual character of the selected text. All character must be bold. Well if it is not enabled, then you won't be able to click the button. You don't make the button enabled or selected. You change the Action. – camickr May 11 '16 at 16:01
  • It print the proper value for me. Post your [SSCCE](http://sscce.org/) demonstrating the problem. That is create a simple app with a JFrame and JTextPane, a Bold button and a CaretListener. As the caret is moved over individual characters the output will change. – camickr May 11 '16 at 16:04
  • @TorbenG, `it returns false if the caret ends up after the last character.` Right, because the caret is for the next character, not the previous character. As I have suggested several times now you need to check each character in the selected text individually! So you need to get the information from the Document. First you get the Element for the specific character, then you get the Attributes from the Element. – camickr May 11 '16 at 17:36
0

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));

    }
Torben G
  • 750
  • 2
  • 11
  • 33
  • That is not a SSCCE. I can't compile that code. There is no frame, textpane or button. So I can't test it to see if I have problems or not. – camickr May 11 '16 at 16:19
0

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                   
}
Torben G
  • 750
  • 2
  • 11
  • 33
  • What do you expect to happen? The code I gave you only looks at the final caret position. So if the selection ends in the bolded text you get true, otherwise you get false. I suggested you need to create a method to test each character in the selected text. As soon as soon as you find an unbolded character you return false. If you reach the end of the string then you return true. – camickr May 11 '16 at 17:19
  • my problem is that it returns false if the caret ends up after the last character. If i have a bold "Hello" and selected everything and stop after the 'o' it returns false... not true. But everything, the whole hello is bold. – Torben G May 11 '16 at 17:26
0

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.

Community
  • 1
  • 1
VGR
  • 40,506
  • 4
  • 48
  • 63
  • This is my code, but e.g. boldAction has no putValue methode.. Action boldAction = new StyledEditorKit.BoldAction(); Action italicAction = new StyledEditorKit.ItalicAction(); Action underlineAction = new StyledEditorKit.UnderlineAction(); – Torben G May 11 '16 at 16:32
  • @TorbenG You will need to call putValue(Action.SELECTED_KEY, false) on each of those actions, if you intend to use each of them in both a button and menu item. – VGR May 11 '16 at 16:39
  • maybe i am too stupid but it doesnt work for me... boldAction.putValue(Action.SELECTED_KEY, false); – Torben G May 11 '16 at 16:48
  • Did you pass that same boldAction in both the constructor of your “bold” button and the constructor of your “bold” menu item? – VGR May 11 '16 at 17:04
  • JCheckBoxMenuItem jCheckBoxBold = new JCheckBoxMenuItem(boldAction); buttonBold = new JButton(boldAction); – Torben G May 11 '16 at 17:08
  • @TorbenG A JButton does not have a persistent selected state. Use a JToggleButton instead. – VGR May 11 '16 at 17:21