Search code examples
javaswingjscrollpanejtextarea

Make JScrollPane control multiple components


For my application I am designing a script editor. At the moment I have a JPanel which contains another JPanel that holds the line number (positioned to the left), and a JTextArea which is used to allow users to type their code in (positioned to the right).

At the moment, I have implemented a JScrollPane on the JTextArea to allow the user to scroll through their code.

For the JPanel containing the line numbers, they increment every time the user presses the enter key.

However, the problem is that I want the same JScrollPane (the one implemented on the JTextArea) to control the scrolling of the line number JPanel as well; i.e. when the user scrolls on the JTextArea, the line number JPanel should also scroll. But since the line numbers are held in a JPanel, I cant add that component to a JTextArea.

The constructor for the JPanel class containing the JTextArea and the line number JPanel:

private ScriptEditor() {

    setBackground(Color.WHITE);

    lineNumPanel = new LineNumberPanel();

    scriptArea = new JTextArea();
    scriptArea.setLineWrap(true);
    scriptArea.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 15));
    scriptArea.setMargin(new Insets(3, 10, 0, 10));

    JScrollPane scrollPane = new JScrollPane(scriptArea);
    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    scrollPane.setPreferredSize(new Dimension(width, height));

    scriptArea.addKeyListener(this);

    add(lineNumPanel);
    add(scrollPane);
}

The constructor for the line number JPanel which adds JLabels within itself to represent the line numbers:

public LineNumberPanel() {

    setPreferredSize(new Dimension(width, height));

    box = Box.createVerticalBox();
    add(box);

    //setup the label
    label = new JLabel(String.valueOf(lineCount));
    label.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 15));

    //setup the label alignment
    label.setVerticalAlignment(JLabel.TOP);
    label.setHorizontalAlignment(JLabel.CENTER);
    label.setVerticalTextPosition(JLabel.TOP);
    setAlignmentY(TOP_ALIGNMENT);

    box.add(label);
}

Solution

  • Create an Outer Panel which holds the Line Number panel and Text Area.

    Then put this new panel into the Scroll Pane so you end up with this arrangement:

    enter image description here

    Which in code is something like:

    private ScriptEditor() {
    
        setBackground(Color.WHITE);
    
        JPanel outerPanel = new JPanel();
    
        lineNumPanel = new LineNumberPanel();
    
        scriptArea = new JTextArea();
        scriptArea.setLineWrap(true);
        scriptArea.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 15));
        scriptArea.setMargin(new Insets(3, 10, 0, 10));
    
        outerPanel.add(lineNumPanel, BorderLayout.WEST)
        outerPanel.add(scriptArea, BorderLayout.CENTER)
    
        JScrollPane scrollPane = new JScrollPane(outerPanel);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setPreferredSize(new Dimension(width, height));
    
        scriptArea.addKeyListener(this);
    
        add(lineNumPanel);
        add(scrollPane);
    }