Jamesy82
Jamesy82

Reputation: 379

JTextPane - scrolling visible text without JScrollPane

So in my application I use a custom component that is an extension of JTextPane. I need to extend this for the styling. I've managed to turn off word wrapping as this component is intended to act as a JTextField ie not mult-lined.

The problem I'm facing however is that JTextPane doesn't appear to handle non word wrapped text very well when not used inside a JScrollpane if the text spans outside the visible area. The text outside the visible area cannot be moved to as you can when using a JTextField.

I don't want to use a JScrollpane as I have a lot of legacy code that assumes a JTextComponent.

So my question is, Is there a way of keeping the visible area inline with the caret position so that when typing reaches the visible edge or attempting to select text that spans outside the visible area, that text moves into view, like JTextField does.

A working example of my problem is below. It shows a JTextField above a JTextPane. If you type into the text field you'll see that the visible area move with the text. If you type into the text pane this does not happen.

Also, im doing this in java 7.

Thanks in advance.

import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;

public class NoAutoScroll {
    public NoAutoScroll() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JTextField textField = new JTextField();
        textField.setText("This text field can show the text outside the visible area.");
        textField.setPreferredSize(new Dimension(150, 30));

        JTextPane textPane = new JTextPane();
        textPane.setEditorKit(new MyEditorKit());
        textPane.setText("This text pane cannot show the text outside the visible area.");
        textPane.setPreferredSize(new Dimension(150, 30));
        textPane.setBorder(textField.getBorder());

        JPanel mainPanel = new JPanel(new GridBagLayout());
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.gridx = 0;
        constraints.gridy = 0;
        mainPanel.add(new JLabel("JTextField"), constraints);
        constraints.gridx = 1;
        constraints.gridy = 0;
        mainPanel.add(textField, constraints);
        constraints.gridx = 0;
        constraints.gridy = 1;
        mainPanel.add(new JLabel("JTextPane"), constraints);
        constraints.gridx = 1;
        constraints.gridy = 1;
        mainPanel.add(textPane, constraints);

        frame.add(mainPanel);
        frame.pack();
        frame.setVisible(true);
    }

    public class MyViewFactory implements ViewFactory {

        private final class NonBreakingLabelView extends LabelView {
            private NonBreakingLabelView(Element elem) {
                super(elem);
            }

            @Override
            public int getBreakWeight(int axis, float pos, float len){
                return BadBreakWeight;
            }
        }

        @Override
        public View create(final Element elem) {
            String kind = elem.getName();
            if (kind != null) {
                if (kind.equals(AbstractDocument.ContentElementName)) {
                return new NonBreakingLabelView(elem);
                } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
                    return new ParagraphView(elem);
                } else if (kind.equals(AbstractDocument.SectionElementName)) {
                return new BoxView(elem, View.Y_AXIS);
                } else if (kind.equals(StyleConstants.ComponentElementName)) {
                return new ComponentView(elem);
                } else if (kind.equals(StyleConstants.IconElementName)) {
                return new IconView(elem);
                }
            }

            // default to text display
            return new LabelView(elem);
        }
    }

    @SuppressWarnings("serial")
    public class MyEditorKit extends StyledEditorKit {

        @Override
        public ViewFactory getViewFactory() {
            return new MyViewFactory();
        }
    }

    public static void main(String[] args) {
        new NoAutoScroll();
    }
}

Upvotes: 0

Views: 684

Answers (1)

mKorbel
mKorbel

Reputation: 109815

correct way

  • not posible without JScrollPane, you can hide both JScrollBars

dirty hack

  • holding two Documents, second and visible will be only ScrollIncrememt generated from mouse events added to JTextPane, but then there no reason to use JTextPane, use JLabel instead,

Upvotes: 2

Related Questions