本文是仿微信聊天程序专栏的第三篇文章,主要记录了【登录界面】的实现。

界面设计

仿微信聊天程序的登录界面跟注册界面差不多,只是比注册界面少了一个昵称输入框,如下图所示:

界面布局

登录界面的界面布局和注册界面的布局差不多,也是使用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();
    }

}
posted on 2023-07-16 13:33  ql1710  阅读(63)  评论(0编辑  收藏  举报