2009-07-17 54 views
2

我總是在Java佈局方面遇到麻煩,但現在困擾我的主要原因是,當內容發生變化時,特別是對其大小進行更改時,它的佈局不正確。以下面的例子:讓Java Swing程序再次佈局

package layouttest; 

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTextArea; 

public class LayoutTestStart extends JFrame implements ActionListener 
{ 
    static JButton button= new JButton("Expand"); 
    static JTextArea f = new JTextArea("A medium sized text"); 
    static LayoutTestStart lst; 

    public static void main(String[] args) { 
     //Schedule a job for the event-dispatching thread: 
     //creating and showing this application's GUI. 
     javax.swing.SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 

    public static void createAndShowGUI() 
    { 
     lst = new LayoutTestStart(); 
     lst.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JPanel all = new JPanel(); 

     button.addActionListener(lst); 

     all.add(button); 
     all.add(f); 
     lst.getContentPane().add(all); 

     lst.setVisible(true); 
     lst.pack(); 
    } 
    @Override 
    public void actionPerformed(ActionEvent e) 
    { 
     f.setText(f.getText()+"\n"+f.getText()); 

     // this doesn't work 
     f.invalidate(); 

     // this does but it's cheating 
//  lst.pack(); 
    } 
} 

我得到這個工作的唯一方法是調用lst.pack(),但是這欺騙從那時起每個組件應該有一個參考,以它的JFrame,它就會變得混亂時,一個組件是一個單獨的課程。讓這個例子工作的首選方式是什麼?

回答

2

那麼,一般來說,用戶不喜歡每次擊中輸入時幀的大小發生變化。框架的設計應該適應增長。所以你可以將文本區域定義爲具有給定數量的行和列。然後,將文本區域添加到滾動窗格並將該滾動窗格添加到框架。然後,隨着數據的變化,滾動條將根據需要出現或消失。

如果您確實需要動態更改框架,那麼您應該使用pack()。您可以使用:

SwingUtilities.windowForComponent(...) 

其中Component是ActionEvent的源組件,查找窗口收拾()。

+0

到目前爲止,這看起來像我最好的選擇 – kresjer 2009-07-20 12:27:44

0

首先考慮到你的假設,你可以通過獲取最高級別​​的anscestor(組件上有這樣的方法)來調用pack並找出調用包。你可以創建一個靜態方法,並從任何需要的地方調用它。這將工作。

另一種選擇(也許真的是首選的選擇)是使用佈局管理器,以適應此。 GridBagLayout當然可以做到這一切,但有些人聲稱它不適合凡人使用。 MigLayout是一個更加理智的開源佈局管理器。

+0

我使用黑客類似於你的第一個建議,但它不覺得很好。 關於第二種選擇:通常將尺寸變化的字段分層爲一系列佈局管理器,所以我必須將它們全部更改爲理智的佈局管理器。 – kresjer 2009-07-17 12:14:29

+0

我看了一下MigLayout,它看起來不錯(除了名字),但我沒有看到我怎麼能改變我的例子來使用MigLayout並自動工作。 – kresjer 2009-07-17 12:21:59

+0

動態佈局管理器(與默認設置不同)可以隨着組件的增長和縮小來改變組件的位置,並且隨着框架的增長和縮小,您不必爲其明確編碼。 – Yishai 2009-07-17 13:19:16

3

revalidate而不是invalidateinvalidate只是將容器標記爲需要佈局。 revalidate這樣做,然後安排validate

順便說一句:我建議:避免從JFrame和其他組件延伸;避免接口的多重繼承,並避免(可變)靜態。

+1

你能進入最後一段湯姆的更多細節嗎?特別是,爲什麼你應該避免擴展組件? – Pool 2009-07-17 12:18:25

+0

如果我在我的源代碼中將invalidate()更改爲revalidate(),它仍然不起作用 - 或者您還在建議其他內容嗎? 我知道我的代碼很醜陋(儘管我可能不知道你給出的所有建議 - 我會看一看),因爲我想在一個類中適合我的示例:)。 – kresjer 2009-07-17 12:21:15

+0

@Pool我不確定接口的多重繼承(這似乎是第一個接口的一半)。但是,擴展組件會污染你的API,這使得每個人都難以使用。相反,如果需要,組件可以是您的類的成員,並提供像getUI一樣的方法來訪問它。 – 2012-08-13 13:17:41

-3

updateUI();應該永遠不會失敗!

+0

updateUI()用於LAF更改。這不是LAF的變化,不應該使用。 – camickr 2009-07-17 23:38:21

0

單獨對JTextArea無效或驗證無效,您必須更改頂部框架的大小,因爲它不會自動更新它的大小。例如,你可以這樣做(改變代碼,刪除靜態變量):

package layouttest; 

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTextArea;  

public class LayoutTestStart extends JFrame implements ActionListener{ 

private JTextArea f = new JTextArea("A medium sized text"); 

public LayoutTestStart(){ 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    JPanel all = new JPanel(); 
    JButton button = new JButton("Expand"); 
    button.addActionListener(this); 

    all.add(button); 
    all.add(f); 
    getContentPane().add(all); 
} 

@Override 
public void actionPerformed(ActionEvent e){ 
    javax.swing.SwingUtilities.invokeLater(new Runnable(){   
     @Override 
     public void run(){ 
      f.setText(f.getText() + "\n" + f.getText()); 
      setSize(getPreferredSize());     
     } 
    }); 

} 

public static void main(String[] args){ 
    // Schedule a job for the event-dispatching thread: 
    // creating and showing this application's GUI. 
    javax.swing.SwingUtilities.invokeLater(new Runnable(){ 
     public void run(){ 
      LayoutTestStart lst = new LayoutTestStart(); 
      lst.setVisible(true); 
      lst.pack(); 
     } 
    }); 
} 
}