1

如果在组件上使用 setPreferredSize(),它会固定宽度和高度。因此,如果我只想要一个固定的宽度,并根据需要调整高度以将内容容纳到该受限制的宽度中,这并不好。

考虑一段 HTML 文本。在浏览器窗口中,字符串将自动换行,并且它需要调整高度,使其适合可用宽度。因此,如果我们要固定浏览器的宽度,文本的高度将保持不变。

用一个组件也能达到同样的效果吗?具体来说,一个JPanel。

请注意,我相信 setMaximumSize() 会做我想做的事 - 允许我设置最大宽度,并将高度设置为很大,这样它就不会比我指定的更宽,但有足够的高度可以增长。但是,系统似乎完全忽略了该功能。例如:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JViewport;

public class TMSApp
{
    public static void main(String[] args)
    {
        JFrame frame = new JFrame("TestMaximumSize"); 
        Container container = frame.getContentPane(); 
        container.setBackground(Color.RED); 

        container.setLayout(new BorderLayout() ); 

        JViewport viewport = new JViewport(); 
        viewport.setBackground(Color.BLACK); 
        viewport.setPreferredSize(new Dimension(640, 480) ); 
        container.add(viewport, BorderLayout.CENTER); 

        JPanel testPanel = new JPanel(); 
        testPanel.setBackground(Color.WHITE); 
        testPanel.setMaximumSize(new Dimension(100, 9999) ); 
        //testPanel.setPreferredSize(new Dimension(100, 9999) ); 

        viewport.setView(testPanel); 

        testPanel.setLayout(new BoxLayout(testPanel, BoxLayout.Y_AXIS) ); 

        testPanel.add(new JLabel("<html>This is a very long HTML label " 
                                    + "that should adapt to the width of " 
                                    + "the parent container by wrapping text, " 
                                    + "just as it would in a web page " 
                                    + "constrained to the window width.</html>") ); 

        frame.setVisible(true); 
        frame.pack(); 

    }

}

如果您运行此应用程序,尽管我说“不超过 100”,但 testPanel 会尽可能宽,将标签留在一行上。对我来说,这违反了 setMaximumSize() 的约定。

(请注意,如果您使用 setPreferredSize(),它确实会正确约束它 - 但我们不能在上面提到的组件上使用 setPreferredSize(),因为它还固定高度而不是赋予它一些流动性 - 是的,setMaximumSize() 会最终限制了高度,但这是可以接受的)。

知道如何控制宽度但让高度根据需要进行调整吗?

(作为记录,我想将一堆面板添加到包裹在 JScrollPane 中的更大面板中,从而充当带有面板而不是标签的列表。我考虑必须横向滚动大面板才能看到所有项目一个糟糕的用户界面,所以我希望宽度不比滚动窗格的实际可显示区域宽,没有滚动条,因此让较小的面板调整它们的高度以适应它们的内容 - 带有 HTML 字符串的 JLabels - 到可用宽度。因此,用户只需垂直滚动即可查看所有项目。如上所示,即使手动使用视口+滚动条也会遇到同样的问题。

如果我只能固定较大面板的宽度,则较小的子面板将自动受宽度约束;或者,如果我只能固定子面板的宽度,那么较大的面板永远不会比我想要的更宽。)

4

1 回答 1

1

我添加了对 SwingUtilities 的调用,以确保您的 Swing 组件位于事件调度线程上。

我让你的 GUI 工作了,但你需要注意 testPanel 的高度。如果您可以只设置首选宽度或首选高度而无需同时设置两者,则 Swing 会更好。

这是我的代码版本。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;

public class TMSApp implements Runnable {

    @Override
    public void run() {
        JFrame frame = new JFrame("TestMaximumSize");
        Container container = frame.getContentPane();
        container.setBackground(Color.RED);
        container.setLayout(new BorderLayout());

        JPanel testPanel = new JPanel();
        testPanel.setBackground(Color.WHITE);
        testPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        testPanel.setPreferredSize(new Dimension(250, 9999));
        testPanel.setLayout(new BoxLayout(testPanel, BoxLayout.Y_AXIS));
        testPanel.add(new JLabel("<html>This is a very long HTML label "
                + "that should adapt to the width of "
                + "the parent container by wrapping text, "
                + "just as it would in a web page "
                + "constrained to the window width.</html>"));

        JScrollPane scrollPane = new JScrollPane(testPanel);
        scrollPane.setHorizontalScrollBarPolicy(
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.getViewport().setPreferredSize(new Dimension(250, 400));

        container.add(scrollPane, BorderLayout.CENTER);

        frame.pack();
        frame.setVisible(true);

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TMSApp());
    }

}
于 2012-12-28T16:33:26.260 回答