Open a JPanel after pressing a button in a JFrame [duplicate]

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.

enter image description hereenter image description here

Take a look at:

for more details.

For a more detail example, take a look at Java and GUI – Where do ActionListeners belong according to MVC pattern?

Leave a Comment