javaswingjscrollpanejtextarearowheader

How to make one JScrollPane connected to two components?,workaround


I'm aware that JViewport is a single-child container,and also that I cant add multiple components to one jscrollpane.

But can I track position of scrollpane and according to it modify view of another component? To show what im trying to do here is a image:

http://i.imgur.com/X9GW3VO.png

here is my code:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.border.MatteBorder;
import javax.swing.text.BadLocationException;
import javax.swing.text.Utilities;

public class XMLSettingsPage extends JPanel {

    private int lines;
    private LinePanel linePanel;
    private JPanel southButtP;
    private JButton saveBtn = new JButton("Save");
    private JButton resetBtn = new JButton("Reset");
    private JScrollPane jsp;
    private JTextArea textArea;
    private JPanel panel;

    public XMLSettingsPage() {

        setBackground(Color.BLACK);
        setLayout(new BorderLayout());

        panel = new JPanel();
        add(panel, BorderLayout.CENTER);
        panel.setLayout(new BorderLayout(0, 0));

        linePanel = new LinePanel();
        panel.add(linePanel, BorderLayout.WEST);
        linePanel.setForeground(Color.GRAY);
        linePanel.setFont(new Font("Tahoma", Font.PLAIN, 13));
        linePanel.setBackground(SystemColor.inactiveCaptionBorder);

        textArea = new JTextArea();
        textArea.setCaretColor(Color.BLACK);
        textArea.setFont(new Font("Tahoma", Font.PLAIN, 13));
        textArea.setForeground(Color.BLACK);
        textArea.setBackground(UIManager.getColor("menu"));

        textArea.addKeyListener(new LinePanel() {
            @Override
            public void keyPressed(KeyEvent e) {
                linePanel.setLine(getLines());

            }
        });

        textArea.addFocusListener(new FocusListener() {

            @Override
            public void focusLost(FocusEvent e) {
                southButtP.setVisible(false);
            }

            @Override
            public void focusGained(FocusEvent e) {
                southButtP.setVisible(true);
            }
        });

        LinePainter painter = new LinePainter(textArea);
        painter.setColor(Color.WHITE);

        jsp = new JScrollPane(textArea);
        panel.add(jsp, BorderLayout.CENTER);
        jsp.setBackground(Color.BLACK);
        jsp.setBorder(null);

        southButtP = new JPanel();
        add(southButtP, BorderLayout.SOUTH);
        southButtP.setBorder(new MatteBorder(1, 0, 0, 0, (Color) Color.WHITE));
        southButtP.add(resetBtn);
        southButtP.add(saveBtn);
        southButtP.setBackground(SystemColor.scrollbar);

        southButtP.setVisible(false);

        resetBtn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                reset();
            }

        });
        resetBtn.setBackground(resetBtn.getParent().getBackground());
        saveBtn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                save();

            }
        });
        saveBtn.setBackground(resetBtn.getParent().getBackground());

    }

    private int getLines() {
        int totalCharacters = textArea.getText().length();
        int lineCount = (totalCharacters == 0) ? 1 : 0;

        try {
            int offset = totalCharacters;
            while (offset > 0) {
                offset = Utilities.getRowStart(textArea, offset) - 1;
                lineCount++;
            }
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
        return lineCount;
    }

    private void reset() {
        textArea.setText(getXMLSettingsData());
    }

    private void save() {
        // write to xml file settings.
    }

    private String getXMLSettingsData() {
        return null;
    }

    public static void setXMLSettingsData() {
        // sets xml data on change
    }

}

// Line Panel.
class LinePanel extends JTextArea implements KeyListener {

    private int lineNumber = 1;
    private StringBuilder sb;
    final private String END_STRING = " \n";

    public LinePanel() {
        sb = new StringBuilder();
        setBackground(Color.BLACK);
        setFont(new Font("Tahoma", Font.PLAIN, 13));
        setEditable(false);

    }

    public void printNumbers(String s) {
        setText(s);
    }

    private void numberFactory(int l) {

        sb.delete(0, sb.length());
        for (int i = 0, a = 1; i < l; i++, a++) {
            sb.append(" " + a + END_STRING);
        }
        printNumbers(sb.toString());
    }

    public void setLine(int line) {
        if (lineNumber != line) {
            lineNumber = line;
            numberFactory(line);

        } else {
        }
    }

    public int getLine() {
        return lineNumber;
    }

    @Override
    public void keyPressed(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

}

When I reach bottom of window I cant see another line numbers for obvious reason(its not scrolling down automaticly nor manually).

Is there any way to connect my JScrollPane to east JTextArea so I can see numbers of each line even after I reach bottom of panel?

And if you know any better way to do this please let me know I'm open to any ideas.

I have tried to put both components into one panel and then put scrollpane to it which didn't worked.I could not even see anything in center of my panel after that. No idea what I did wrong bud didn't seen as a good way to do this.


Solution

  • Use the rowHeader view.

    enter image description here

    jsp.setRowHeaderView(textArea);