本文是仿微信聊天程序专栏的第八篇文章,主要记录了【聊天窗口】的界面实现。
界面设计
聊天窗口是整个聊天程序的核心控件,比较复杂,大致可以分为上中下三个部分,上面显示用户昵称以及一些操作菜单,中间是聊天内容显示区域,下面的信息发送的区域,总体界面设计如下:
界面布局
根据界面设计的划分,将整个聊天窗口布局划分为上中下三个部分,中间使用WebView用于显示聊天内容,完整的fxml布局代码如下:
<StackPane prefHeight="610.0" prefWidth="546.0" stylesheets="@ChatMainController.css" xmlns:fx="http://javafx.com/fxml" fx:controller="michong.javafx.wx.view.chat.ChatMainController"> <SplitPane dividerPositions="0.65" orientation="VERTICAL" styleClass="chat-main-pane"> <items> <VBox> <children> <HBox alignment="CENTER" prefHeight="40.0" styleClass="chat-main-menu"> <children> <Label fx:id="nicknameLabel" styleClass="name-label"/> <Pane HBox.hgrow="ALWAYS"/> <MenuButton styleClass="chat-main-menu-more"> <items> <MenuItem text="清空" styleClass="chat-main-menu-item" onAction="#onClearClick"/> <MenuItem text="关闭" styleClass="chat-main-menu-item" onAction="#onCloseClick"/> </items> </MenuButton> </children> <padding> <Insets left="20.0" right="5.0"/> </padding> </HBox> <Separator styleClass="wx-separator"/> <!--<Pane VBox.vgrow="ALWAYS"/>--> <WebView fx:id="chatWebView" VBox.vgrow="ALWAYS"/> </children> </VBox> <VBox alignment="TOP_RIGHT" styleClass="chat-main-input"> <children> <HBox spacing="10.0"> <children> <Button styleClass="face-button"/> <Button styleClass="message-button"/> <Pane HBox.hgrow="ALWAYS"/> <Button styleClass="audio-button"/> <Button styleClass="video-button"/> </children> <padding> <Insets bottom="5.0" left="20.0" right="20.0" top="5.0"/> </padding> </HBox> <StackPane VBox.vgrow="ALWAYS"> <children> <TextArea fx:id="messageTextArea" wrapText="true"/> </children> <padding> <Insets bottom="5.0" left="20.0" right="20.0" top="5.0"/> </padding> </StackPane> <ButtonBar prefHeight="80.0"> <buttons> <Button styleClass="wx-btn-send" text="发送(S)" onAction="#onSendClick"/> </buttons> <padding> <Insets bottom="5.0" right="20.0" top="5.0"/> </padding> </ButtonBar> </children> </VBox> </items> </SplitPane> </StackPane>
样式美化
跟其他界面一样,JavaFX默认提供的控件样式风格跟聊天程序并不搭,所以聊天窗口仍需要进行样式美化,完整的CSS代码如下:
.chat-main-pane { -fx-background-color: #fafafa; -fx-border-color: transparent; } .chat-main-pane .button { -fx-cursor: hand; -fx-background-color: transparent; -fx-border-color: transparent; -fx-pref-width: 30px; -fx-pref-height: 30px; -fx-background-size: 30px 30px; } .chat-main-menu { -fx-background-color: #fafafa; } .name-label { -fx-font-size: 20px; -fx-text-fill: black; } .chat-main-menu-more { -fx-cursor: hand; -fx-background-color: transparent; -fx-border-color: transparent; -fx-pref-width: 44px; -fx-pref-height: 30px; -fx-background-size: 44px 30px; -fx-background-image: url("/icon/more.png"); } .chat-main-menu-item { -fx-padding: 5 0 5 5; } .chat-main-menu-item:hover, .chat-main-menu-item:focused { -fx-cursor: hand; -fx-background-color: #dbd9d8; } .chat-main-menu-item:hover .label, .chat-main-menu-item:focused .label { -fx-text-fill: black; } .separator .line { -fx-border-color: derive(#eee9e9, 20%); -fx-border-width: 1; } .chat-main-input > * { -fx-background-color: #ffffff; } .face-button { -fx-background-image: url("/icon/face_0.png"); } .face-button:hover { -fx-background-image: url("/icon/face_1.png"); } .message-button { -fx-background-image: url("/icon/message_0.png"); } .message-button:hover { -fx-background-image: url("/icon/message_1.png"); } .audio-button { -fx-background-image: url("/icon/audio_0.png"); } .audio-button:hover { -fx-background-image: url("/icon/audio_0.png"); } .video-button { -fx-background-image: url("/icon/video_0.png"); } .video-button:hover { -fx-background-image: url("/icon/video_0.png"); } .send-button { -fx-padding: 5px 10px; -fx-font-size: 12px; -fx-background-color: #f5f5f5; } .send-button:hover { -fx-cursor: hand; -fx-text-fill: #ffffff; -fx-background-color: #5cb85c; -fx-border-color: #4cae4c; } .text-area { -fx-font-size: 14px; -fx-padding: 0; -fx-cursor: default; -fx-background-color: #ffffff; } .text-area .content { -fx-cursor: text; -fx-background-color: #ffffff; } .text-area:focused .content { -fx-background-color: #ffffff; }
逻辑控制
调整原来聊天列表的事件控制逻辑,当单击聊天列表项时显示聊天信息界面,这里只是静态显示,动态拉取聊天信息后续功能将继续完善,控制代码如下:
void initializeEvent() { chatListView.getSelectionModel().selectedItemProperty().addListener((obj, ov, nv) -> { if (Objects.nonNull(nv)) { Pane main = FXComponent.mainComponent(); main.getChildren().clear(); main.getChildren().add(FXComponent.chatMainComponent(nv.getId())); } }); }
数据填充
跟好友信息的处理方式类似,这里直接给出Controller的代码:
/** * @author michong */ public class ChatMainController implements UserDataController { public Label nicknameLabel; public WebView chatWebView; public TextArea messageTextArea; private Long contactsId; @Override public void initialize(Object data) { contactsId = (Long) data; initializeUI(); initializeEvent(); renderDebugData(); } void initializeUI() { } void initializeEvent() { } void renderDebugData() { nicknameLabel.setText("WxID: " + contactsId); } public void onClearClick(ActionEvent actionEvent) { } public void onCloseClick(ActionEvent actionEvent) { } public void onSendClick(ActionEvent actionEvent) { } }
更多细节,可以查看第7节【好友信息】的实现。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~