I'm working on a java project, I handled every functionality but when it comes to GUI I'm a beginner. What I want to know is can i use java to display different scenes in one stage like in javaFX? e.g my starting point is a login panel after login empty the Jframe and display next veiw or scene. there are a lot of views what should i do?
-
1Since you seem to be familiar with JavaFX why don't you just use JavaFX? – Gumbo Apr 10 '15 at 22:40
-
I'm not good with javaFX. – HAMZA PERVEZ Apr 10 '15 at 22:40
-
1The answer is yes, you can use a `CardLayout` to switch views, a `JTabbedPane` to show multiple view which the user can select between and a verity of other approaches – MadProgrammer Apr 10 '15 at 22:42
-
thanks i'll try these. could you tell some other approaches? @MadProgrammer – HAMZA PERVEZ Apr 10 '15 at 22:44
-
1See [How to Use CardLayout](http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html) for more details. – MadProgrammer Apr 10 '15 at 22:45
-
`CardLayout` would generally be the preferred solution, otherwise you will need to simply remove the current view and add the new view manually – MadProgrammer Apr 10 '15 at 22:45
-
@MadProgrammer You can indeed, but i think swing is a pain in the ass for more complex layouts, that is the reason why JavaFX exists. – Gumbo Apr 10 '15 at 22:46
-
3@Gumbo Excuse my while I laugh my self silly... – MadProgrammer Apr 10 '15 at 22:47
-
@MadProgrammer wow kinda trolly if you ask me but yes Swing is much more complicated than FX (check my solution below if you don't believe me, as I've used both). – Philip Vaughn Apr 14 '15 at 16:26
-
@PhilipVaughn But that's not why we have JavaFX, we have it because Sun wanted to compete against flash, but HTML 5 killed both... – MadProgrammer Apr 14 '15 at 20:49
2 Answers
Basically, in Swing CardLayout
allows you to switch between views within a single container. Start by taking a look at How to Use CardLayout for more details.
The following example use a Model-View-Controller approach and is intended to decouple of the code at the same time, so I'm afraid it's a little long winded, but that's a result of using the MVC and code separation approaches (I like coding to interfaces)
Lets start by defining the views we want...
public interface IView<C extends IViewController> {
public JComponent getView();
public C getViewController();
}
public interface ILoginView extends IView<ILoginViewController> {
}
public interface IWelcomeView extends IView<IWelcomeViewController> {
}
Obviously, we start with a base concept of a view and build on it. Each view has a controller, which dictates what each view is capable of doing...
public interface IViewController {
}
public interface ILoginViewController extends IViewController {
public void loginWasSuccessful(ICredentials credentials);
public void loginDidFail();
public void loginWasCancelled();
}
public interface IWelcomeViewController extends IViewController {
public ICredentials getCredentials();
public void setCredentials(ICredentials credentials);
public void setCredentialsListener(ICredentialsListener listener);
public ICredentialsListener getCredentialsListener();
public interface ICredentialsListener {
public void credentialsWereUpdated(ICredentials credentials);
}
}
Now obviously, we need to be able to pass some data between views (in this case the user details or "credentials")
public interface ICredentials {
public String getUserName();
}
Now, lets get to the nitty gritty and define the actual implementations of the views...
public abstract class AbstractView<C extends IViewController> extends JPanel implements IView<C> {
private C viewController;
public AbstractView(C viewController) {
this.viewController = viewController;
}
@Override
public JComponent getView() {
return this;
}
@Override
public C getViewController() {
return viewController;
}
}
public class WelcomeView extends AbstractView<IWelcomeViewController> implements IWelcomeView {
private JLabel userName;
public WelcomeView(IWelcomeViewController viewContoller) {
super(viewContoller);
viewContoller.setCredentialsListener((ICredentials credentials) -> {
userName.setText(credentials.getUserName());
revalidate();
repaint();
});
userName = new JLabel("...");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(10, 10, 10, 10);
add(new JLabel("WELCOME!"), gbc);
add(userName, gbc);
}
}
public class LoginView extends AbstractView<ILoginViewController> implements ILoginView {
private JTextField userName;
private JPasswordField password;
private JButton login;
private JButton cancel;
public LoginView(ILoginViewController controller) {
super(controller);
setLayout(new GridBagLayout());
userName = new JTextField(10);
password = new JPasswordField(10);
login = new JButton("Login");
cancel = new JButton("Cancel");
login.addActionListener((ActionEvent e) -> {
// Fake the login process...
// This might be handed off to another controller...
String name = userName.getText();
if (name != null && !name.isEmpty()) {
Random rnd = new Random();
if (rnd.nextBoolean()) {
getViewController().loginWasSuccessful(new DefaultCredentials(userName.getText()));
} else {
getViewController().loginDidFail();
}
}
});
cancel.addActionListener((ActionEvent e) -> {
getViewController().loginWasCancelled();
});
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(new JLabel("Login"), gbc);
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 1;
add(new JLabel("Username:"), gbc);
gbc.gridy++;
add(new JLabel("Password:"), gbc);
gbc.gridx++;
gbc.gridy = 1;
add(userName, gbc);
gbc.gridy++;
add(password, gbc);
JPanel controls = new JPanel();
controls.add(login);
controls.add(cancel);
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(controls, gbc);
}
public class DefaultCredentials implements ICredentials {
private final String userName;
public DefaultCredentials(String userName) {
this.userName = userName;
}
@Override
public String getUserName() {
return userName;
}
}
}
Okay, now we have all that, we need to group it all together, through the CardLayout
, this is where the controllers come into play...
public class MainPane extends JPanel {
protected static final String LOGIN_VIEW = "View.login";
protected static final String WELCOME_VIEW = "View.welcome";
private CardLayout cardLayout;
private ILoginView loginView;
private IWelcomeView welcomeView;
public MainPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
// This could be established via a factory or builder pattern
loginView = new LoginView(new LoginViewController());
welcomeView = new WelcomeView(new WelcomeViewController());
add(loginView.getView(), LOGIN_VIEW);
add(welcomeView.getView(), WELCOME_VIEW);
cardLayout.show(this, LOGIN_VIEW);
}
protected class LoginViewController implements ILoginViewController {
@Override
public void loginWasSuccessful(ICredentials credentials) {
welcomeView.getViewController().setCredentials(credentials);
cardLayout.show(MainPane.this, WELCOME_VIEW);
}
@Override
public void loginDidFail() {
JOptionPane.showMessageDialog(MainPane.this, "Login vaild", "Error", JOptionPane.ERROR_MESSAGE);
}
@Override
public void loginWasCancelled() {
SwingUtilities.windowForComponent(MainPane.this).dispose();
}
}
protected class WelcomeViewController implements IWelcomeViewController {
private IWelcomeViewController.ICredentialsListener credentialsListener;
private ICredentials credentials;
@Override
public ICredentials getCredentials() {
return credentials;
}
@Override
public void setCredentials(ICredentials credentials) {
this.credentials = credentials;
IWelcomeViewController.ICredentialsListener listener = getCredentialsListener();
if (listener != null) {
listener.credentialsWereUpdated(credentials);
}
}
@Override
public void setCredentialsListener(IWelcomeViewController.ICredentialsListener listener) {
this.credentialsListener = listener;
}
@Override
public IWelcomeViewController.ICredentialsListener getCredentialsListener() {
return credentialsListener;
}
}
}
This is pretty much the "core" Swing integration. With very little work, you could use the controller and view interfaces in JavaFX if you wanted to.
Now all this does is presents the login view to the user, if the user is successfully logged in, it will switch the views to the welcome view and pass the user credentials to it...
And in case you don't want to copy and paste all that, this is a simple runnable example I used to test it...
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestCardLayout {
public static void main(String[] args) {
new TestCardLayout();
}
public TestCardLayout() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
protected static final String LOGIN_VIEW = "View.login";
protected static final String WELCOME_VIEW = "View.welcome";
private CardLayout cardLayout;
private ILoginView loginView;
private IWelcomeView welcomeView;
public MainPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
// This could be established via a factory or builder pattern
loginView = new LoginView(new LoginViewController());
welcomeView = new WelcomeView(new WelcomeViewController());
add(loginView.getView(), LOGIN_VIEW);
add(welcomeView.getView(), WELCOME_VIEW);
cardLayout.show(this, LOGIN_VIEW);
}
protected class LoginViewController implements ILoginViewController {
@Override
public void loginWasSuccessful(ICredentials credentials) {
welcomeView.getViewController().setCredentials(credentials);
cardLayout.show(MainPane.this, WELCOME_VIEW);
}
@Override
public void loginDidFail() {
JOptionPane.showMessageDialog(MainPane.this, "Login vaild", "Error", JOptionPane.ERROR_MESSAGE);
}
@Override
public void loginWasCancelled() {
SwingUtilities.windowForComponent(MainPane.this).dispose();
}
}
protected class WelcomeViewController implements IWelcomeViewController {
private IWelcomeViewController.ICredentialsListener credentialsListener;
private ICredentials credentials;
@Override
public ICredentials getCredentials() {
return credentials;
}
@Override
public void setCredentials(ICredentials credentials) {
this.credentials = credentials;
IWelcomeViewController.ICredentialsListener listener = getCredentialsListener();
if (listener != null) {
listener.credentialsWereUpdated(credentials);
}
}
@Override
public void setCredentialsListener(IWelcomeViewController.ICredentialsListener listener) {
this.credentialsListener = listener;
}
@Override
public IWelcomeViewController.ICredentialsListener getCredentialsListener() {
return credentialsListener;
}
}
}
public interface IViewController {
}
public interface ILoginViewController extends IViewController {
public void loginWasSuccessful(ICredentials credentials);
public void loginDidFail();
public void loginWasCancelled();
}
public interface IWelcomeViewController extends IViewController {
public ICredentials getCredentials();
public void setCredentials(ICredentials credentials);
public void setCredentialsListener(ICredentialsListener listener);
public ICredentialsListener getCredentialsListener();
public interface ICredentialsListener {
public void credentialsWereUpdated(ICredentials credentials);
}
}
public interface ICredentials {
public String getUserName();
}
public interface IView<C extends IViewController> {
public JComponent getView();
public C getViewController();
}
public interface ILoginView extends IView<ILoginViewController> {
}
public interface IWelcomeView extends IView<IWelcomeViewController> {
}
public abstract class AbstractView<C extends IViewController> extends JPanel implements IView<C> {
private C viewController;
public AbstractView(C viewController) {
this.viewController = viewController;
}
@Override
public JComponent getView() {
return this;
}
@Override
public C getViewController() {
return viewController;
}
}
public class WelcomeView extends AbstractView<IWelcomeViewController> implements IWelcomeView {
private JLabel userName;
public WelcomeView(IWelcomeViewController viewContoller) {
super(viewContoller);
viewContoller.setCredentialsListener((ICredentials credentials) -> {
userName.setText(credentials.getUserName());
revalidate();
repaint();
});
userName = new JLabel("...");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(10, 10, 10, 10);
add(new JLabel("WELCOME!"), gbc);
add(userName, gbc);
}
}
public class LoginView extends AbstractView<ILoginViewController> implements ILoginView {
private JTextField userName;
private JPasswordField password;
private JButton login;
private JButton cancel;
public LoginView(ILoginViewController controller) {
super(controller);
setLayout(new GridBagLayout());
userName = new JTextField(10);
password = new JPasswordField(10);
login = new JButton("Login");
cancel = new JButton("Cancel");
login.addActionListener((ActionEvent e) -> {
// Fake the login process...
// This might be handed off to another controller...
String name = userName.getText();
if (name != null && !name.isEmpty()) {
Random rnd = new Random();
if (rnd.nextBoolean()) {
getViewController().loginWasSuccessful(new DefaultCredentials(userName.getText()));
} else {
getViewController().loginDidFail();
}
}
});
cancel.addActionListener((ActionEvent e) -> {
getViewController().loginWasCancelled();
});
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(new JLabel("Login"), gbc);
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 1;
add(new JLabel("Username:"), gbc);
gbc.gridy++;
add(new JLabel("Password:"), gbc);
gbc.gridx++;
gbc.gridy = 1;
add(userName, gbc);
gbc.gridy++;
add(password, gbc);
JPanel controls = new JPanel();
controls.add(login);
controls.add(cancel);
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(controls, gbc);
}
public class DefaultCredentials implements ICredentials {
private final String userName;
public DefaultCredentials(String userName) {
this.userName = userName;
}
@Override
public String getUserName() {
return userName;
}
}
}
}

- 343,457
- 22
- 230
- 366
Well I'd suggest learning JavaFX if you want a different approach. You can load a StackPane into an FX scene (a scene is an FX object, not a scene like you're talking about) and then load another stackpane (your scene) into the first stackpane. When you wish to change scenes you just unload the stackpane from the first one and load a different one.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloWorld extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage window) {
window.setTitle("Hello World!");
root.getChildren().add(sceneOne);
Scene scene = new Scene(root, 400, 400);
window.setScene(scene);
window.show();
}
private StackPane root = new StackPane();
private MyFirstScene sceneOne = new MyFirstScene();
private MySecondScene sceneTwo = new MySecondScene();
}
For your MyFirstScene (MySecondScene) you just extend StackPane and you can add all the elements you wish. The reason I'm suggesting FX is because Swing is a bit depreciated and Oracle made FX to replace it. I'd get familiar with it if you're going to be making many GUIs using Java.

- 606
- 6
- 20
-
*"Oracle made FX to replace it"* - No, they didn't, Sun made it to compete against Flash, but HTML 5 killed both and instead of wanting to waste their time, they tacked on support for things like table and tree components, which were missing in version 1 (and dropping the requirement for the fxxml) and have tacked on 3D support in version 3 (fx8), so I'm not sure anybody really knows what fx is suppose to use for. The lack of inbuilt support for system look and feels is the killer for me, but that's my experience – MadProgrammer Apr 14 '15 at 20:54
-
http://www.oracle.com/technetwork/java/javafx/overview/faq-1446554.html Point 6 is the one of interest. I'm not here to argue I'm just saying the amount of code required to switch application pages in FX is much more precise and easy to follow. – Philip Vaughn Apr 15 '15 at 21:27
-
Sure, but it's not why it was "created", it's a decision that was made after the fact when it failed to meet its original expectations. I have no issue with fx, I have issue with people who suggest its original intention was to replace Swing (especially because Swing is "hard" - any new API takes time to learn), when it wasn't. And I'm not sure that CardLayout.show(Container, String) is a lot of code ;) – MadProgrammer Apr 15 '15 at 21:33
-
Also giving job posting trends, I'm not sure that Swing or fx have that bright a future, web based technologies seem to be the trend (as well as mobile based Apis :P) – MadProgrammer Apr 15 '15 at 21:40
-
Your last comment is actually probably true. Java has failed to create a GUI platform that is useful. Whenever people think of Java they think of a platform that is used for server-based applications. I work at Home Depot and all of our store systems are Java there, however you never see games programmed in Java mainly C++. – Philip Vaughn Apr 15 '15 at 21:45