Как я могу изменить JPanel внутри JFrame на лету? - PullRequest
39 голосов
/ 20 октября 2008

Проще говоря, есть простое Java-приложение, которое состоит из JFrame с некоторыми компонентами. Одним из компонентов является JPanel, который должен быть заменен другим JPanel при действии пользователя.

Итак, как правильно делать такие вещи? Я пробовал

panel = new CustomJPanelWithComponentsOnIt();
parentFrameJPanelBelongsTo.pack();

но это не сработает. Что бы вы предложили?

Ответы [ 14 ]

49 голосов
/ 20 октября 2008

Ваш вариант использования, кажется, идеально подходит для CardLayout .

В макете карты вы можете добавить несколько панелей в одном месте, а затем показать или скрыть, по одной панели за раз.

24 голосов
/ 20 октября 2008

1) Настройка первой панели:

JFrame frame=new JFrame();
frame.getContentPane().add(new JPanel());

2) Замена панели:

frame.getContentPane().removeAll();
frame.getContentPane().add(new JPanel());

Также обратите внимание, что вы должны сделать это в ветке события, чтобы обеспечить использование SwingUtilities.invokeLater или SwingWorker

17 голосов
/ 20 октября 2008
frame.setContentPane(newContents());
frame.revalidate(); // frame.pack() if you want to resize.

Помните, Java использует передачу аргументов 'copy reference by value'. Таким образом, изменение переменной не приведет к изменению копий ссылки, передаваемой другим методам.

Также обратите внимание, JFrame очень запутанно во имя юзабилити. Добавление компонента или настройка макета (обычно) выполняет операцию на панели содержимого. Как ни странно, получение макета действительно дает вам менеджер компоновки фрейма.

6 голосов
/ 22 мая 2009

Надеюсь, этот фрагмент кода даст вам представление об изменении jPanels внутри JFrame.

public class PanelTest extends JFrame {

        Container contentPane;

        public PanelTest()  {
           super("Changing JPanel inside a JFrame");
           contentPane=getContentPane();
        }

        public void createChangePanel() {
           contentPane.removeAll();
           JPanel newPanel=new JPanel();
           contentPane.add(newPanel);
           System.out.println("new panel created");//for debugging purposes
           validate();
           setVisible(true);
        }
}
5 голосов
/ 21 октября 2008

На действие пользователя:

// вы должны сделать что-то вроде

myJFrame.getContentPane().removeAll()
myJFrame.getContentPane().invalidate()

myJFrame.getContentPane().add(newContentPanel)
myJFrame.getContentPane().revalidate()

Затем вы можете изменить размер окна по мере необходимости.

3 голосов
/ 20 октября 2008

Все зависит от того, как его собираются использовать. Если вы хотите переключаться между этими двумя панелями, используйте CardLayout. Если вы переходите от первого ко второму только один раз и (и не возвращаетесь), я бы использовал предложение telcontar и просто заменил его. Хотя, если JPanel не единственная вещь в вашем кадре, я бы использовал remove (java.awt.Component) вместо removeAll.

Если вы находитесь где-то посередине между этими двумя случаями, это в основном компромисс между временем и пространством. CardLayout сэкономит ваше время, но потребует больше памяти, так как необходимо постоянно сохранять в памяти всю эту другую панель. Но если вы просто заменяете панель, когда это необходимо, и строите ее по требованию, вам не нужно держать это в порядке, а переключение занимает больше времени.

Также вы можете попробовать JTabbedPane вместо этого использовать вкладки (это даже проще, чем CardLayout, потому что он обрабатывает отображение / скрытие автоматически)

1 голос
/ 11 сентября 2015

Ответ layout.replace () существует только / работает в GroupLayout Manager.

Другие LayoutManager (CardLayout, BoxLayout и т. Д.) НЕ поддерживают эту функцию, но требуют от вас сначала RemoveLayoutComponent (а затем AddLayoutComponent (обратно. :-) [Просто установить запись прямо] *

1 голос
/ 23 апреля 2012

Проблема : Мой компонент не отображается после добавления его в контейнер.

Вам необходимо вызвать revalidate и repaint после добавления компонента до того, как он отобразится в вашем контейнере.

Источник: http://docs.oracle.com/javase/tutorial/uiswing/layout/problems.html

1 голос
/ 20 мая 2011

У меня была точно такая же проблема !! Increadible !! Решение, которое я нашел, было:

  1. Добавление всех компонентов (JPanels) в контейнер;
  2. Использование метода setVisible (false) для всех из них;
  3. При действии пользователя установите setVisible (true) для панели, которую я хотел показать.
// Hiding all components (JPanels) added to a container (ex: another JPanel)
for (Component component : this.container.getComponents()) {
      component.setVisible(false);
}
// Showing only the selected JPanel, the one user wants to see
panel.setVisible(true);

Нет revalidate (), нет validate (), не требуется CardLayout.

1 голос
/ 20 октября 2008

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

...