Как я могу изменить JPanel внутри JFrame на лету?

37

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

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

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

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

Теги:
swing
jpanel
layout-manager
cardlayout

14 ответов

47
Лучший ответ

Ваш прецедент, кажется идеальным для CardLayout.

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

  • 3
    При использовании CardLayout имейте в виду, что предпочтительным размером для панели, которая его использует, будет размер самой БОЛЬШОЙ панели в макете. Если вы хотите, чтобы пространство было освобождено, вам нужно использовать setVisible (false) и setPreferredSize (new Dimension (0,0)), чтобы скрыть компонент.
  • 0
    Я не слышал о CardLayout раньше. Спасибо - идеально подходит для того, что мне нужно было сделать.
Показать ещё 1 комментарий
22

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

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

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

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

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

15
frame.setContentPane(newContents());
frame.revalidate(); // frame.pack() if you want to resize.

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

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

  • 0
    Том, спасибо за твой ответ. Я не собираюсь заменять панель содержимого, просто поместил на нее jpanel (например, frame.add (jpanel1), frame.add (jpanel2), frame.add (jpanel3)). Не могли бы вы предложить разумное решение в коде?
  • 0
    Эй, Джон, Ваш вариант использования кажется идеальным для CardLayout. java.sun.com/docs/books/tutorial/uiswing/layout/card.html В макете карты можно добавить несколько панелей в одном месте, а затем показать или скрыть по одной панели за раз.
Показать ещё 2 комментария
6

Надеюсь, что этот фрагмент кода даст вам представление об изменении 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

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

//вам нужно что-то делать по строкам

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

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

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

3

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

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

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

1

Ответ layout.replace() существует или работает только в диспетчере GroupLayout.

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

1

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

  • Добавление всех компонентов (JPanels) в контейнер;
  • Использование метода setVisible (false) для всех из них;
  • В действии пользователя, установив 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(), no validate(), не требуется CardLayout.

1

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

0

Просто вызовите метод pack() после установки ContentPane, (java 1.7, может быть, старше), например:

JFrame frame = new JFrame();  
JPanel panel1 = new JPanel(); 
JPanel panel2 = new JPanel(); 
....
frame.setContentPane(panel1);
frame.pack();
...

frame.setContentPane(panel2);
frame.pack();
...
0

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

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

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

0
class Frame1 extends javax.swing.JFrame {

    remove(previouspanel); //or getContentPane().removeAll();

    add(newpanel); //or setContentPane(newpanel);

    invalidate(); validate(); // or ((JComponent) getContentPane()).revalidate();

    repaint(); //DO NOT FORGET REPAINT

}

Иногда вы можете выполнять работу без использования повторной аттестации, а иногда и без использования repaint.My советуем использовать оба.

0

Я предлагаю вам добавить обе панели при создании фрейма, а затем изменить видимую панель, вызвав setVisible (true/false) на обоих. При вызове setVisible родитель будет уведомлен и попросит перекрасить себя.

-2

вы можете использовать метод замены макета:

layout.replace(existingComponent, newComponent)

существующие и новые компоненты также могут быть JPanels.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню