本文是仿微信聊天程序专栏的第三篇文章,主要记录了【登录界面】的实现。
界面设计
仿微信聊天程序的登录界面跟注册界面差不多,只是比注册界面少了一个昵称输入框,如下图所示:
界面布局
登录界面的界面布局和注册界面的布局差不多,也是使用fxml,采用VBox从上到下布局,中间的表单使用formsfx
,预留一个StackPane给表单。
<VBox alignment="CENTER" prefHeight="300.0" prefWidth="480.0" spacing="10.0" stylesheets="@/css/bootstrapfx.css" xmlns:fx="http://javafx.com/fxml" fx:controller="michong.javafx.wx.view.login.LoginController"> <children> <HBox alignment="CENTER_LEFT"> <children> <Label text="登录" styleClass="h3,b"/> <Pane HBox.hgrow="ALWAYS"/> <Hyperlink text="注册" onAction="#onRegisterClick"/> </children> <padding> <Insets left="20.0" right="20.0"/> </padding> </HBox> <StackPane fx:id="formStackPane"/> <Button minWidth="120" text="登录" styleClass="btn-primary" onAction="#onLoginClick"/> </children> <padding> <Insets bottom="30.0" left="30.0" right="30.0" top="5.0"/> </padding> </VBox>
表单构建
同样的表单构建也跟注册界面一样,只不过少了一个昵称的输入框:
/** * @author michong */ public class LoginForm { private final LoginVO vo = new LoginVO(); private Form form; private FormRenderer renderer; private LoginForm() { } public static LoginForm getInstance() { LoginForm rf = new LoginForm(); rf.build(); return rf; } private void build() { // @formatter:off String username = "账号"; String password = "密码"; String placeholderTextFmt = "请输入%s"; String requiredTextFmt = "%s必填"; form = Form.of( Group.of( Field.ofStringType(vo.usernameProperty()) .label(username) .placeholder(String.format(placeholderTextFmt, username)) .required(String.format(requiredTextFmt, username)), PasswordField.ofPasswordType(vo.passwordProperty()) .label(password) .placeholder(String.format(placeholderTextFmt, password)) .required(String.format(requiredTextFmt, password)) ) ); // @formatter:on renderer = new FormRenderer(form); } }
事件处理
事件处理这里,要跟注册界面的跳转关联起来,在注册界面点击登录时,切换成登录界面,而在登录界面点击注册时,切换成注册界面:
public class LoginController implements Initializable { public StackPane formStackPane; private LoginForm form; @Override public void initialize(URL location, ResourceBundle resources) { initializeUI(); initializeEvent(); } void initializeUI() { form = LoginForm.getInstance(); formStackPane.getChildren().add(form.getRenderer()); } void initializeEvent() { } public void onRegisterClick(ActionEvent actionEvent) { formStackPane.getScene().setRoot(FXComponent.register()); } public void onLoginClick(ActionEvent actionEvent) { form.getForm().persist(); if (form.getForm().isValid()) { // FX.info(form.getVO().getUsername() + "登录成功", FXContext.getLoginStage()); FXContext.getLoginStage().close(); FXContext.getPrimaryStage().show(); } } }
更新注册页面点击登录的处理以及点击注册的处理:
public void onLoginClick(ActionEvent actionEvent) { formStackPane.getScene().setRoot(FXComponent.login()); } public void onRegisterClick(ActionEvent actionEvent) { form.getForm().persist(); if (form.getForm().isValid()) { FX.info(form.getVO().getUsername() + "注册成功", FXContext.getLoginStage()); onLoginClick(actionEvent); } }
登录窗口
登录和注册使用独立的窗口,登录成功后再显示住窗口,定制登录窗口:
public class LoginStage extends Stage { public static LoginStage build() { LoginStage stage = new LoginStage(); stage.setTitle("米虫IM"); stage.setScene(new Scene(FXComponent.login())); if (Platform.isSupported(ConditionalFeature.EFFECT)) { stage.initStyle(StageStyle.UNIFIED); } stage.getIcons().clear(); stage.getIcons().add(FXIcon.logo()); stage.setResizable(false); stage.setWidth(450); stage.setHeight(350); stage.initOwner(FXContext.getPrimaryStage()); return stage; } }
启动流程
调整启动流程,启动时显示登录窗口,不直接显示主窗口:
public class AppStarter { public static void start(Stage primaryStage) { FXContext.setPrimaryStage(primaryStage); BorderPane root = new BorderPane(); root.setCenter(new Label("米虫IM")); primaryStage.setScene(new Scene(root)); primaryStage.getIcons().clear(); primaryStage.getIcons().add(FXIcon.logo()); primaryStage.setResizable(false); primaryStage.setWidth(640); primaryStage.setHeight(480); LoginStage loginStage = LoginStage.build(); FXContext.setLoginStage(loginStage); loginStage.show(); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)