写在JTextArea的底部

时间:2014-03-25 00:56:51

标签: java swing jscrollpane jtextarea

我有一个JScrollPane和一个JTextArea(可编辑),有10行。我希望第一个用户输入显示在JTextArea的底部,最近的输入应该向上推送前一个输入。要实现这一点,我使用textArea.setMargin(new Insets(x,0,0,0));并且一切正常 - 除了我的第二个输入将切换JScrollPane

如何从JTextArea的底部开始,只在整个原始视口填充时启用滚动?

enter image description here

3 个答案:

答案 0 :(得分:2)

基本上,您可以将JTextText添加到JPanel上,其他JPanel作为填充符,使JTextArea占用实际需要的最小空间。< / p>

我是通过使用GridBagLayout强制填充占据其可能的大部分空间来实现的。

Scrolling

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestTextArea {

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

    public TestTextArea() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(new TestPane()));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTextArea ta;

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 1;
            gbc.weighty = 1;
            gbc.fill = GridBagConstraints.BOTH;

            JPanel filler = new JPanel();
            filler.setBackground(Color.WHITE);
            add(filler, gbc);

            gbc.gridy = 1;
            gbc.weighty = 0;
            ta = new JTextArea(1, 20);
            add(ta, gbc);
        }
    }

}

答案 1 :(得分:1)

  

为了达到这个目的,我使用textArea.setMargin(new Insets(x,0,0,0));并且一切正常 - 除了我的第二个输入将切换JScrollPane。

我猜想每次向文本区域添加文本时都需要重置边距,以考虑与滚动窗格大小相关的文本区域的新首选大小。

您应该能够将DocumentListener添加到文本区域,并在文档添加到文档时进行调整。

答案 2 :(得分:1)

我认为使用边距和插图是不可取的,因为您正在使用布局调整来实现文本(内容)功能。这应该由Document对象控制,这是JTextArea对其内容进行调用的内容。

如果你在内部调用append,那么在扩展JTextArea的新类中覆盖它:

public class Test {

static MyTextArea ta = new MyTextArea();
static int x = 0;

    public static void main(String[] args) {

        ta.setRows(10);
        ta.setText("\n\n\n\n\n\n\n\n\n");
        ta.setCaretPosition(ta.getDocument().getLength());

        JButton append = new JButton("Append");
        append.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ta.append("\n" + x);
                x++;
            }
        });

        JFrame frame= new JFrame();
        frame.setContentPane(new JPanel(new BorderLayout()));
        frame.getContentPane().add(new JScrollPane(ta), BorderLayout.CENTER);
        frame.getContentPane().add(append, BorderLayout.LINE_START);

        frame.pack();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    static class MyTextArea extends JTextArea {

        @Override
        public void append(String str) {

            super.append(str);
            try {
                if (getDocument().getText(0, 1).equals("\n"))
                    getDocument().remove(0, 1);
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
        }
    }
}

如果您手动编辑,请添加DocumentListener:

public class Test {

    public static void main(String[] args) {

        JTextArea ta = new JTextArea();
        ta.setRows(10);
        ta.setText("\n\n\n\n\n\n\n\n\n");
        ta.setCaretPosition(ta.getDocument().getLength());
        ta.getDocument().addDocumentListener(new MyDocListener());

        JFrame frame= new JFrame();
        frame.setContentPane(new JPanel(new BorderLayout()));
        frame.getContentPane().add(new JScrollPane(ta), BorderLayout.CENTER);

        frame.pack();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    static class MyDocListener implements DocumentListener {

        @Override
        public void insertUpdate(DocumentEvent e) {

            final DocumentEvent de = e;

            Runnable pushUp = new Runnable() {

                @Override
                public void run() {

                    String t = null;
                    try {
                        t = de.getDocument().getText(de.getOffset(), de.getLength());
                        if (t.equals("\n") && de.getDocument().getText(0, 1).equals("\n"))
                            ta.getDocument().remove(0, 1);
                    } catch (BadLocationException e1) {
                        e1.printStackTrace();
                    }
                }
            };       
            SwingUtilities.invokeLater(pushUp);     
        }

        @Override
        public void removeUpdate(DocumentEvent e) {}

        @Override
        public void changedUpdate(DocumentEvent e) {}
    }
}

请注意,代码中所需的只是内部类,其余的只是让您看到它正常工作。我也没有关于文本区域的初始状态的信息。在这里,我只将行数设置为10,将文本设置为10个空行。我也不确定你在文本区域可以做什么。此解决方案假设您不能跳线,并且每次插入一行时它都不是空白,而是在前一行之后。