Как установить размер JFrame, чтобы соответствовать JPanel, отображаемому CardLayout? - PullRequest
6 голосов
/ 26 ноября 2011

У меня есть JFrame, содержащий набор JPanels в CardLayout. Каждый JPanel имеет свой размер, и я хочу, чтобы JFrame адаптировался к размеру отображаемого в данный момент JPanel (не JPanel для адаптации к размеру JFrame).

Как мне этого добиться?

Ответы [ 4 ]

12 голосов
/ 27 ноября 2011

Общее правило: если у вас есть проблема с макетом, всегда решите ее с помощью соответствующего LayoutManager. Никогда не изменяйте подсказку к размеру компонента, чтобы достичь своей цели.

В этом случае особенно легко настроить CardLayout.По умолчанию он рассчитывает свой prefSize до максимального значения prefSize для всех карт.Просто создайте подкласс и реализуйте, чтобы вернуть prefSize (плюс вставки) текущей видимой карты:

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

}

Используя это (пример заимствования @ 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);
}
4 голосов
/ 26 ноября 2011

Вот это SSCCE .

1) Для непрерывного увеличения / уменьшения размера, вы должны поискать некоторые API анимации.

или

2) Если нет фоновой задачи с выводом в графический интерфейс, вы можете сделать паузу при определении размера JFrame.В этом случае вы бы откладывали увеличение / уменьшение, используя Thread#sleep(int), завернутый в поток Runnable.

3) Уведомление (не для OP), использующее Thread#sleep(int) непосредственно во время EDT, будет останавливать GUI до тех пор, показадержка закончилась.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.Border;
//based on HFOE /4701323/izmenit-razmer-jpanel-s-pomoschy-cardlayout#4701335
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();
            }
        });
    }
}
2 голосов
/ 26 ноября 2011

Я думаю, что у вас может быть неправильный менеджер раскладки для того, что вы хотите сделать (оставляя в стороне, на данный момент, я не уверен, что вы хотите делать то, что вы говорите, что хотите сделать).

Я еще не нашел документацию о том, что я подозреваю, что CardLayout изменяет размеры всех своих дочерних элементов до размера своего контейнера.Я нашел следующий комментарий для его метода "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.

Я думаю, что это разумное поведение, так как для пользователя было бы очень неприятно, когда размер панели прыгает вокруг при обходе панелей.

Если это действительно то поведение, которое вам нужно, то я думаю, что вам нужен другой менеджер раскладки.А поскольку для пользовательского интерфейса в целом это необычное поведение, вполне возможно, что вы не найдете стандартного для этой конкретной «функции», поэтому вам, возможно, придется написать свой собственный.

0 голосов
/ 05 февраля 2013
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);
}}
...