Reputation: 5
I am learning Java and I have to develop an application using a GUI. I have the application working in command line already, but the GUI is driving me insane and costing me in lost hours of head banging and research which is leading nowhere. Can you please help me get the basics working so that i can develop further from there. I want to have a single frame application that can switch between frames on a button click. I created a frame and added three panels P1-P3. These are set as Card Layout (from what i read from forums). Then I added additional panels to these to which i have set colour and buttons.
'''
public class MyMainForm extends JFrame{
private JPanel P1;
private JPanel P2;
private JPanel P3;
private JButton btnFrame1;
private JButton btnFrame2;
private JButton button1;
private JTextField thisIsPanel3TextField;
private JButton btn2Frame1;
private final JFrame frame = new JFrame("MyMain Frame");
public MyMainForm() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(P1);
pack();
setSize(1000,800);
//setLocation(null);
btnFrame1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
P1.setVisible(false);
setContentPane(new MyMainForm().P2);
}
});
btnFrame2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
P2.setVisible(false);
setContentPane(new MyMainForm().P3);
}
});
button1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
P3.setVisible(false);
setContentPane(new MyMainForm().P2);
}
});
btn2Frame1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
P1.setVisible(false);
setContentPane(new MyMainForm().P3);
}
});
}
public static void main(String[] args) {
MyMainForm MyMainForm = new MyMainForm();
MyMainForm.setVisible(true);
}
}
''' I can display P2 or P3 with this new code example above. When i try to go from P2 or P3 back to P1 the content pane doesn't show? Do i need to revalidate the content pane for this to work? I really need to be able to go from P1 to P2
Upvotes: 0
Views: 2384
Reputation: 148
CardLayout
is a good quick option, but could get hard to maintain when more business logic and many screens are introduced.
A more versatile/maintainable solution to switch between panels in a swing app would be to use the State design pattern. This will allow you to have one JFrame as the "Context" and the different panels can be configured by switching between various "State" implementations. The result is more versatile control over the entire app using the various states, and additionally you will end up with cleaner code and separation of concerns.
Here's a simple example using a Dashboard that can have different states:
First we will make a Dashboard class which serves as our main app containing the frames/panels we want to change when clicking buttons.
Dashboard.java
public class Dashboard {
private JFrame mainFrame;
private JPanel mainPanel;
private JButton changeStateButton("Click me");
// Initialize the DashboardState as NullState to avoid NPE
private DashboardState state = new NullDashboardState();
public Dashboard() {
// Configure all your buttons to change state to the desired state
changeStateButton.addActionListener(event -> {
changeState(new ExampleDashboardState(this)));
});
}
private void changeState(DashboardState state) {
this.state.clear();
this.state = state;
this.state.render();
}
// Use these accessors to make modifications from the state class
public JFrame getMainFrame() {
return mainFrame;
}
public JPanel getMainPanel() {
return mainPanel;
}
}
Next, define a simple State interface.
DashboardState.java
public interface DashboardState {
// Render the dashboard state
void render();
// Clear the dashboard state to make room for the next state
void clear();
}
Next, define implementations of your DashboardState
interface.
ExampleDashboardState.java
public class ExampleDashboardState implements DashboardState {
private Dashboard dashboard;
private JPanel dashboardPanel;
public DashboardState(Dashboard dashboard) {
this.dashboard = dashboard;
}
public void render() {
dashboardPanel = dashboard.getMainPanel();
// Do stuff with dashboardPanel
dashboardPanel.revalidate();
dashboardPanel.repaint();
}
public void clear() {
dashboardPanel.removeAll()
// Any other cleanup code runs here
}
}
Finally, create a Null implementation of your DashboardState
interface.
NullDashboardState.java
public class NullDashboardState implements DashboardState {
public void render() {
// Do nothing
}
public void clear() {
// Do nothing
}
}
Upvotes: 0
Reputation: 6168
The easiest way to do this is to use a CardLayout
. Just follow this example:
JFrame frame = new JFrame();
JPanel p1 = new JPanel();
p1.setBackground(Color.RED);
JPanel p2 = new JPanel();
p2.setBackground(Color.WHITE);
JPanel p3 = new JPanel();
p3.setBackground(Color.BLUE);
//Create the panel that contains the "cards".
JPanel cards = new JPanel(new CardLayout());
cards.add(p1, "Panel 1");
cards.add(p2, "Panel 2");
cards.add(p3, "Panel 3");
// Add your card container to the frame
Container pane = frame.getContentPane();
pane.add(cards, BorderLayout.CENTER);
JButton btn = new JButton("Click me!");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed (ActionEvent e) {
CardLayout cl = (CardLayout)(cards.getLayout());
cl.next(cards);
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(btn);
pane.add(btnPanel, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
Alternatively, you can switch to a specific panel by calling cl.show(cards, "Panel X")
where X is the number of the panel. This is because the swing argument is the name I assigned to each "card" and the show
method recalls panels added to CardLayout
by name. For your example, each button should have a listener that uses this method to "show" its assigned panel.
Upvotes: 1