Проще говоря, есть простое приложение java swing, состоящее из JFrame с некоторыми компонентами в нем. Одним из компонентов является JPanel, который должен быть заменен другим JPanel на действие пользователя.
Итак, какой правильный способ сделать такое? Я пробовал
panel = new CustomJPanelWithComponentsOnIt();
parentFrameJPanelBelongsTo.pack();
но это не сработает. Что бы вы предложили?
Ваш прецедент, кажется идеальным для CardLayout.
В макете карты вы можете добавить несколько панелей в одном и том же месте, но затем показать или скрыть одну панель за раз.
1) Настройка первой панели:
JFrame frame=new JFrame();
frame.getContentPane().add(new JPanel());
2) Замена панели:
frame.getContentPane().removeAll();
frame.getContentPane().add(new JPanel());
Также обратите внимание, что вы должны сделать это в потоке событий, чтобы обеспечить использование SwingUtilities.invokeLater или SwingWorker
frame.setContentPane(newContents());
frame.revalidate(); // frame.pack() if you want to resize.
Помните, что Java использует передачу аргументов 'copy reference by value'. Таким образом, изменение переменной не изменит копии ссылки, переданной другим методам.
Также обратите внимание, что JFrame
очень сбивает с толку имя юзабилити. Добавление компонента или настройка макета (обычно) выполняет операцию на панели содержимого. Как ни странно, получение макета действительно дает вам менеджер компоновки фреймов.
Надеюсь, что этот фрагмент кода даст вам представление об изменении 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);
}
}
В действии пользователя:
//вам нужно что-то делать по строкам
myJFrame.getContentPane().removeAll()
myJFrame.getContentPane().invalidate()
myJFrame.getContentPane().add(newContentPanel)
myJFrame.getContentPane().revalidate()
Затем вы можете изменить размер своего wndow по мере необходимости.
Все зависит от того, как его использовать. Если вам нужно переключаться между этими двумя панелями, используйте CardLayout. Если вы только переключаетесь с первого на второй один раз (и не возвращаетесь назад), я бы использовал telcontar предложение и просто заменил его. Хотя если JPanel не единственная вещь в вашем фрейме, я бы использовал remove(java.awt.Component) вместо removeAll.
Если вы находитесь где-то между этими двумя случаями, это в основном компромисс между временным пространством. CardLayout сэкономит ваше время, но займет больше памяти, если вы будете постоянно держать эту всю панель в памяти. Но если вы просто заменяете панель, когда это необходимо, и создавайте ее по требованию, вам не нужно поддерживать этот круг, но требуется больше времени для переключения.
Также вы можете попробовать использовать JTabbedPane для использования вкладок (это даже проще, чем CardLayout, потому что оно автоматически обрабатывает отображение/скрытие)
Ответ layout.replace() существует или работает только в диспетчере GroupLayout.
Другие LayoutManagers (CardLayout, BoxLayout и т.д.) НЕ поддерживают эту функцию, но требуют сначала RemoveLayoutComponent (а затем AddLayoutComponent (назад снова.:-) [Только установление прямой записи]
У меня была такая же проблема!! Increadible!! Решение, которое я нашел, было:
// 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.
Другие люди ответили на вопрос. Я хочу предложить вам использовать JTabbedPane вместо замены содержимого. Как правило, плохо видеть, что визуальные элементы вашего приложения исчезают или заменяются другим контентом. Конечно, есть исключения для каждого правила, и только вы и ваше сообщество пользователей можете выбрать наилучший подход.
Просто вызовите метод 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();
...
Проблема. Мой компонент не появляется после добавления его в контейнер.
Вам нужно вызвать revalidate и repaint после добавления компонента , прежде чем он отобразит в вашем контейнере.
Источник: http://docs.oracle.com/javase/tutorial/uiswing/layout/problems.html
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 советуем использовать оба.
Я предлагаю вам добавить обе панели при создании фрейма, а затем изменить видимую панель, вызвав setVisible (true/false) на обоих. При вызове setVisible родитель будет уведомлен и попросит перекрасить себя.
вы можете использовать метод замены макета:
layout.replace(existingComponent, newComponent)
существующие и новые компоненты также могут быть JPanels.