Java应用程序,具有多个场景

我正在研究一个java项目,我处理了所有function,但是当涉及到GUI我是初学者。 我想知道的是,我可以使用java在一个阶段中显示不同的场景,就像在javaFX中一样吗? 例如,我的起点是登录后清空Jframe并显示下一个视图或场景的登录面板。 有很多意见我该怎么办?

基本上,在Swing中, CardLayout允许您在单个容器内切换视图。 首先来看看如何使用CardLayout获取更多详细信息。

以下示例使用模型 – 视图 – 控制器方法,旨在同时解耦代码,所以我担心它有点长,但这是使用MVC和代码分离方法的结果(我喜欢编码到接口)

CardLayout

让我们从定义我们想要的视图开始……

 public interface IView { public JComponent getView(); public C getViewController(); } public interface ILoginView extends IView { } public interface IWelcomeView extends IView { } 

显然,我们从视图的基本概念开始并以此为基础。 每个视图都有一个控制器,它决定了每个视图的function……

 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 abstract class AbstractView extends JPanel implements IView { 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 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 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; } } } 

好的,现在我们拥有了所有这些,我们需要将它们组合在一起,通过CardLayout ,这是控制器发挥作用的地方……

 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; } } } 

这几乎是“核心”Swing集成。 只需很少的工作,如果您愿意,可以使用JavaFX中的控制器和视图接口。

现在这一切都是向用户显示登录视图,如果用户成功登录,它会将视图切换到欢迎视图并将用户凭据传递给它…

如果你不想复制和粘贴所有这些,这是一个简单的可运行的例子我用来测试它…

 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 { public JComponent getView(); public C getViewController(); } public interface ILoginView extends IView { } public interface IWelcomeView extends IView { } public abstract class AbstractView extends JPanel implements IView { 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 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 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; } } } } 

好吧,如果你想要一个不同的方法,我建议学习JavaFX。 您可以将StackPane加载到FX场景中(场景是FX对象,而不是您正在谈论的场景),然后将另一个堆栈窗格(您的场景)加载到第一个堆栈窗格中。 当您想要更改场景时,您只需从第一个堆栈窗口卸载堆栈窗口并加载另一个堆栈窗格。

 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(); } 

对于MyFirstScene(MySecondScene),您只需扩展StackPane,就可以添加所需的所有元素。 我建议FX的原因是因为Swing有点贬值而且Oracle使FX取代它。 如果您要使用Java制作许多GUI,我会熟悉它。