2014-03-25 29 views
2

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

我怎样才能从JTextArea的底部开始,并且只在整个原始视口被填充时才启用滚动?

enter image description here

回答

2

基本上,你可以与其他JPanel作用的填充物,造成JTextArea占据其实际所需的最小空间添加JTextTextJPanel

我这样做是通过使用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

我还不够。你能否详细说明一下?而且你知道我输入的最后几行始终是可见的。这只是JScrollPane的即时切换而使我感到困惑。 – user2651804

+1

@ user2651804也许你应该考虑提供[可运行示例来演示你的问题](https://stackoverflow.com/help/mcve),所以我们都在同一页 – MadProgrammer

+0

这里有两个截屏视频,应该说明我的问题:http ://screencast.com/t/dBPyVAwfT和http://截屏。com/t/ZolTEEADS – user2651804

1

要做到这一点我使用textArea.setMargin(新插图(X,0,0,0));并且一切正常,除了我的第二个输入将切换JScrollPane。

嗯,我想你会需要重置边缘每次你添加文本到文本区域考虑到新的首选大小的文本区域相对于滚动窗格的大小。

您应该可以添加一个DocumentListener到文本区域,并在文本添加到文档时进行调整。

+0

我有两个问题:1)我听说instanciating对象是一个高成本的任务对于该程序:该程序将自动添加大量文本! 2)我没有设置textarea的首选高度。我也没有指定行数:它的高度由BorderLayout中相邻组件的首选高度决定。这是否意味着首选高度与滚动窗格切换无关? – user2651804

+0

首选高度与出现的滚动条有关的“一切”。推测“x”的值基本上代表了9行文本的高度。当添加一行文本时,首选高度仍然小于滚动窗格的大小。当添加第二行文本时,首选高度变得比滚动窗格的大小更大,以便滚动条出现。 1)创建对象不是问题。甚至可以编写代码来重用相同的Insets,或者只在“x”值实际发生更改时创建新的Insets。 – camickr

+0

你说的是,如果我有panel1与preferredSize(0,0),并将panel2与preferredSize(100,100)放入面板1,我的面板将有prefferedSize(100,100) – user2651804

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个空行。我也不确定你在文本区域允许做什么。此解决方案假定您不能跳线,并且每次插入一行时都不是空白,并且它沿着上一行。

+0

啊!非常可以理解,非常偷偷摸摸!感谢你的回答 ;-) – user2651804