【问题标题】:Forcing minimum JPanel size强制最小 JPanel 大小
【发布时间】:2017-05-12 14:34:49
【问题描述】:

我正在尝试使用 Java Swing 为小型电话簿应用程序编写布局。我遇到了无法修复的尺寸问题。我希望过滤器(显示在搜索结果下)足够宽以在搜索短语很短时显示整个标题。这是它的样子:

如您所见,名称已缩短。姓氏带有较长的文本,并按我的意愿显示。

过滤器类:

import javax.swing.*;
import javax.swing.border.CompoundBorder;
import java.awt.*;

public class Filter
{
    private JLabel label;
    private JPanel filterPane;

    Filter(String name)
    {
        // Filter text
        label = new JLabel();
        label.setForeground(new Color(0xAA0000));

        // Closing button
        JButton closeButton = new JButton("X");
        closeButton.setFont(new Font("Dialog", Font.BOLD, 20));
        closeButton.setMargin(new Insets(0, 0, 0, 0));

        filterPane = new JPanel();
        filterPane.setLayout(new BoxLayout(filterPane, BoxLayout.X_AXIS));
        // Frame with title + 50px padding on the right side for the next filter
        filterPane.setBorder(new CompoundBorder(
                BorderFactory.createEmptyBorder(0, 0, 0, 50),
                BorderFactory.createTitledBorder(name)));
        filterPane.add(closeButton);
        filterPane.add(Box.createRigidArea(new Dimension(5, 0)));
        filterPane.add(label);
        filterPane.setVisible(false);
    }

    public void setValue(String value) {
        if (value == null || value.isEmpty())
            filterPane.setVisible(false);
        else
        {
            this.label.setText(value);
            filterPane.setVisible(true);
        }
    }

    public JPanel getFilterPane() {
        return filterPane;
    }
}

主类:

import javax.swing.*;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;

public class TestWindow
{
    private static void init()
    {
        JFrame frame = new JFrame("Stackoverflow test window");
        frame.setSize(new Dimension(480, 320));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        // Main panel - 20 px padding from each side
        JPanel pane = new JPanel();
        pane.setLayout(new BorderLayout());
        pane.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

        // Create panel for filters
        JPanel filterPane = new JPanel();
        filterPane.setLayout(new BoxLayout(filterPane, BoxLayout.X_AXIS));
        filterPane.setPreferredSize(new Dimension(0, 60));

        // Add sample filters
        Filter filter = new Filter("name");
        filter.setValue("i");
        filter.getFilterPane().setAlignmentY(Component.BOTTOM_ALIGNMENT);
        filterPane.add(filter.getFilterPane());

        filter = new Filter("surname");
        filter.setValue("loooooong text");
        filter.getFilterPane().setAlignmentY(Component.BOTTOM_ALIGNMENT);
        filterPane.add(filter.getFilterPane());

        // Add everything to main panel
        pane.add(new JTextArea("Nothing fancy here, just to fill out space"), BorderLayout.CENTER);
        pane.add(filterPane, BorderLayout.SOUTH);
        frame.setContentPane(pane);
        frame.setVisible(true);
    }

    public static void main (String [] args) throws InterruptedException, InvocationTargetException {
        SwingUtilities.invokeLater(TestWindow::init);
    }
}

我在 Filter 构造函数中为labelfilterPane 尝试了setMinimumSizesetPreferredSize,但它没有帮助。你能帮帮我吗?

【问题讨论】:

  • 如何将窗格添加到父窗口?你用的是什么布局?请edit问题并添加适用的代码。
  • 谢谢,你是对的。完成。
  • 覆盖类的getXxxSize,而不是设置大小。发布minimal reproducible example
  • JComponent.setMinimumSize,试过了吗?
  • 是的,filterPane 和 label 都适用。没用。 @user1803551 你的意思是应用这些规则重写我的问题?

标签: java swing


【解决方案1】:

这个问题实际上是由两个问题组成的。

  1. 使用TitledBorder 时,组件在计算其首选大小时不会考虑标题的大小。
  2. 使用BoxLayout 时,首选宽度将被忽略,除非您在组件后添加“水平粘合”。

所以,要解决第一个问题,你需要重写 JPanel 的getPreferredSize() 方法。但要实现这一点,您还需要通过添加胶水来绕过第二个问题。

要覆盖getPreferredSize(),您可以使用类似:

class MinSizePanel extends JPanel {

    public Dimension getPreferredSize() {
        Dimension original = super.getPreferredSize();
        TitledBorder titleBorder = (TitledBorder)((CompoundBorder)getBorder()).getInsideBorder();
        int width = (int)Math.max( original.getWidth(), 60 + (int)titleBorder.getMinimumSize(this).getWidth());
        return new Dimension( width, (int)original.getHeight() );
    }
}

这会从CompoundBorder 获取TitledBorder,获取它的最小尺寸(这是一种考虑标题宽度的方法),为空边框和插图添加一些额外内容(您可以添加适当的计算,我做了一个快捷方式,只是使用了60...),然后使用它(如果它超过了组件的原样宽度)。

代替

filterPane = new JPanel();

使用

filterPane = new MinSizePanel();

(您真的应该将面板的所有其余构造也移到该类中)。

TestWindow 类中,在最后一个之后

    filterPane.add(filter.getFilterPane());

同时添加

    filterPane.add(Box.createHorizontalGlue());

【讨论】:

  • 非常感谢,它解决了这个问题。所以BoxLayout 会忽略它绑定到的容器的首选宽度,除非也有胶水?
  • @PKua 它忽略了组件的首选宽度,而不是容器的首选宽度。我认为它试图使布局紧凑,就像向左对齐的一行文本。添加胶水会导致它计算不同的最大宽度并更改其策略。可能还有其他方法可以达到相同的效果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-10
相关资源
最近更新 更多