2014-03-25 58 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