25.4.20学习总结

news2025/4/21 7:36:26

如何使用listView组件来做聊天界面

1. 什么是CellFactory

在JavaFX中,控件(比如ListViewTableView等)用Cell来显示每一条数据。

  • Cell:代表这个单元格(即每个列表项)中显示的内容和样式。

  • CellFactory:是一个工厂接口,负责创建和配置每个Cell

简单来说,

CellFactory用于定义如何将数据对象(比如好友信息)转化为界面显示的单元格(Cell)。


2. 为什么要自定义CellFactory

默认的Cell只显示数据的toString()方法的内容,
如果你需要自定义界面布局(比如显示头像、名字、状态指示等),
就需要自定义Cell,通过实现自己的CellFactory

3. 如何自定义CellFactory

  • 自定义CellFactory的步骤:

    1. 调用listView.setCellFactory()

    2. call()中返回一个自定义的ListCell<T>

    3. 重写updateItem(),设置每个单元格的内容。

详细的步骤:

 1.创建一个消息属性类;

例如,以聊天室的聊天界面为例

import javafx.scene.image.Image;

public class TextMessage {
    private final String content;
    private final int MessageType;
    private final String userName;
    private final Image  profilePicture;
    private final boolean isSender;
    public TextMessage(String content, int MessageType, String userName, Image profilePicture, boolean isSender) {
        this.content = content;
        this.MessageType = MessageType;
        this.userName = userName;
        this.profilePicture = profilePicture;
        this.isSender = isSender;
    }
    public String getContent() {
        return content;
    }
    public int getMessageType() {
        return MessageType;
    }
    public String getUserName() {
        return userName;
    }
    public Image getProfilePicture() {
        return profilePicture;
    }
    public boolean getIsSender() {
        return isSender;
    }

}

2.创建Cell类(稍后写详细代码)

其中,ListCell后跟着的是你创建的属性类。重写方法后,我们将在else里写具体代码。 

public class ChatTextMessageCell extends ListCell<TextMessage> {
    @Override
    protected void updateItem(TextMessage item, boolean empty) {
    super.updateItem(item, empty);
        if (empty || item == null) {
            setText(null);
            setGraphic(null);
        } else {
 



        }
    }
}

3.在控制器类里初始化

首先,在类里添加如下代码:

private ObservableList<TextMessage> messages;

其中,ObservableList是 JavaFX 中用于实现数据绑定的重要接口。它允许 UI 控件自动响应数据变化。

将你的listView组件声明一下,如下,

@FXML public ListView<TextMessage> chatList;

初始化方法(注意:以initialize为名的无参方法无论加不加注解都会在应用启动时执行):

@FXML public void initialize(){
        messages = FXCollections.observableArrayList();
        chatList.setItems(messages);
        chatList.setCellFactory(param -> new ChatTextMessageCell());
    }

 4.具体写Cell类

注意:这个类对于初学者来说并不好写,可能需调整多次才能达到预期。

 对于javaFX有过了解的知道,VBox和HBox的区别,我们将在下面可能频繁使用这两个容器。

我们需要聊天界面显示的每条消息由头像,昵称,发出的消息等组成,其中,头像位于最左端或者最右端,昵称和发出的消息共同组成上下结构位于头像的另一端。也就是说,根容器,是需要展示左右两端的,我们使用HBox作为根容器,如下:

HBox root = new HBox();

之后,我们分别声明头像的组件和另一端的容器,又因为另一端是上下结构,我们使用VBox作为容器。如下:

ImageView imageView = new ImageView(item.getProfilePicture());
VBox messageBox = new VBox();

之后,我们将两者放入根容器中,如下:

root.getChildren().addAll(imageView, messageBox);

 之后便是相同的操作了,依次处理上下结构即可。

显然,这样的结果不符合要求,我们还行对组件进行设置。在这便需要各位查阅官方文档了。

记得在最后加上setGraphic(root);应用设置!!!

完整代码引用:
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Circle;

public class ChatTextMessageCell extends ListCell<TextMessage> {
    @Override
    protected void updateItem(TextMessage item, boolean empty) {
        super.updateItem(item, empty);
        if (empty || item == null) {
            setText(null);
            setGraphic(null);
        } else {
            HBox root = new HBox();
            if (item.getMessageType() == 1) {
                // 时间消息样式保持不变
                Label timeLabel = new Label(item.getContent());
                timeLabel.setStyle("-fx-font-size: 10px; -fx-text-fill: gray;");
                root.getChildren().add(timeLabel);
                root.setAlignment(Pos.CENTER);
            } else {
                // ================== 头像区域 ==================
                ImageView imageView = new ImageView(item.getProfilePicture());
                imageView.setFitHeight(40);
                imageView.setFitWidth(40);
                imageView.setPreserveRatio(false);
                imageView.setClip(new Circle(20, 20, 15));

                // ================== 消息内容区域 ==================
                VBox messageBox = new VBox();

                // 昵称标签(添加左外边距贴近头像)
                Label nameLabel = new Label(item.getUserName());
                nameLabel.setStyle("-fx-font-size: 12px; -fx-text-fill: #666; /*-fx-padding: 0 0 2px 8px;*/");

                // 消息气泡
                if(item.getMessageType()==2){
                    HBox bubble = new HBox();
                    bubble.setMaxWidth(200);
                    bubble.setStyle(
                            "-fx-background-radius: 15px; " +
                                    "-fx-padding: 8px 12px; " +
                                    "-fx-background-color: " + (item.getIsSender() ? "#f5f5f5" : "#0099ff") + ";"
                    );

                    // 消息文本
                    Label messageLabel = new Label(item.getContent());
                    messageLabel.setStyle(
                            "-fx-font-size: 14px; " +
                                    "-fx-text-fill: " + (item.getIsSender() ? "black" : "white") + ";"
                    );
                    messageLabel.setWrapText(true);

                    // ================== 布局组装 ==================
                    bubble.getChildren().add(messageLabel);
                    messageBox.getChildren().addAll(nameLabel, bubble);

                    // 根容器设置
                    root.setSpacing(5);
                    if (item.getIsSender()) {
                        messageBox.setAlignment(Pos.CENTER_LEFT);
                        root.setAlignment(Pos.CENTER_LEFT);
                        root.getChildren().addAll(imageView, messageBox);
                    } else {
                        messageBox.setAlignment(Pos.CENTER_RIGHT);
                        root.setAlignment(Pos.CENTER_RIGHT);
                        root.getChildren().addAll(messageBox, imageView);
                    }
                }
            }
            setGraphic(root);
        }
    }
}

5.将listView的默认样式去除

在你的resources文件中,创建css文件,内容如下:

.list-view { /* 应用于整个ListView */
    -fx-background-color: WHITE; /* ListView 背景透明 */
}

.list-cell {
    -fx-background-color: transparent; /* 单元格背景透明 */
    -fx-padding: 0;                  /* 移除默认内边距 */
    -fx-border: none;                /* 移除边框 */
    -fx-focus-color: transparent;     /* 移除焦点效果 */
    -fx-control-inner-background: transparent; /* 解决部分主题背景问题 */
    -fx-text-fill: black;           /* 默认文本颜色,并保持 */
}

.list-cell:hover {
    -fx-background-color: transparent; /* 悬停时透明 */
}

.list-cell:selected {
    -fx-background-color: transparent; /* 选中时透明 */
}

.list-cell:selected:focused {
    -fx-background-color: transparent; /* 选中并聚焦时透明 */
}

.list-cell:pressed {
    -fx-background-color: transparent; /* 按下时透明 */
}

将此css文件导入即可。

FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 900, 618);
// 加载 CSS 文件
scene.getStylesheets().add(Objects.requireNonNull(getClass().getResource("style.css")).toExternalForm());

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2339282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV基础01-图像文件的读取与保存

介绍: OpenCV是 Open Souce C omputer V sion Library的简称。要使用OpenCV需要安装OpenCV包&#xff0c;使用前需要导入OpenCV模块 安装 命令 pip install opencv-python 导入 模块 import cv2 1. 图像的读取 import cv2 img cv2.imread(path, flag)这里的flag 是可选参数&…

go语言优雅关机和优雅重启笔记

一、优雅关机 生活化例子 餐馆关门&#xff1a;你去餐馆吃火锅&#xff0c;刚坐下点完菜&#xff08;客户端发请求&#xff09;&#xff0c;餐馆老板突然接到通知要停电&#xff08;收到关机指令&#xff09;。老板很贴心&#xff0c;先停止接待新客人&#xff08;停止接收新请…

【算法】计数排序、桶排序、基数排序

算法系列八&#xff1a;非比较排序 一、计数排序 1.实现 1.1步骤 1.2代码 2.性质 2.1稳定性 2.1.1从前往后前始版&#xff1a; 2.1.2从后往前末始版&#xff1a; 2.2复杂度 2.2.1时间复杂度 2.2.2空间复杂度 二、桶排序 1.实现 1.1步骤 1.2代码 2.稳定性 三、…

Halcon应用:相机标定

提示&#xff1a;若没有查找的算子&#xff0c;可以评论区留言&#xff0c;会尽快更新 Halcon应用&#xff1a;相机标定 前言一、Halcon应用&#xff1f;二、应用实战1、图像理解1.1、开始标定 前言 本篇博文主要用于记录学习Halcon中算子的应用场景&#xff0c;及其使用代码和…

【C++ 程序设计】实战:C++ 实践练习题(31~40)

目录 31. 数列&#xff1a;s 1 &#xff0b; 2 &#xff0b; 3 &#xff0b; … &#xff0b; n 32. 数列&#xff1a;s 1 - 2 - 3 - … - n 33. 数列&#xff1a;s 1 &#xff0b; 2 - 3 &#xff0b; … - n 34. 数列&#xff1a;s 1 - 2 &#xff0b; 3 - … &#…

绿幕抠图直播软件-蓝松抠图插件--使用相机直播,灯光需要怎么打?

使用SONY相机进行绿幕抠图直播时&#xff0c;灯光布置是关键&#xff0c;直接影响抠图效果和直播画质。以下是详细的灯光方案和注意事项&#xff1a; 一、绿幕灯光布置核心原则 均匀照明&#xff1a;绿幕表面光线需均匀&#xff0c;避免阴影和反光&#xff08;亮度差控制在0.5…

从外网访问局域网服务器的方法

一、为什么局域网的服务器无法在外网访问&#xff1f; 服务器、电脑之间靠IP地址寻址&#xff0c;目前大部分基于IPV4进行寻址访问。但是因为IPV4的地址数量有限&#xff0c;中国分到的还比较少&#xff0c;所以非常紧缺。 一个解决方案就是在局域网来建立一个内部的网…

机器学习 Day12 集成学习简单介绍

1.集成学习概述 1.1. 什么是集成学习 集成学习是一种通过组合多个模型来提高预测性能的机器学习方法。它类似于&#xff1a; 超级个体 vs 弱者联盟 单个复杂模型(如9次多项式函数)可能能力过强但容易过拟合 组合多个简单模型(如一堆1次函数)可以增强能力而不易过拟合 集成…

交换机与路由器的主要区别:深入分析其工作原理与应用场景

在现代网络架构中&#xff0c;交换机和路由器是两种至关重要的设备。它们在网络中扮演着不同的角色&#xff0c;但很多人对它们的工作原理和功能特性并不十分清楚。本文将深入分析交换机与路由器的主要区别&#xff0c;并探讨它们的工作原理和应用场景。 一、基本定义 1. 交换…

【Oracle专栏】Oracle中的虚拟列

Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.背景 在EXP方式导出时&#xff0c;发现 出现如下提示 EXP-00107: virtual column 不支持&#xff0c;因此采用expdp方式导出。于是本文针对oracle虚拟列进行简单介绍。 2. 相…

2020 年 7 月大学英语四级考试真题(组合卷)——解析版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;目前中南大学MBA在读&#xff0c;也考取过HCIE Cloud Computing、CCIE Security、PMP、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &…

大语言模型的训练、微调及压缩技术

The rock can talk — not interesting. The rock can read — that’s interesting. &#xff08;石头能说话&#xff0c;不稀奇。稀奇的是石头能读懂。&#xff09; ----硅谷知名创业孵化器 YC 的总裁 Gar Tan 目录 1. 什么是大语言模型&#xff1f; 2. 语言建模&#xff…

firewall指令

大家好,今天我们继续来了解服务管理,来看看打开或关闭指定端口,那么话不多说,开始吧. 1.打开或者关闭指定端口 在真正的生产环境,往往需要防火墙,但问题来了,如果我们把防火墙打开,那么外部请求数据包就不能跟服务器监听通讯,这时,需要打开指定的端口,比如80,22,8080等. 2.fi…

【MySQL】MySQL表的增删改查(CRUD) —— 上篇

目录 MySQL表的增删改查&#xff08;CRUD&#xff09; 1. 新增&#xff08;Create&#xff09;/插入数据 1.1 单行数据 全列插入 insert into 表名 values(值, 值......); 1.2 单行数据 指定列插入 1.3 多行数据 指定列插入 1.4 关于时间日期&#xff08;datetime&am…

软考高级系统架构设计师-第15章 知识产权与标准化

【本章学习建议】 根据考试大纲&#xff0c;本章主要考查系统架构设计师单选题&#xff0c;预计考3分左右&#xff0c;较为简单。 15.1 标准化基础知识 1. 标准的分类 分类 内容 国际标准&#xff08;IS&#xff09; 国际标准化组织&#xff08;ISO&#xff09;、国际电工…

Spring Boot 整合 DeepSeek 实现AI对话 (保姆及教程)

文章目录 文章目录 前言 一、创建 spring boot 工程 二、申请key 三、修改配置文件 application.properties 四、编写控制器&#xff08;controller&#xff09; 五、运行调试 前言 提示&#xff1a;随着人工智能的不断发展&#xff0c;ai这门技术也越来越重要&#xff0c;很多…

前端与传统接口的桥梁:JSONP解决方案

1.JSONP原理 1.1.动态脚本注入 说明&#xff1a;通过创建 <script> 标签绕过浏览器同源策略 1.2.回调约定 说明&#xff1a;服务端返回 函数名(JSON数据) 格式的JS代码 1.3.自动执行 说明&#xff1a;浏览器加载脚本后立即触发前端预定义的回调函数&#xff08;现代开…

编码器---正交编码器

一、正交编码器定义与核心作用 正交编码器&#xff08;Orthogonal Encoder&#xff09;&#xff0c;又称增量式编码器&#xff0c;是一种通过输出两路相位差90的脉冲信号&#xff08;A相、B相&#xff09;来测量旋转角度、速度和方向的传感器。其核心优势是通过A/B相的脉冲顺序…

开发环境解决浏览器层面跨域问题

适用于开发环境临时调试等情况 新建一个 Chrome 的快捷方式&#xff0c;目标后面跟上&#xff1a; –disable-web-security --disable-gpu --user-data-dir%LOCALAPPDATA%\Google\chromeTemp 打开后会给出不安全的提示

2025年渗透测试面试题总结-拷打题库07(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 2025年渗透测试面试题总结-拷打题库07 1. CMS目录扫描的意义 2. 常见网站服务器容器 3. MySQL写入We…