Open a JPanel after pressing a button in a JFrame
Let's start with, you should avoid, wherever possible, extending directly from a top level container, like JFrame
. This ties you down to a single use component, you couldn't, for example, re-use the login controls in another window (as part of a large component hierarchy) or within an applet context. You're also not adding any new functionality to the class itself.
You should also limit the number of windows you are push onto your user, as it can become confusing quickly. Take a look at The Use of Multiple JFrames, Good/Bad Practice? for more details.
Instead, you should consider using a MVC (Model-View-Controller) design to reduce the amount of coupling between classes and exposure of your components to unwarrented/undesirable modifications.
Contract (view)
Lets start by defining the contracts, this defines what each element in the process can and is expected to do and the information which is passed around
View
This defines the core functionality of each view in your application. Each view can have a controller (as defined by C
) and is expected to provide a JComponent
as the base representation, which is used to physically add the view to the Container
public interface View<C> {
public JComponent getView();
public void setController(C controller);
public C getController();
}
LoginView
This defines what information the login view is expected to provide, in this example, we provide the username and password information as well as a means by which the controller can tell the view that the login attempt failed. This allows the view to reset the view and display an error message if required
public interface LoginView extends View<LoginController> {
public String getUserName();
public char[] getPassword();
public void loginFailed(String errorMessage);
}
LoginController
This defines the expected actions a controller for the login view can expected to occur, this are called by the view to tell the controller it should do something...
public interface LoginController {
public void performLogin(LoginView view);
public void loginCanceled(LoginView view);
}
ApplicationView
I've not provided an example of this, but you can imagine that you'd need to provide the details you might like to provide for interested parties to extract details from the view.
Implementation
LoginPane
This is the basic LoginView
implementation...
public class LoginPane extends JPanel implements LoginView {
private JTextField userName;
private JPasswordField password;
private JButton okButton;
private JButton cancelButton;
private LoginController controller;
public LoginPane() {
setLayout(new GridBagLayout());
userName = new JTextField(10);
password = new JPasswordField(10);
okButton = new JButton("Ok");
cancelButton = new JButton("Cancel");
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.anchor = GridBagConstraints.WEST;
add(new JLabel("User name: "), gbc);
gbc.gridy++;
add(new JLabel("Password: "), gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.gridwidth = 2;
add(userName, gbc);
gbc.gridy++;
add(password, gbc);
gbc.gridwidth = 1;
gbc.gridy++;
add(okButton, gbc);
gbc.gridx++;
add(cancelButton, gbc);
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getController().performLogin(LoginPane.this);
}
});
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getController().loginCanceled(LoginPane.this);
}
});
}
@Override
public String getUserName() {
return userName.getText();
}
@Override
public char[] getPassword() {
return password.getPassword();
}
@Override
public void loginFailed(String errorMessage) {
JOptionPane.showMessageDialog(this, errorMessage, "Login failed", JOptionPane.ERROR_MESSAGE);
}
@Override
public void setController(LoginController controller) {
this.controller = controller;
}
@Override
public JComponent getView() {
return this;
}
@Override
public LoginController getController() {
return controller;
}
}
ApplicationPane
The basic application View
public class ApplicationPane extends JPanel implements View {
public ApplicationPane() {
setLayout(new GridBagLayout());
add(new JLabel("Welcome to my awesome application"));
}
@Override
public JComponent getView() {
return this;
}
@Override
public void setController(Object controller) {
// What ever controller you want to use...
}
@Override
public Object getController() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
Putting it all together...
We'll, that's a lot of info, but how do you use it?
public class CoreApplicationCPane extends JPanel {
protected static final String LOGIN_VIEW = "View.login";
protected static final String APPLICATION_VIEW = "View.application";
private LoginView loginView;
private ApplicationPane applicationView;
private CardLayout cardLayout;
public CoreApplicationCPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
loginView = new LoginPane();
applicationView = new ApplicationPane();
add(loginView.getView(), LOGIN_VIEW);
add(applicationView.getView(), APPLICATION_VIEW);
loginView.setController(new LoginController() {
@Override
public void performLogin(LoginView view) {
// Do what ever you need to do...
String name = view.getUserName();
char[] password = view.getPassword();
//...
cardLayout.show(CoreApplicationCPane.this, APPLICATION_VIEW);
}
@Override
public void loginCanceled(LoginView view) {
SwingUtilities.windowForComponent(CoreApplicationCPane.this).dispose();
}
});
cardLayout.show(this, LOGIN_VIEW);
}
}
This is basically where everything gets plugged together. The LoginView
and ApplicationView
's are instantiated and added to the main view and the controller's are plugged in.
Take a look at:
- Laying Out Components Within a Container
- How to Use CardLayout
for more details.
For a more detail example, take a look at Java and GUI - Where do ActionListeners belong according to MVC pattern?
Clicking a button within a JFrame passes an data to a JPanel
The Coordinates and Number classes weren't included, so I had to modify the code somewhat.
Here's the GUI I created.
The first thing I did was create a model class for the GUI. By creating a model class, I could make the display string and the drawing coordinate available to the view and the controller classes. This is a simple example of the model / view / controller pattern.
package com.ggl.drawing;
import java.awt.Point;
public class GUIModel {
private String displayString;
private Point coordinate;
public GUIModel(String displayString) {
this.displayString = displayString;
}
public Point getCoordinate() {
return coordinate;
}
public void setCoordinate(int x, int y) {
this.coordinate = new Point(x, y);
}
public void setCoordinate(Point coordinate) {
this.coordinate = coordinate;
}
public void setDisplayString(String displayString) {
this.displayString = displayString;
}
public String getDisplayString() {
return displayString;
}
}
Now that we have a model, lets look at the DrawFrame class.
package com.ggl.drawing;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DrawFrame implements Runnable {
private final int WIDTH = 500;
private final int HEIGHT = 300;
private JFrame frame;
private GUIModel model;
public DrawFrame() {
this.model = new GUIModel("A");
}
@Override
public void run() {
frame = new JFrame("Draw Letters");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createSelectionPanel(), BorderLayout.WEST);
frame.add(new DrawPanel(WIDTH, HEIGHT, model), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
private JPanel createSelectionPanel() {
JPanel numberPanel = new JPanel();
ButtonListener listener = new ButtonListener();
JButton number1 = new JButton("A");
number1.addActionListener(listener);
JButton number2 = new JButton("B");
number2.addActionListener(listener);
numberPanel.setLayout(new GridLayout(0, 2));
numberPanel.add(number1);
numberPanel.add(number2);
return numberPanel;
}
private class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
model.setDisplayString(event.getActionCommand());
}
}
// creates a drawing frame
public static void main(String[] args) {
SwingUtilities.invokeLater(new DrawFrame());
}
}
I started the Java Swing application on the Event Dispatch thread with the call to the SwingUtilities invokeLater method.
I separated the JFrame construction from the 2 JPanels construction. I used a JFrame, rather than extend a JFrame. The only time you should extend any Java class is if you want to override one or more of the class methods.
I used the same ButtonListener for both JButtons. I'm guessing what you want, but I drew either an "A" or a "B", depending on which button you left clicked.
Let's look at the DrawPanel class.
package com.ggl.drawing;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
public class DrawPanel extends JPanel {
private static final long serialVersionUID = 3443814601865936618L;
private GUIModel model;
public DrawPanel(int width, int height, GUIModel model) {
this.setPreferredSize(new Dimension(width, height));
this.model = model;
// add mouse listeners
MouseHandler mouseHandler = new MouseHandler();
this.addMouseListener(mouseHandler);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (model.getCoordinate() != null) {
Point p = model.getCoordinate();
Font font = g.getFont().deriveFont(48F);
g.setFont(font);
g.drawString(model.getDisplayString(), p.x, p.y);
}
}
// class to handle all mouse events
private class MouseHandler extends MouseAdapter {
@Override
public void mousePressed(MouseEvent event) {
model.setCoordinate(event.getPoint());
}
@Override
public void mouseReleased(MouseEvent event) {
DrawPanel.this.repaint();
}
}
}
The major change I made in this class was to use the paintComponent method, rather than the paint method. The paintComponent method is the correct method to override.
I set the size of the drawing panel in the DrawPanel constructor. It's much better to let Swing figure out the size of the JFrame. That's what the pack method in the DrawFrame run method does.
I increased the font size so you can see the drawn letter better.
I removed the mouse motion listener code, as it wasn't needed.
I hope this was helpful to you.
How to open a new JPanel with a JButton?
The problem is that you have duplicate variables home
and clients
.
The folllowing is your modified code to fix that, with comments on the changed lines (five lines total) :
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class IA extends JFrame {
private final JPanel contentPane;
// private final JPanel home; // REMOVED
// private JPanel clients; // REMOVED
/**
* Launch the application.
*/
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
IA frame = new IA();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public IA() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new CardLayout(0, 0));
final JPanel home = new JPanel();
contentPane.add(home, "name_714429679706141");
home.setLayout(null);
final JPanel clients = new JPanel(); // MOVED UP
contentPane.add(clients, "name_714431450350356"); // MOVED UP
clients.setLayout(null); // MOVED UP
JButton btnClients = new JButton("Clients");
btnClients.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
home.setVisible(false);
clients.setVisible(true);
}
});
btnClients.setBounds(160, 108, 89, 23);
home.add(btnClients);
JButton btnHome = new JButton("Home");
btnHome.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
clients.setVisible(false);
home.setVisible(true);
}
});
btnHome.setBounds(169, 107, 89, 23);
clients.add(btnHome);
}
}
Java Swing. Opening a new JPanel from a JButton and making the buttons pretty
Start by using a different layout manager, FlowLayout
or GridBagLayout
might work better
JPanel centerPanel = new JPanel(new FlowLayout());
centerPanel.add(openReportSelection);
centerPanel.add(closeButton);
These layouts will honour the preferred sizes of your buttons
As for opening another window, well, you've already create one, so the process is pretty much the same. Having said that, you might consider having a look at The Use of Multiple JFrames: Good or Bad Practice? before you commit yourself to far.
A better approach might be to use a JMenuBar
and JMenuItem
s to act as the "open" and "exit" actions. Take a look at How to Use Menus then you could use a CardLayout
to switch between views instead, for example
From a pure design perspective (I know it's only practice, but perfect practice makes perfect), I wouldn't extend anything from JFrame
and instead would rely on building your main GUIs around something like JPanel
instead.
This affords you the flexibility to decide how to use these components, as you could add them to frames, applets or other components...
How do I open a JFrame from a button click
Create ActionListeners for your buttons. Define your frames, and you can access them with your class name. For example;
class mainClient extends JPanel {
JFrame mainClientFrame = new JFrame();
}
and then;
mainClient mc = new mainClient();
mc.mainClientFrame.setVisible(true);
if you want to use this frames in your main void, define them static.
class mainClient extends JPanel {
static JFrame mainClientFrame = new JFrame();
}
change JPanel after clicking on a button
Simple as:
jframe.setContentPane(your_new_panel);
jframe.invalidate();
jframe.validate();
Make a Panel open when i click a button
I guess JDialog is what you need.
See this for details : How to Make Dialogs
Here is a sample :
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class CreateDialogFromOptionPane {
public static void main(final String[] args) {
JFrame parent = new JFrame();
JButton button = new JButton();
button.setText("Click me to show dialog!");
parent.add(button);
parent.pack();
parent.setVisible(true);
button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
JOptionPane optionPane = new JOptionPane("Is this what you need?", JOptionPane.QUESTION_MESSAGE,JOptionPane.YES_NO_OPTION);
JDialog dialog = optionPane.createDialog("Dialog");
dialog.setVisible(true);
}
});
}
}
Switch between panels using a button inside one of them
Your Program Works
That is, it switches panels.
The reason nothing happens when you try to switch to another panel using a button (by button you mean, JLabel
with MouseListener
) inside the scene0
class is that, in your jLabel1MouseClicked
method, you are actually creating a new instance of MainPanel
.
So, instead of changing panels in the already visible MainPanel
, you are changing panels in a new MainPanel
frame.
Solution:
Although there are other solutions, the solution that I could think for the long run is that, you should create a Main class in your Vista
package. In that class you should create the instances of all your panels. Whenever, you run your program, run this class instead of running MainPanel
class.
Demo-code of the Main class:
public class Main
{
public static MainPanel mainPanel;
public static scene0 firstScene = new scene0();
public static scene1 secondScene = new scene1();
public static void main(String[] args)
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
mainPanel = new MainPanel()
}
});
}
}
Now, whenever you are trying to access MainPanel
,scene0
or scene1
, access it usingMain.mainPanel
or Main.scene0
or Main.scene1
.
Modify your jLabel1MouseClicked
method in this manner :
private void jLabel1MouseClicked(java.awt.event.MouseEvent evt) {
Main.mainPanel.loadscene1();
}
You should also modify the sol()
and loadscene1()
method in this manner:
public void sol() {
mostrarPanel(Main.firstScene);
}
public void loadscene1(){
mostrarPanel(Main.secondScene);
}
Note: The code is not tested but I am sure it will work.
Related Topics
How to Specify the Root Context in Your <Web-App> Tags in Web.Xml
Converting a Jfreechart Timeseries Series with Day Data to Week or Month Data
How to Update an Entity Using Spring-Data-Jpa
Why Can Final Object Be Modified
Integer Arithmetic in Java with Char and Integer Literal
Enhanced 'For' Loop Causes an Arrayindexoutofboundsexception
Java.Lang.Verifyerror: Expecting a Stackmap Frame at Branch Target Jdk 1.7
Why Generate Long Serialversionuid Instead of a Simple 1L
Jtable Row Hightlighter Based on Value from Tablecell
Priorityqueue Not Sorting on Add
How to Sort Two Arrays in Relation to Each Other
What Are the Main Uses of Yield(), and How Does It Differ from Join() and Interrupt()
How to Create a Custom Exception Type in Java
Sorting an Array of Int Using Bubblesort