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

界面设计

仿微信聊天程序的主界面总体跟微信的主界面差不多,但是比微信的主界面简单得多,如下图所示:

界面布局

主界面整个界面采用HBox布局,分为左中右三个部分,最左边是菜单栏,中间是联系人列表或对话信息列表,最右边是聊天窗口或设置信息窗口,完整的fxml如下:

<HBox prefHeight="640.0"
      prefWidth="860.0" stylesheets="@MainController.css" xmlns:fx="http://javafx.com/fxml"
      fx:controller="michong.javafx.wx.view.main.MainController">

    <children>
        <VBox alignment="CENTER" prefWidth="64.0" spacing="30.0" styleClass="left-menu">
            <children>
                <ImageView fx:id="avatarImageView" fitWidth="40" fitHeight="40"/>
                <ToggleButton fx:id="chatButton" selected="true" styleClass="chat-button"
                              onAction="#onChatClick"/>
                <ToggleButton fx:id="contactsButton" styleClass="contacts-button" onAction="#onContactsClick"/>
                <Pane VBox.vgrow="ALWAYS"/>
                <Button styleClass="setting-button"/>
            </children>
            <padding>
                <Insets bottom="20.0" top="20.0"/>
            </padding>
        </VBox>
        <VBox fx:id="listVBox" prefWidth="250.0" alignment="CENTER"/>
        <VBox HBox.hgrow="ALWAYS">
            <children>
                <HBox prefHeight="30.0" styleClass="top-menu">
                    <children>
                        <Pane HBox.hgrow="ALWAYS"/>
                        <Button onAction="#onMinimizeClick" styleClass="minimize-button"/>
                        <Button onAction="#onExitClick" styleClass="exit-button"/>
                    </children>
                </HBox>
                <Pane fx:id="mainPane" VBox.vgrow="ALWAYS">
                </Pane>
            </children>
        </VBox>
    </children>
</HBox>

样式优化

在界面设计的图中,可以看到主界面针对一些按钮进行了样式优化,采用图片代替原始的按钮样式,具体的css样式如下:

.contacts-button {
  -fx-cursor: hand;
  -fx-background-color: transparent;
  -fx-border-color: transparent;
  -fx-pref-width: 32px;
  -fx-pref-height: 32px;
  -fx-background-size: 32px 32px;
  -fx-background-image: url("/icon/contacts_0.png");
}
.contacts-button:selected {
  -fx-background-image: url("/icon/contacts_1.png");
}

事件处理

主界面的事件主要涉及两个部分,菜单的切换以及最小化和关闭事件处理,具体的处理代码如下:

public class MainController implements Initializable {

    public ImageView avatarImageView;
    public ToggleButton chatButton;
    public ToggleButton contactsButton;
    public VBox listVBox;
    public Pane mainPane;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        initializeUI();
        initializeEvent();
    }

    void initializeUI() {
        ToggleGroup leftMenuToggleGroup = new ToggleGroup();
        chatButton.setToggleGroup(leftMenuToggleGroup);
        contactsButton.setToggleGroup(leftMenuToggleGroup);
        onChatClick(null);
    }

    void initializeEvent() {
    }

    public void onChatClick(ActionEvent actionEvent) {
        listVBox.getChildren().clear();
        listVBox.getChildren().add(FXComponent.chatListController());
    }

    public void onContactsClick(ActionEvent actionEvent) {
        listVBox.getChildren().clear();
        listVBox.getChildren().add(FXComponent.contactsListController());
    }

    public void onMinimizeClick(ActionEvent actionEvent) {
        FXContext.getPrimaryStage().setIconified(true);
    }

    public void onExitClick(ActionEvent actionEvent) {
        Optional.ofNullable(FXContext.getPrimaryStage().getOnCloseRequest()).ifPresent(
                e -> e.handle(new WindowEvent(FXContext.getPrimaryStage(), WindowEvent.WINDOW_CLOSE_REQUEST)));
        FXContext.getPrimaryStage().close();
    }

}

拖动支持

从界面设计图中可以看出,主界面抛弃了JavaFX原始的窗体外壳,自定义了最小化和关闭按钮来实现这些功能,具体的窗体配置如下:

primaryStage.initStyle(StageStyle.TRANSPARENT);

将窗体设置为StageStyle.TRANSPARENT后,需要自己实现窗体的拖动功能:

Parent root = FX.fxml(MainController.class);
FX.drag(primaryStage, root);

其中FX.drag的实现如下:

public static void drag(Stage stage, Parent root) {
    EventHandler<MouseEvent> eventHandler = new EventHandler<MouseEvent>() {
        private double xOffset = 0;
        private double yOffset = 0;

        @Override
        public void handle(MouseEvent event) {
            if (event.getEventType() == MouseEvent.MOUSE_PRESSED) {
                xOffset = event.getSceneX();
                yOffset = event.getSceneY();
            } else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) {
                stage.setX(event.getScreenX() - xOffset);
                if (event.getScreenY() - yOffset < 0) {
                    stage.setY(0);
                } else {
                    stage.setY(event.getScreenY() - yOffset);
                }
            }
        }
    };
    root.setOnMousePressed(eventHandler);
    root.setOnMouseDragged(eventHandler);
}

登录流程

调整原来的登录流程,登录成功后关闭登录窗口,显示主窗口:

public void onLoginClick(ActionEvent actionEvent) {
    form.getForm().persist();
    if (form.getForm().isValid()) {
        FXContext.getLoginStage().close();
        FXContext.getPrimaryStage().show();
    }
}
posted on 2023-07-16 13:34  ql1710  阅读(66)  评论(0编辑  收藏  举报