I am working on a Java Swing desktop application project. The application has about 15 GUI pages. I can use Layered Panes and Tabbed Panes to put all the GUI components in one class. But that class will be huge. It would be idea if I can divide the project into several smaller sub-projects and let each have one or a few GUI pages. I can work on each sub-project individually and integrate them back into one application when all sub-projects are finished. My question is that how I can integrate all GUI pages from different classes so I can navigate back and force among different pages on button clicks? Since the sub-projects contain GUI pages each needs to have a JFrame. How I can switch back and force between JFrame 1 to JFrame 2 and make one visible and the other invisible? This question shows how to create new JFrames. But did not show how switch back and forth among the JFrames.
-
2You really shouldn't be flinging a bunch of JFrames at the poor user. Why not simply use a CardLayout to swap views? – Hovercraft Full Of Eels Aug 03 '12 at 19:47
-
@Hovercraft Why multiple JFrames GUI is bad? What are the negative impacts it has on the program ? – David Aug 06 '12 at 04:00
4 Answers
... The application has about 15 GUI pages. I can use Layered Panes and Tabbed Panes to put all the GUI components in one class. But that class will be huge.
Not necessarily. The GUI could be quite simple, and could have a method that would allow other classes to add a page, say something called registerPage(...)
:
public void registerPage(JComponent page, String name) {
pageHolder.add(page, name);
nameComboModel.addElement(name);
}
Then give the class methods to allow one to go to the next or previous page or to a random page. For example a class as small as this could work:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class LotsOfPagesPanel extends JPanel {
private CardLayout cardlayout = new CardLayout();
private JPanel pageHolder = new JPanel(cardlayout);
private DefaultComboBoxModel<String> nameComboModel = new DefaultComboBoxModel<String>();
private JComboBox<String> nameCombo = new JComboBox<String>(nameComboModel);
public LotsOfPagesPanel() {
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0));
btnPanel.add(new JButton(new PrevAction(this, "Previous", KeyEvent.VK_P)));
btnPanel.add(new JButton(new NextAction(this, "Next", KeyEvent.VK_N)));
JPanel bottomPanel = new JPanel();
bottomPanel.add(btnPanel);
bottomPanel.add(nameCombo);
nameCombo.addActionListener(new NameComboListener());
pageHolder.setBorder(BorderFactory.createEtchedBorder());
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
setLayout(new BorderLayout(5, 5));
add(pageHolder, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
public void previousPage() {
cardlayout.previous(pageHolder);
}
public void nextPage() {
cardlayout.next(pageHolder);
}
public void show(String name) {
cardlayout.show(pageHolder, name);
}
public void registerPage(JComponent page, String name) {
pageHolder.add(page, name);
nameComboModel.addElement(name);
}
private class NameComboListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String selection = nameCombo.getSelectedItem().toString();
show(selection);
}
}
}
All this class really does is act as a repository for your "pages" and has the logic to allow flipping through pages either contiguously or randomly, and not much else, but that's all it really needs to do, and by limiting it so, we limit the class's size. If other functionality is needed, create other classes for these
... such as our Action classes including the PrevAction class:
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
public class PrevAction extends AbstractAction {
private LotsOfPagesPanel lotsOfPages;
public PrevAction(LotsOfPagesPanel lotsOfPages, String name, Integer keyCode) {
super(name);
this.lotsOfPages = lotsOfPages;
putValue(MNEMONIC_KEY, keyCode);
}
@Override
public void actionPerformed(ActionEvent e) {
lotsOfPages.previousPage();
}
}
and NextAction.java
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
public class NextAction extends AbstractAction {
private LotsOfPagesPanel lotsOfPages;
public NextAction(LotsOfPagesPanel lotsOfPages, String name, Integer keyCode) {
super(name);
this.lotsOfPages = lotsOfPages;
putValue(MNEMONIC_KEY, keyCode);
}
@Override
public void actionPerformed(ActionEvent e) {
lotsOfPages.nextPage();
}
}
And you would need to have a main method of course:
import java.awt.Color;
import java.awt.Dimension;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class LotsOfPagesMain {
private static final String[] LABELS = { "One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve",
"Thirteen", "Fourteen", "Fifteen" };
private static final Dimension LABEL_SIZE = new Dimension(400, 300);
private static void createAndShowGui() {
LotsOfPagesPanel lotsOfPages = new LotsOfPagesPanel();
Random random = new Random();
// I'm using JLabels as a simple substitute for your complex JPanel GUI "pages"
for (String labelText : LABELS) {
JLabel label = new JLabel(labelText, SwingConstants.CENTER);
label.setPreferredSize(LABEL_SIZE);
label.setOpaque(true);
label.setBackground(new Color(random.nextInt(170) + 85, random
.nextInt(170) + 85, random.nextInt(170) + 85));
lotsOfPages.registerPage(label, labelText);
}
JFrame frame = new JFrame("LotsOfPages");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(lotsOfPages);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
But it wouldn't be a huge class by any means, and you wouldn't have to worry about flipping multiple JFrames at the user.

- 283,665
- 25
- 256
- 373
Your idea of a centralised controller isn't a bad one.
Personally, my first thoughts would be to try a group these separate pages into domain groups (or groups of responsibility). This would give me my first level of control. I'd decide how I would like these domains to be used by the user.
Once you have that working, you can move to the next level, which groups work with each other (if any) & how would you like the user to interact with these
And so forth.
I agree with HovercraftFullOfEels, you don't want to throw lots of windows at users, this just frustrates them, you also don't want them to have to flick between related pages, where the information on one is useful on another.
You might find that you end up with a combination of both. That is, you might need to provide the user with the flexibility to open some pages in frames. This would allow them the ability to decide what information they always need & what information they can flip through.
IMHO

- 343,457
- 22
- 230
- 366
You have a couple of options:
- You can hide the old JFrame with setVisible(false)
- You can get rid of the old JFrame with dispose()
You can get some more information on these methods and how they should be called here: http://docs.oracle.com/javase/6/docs/api/javax/swing/JFrame.html
Hope this helps!

- 1,425
- 4
- 21
- 37
-
Why have him flip JFrames when the user is much better off swapping views on a single JFrame? CardLayout is the way to go for this problem. Sometimes the best answer is not to solve what the original poster is requesting but rather to give them a better solution for their program's behavior. – Hovercraft Full Of Eels Aug 03 '12 at 20:41
The method I use to do that is to make pages as panels and make these panels static and add the panel that I want to my frame and delete the previous panel here is the function that I use :
public static void add(JPanel panelYouWantToAdd, JPanel prevPanelToRemove) {
prevPanelToRemove.setVisible(false);
panelYouWantToAdd.setVisible(true);
appFrame.add(panelYouWantToAdd);
appFrame.getContentPane().remove(prevPanelToRemove);
appFrame.getContentPane().invalidate();
appFrame.getContentPane().validate();
}
using this method you should just send the panel you want to use and the previous panel that is already on the frame

- 121
- 1
- 5