简体   繁体   English

如何设置JFrame大小以适合显示JPanel的CardLayout?

[英]How to set a JFrame size to fit the CardLayout displayed JPanel?

I have a JFrame containing a set of JPanels in a CardLayout . 我在CardLayout中有一个包含一组JPanelsJFrame Each JPanel has a different size and I want the JFrame to adapt to the size of the currently displayed JPanel (not the JPanel to adapt to the size of the JFrame ). 每个JPanel都有不同的大小,我希望JFrame适应当前显示的JPanel的大小(而不是JPanel以适应JFrame的大小)。

How can I achieve this? 我怎样才能做到这一点?

The general is: if you have a layout problem, always solve it with an appropriate LayoutManager. 一般是:如果您有布局问题,请始终使用适当的LayoutManager解决它。 Never tweak a component's sizing hint to reach your goal. 永远不要调整组件的大小提示以达到目标。

In this case, it's particularly easy to adjust the CardLayout. 在这种情况下,调整CardLayout特别容易。 By default, it calculates its prefSize to the max of prefSizes of all cards. 默认情况下,它会将prefSize计算为所有卡的prefSizes的最大值。 Simply subclass and implement to return the prefSize (plus insets) of the currently visible card: 只需子类化并实现以返回当前可见卡的prefSize(加上insets):

public static class MyCardLayout extends CardLayout {

    @Override
    public Dimension preferredLayoutSize(Container parent) {

        Component current = findCurrentComponent(parent);
        if (current != null) {
            Insets insets = parent.getInsets();
            Dimension pref = current.getPreferredSize();
            pref.width += insets.left + insets.right;
            pref.height += insets.top + insets.bottom;
            return pref;
        }
        return super.preferredLayoutSize(parent);
    }

    public Component findCurrentComponent(Container parent) {
        for (Component comp : parent.getComponents()) {
            if (comp.isVisible()) {
                return comp;
            }
        }
        return null;
    }

}

Using that (borrowing @mKorbel's example), the main method cleanly shrinks down: 使用它(借用@ mKorbel的例子),主要方法干净利落:

private static void createAndShowUI() {
    final CardLayout cardLayout = new MyCardLayout();
    final JPanel cardHolder = new JPanel(cardLayout);
    final JFrame frame = new JFrame("MultiSizedPanels");
    JLabel[] labels = {
        new JLabel("Small Label", SwingConstants.CENTER),
        new JLabel("Medium Label", SwingConstants.CENTER),
        new JLabel("Large Label", SwingConstants.CENTER)};

    for (int i = 0; i < labels.length; i++) {
        int padding = 50 * (i + 1);
        Border lineBorder = BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(Color.blue),
            BorderFactory.createEmptyBorder(padding, padding, padding, padding));
        labels[i].setBorder(lineBorder);
        JPanel containerPanel = new JPanel();
        containerPanel.add(labels[i]);
        cardHolder.add(containerPanel, String.valueOf(i));
    }
    JButton nextButton = new JButton("Next");
    nextButton.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            cardLayout.next(cardHolder);
            frame.pack();
        }
    });
    JPanel btnHolder = new JPanel();
    btnHolder.add(nextButton);

    frame.add(cardHolder, BorderLayout.CENTER);
    frame.add(btnHolder, BorderLayout.SOUTH);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setLocation(150, 150);
    frame.setVisible(true);
}

Here is the SSCCE . 这是SSCCE

1) For continuous increase/decrease of size, you should look for some animation API. 1)为了连续增加/减少大小,你应该寻找一些动画API。

or 要么

2) If isn't there any background task with output to the GUI, you can to pause while sizing the JFrame . 2)如果没有任何后台任务输出到GUI,您可以在调整JFrame大小时暂停。 In that case, you would delay the increase/decrease by using Thread#sleep(int) wrapped into Runnable thread. 在这种情况下,您可以通过使用包装到Runnable线程中的Thread#sleep(int)来延迟增加/减少。

3) Notice (not for OP) using Thread#sleep(int) directly during EDT would be freeze GUI until the delay ended. 3)在EDT期间直接使用Thread#sleep(int) )的注意事项(不适用于OP)将冻结GUI直到延迟结束。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.Border;
//based on HFOE http://stackoverflow.com/questions/5414177/change-size-of-jpanel-using-cardlayout/5414770#5414770
public class MultiSizedPanels {

    private static void createAndShowUI() {
        final CardLayout cardLayout = new CardLayout();
        final JPanel cardHolder = new JPanel(cardLayout);
        final JFrame frame = new JFrame("MultiSizedPanels");
        JLabel[] labels = {
            new JLabel("Small Label", SwingConstants.CENTER),
            new JLabel("Medium Label", SwingConstants.CENTER),
            new JLabel("Large Label", SwingConstants.CENTER)};

        for (int i = 0; i < labels.length; i++) {
            int padding = 50;
            Dimension size = labels[i].getPreferredSize();
            size = new Dimension(size.width + 2 * (i + 1) * padding, size.height + 2 * (i + 1) * padding);
            labels[i].setPreferredSize(size);
            Border lineBorder = BorderFactory.createLineBorder(Color.blue);
            labels[i].setBorder(lineBorder);
            JPanel containerPanel = new JPanel();
            if (i == 1) {
                containerPanel.setPreferredSize(new Dimension(300, 200));
                containerPanel.add(labels[i], BorderLayout.CENTER);
                cardHolder.add(containerPanel, String.valueOf(i));
            } else if (i == 2) {
                containerPanel.setPreferredSize(new Dimension(600, 400));
                containerPanel.add(labels[i], BorderLayout.CENTER);
                cardHolder.add(containerPanel, String.valueOf(i));
            } else {
                containerPanel.setPreferredSize(new Dimension(800, 600));
                containerPanel.add(labels[i], BorderLayout.CENTER);
                cardHolder.add(containerPanel, String.valueOf(i));
            }
        }
        JButton nextButton = new JButton("Next");
        nextButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                cardLayout.next(cardHolder);
                Dimension dim = new Dimension();
                for (Component comp : cardHolder.getComponents()) {
                    if (comp.isVisible() == true) {
                        dim = comp.getPreferredSize();
                    }
                }
                frame.setPreferredSize(dim);
                java.awt.EventQueue.invokeLater(new Runnable() {

                    public void run() {
                        frame.pack();
                    }
                });
            }
        });
        JPanel btnHolder = new JPanel();
        btnHolder.add(nextButton);

        frame.add(cardHolder, BorderLayout.CENTER);
        frame.add(btnHolder, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocation(150, 150);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                createAndShowUI();
            }
        });
    }
}

I think you may have the wrong layout manager for what you want to do (leaving aside, for the moment, that I am not sure you want to do what you say you want to do). 我想你可能有一个错误的布局经理你想做什么(暂时搁置,暂时,我不确定你想做你说你想做的事)。

I have not yet found documentation on what I suspect, which is that CardLayout resizes all of its children to the size of its container. 我还没有找到我怀疑的文档,也就是CardLayout将其所有子节点调整到其容器的大小。 I did find the following comment for its "layoutContainer" method: 我确实为其“layoutContainer”方法找到了以下注释:

         * Each component in the <code>parent</code> container is reshaped
         * to be the size of the container, minus space for surrounding
         * insets, horizontal gaps, and vertical gaps.

I think this is reasonable behavior, since it would be very annoying for a user to have the panel size jump around as panels are traversed. 我认为这是合理的行为,因为当遍历面板时,用户让面板大小跳跃会非常烦人。

If this is really the behavior you want, then I think you want a different layout manager. 如果这确实是你想要的行为,那么我认为你想要一个不同的布局管理器。 And since it is unusual behavior for a UI in general, you may well not find a standard one to do this particular 'feature', so you may have to write your own. 而且由于一般来说UI是不寻常的行为,你很可能找不到一个标准的来执行这个特定的“功能”,所以你可能必须自己编写。

Try this code this may help you.




protected void paintComponent(Graphics g) {
if (getModel().isArmed()) {
      g.setColor(Color.lightGray);
} else {
     g.setColor(getBackground());
}
g.fillOval(0, 0, getSize().width-1, getSize().height-1);
System.out.println("width is "+getSize().width+"height is "+getSize().height);
super.paintComponent(g);
}
protected void paintBorder(Graphics g) {
g.setColor(getForeground());
g.drawOval(0, 0, getSize().width-1, getSize().height-1);
}
Shape shape;
public boolean contains(int x, int y) {
if (shape == null || !shape.getBounds().equals(getBounds())) {
     shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight());
}
return shape.contains(x, y);
}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM