2010-08-14 29 views
1

晚上好,返回JComponent中的實際大小,如顯示

我想知道如何獲得一個JComponent的大小,它已經與佈局管理奠定了後。我已經讀過,如果你事先調用dolayout(),validate()或setVisible(),這是可能的。但是,我無法讓它在我的代碼中工作。

我想知道這一點的原因是,只添加儘可能多的組件,以適應框架的集合大小,而事先不知道組件的大小。調用validate()不會設置此代碼示例中組件的大小。關於如何獲得合適尺寸的任何想法?

public class TestFrame extends JFrame { 

    public static void main(String args[]) { 
     TestFrame frame = new TestFrame(); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 

    public TestFrame() { 
     super("Test Frame"); 
     super.setSize(300, 600); 
     this.addComponents(); 
    } 

    private void addComponents() { 

     int heightLeft = this.getHeight(); 
     JPanel panel = new JPanel(); 
     panel.setSize(300, 600); 
     panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 
     String text = "This is a long String that represents " 
      + "the length of strings in my application. " 
      + "This will vary in the real application." 
      + "<ul><li>It uses html</li><li>not just</li>" 
      + "<li>plain text</li></ul>" 
      + "I'd like as many as will fit in the fame to be added.\n"; 

     while (true) { 
      JTextPane textPane = createTextPane(text); 

      this.invalidate(); 

      if (heightLeft > 0) { 
       panel.add(textPane); 
      } else { 
       break; 
      } 
      System.out.println("Before validation:" + textPane.getSize()); 
      // returns width and height = 0 
      this.validate(); 
      System.out.println("After validation:" + textPane.getSize()); 
      // Still returns width and height = 0 
      heightLeft -= textPane.getPreferredSize().getHeight(); 
     } 

     super.add(panel); 
    } 

    public JTextPane createTextPane(String text) { 
     JTextPane textPane = new JTextPane(); 

     textPane = new JTextPane(); 
     textPane.setEditorKit(new StyledEditorKit()); 
     textPane.setEditable(false); 
     textPane.setOpaque(false); 

     textPane.setContentType("text/html"); 
     textPane.setText(text); 

     return textPane; 
    } 
} 

感謝您的時間!

+0

重新格式化的代碼;如果不正確請回復。 – trashgod 2010-08-14 10:43:46

+0

'JScrollPane'會更合適嗎? http://download.oracle.com/javase/tutorial/uiswing/components/scrollpane.html – trashgod 2010-08-14 10:45:23

+0

感謝您的重新格式化。它看起來更好。 JScrollPane絕對是我的後備選項。我認爲這看起來不會太糟糕,但是我想出了讓應用程序看起來有特定意義的想法,團隊中的其他人都非常喜歡這個想法,現在我一直在試圖弄清楚要做到這一點:p – nova 2010-08-15 04:44:08

回答

3

你試圖完成的任務看起來非常困難,因爲你必須依靠Swing的計算各種組件的大小的方法,然後設法獲得正確的值來對它們執行計算。儘管基於可用的API方法,它看起來相當平凡,但對源代碼的一瞥揭示了另一個不同的故事。另外一個事實是,有些值只有在組件實際顯示時才能正確計算,這意味着您在此之前嘗試獲得的值並不代表您在屏幕上看到的值(如您發現的那樣)。除此之外,看起來應該可以做你想要做的事情。請記住,在將元素添加到BoxLayout時,預期的行爲是將用於分配佈局管理器的容器的整個空間用於定位子組件。這意味着,當您將JTextPane對象添加到您的JPanel時,它們將伸展,以便它們的總高度佔據您指定的所有600個像素。因此,您需要確定何時已超出可用高度,因爲每個組件的渲染高度可能在進程中發生變化。

與它一點點,罵搖擺反覆玩弄後,我有我雖沒有使用getBounds()(其中BoxLayout使用在代表團的LayoutParameters確定元件高度)想出了一個解決方案,但這種方法我有原來不是很可靠。我會繼續玩弄它,所以希望我能拿出一些可用的代碼,或者別人會提出一個我忽略的解決方案。

編輯:爲了完整起見,這裏的調用doLayout()顯示窗體(仍的BoxLayout的缺點)之前計算所需大小的代碼示例。它不會運行在我的JRE 1.5上,因爲ArrayIndexOutOfBoundsExceptionSizeRequirements中,但是這個bug似乎已經在1.6中被修復了。在1.5中,如果你的組件列表不是太大,你可以將它們全部添加,在循環之後調用doLayout()(因爲無論出於何種原因,這似乎工作在1.5),然後只遍歷getComponents()返回的數組,最大高度已被超過。

作爲最後一點,我個人很喜歡MigLayout用於更復雜的佈局,因爲我發現它的定位和樣式機制比現有的內置佈局管理器更容易使用。這裏不太相關,不過值得一提的是。

import java.awt.Dimension; 
import java.awt.Rectangle; 

import javax.swing.BoxLayout; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTextPane; 
import javax.swing.text.StyledEditorKit; 

public class TestFrame extends JFrame { 
    private static final int CONTENT_HEIGHT = 600; 
    private static final int CONTENT_WIDTH = 300; 

    public static void main(String[] args) { 
     TestFrame frame = new TestFrame(); 

     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 

    public TestFrame() { 
     super("Test Frame"); 
     this.addComponents(); 
     this.pack(); 
    } 

    private void addComponents() { 
     JPanel panel = new JPanel(); 

     panel.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT)); 
     panel.setBounds(new Rectangle(CONTENT_WIDTH, CONTENT_HEIGHT)); 
     panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 

     String text = "This is a long String that represents the length of" + 
      " stings in my application. This will vary in the real" + 
      " application.<ul><li>It uses html</li><li>not just</li>" + 
      "<li>plain text</li></ul>I'd like only as many as will fit" + 
      " in the fame to be added.\n"; 

     this.setContentPane(panel); 

     int height = 0; 

     while(height < CONTENT_HEIGHT) { 
      JTextPane textPane = createTextPane(text); 

      panel.add(textPane); 
      panel.doLayout(); 

      // The height on the preferred size has been set to reflect 
      // the rendered size after calling doLayout() 
      height += textPane.getPreferredSize().getHeight(); 

      // If we've exceeded the height, backtrack and remove the 
      // last text pane that we added 
      if (height > CONTENT_HEIGHT) { 
       panel.remove(textPane); 
      } 
     } 
    } 

    private JTextPane createTextPane(String text) { 
     JTextPane textPane = new JTextPane(); 

     textPane.setEditorKit(new StyledEditorKit()); 
     textPane.setEditable(false); 
     textPane.setOpaque(false); 
     textPane.setContentType("text/html"); 
     textPane.setText(text); 

     return textPane; 
    } 
} 
+0

感謝您對此進行了詳細的瞭解。我不知道BoxLayout的工作方式。我會研究可能會避免此問題的其他佈局管理器。在爲所有組件設置了固定寬度後,可能還有FlowLayout? (讓組件像頁面上的段落一樣流動很重要。)玩弄它並詛咒Swing是我一直在做的大部分工作,很高興我並不孤單。 – nova 2010-08-15 05:04:00

+0

沒問題,這是一個有趣的問題。只要你給容器固定寬度,FlowLayout也可以像你想要的那樣工作。這可能需要使用'setPreferredSize()'完成,儘管在給定其他選項(setSize(),setMaximumSize())的情況下,它看起來有點反直覺。 Swing有很多好意,但最終的實現有時會忽略我感受到的標誌。但是,一旦你習慣了它,它並不是那麼糟糕。 – 2010-08-15 18:13:31

+0

它的工作原理!完美!謝謝!這是一個很好的解決方案來解決我的問題,儘管我會玩弄不同的佈局管理器,至於我的項目,最好的設計應該是將所有文本聚集在頁面頂部,就像表格上的文本一樣儘可能的紙張。 – nova 2010-08-16 05:32:27

1

顯示組件的框架必須是可見的才能獲取大小(因爲如果框架不可見,佈局管理器將大小設置爲(0,0))。在添加組件之前,您必須撥打frame.setVisible(true)。我還建議你製作自己的面板類(它將擴展JPanel)並創建組件,並將它們放在面板上,而不是從主類。

+0

在我的代碼中這樣做使大小按預期設置。謝謝。然而,正如Tim指出的那樣,BoxLayout伸展組件,所以只添加2個textPanel,而不是像框架那樣多。 – nova 2010-08-15 05:46:25

+0

是的,我在閱讀Tim的評論後才意識到這一點。你應該明確地使用另一個佈局管理器。我總是使用GridBagLayout,起初看起來有點複雜,但它從來沒有給我帶來太多麻煩,所以我建議你使用它。 – protector 2010-08-15 07:59:58

相關問題