返回显示的JComponent的实际大小

时间:2010-08-14 07:08:58

标签: java swing size

晚上好,

我想知道如何在使用LayoutManager布局后获取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;
    }
}

谢谢你的时间!

2 个答案:

答案 0 :(得分:3)

您要完成的任务似乎非常困难,因为您必须依赖Swing计算各种组件大小的方法,然后设法获取正确的值以对其执行计算。虽然基于可用的API方法看起来相当微不足道,但只需浏览一下源代码即可揭示出不同的故事。另外一些事实是,只有在实际显示组件时才能正确计算某些值,这意味着在此之前尝试获取的值不能代表您在屏幕上看到的值(如您所见)。 / p>

除此之外,似乎应该可以做你想要的目标。但请记住,在向BoxLayout添加元素时,预期的行为是,您已为其分配布局管理器的容器的整个空间用于定位子组件。这意味着,当您向JTextPane添加JPanel个对象时,它们会拉伸,以便它们的总高度占据您指定的所有600个像素。因此,您需要确定何时超出可用高度的方式略有不同,因为每个组件的渲染高度可能会在进程中发生变化。

稍微玩了一下并反复咒骂Swing之后,我曾经使用getBounds()BoxLayout使用LayoutParameters委托给doLayout()来解决问题。确定组件高度),但我发现的方法不太可靠。我将继续玩它,所以希望我能提出一些可用的代码,或者其他人会提出我忽略的解决方案。

修改:为了完整起见,这是一个代码示例,在显示表单之前调用BoxLayout来计算必要的大小(仍有ArrayIndexOutOfBoundsException的缺点)。由于SizeRequirements中的某些doLayout(),它不会在我的JRE 1.5上运行,但该错误似乎已在1.6中修复。在1.5中,如果您的组件列表不是太大,您可以将它们全部添加,在循环后调用getComponents()(因为这似乎在1.5中因任何原因而工作),然后只遍历由{返回的数组{1}},在超出最大高度后删除所有内容。

作为最后一点,我个人喜欢使用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;
    }
}

答案 1 :(得分:1)

显示组件的框架必须可见才能获得大小(因为如果框架不可见,布局管理器会将大小设置为(0,0))。在添加组件之前,您必须致电frame.setVisible(true)。我还建议您创建自己的面板类(这将扩展JPanel)并创建组件并将它们放在面板上,而不是从主类。