设置 JDialog 的最大尺寸?

6
简短版:我需要使用什么技巧才能使JDialog的setMaximumSize()起作用?
完整版:我有一个JDialog(布局管理器:BorderLayout),其中包含一个带有提交按钮的滚动窗格和底部的JPanel。
滚动窗格包含在系统的其他地方动态构建的JPanel。
我想要的是,对话框会根据JPanel自动调整大小,直到达到一定的大小,然后开始增加滚动条。这基本上是默认情况下发生的事情,但最大尺寸似乎是我的显示器大小。
我认为从java.awt.Component继承的.setMaximumSize()方法可以实现这一点,但设置它似乎没有任何效果。
设置首选大小确实有影响-但是然后对话框始终是那个大小,无论如何,这确实不是我想要的。
(如果在滚动窗格上设置最大/首选大小属性,则效果相同。)
我错过了什么非常明显的东西吗?是否存在我不知道的奇怪的JDialog / BorderLayout / MaximumSize交互?

1
“某个大小”是如何确定的?我下面的答案假设它由面板的内容控制。 setMaximunSize(不要,不要,不要!)没有效果的原因是BorderLayout不尊重最大大小提示。 - kleopatra
“某个尺寸”基本上是“足够大,可以容纳所有内容,除非它比屏幕高度的一半还要高。”这也回答了我的另一个问题:我以前从未使用过setMaximumSize()方法,有点惊讶它们不起作用。但是-边界布局。好知道。 (现在我又要忘记它们的存在了。) - Electrons_Ahoy
4个回答

9

设置滚动面板大小中所讨论的那样,一些组件可以提供有关设置视口首选大小的有用信息。 JListsetVisibleRowCount()方法特别方便,但即使是getViewport().setPreferredSize(…)也可能足够。当然,一个SSCCE示例会很有帮助。

附加说明:作为一个具体的示例,下面的对话框最初被调整为具有N-2行。随着添加的内容越来越多,对话框会增长,直到数量达到N。此时,滚动条开始“增长”。该示例使用了一个JList,但任何Scrollable组件都应该是可适应的。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

/** @see https://dev59.com/E1bTa4cB1Zd3GeqP_H2B */
public class ListDialog {

    private static final int N = 12;
    private JDialog dlg = new JDialog();
    private DefaultListModel model = new DefaultListModel();
    private JList list = new JList(model);
    private JScrollPane sp = new JScrollPane(list);
    private int count;

    public ListDialog() {
        JPanel panel = new JPanel();
        panel.add(new JButton(new AbstractAction("Add") {

            @Override
            public void actionPerformed(ActionEvent e) {
                append();
                if (count <= N) {
                    list.setVisibleRowCount(count);
                    dlg.pack();
                }
            }
        }));
        for (int i = 0; i < N - 2; i++) {
            this.append();
        }
        list.setVisibleRowCount(N - 2);
        dlg.add(sp, BorderLayout.CENTER);
        dlg.add(panel, BorderLayout.SOUTH);
        dlg.pack();
        dlg.setLocationRelativeTo(null);
        dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dlg.setVisible(true);
    }

    private void append() {
        model.addElement("String " + String.valueOf(++count));
        list.ensureIndexIsVisible(count - 1);
    }

    public static void main(String[] a_args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ListDialog pd = new ListDialog();
            }
        });
    }
}

这里显示了相应的“删除”按钮 链接 - trashgod

6
使面板可滚动是正确的方法。除了Trashgod提供的教程链接外,还可以参考Rob的博客文章:http://tips4java.wordpress.com/2009/12/20/scrollable-panel/
然后: 1)根据典型内容实现getPreferredScrollableViewportSize()(对于JList来说,这是要显示的首选行数,也就是visibleRowCount) 2)为这些“合理条件”实现setter/getter 这个附加层(协调“合理条件”)使得所有协作组件都能尽力提供强大的大小提示,而不会受到setXXSize(这是一个绝对不能使用的方法,请忘记它们的存在;)的干扰。

AHA!实现可滚动正是解决之道。出于某种原因,我认为setMaximumSize()会像getPreferredScrollableViewportSize()一样起作用。(我为什么会这么想呢?)非常感谢! - Electrons_Ahoy

2

pack() 方法会根据 getPreferredSize() 的调用来确定 JDialog 的大小。

如果您想要限制 JDialog 的最大尺寸,可以通过子类化该方法来实现。

示例:

@Override 
public Dimension getPreferredSize() {    
  int maxWidth=500;    
  int maxHeight=300;    
  Dimension dim=super.getPreferredSize();    
  if (dim.width>maxWidth) dim.width=maxWidth;    
  if (dim.height>maxHeight) dim.height=maxHeight;    
  return dim; 
}

1
你需要计算JScrollPane里面的JComponents的getSize(),这只是一个简单的例子。
编辑:并调用JDialog#pack()函数。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class PackDialog {
    private JDialog dlg;
    private JScrollPane scrollPane;
    private JPanel panel;
    private JButton btn;

    public PackDialog() {
        btn = new JButton();
        btn.setPreferredSize(new Dimension(300, 30));
        btn.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnActionPerformed(evt);
            }

            private void btnActionPerformed(ActionEvent evt) {
                int h = panel.getHeight();
                h += btn.getHeight();
                int w = panel.getWidth();
                dlg.setPreferredSize(new Dimension(w, h));
                dlg.pack();
            }
        });
        panel = new JPanel();
        panel.setPreferredSize(new Dimension(300, 600));
        panel.setLayout(new BorderLayout(10, 10));
        panel.add(btn, BorderLayout.SOUTH);
        scrollPane = new JScrollPane(panel);
        dlg = new JDialog();
        dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dlg.setPreferredSize(new Dimension(400, 300));
        dlg.add(scrollPane);
        dlg.pack();
        dlg.setVisible(true);
    }

    public static void main(String[] a_args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                PackDialog pd = new PackDialog();
            }
        });
    }}

我不是你的投票者,但是我在这个例子中遇到了麻烦。每次按下按钮时,它似乎会缩小对话框。 - trashgod
@trashgod 是的,输出是正确的,也许有点加密,但我仍然认为不可能为BorderLayout.CENTER设置MinSize或MaxSize,否则如果我将JScrollPane放置在另一个位置/地方NOTRH、SOUTH(等等),那么输出就会像从AbsoluteLaoyut一样糟糕。 - mKorbel
如果我要将JScrollPane添加到TopLayoutContainer中,我不需要声明某个LayoutManager,它总是占用BorderLayout.CENTER。然后,对于另一个JComponent(不使用任何LayoutManager),它只有FlowLayout。 - mKorbel
啊,我现在明白了;不知怎么的,我错过了 dlg.pack() - trashgod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接