Disable editing in a JTextPane while allowing visible cursor movement
Asked Answered
S

4

5

I have a JTextPane which is populated by reading from a file, after which the data is parsed and formatted. The user is not allowed to edit the JTextPane, but I want them to be able to navigate in it with a visible cursor.

If I use setEditable(false), the cursor is invisible, although it is possible to indirectly observe the position of the invisible cursor by holding down Shift and using the arrow keys to select a block of text.

To enable a visible cursor while disallowing editing, instead of setEditable(false) I created a dummy DocumentFilter that simply does nothing for its insertString(), remove(), and replace() methods. But then I have to swap in a regular filter in order to programmatically populate the JTextPane from a file, then put back the dummy filter right before returning control to the user.

So far this seems to work, but is there a simpler solution? If I leave this as is, is there any sequence of keystrokes or mouse activity that could somehow allow the user to edit the text pane, given that it is technically editable as per setEditable?

Scruffy answered 3/10, 2012 at 1:2 Comment(0)
F
5

Extend your DocumentFilter introducing flag isAPI. If it's false prevent all the changes. When you need to add content programmatically set the flag, add the content, and reset the flag back to false.

Fluoro answered 3/10, 2012 at 5:57 Comment(1)
I implemented a variation of this. I created a class which takes an optional DocumentFilter as a constructor. Each of the insertString(), remove() and replace() methods have a check for the flag, and depending on the flag they will either do nothing or pass on the instruction to the filter that was provided at construction time (or to the superclass if there was no such filter provided).Scruffy
A
6
textPane.addFocusListener(new FocusListener() {

        @Override
        public void focusLost(FocusEvent e) {
            textPane.setEditable(true);

        }

        @Override
        public void focusGained(FocusEvent e) {
            textPane.setEditable(false);

        }
    });

Yet another dirty hack! It seems to provide what you need!

Acropolis answered 3/10, 2012 at 2:0 Comment(0)
F
5

Extend your DocumentFilter introducing flag isAPI. If it's false prevent all the changes. When you need to add content programmatically set the flag, add the content, and reset the flag back to false.

Fluoro answered 3/10, 2012 at 5:57 Comment(1)
I implemented a variation of this. I created a class which takes an optional DocumentFilter as a constructor. Each of the insertString(), remove() and replace() methods have a check for the flag, and depending on the flag they will either do nothing or pass on the instruction to the filter that was provided at construction time (or to the superclass if there was no such filter provided).Scruffy
D
3

This did the trick for me (a combination of the previous suggestions):

textPane.addFocusListener(new FocusListener() {

    @Override
    public void focusGained(FocusEvent e) {
         textPane.getCaret().setVisible(true);
    }
});
Diplostemonous answered 5/9, 2014 at 12:31 Comment(0)
K
2

This is probably a dirty, dirty hack, but I got this to work.

After you have set the text pane to un-editable, use textPane.getCaret().setVisible(true) to re-enable the caret

Kibler answered 3/10, 2012 at 1:47 Comment(2)
The problem with this approach is that it leaves a blinking cursor in the text pane after the focus has moved to another field, which makes the screen look strange with multiple blinking cursors at the same time. Avoiding that requires additional code to show/hide the caret as the user navigates from field to field.Scruffy
Yep, you'd probably need to attach a focus lost listener to disable the cursor :P - You have to remember, you're trying to do something that the components weren't designed for, you have to take some responsibility for it ;)Kibler

© 2022 - 2024 — McMap. All rights reserved.