返回 JComponent 的实际大小,如显示的那样

发布于 2024-09-14 11:24:45 字数 2239 浏览 4 评论 0原文

晚上好,

我想知道如何在使用 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;
    }
}

感谢您抽出时间!

Good evening,

I'd like to know how to get the size of a JComponent after it's been laid out with a LayoutManager. I've read that this is possible, if you just call dolayout(), validate(), or setVisible() beforehand. However, I can't get it to work in my code.

The reason I'd like to know this is to only add as many components as will fit in the frame's set size, while not knowing the size of the components beforehand. Calling validate() doesn't set the size of the components in this code sample. Any ideas on how I can get the right size?

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;
    }
}

Thanks for your time!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

感性不性感 2024-09-21 11:24:45

您想要完成的任务似乎出奇地困难,因为您必须依赖 Swing 的方法来计算各个组件的大小,然后设法获取正确的值来对它们执行计算。虽然根据可用的 API 方法,它看起来相当微不足道,但浏览一下源代码就会发现不同的情况。由于某些值仅在组件实际显示时才能正确计算,这意味着您在此之前尝试获取的值并不代表您在屏幕上看到的内容(正如您所发现的),这一事实使情况变得更加复杂。

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

经过一番尝试并反复咒骂 Swing 后,我虽然已经通过使用 getBounds() 提出了一个解决方案(BoxLayout 用于委托其 getBounds())。 code>LayoutParameters 来确定组件高度),但事实证明我的方法不是很可靠。我将继续尝试它,所以希望我能提出一些可用的代码,或者其他人会提出我忽略的解决方案。

编辑:为了完整起见,这里有一个代码示例,它调用 doLayout() 在显示表单之前计算必要的尺寸(仍然存在 BoxLayout 的缺点>)。由于 SizeRequirements 中的一些 ArrayIndexOutOfBoundsException,它无法在我的 JRE 1.5 上运行,但该错误似乎已在 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;
    }
}

What you're trying to accomplish seems to be surprisingly difficult, because you have to rely on Swing's method of calculating the size of your various components, and then manage to get the correct values out to perform the calculations on them. While it looks fairly trivial based on the available API methods, a glance at the source code reveals a different story. This is additionally complicated by the fact that some values are only correctly calculated when the component is actually displayed, meaning that the values you try to get before that aren't representative of what you see on the screen (as you found out).

That aside, it seems like it should be possible to do what you're aiming for. Keep in mind though that when adding elements to a BoxLayout, the expected behaviour is that the entire space of the container to which you've assigned the layout manager is utilized in positioning the child components. This means that as you add JTextPane objects to your JPanel, they will stretch so that their summed heights takes up all 600 pixels you've specified. As a result, you need to go about determining when you've exceeded the available height a little differently, since the rendered height of each component might change in-process.

After playing around with it a little and cursing Swing repeatedly, I had though I had come up with a solution by using getBounds() (which BoxLayout uses in delegation to its LayoutParameters to determine the component height), but the method I had turned out to not be very reliable. I'm going to keep playing around with it, so hopefully I'll come up with some usable code, or someone else will come along with a solution that I've overlooked.

Edit: For completeness, here's a code sample that calls doLayout() to calculate the necessary sizes before showing the form (still with the drawbacks of BoxLayout). It won't run on my JRE 1.5 due to some ArrayIndexOutOfBoundsException in SizeRequirements, but that bug seems to have been fixed in 1.6. In 1.5, if your list of components wasn't too large, you could add them all, call doLayout() after the loop (as this seems to work in 1.5 for whatever reason), then just traverse the array returned by getComponents(), removing everything after the maximum height has been exceeded.

As a final note, I'm personally a fan of using MigLayout for more complex layouts, since I find its positioning and styling mechanism a bit easier to work with than the current built-in layout managers. Not overly relevant here, but worth a mention anyway.

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;
    }
}
自由如风 2024-09-21 11:24:45

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

The frame on which the components are displayed must be visible in order to get the size (because if the frame is not visible, layout manager sets the size to (0, 0)). You must call frame.setVisible(true) before adding the components. I also recommend that you make your own panel class (which would extend JPanel) and to create components and put them on panel from there, not from the main class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文