简体   繁体   中英

Get attributes of selected text in JTextPane

I'm trying to find out, how to get attributes of selected text in JTextPane. I found that best solution is do it with getInputAttributes() and CaretListener. But I have some issues with this implementation.

My solution showing attributes of text on last position of caret, but not on actual position of caret. What I'm doing wrong? Please.

在此处输入图片说明

There is my SSCCE:

public class Testovani{
static JTextPane pane;
static JLabel label;

public static void main(String[] args) throws BadLocationException {
    JFrame frame = new JFrame();
    frame.setSize(350, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new BorderLayout());

    pane = new JTextPane();
    label = new JLabel();
    pane.addCaretListener(new SelectionListener());

    MutableAttributeSet attrs = new SimpleAttributeSet();
    StyleConstants.setBold(attrs, true);
    pane.getDocument().insertString(0, "\n", null);
    pane.getDocument().insertString(0, "This is first row non bold", null);
    pane.getDocument().insertString(0, "\n", null);
    pane.getDocument().insertString(0, "This is second row bold", attrs);
    pane.getDocument().insertString(0, "\n", null);
    pane.getDocument().insertString(0, "This is third row bold", attrs);
    pane.getDocument().insertString(0, "\n", null);

    frame.add(pane);
    frame.add(label, BorderLayout.SOUTH);
    frame.setVisible(true);
}

private static class SelectionListener implements CaretListener{
    @Override
    public void caretUpdate(CaretEvent e) {
        AttributeSet attrs =((StyledEditorKit)pane.getEditorKit()).getInputAttributes();
        label.setText("Is bold: " + String.valueOf(StyleConstants.isBold(attrs)));
    }   
}}

And I have two bonus question. Is this approach functional for selection or just for position of caret? And what returns, if there is selection of text whose one part is bold and second part not?

Actually attributes of selection is complicated question and need your understanding of business requirements.

Suppose a fragment of text is selected and you need the selection font size. But the fragment has 3 different pieces of text with 3 different sizes.

Selection start position is placed in the mid of 10pt text, then piece of text with 12pt size and selection ends in the mid of 14pt size fragment.

What size do you expect? 10, 12, 14 or (multiple)?

The simplest approach is to use inputAttributes.

By default the attributes are copied from caret position but of course you can add a caret listener and on each update check and fill the input attributes as you need according to your business logic (processing the multiple text fragments with different attributes).

UPDATE: Try to wrap the AttributeSet attrs =((StyledEditorKit)pane.getEditorKit()).getInputAttributes(); in SwingUtilities.invokeLater() call

There is no expected behaviour for getting the attributes of a selection, simply because a selection can have character elements with each different attributes.

You have to understand that there is a difference between getInputAttributes which returns the attributes that the textPane calculated the best for a next input, and getCharacterAttributes that returns the attributes of the current caret position. In the case of a selection, the caret is the position where you ended the selection. It can be the getSelectionStart or getSelectionEnd given if you selected text from left to right or from right to left.

Anyway, what I advice you is to get the StyledDocument of your JTextPane, and then iterate through the character elements from getSelectionStart to getSelectionEnd :

for(int i=jtp.getSelectionStart(); i<jtp.getSelectionEnd(); i++) {
    AttributeSet set = jtp.getStyledDocument().getCharacterElement(i).getAttributes();
    //here, combine, analyse, do whatever you like with your AttributeSet
    //You can use StyleConstants.xxx to analyse the attributes
}

I used @Sharcoux 's solution with one change: I made sure that there there was always at least one character to iterate over. When there's no selection, getSelectionStart() == getSelectionEnd() . For this reason I would make the slight change of:

int iStart = jtp.getSelectionStart();
int iEnd = jtp.getSelectionEnd();
if(iStart > 0) iStart--;
else if(iEnd < jtp.getDocument().getEndPosition().getOffset()) iEnd++;
for(int i = iStart; i < iEnd; i++) {
    AttributeSet set = jtp.getStyledDocument().getCharacterElement(i).getAttributes();
    //here, combine, analyse, do whatever you like with your AttributeSet
    //You can use StyleConstants.xxx to analyse the attributes
}

The only instance in which this changes nothing is when the document is completely empty, in which case getInputAttributes should work fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM