2015-04-23 61 views
1

我有一個JTextArea,我希望用戶輸入一個人的地址。我知道用戶輸入的有效地址不會超過5 rows10 columns。所以我把它設置爲JTextArea (5,10)。這樣它工作正常。當用戶按回車時禁用JTextArea調整大小

問題是,當用戶繼續按住enter 5次以上時,文本區域將開始調整大小。我不想將文本區域放在JScrollPane中,因爲用戶輸入的文本對於滾動來說並不多。

問題:當用戶按enter時,我們如何禁用JTextArea調整大小?

這裏是我的代碼:

public class JTextAreaDemo { 

private JFrame frame; 

JTextAreaDemo(){ 
    frame= new JFrame(); 
    frame.setSize(300, 300); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setLayout(new net.miginfocom.swing.MigLayout()); 
    frame.setVisible(true); 
    frame.setLocationRelativeTo(null); 

    JLabel label=new JLabel("Address :"); 
    JTextArea address= new JTextArea(5,20); 
    frame.add(label,"cell 0 0"); 
    frame.add(address, "cell 1 0"); 
} 

public static void main(String [] args){ 
    SwingUtilities.invokeLater(new Runnable(){ 

     @Override 
     public void run() { 
      new JTextAreaDemo(); 

     }}); 
    } 
} 
+1

把它放在一個'JScrollPane'中,它的大小正在改變,因爲它的首選大小正在改變 – MadProgrammer

+0

你的意思是說,當用戶第五次按下輸入按鈕時它將被一個空格替換或被忽略? – Blip

+0

@MadProgrammer那麼,這是工作。有一件事,當用戶按下回車鍵時,如何避免光標移動到第六行/行? – JWizard

回答

2

你可以嘗試使用DocumentFilter,例如:

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.text.AbstractDocument; 
import javax.swing.text.AttributeSet; 
import javax.swing.text.BadLocationException; 
import javax.swing.text.DocumentFilter; 

public class TestFrame extends JFrame { 

    public static void main(String... s) { 
     new TestFrame(); 
    } 

    private JTextArea area; 

    public TestFrame() { 
     init(); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     pack(); 
     setLocationRelativeTo(null); 
     setVisible(true); 
    } 


    private void init() { 
     area = new JTextArea(); 
     ((AbstractDocument)area.getDocument()).setDocumentFilter(getFilter(5)); 
     add(new JScrollPane(area)); 
    } 

    private DocumentFilter getFilter(final int lineCount) { 
     return new DocumentFilter(){ 

      @Override 
      public void replace(FilterBypass fb, int offset, int length, 
        String text, AttributeSet attrs) 
        throws BadLocationException { 
       if(area.getLineCount()<=lineCount && area.getLineOfOffset(area.getCaretPosition())<lineCount) 
         if(text.contains("\n") && area.getLineCount()<lineCount) 
          super.replace(fb, offset, length, text, attrs); 
         else if(!text.contains("\n")) 
          super.replace(fb, offset, length, text, attrs); 
      } 
     }; 
    } 

} 
+0

嗯,這實際上是我正在考慮限制行數/行數。 – JWizard

+0

@Giovanrich歡迎您 – alex2410

+0

作爲一般的經驗法則,過濾器不應該知道文本組件,它有點失敗的目的。 – MadProgrammer

1

使用setPreferredSize(new Dimension(X,Y)),使JTextArea中會讓你設置的尺寸,並不會動彈! 您仍然需要將您的JTextArea放在JScrollPane的思想中。

+0

好吧,使用'JScrollPane'並行設置首選大小。無論如何,感謝您的提示,單獨設置首選尺寸是無法實現的。 – JWizard

+0

@Giovanrich不客氣,我編輯了我對你答案的回答,不要忘記在你完成時關閉你的問題。 – Mekap

+0

JTextArea和MigLayout討厭setPreferredSize,這是關於JScrollPane中JTextArea的換行/字換行,否則.... :-) – mKorbel

0

我建議你應該使用一個InputVerifier這將跟蹤輸入已經輸入在你的JTextArea的數量,當它達到4,那麼它應該忽略輸入。

正如你在你的評論中指出DocumentListener會做同樣的事情,KeyListener也可以做同樣的事情。

+0

「InputVerifer」僅在焦點丟失時纔會收到通知?當字段設置爲包裝時,這不會阻止用戶使用文本溢出字段,例如 – MadProgrammer

+0

@MadProgrammer如何處理'DocumentListener'? - 它不是保存跟蹤的目的嗎? – JWizard

+0

@MadProgrammer我真的忽略了**是的,這是真實的**,我正在糾正我的答案,以適應這一點。 – Blip

2

如前所述,DocumentFilter可以使用。我發佈這個答案是由於它提供的優雅的解決方案。

public class JTextAreaDemo { 

    private JFrame frame = new JFrame(); 
    JTextArea address = new JTextArea(5, 20); 

    JTextAreaDemo() { 

     JLabel label = new JLabel("Address :"); 
     frame.getContentPane().add(label, BorderLayout.CENTER); 
     frame.getContentPane().add(address, BorderLayout.SOUTH); 

     ((PlainDocument) address.getDocument()).setDocumentFilter(new LineFilter()); 

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

    class LineFilter extends DocumentFilter { 

     @Override 
     public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException { 

      if (address.getLineCount() < 5 || !string.contains("\n")) 
       super.insertString(fb, offset, string, attr); 
     } 

     @Override 
     public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { 

      if (address.getLineCount() < 5 || !text.contains("\n")) 
       super.replace(fb, offset, length, text, attrs); 
     } 
    } 

    public static void main(String[] args) { 

     new JTextAreaDemo(); 
    } 
} 

雖然用戶輸入的覆蓋方法insertString將是不相關的,它通常是覆蓋所有基地是一個好主意。否則,它可以被刪除。請注意,JScrollBar不需要。

編輯:

爲了允許@MadProgrammer靜靜地在晚上睡覺時,行計數完成(以不太優雅的方式)直接從文件:

@Override 
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { 

    String content = fb.getDocument().getText(0, fb.getDocument().getLength()); 
    Matcher matcher = Pattern.compile("\n").matcher(content); 
    int lines = 0; 
    while (matcher.find()) { 
     lines++; 
    } 
    if (lines < 4 || !text.contains("\n")) 
     super.replace(fb, offset, length, text, attrs); 
} 

insertString方法可以使用相同的代碼。

+0

通用經驗法則,過濾器不應該知道使用它的UI /文本組件。假設文本區域沒有啓用換行功能,那麼它就變成了一件相對容易的事情......如果沒有... – MadProgrammer

+0

@MadProgrammer我完全同意經驗法則,儘管當內容(文檔面)影響到視覺效果(UI組件方),我認爲這是有價值的。我添加了一個經驗法則的解決方案。 – user1803551

+0

如果換行,它不會幫助你。檢查[that](http://stackoverflow.com/questions/12837605/how-to-take-line-wrap-in-account-for-jtextarea-line-counting) – alex2410