JavaFX作业

前言:

在写这个作业之前,尝试在JavaFX中添加全局快捷键,测试了大概5个小时,到处找教程换版本,结果最后还是没找到支持Java8以上的(也有可能是我自己的问题),最后只能退而求其次,用jintellitype这个库来在原生swing里面添加了全局快捷键,算是圆了我对SAO Utils的一个执念吧,虽然实际上相差甚远。

作业:

1.安装向导

提供一个setup.jar,模拟常见的软件安装交互特性。

主要功能:上一步下一步的页面切换,按钮交互响应,页面创建

2.广播

制作一个可以向子窗体同步信息的父窗体,内容由文本框输入,父窗体上放一个广播按钮和一个子窗体创建按钮,广播按钮点击后可以让父窗体输入文本显示到所有子窗体上,子窗体创建按钮点击后创建新的窗体(点击一次创建一次)。

主要功能:文本输入,信息同步,按钮交互响应,窗体创建

3.监控

制作一个可以收集自己创建的子窗体信息的父窗体,父窗体上有一个子窗体创建按钮和一个显示框,子窗体创建按钮点击后创建一个子窗体,显示框内显示当前已经创建的子窗体的名字(依次命名为1,2,3...)和每个子窗体上按钮被点击的次数;每个子窗体中心有一个点击按钮,点击后主窗体更新内容。

主要功能:窗体创建,信息传递,按钮交互响应,计数计算

4.双向实时通讯

创建一个主窗体和一个从窗体,主窗体上显示"已完成了 %",从窗体上显示一个进度条(初始为0,在下方显示百分比)和两个按钮,一个增加按钮一个减少按钮,点击增加按钮,进度条增加1%,点击减少,进度条减少1%,从窗体的进度条和主窗体显示的 %相关联,同样的,主窗体上也有这两个按键。

主要功能:按钮响应,信息双向同步,计数,线程安全(我在主窗体的按钮上加上了长按加速功能,方便调试,不然点来点去好难受)

5.微信群模拟

用JavaFX模拟微信群聊功能。

程序运行时可以动态创建多个窗体,也就是说先有一个主窗体,在创建从窗体时,用户可以选择一个群加入(相当于一个class来将从窗体分到不同的类别里,参见html的class),每个窗体代表一个用户(每个用户按照创建窗体的先后顺序有一个id),使用窗体背景色区分开各个群的成员。一个用户发送的消息只有他所属的群内的其他用户能看到。【我新加入了历史记录的模块,但是似乎效果并不是很好,当前的同步方式是一次性同步所有历史数据,显然当数据量较大时不太合适,而且太低效了(这个好改,但是懒)】

JavaFX学习记录

1.布局·

VBox垂直布局,HBox水平布局

2.线程安全

确保在多条线程访问的时候,我们的程序还能按照我们预期的行为去执行。

关键字:synchronized,lock,volatile

完成(慢慢更新ing,注解有时间再写当做复习)

1.安装向导

java 复制代码
package com.example.test10;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class SetupWizard extends Application {
    private Stage stage;
    private int currentPage;
    private VBox pageContainer;
    private final Button backButton = new Button("Back");
    private final Button nextButton = new Button("Next");

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        stage = primaryStage;
        stage.setTitle("Setup Wizard");

        BorderPane root = new BorderPane();
        Scene scene = new Scene(root, 400, 300);

        // 创建页面容器
        pageContainer = new VBox();
        pageContainer.setPadding(new Insets(20));
        pageContainer.setAlignment(Pos.CENTER_LEFT);
        // 创建页面
        VBox page1 = createPage1();
        VBox page2 = createPage2();
        VBox page3 = createPage3();

        // 添加页面到容器
        pageContainer.getChildren().addAll(page1, page2, page3);

        // 设置当前页面
        currentPage = 0;
        showCurrentPage();

        // 创建按钮容器
        HBox buttonContainer = new HBox();
        buttonContainer.setPadding(new Insets(20));
        buttonContainer.setAlignment(Pos.BOTTOM_RIGHT);

        // 设置布局
        HBox.setMargin(backButton, new Insets(0, 10, 0, 0));
        backButton.setOnAction(event -> showPreviousPage());
        nextButton.setOnAction(event -> showNextPage());

        buttonContainer.getChildren().addAll(backButton, nextButton);
        root.setCenter(pageContainer);
        root.setBottom(buttonContainer);
        nextButton.setDisable(true);
        stage.setScene(scene);
        stage.show();
    }

    private VBox createPage1() {
        VBox page = new VBox();
        page.setSpacing(10);
        Label label = new Label("Please read and accept the agreement:");
        CheckBox checkBox = new CheckBox("I agree to the above terms and conditions");
        checkBox.setOnAction(event -> nextButton.setDisable(!checkBox.isSelected()));
        page.getChildren().addAll(label, checkBox);
        return page;
    }

    private VBox createPage2() {
        VBox page = new VBox();
        page.setSpacing(10);
        Label label = new Label("Please enter the installation directory:");
        TextField directoryField = new TextField();
        directoryField.textProperty().addListener((observable, oldValue, newValue) ->
                nextButton.setDisable(newValue.isEmpty()));
        page.getChildren().addAll(label, directoryField);
        return page;
    }

    private VBox createPage3() {
        VBox page = new VBox();
        page.setSpacing(10);
        Label label = new Label("Please select an option:");
        Button exitButton = new Button("Exit");
        exitButton.setOnAction(event -> stage.close());

        HBox buttonContainer = new HBox();
        buttonContainer.setAlignment(Pos.BOTTOM_RIGHT);
        buttonContainer.getChildren().addAll(backButton, exitButton);

        page.getChildren().addAll(label, buttonContainer);
        return page;
    }

    private void showPreviousPage() {
        if (currentPage > 0) {
            currentPage--;
            showCurrentPage();
        }
    }

    private void showNextPage() {
        if (currentPage < pageContainer.getChildren().size() - 1) {
            currentPage++;
            showCurrentPage();
            nextButton.setDisable(true);
        }
    }

    private void showCurrentPage() {
        pageContainer.getChildren().forEach(page -> page.setVisible(false));
        pageContainer.getChildren().get(currentPage).setVisible(true);

        backButton.setDisable(currentPage == 0);
        nextButton.setDisable(currentPage == pageContainer.getChildren().size() - 1);
    }
}

2. 广播

java 复制代码
package com.example.test11;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;

public class ParentWindow extends Application {
    private final List<ChildWindow> childWindows = new ArrayList<>();
    private double childWindowOffsetY = 0;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Parent Window");

        // 创建文本输入框
        TextField inputTextField = new TextField();
        inputTextField.setPromptText("输入要广播的文本");

        // 创建广播按钮
        Button broadcastButton = new Button("广播");
        broadcastButton.setOnAction(e -> broadcastMessage(inputTextField.getText()));

        // 创建子窗体创建按钮
        Button createChildButton = new Button("创建子窗体");
        createChildButton.setOnAction(e -> createChildWindow(primaryStage));

        // 创建按钮布局
        HBox buttonLayout = new HBox(10);
        buttonLayout.getChildren().addAll(broadcastButton, createChildButton);

        // 创建父窗体布局
        VBox parentLayout = new VBox(10);
        parentLayout.setPadding(new Insets(10));
        parentLayout.getChildren().addAll(inputTextField, buttonLayout);

        primaryStage.setScene(new Scene(parentLayout, 500, 350));
        primaryStage.show();
    }

    // 广播消息给所有子窗体
    private void broadcastMessage(String message) {
        for (ChildWindow childWindow : childWindows) {
            childWindow.showMessage(message);
        }
    }

    // 创建子窗体
    private void createChildWindow(Stage parentStage) {
        ChildWindow childWindow = new ChildWindow();
        childWindows.add(childWindow);
        
        // 为了方便观察效果
        // 我把子窗体放在了在父窗体的右侧
        // 并设置childWindowOffsetY作为子窗体的垂直偏移量
        double parentX = parentStage.getX();
        double parentY = parentStage.getY();
        double parentWidth = parentStage.getWidth();
        double parentHeight = parentStage.getHeight();
        childWindow.setX(parentX + parentWidth + 2);
        childWindow.setY(parentY-parentHeight/2+childWindowOffsetY);
        childWindowOffsetY += 120;

        childWindow.show();
    }

    // 子窗体类
    private static class ChildWindow extends Stage {
        private final TextArea messageArea;

        public ChildWindow() {
            setTitle("Child Window");

            // 消息显示区域
            messageArea = new TextArea();
            messageArea.setEditable(false);

            // 子窗体布局
            VBox childLayout = new VBox(10);
            childLayout.setPadding(new Insets(10));
            childLayout.getChildren().addAll(messageArea);

            setScene(new Scene(childLayout, 250, 180));
        }

        // 在子窗体上显示消息
        public void showMessage(String message) {
            Platform.runLater(() -> messageArea.appendText(message + "\n"));
        }
    }
}

3.监控

java 复制代码
package com.example.text12;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;

public class ParentWindow extends Application {
    private int childWindowCount = 0;
    private double childWindowOffsetY = 0;
    private final List<ChildWindow> childWindows = new ArrayList<>();
    private Label infoLabel;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Parent Window");

        // 创建子窗体创建按钮
        Button createChildButton = new Button("创建子窗体");
        createChildButton.setOnAction(e -> createChildWindow(primaryStage));

        // 创建信息显示标签
        infoLabel = new Label("已创建子窗体信息:");

        // 创建父窗体布局
        VBox parentLayout = new VBox(10);
        parentLayout.setPadding(new Insets(10));
        parentLayout.getChildren().addAll(createChildButton, infoLabel);

        primaryStage.setScene(new Scene(parentLayout, 500, 350));
        primaryStage.show();
    }

    // 创建子窗体
    private void createChildWindow(Stage parentStage) {
        childWindowCount++;
        String childWindowName = String.valueOf(childWindowCount);
        ChildWindow childWindow = new ChildWindow(childWindowName, this);

        childWindows.add(childWindow);

        double parentX = parentStage.getX();
        double parentY = parentStage.getY();
        double parentWidth = parentStage.getWidth();
        double parentHeight = parentStage.getHeight();
        childWindow.setX(parentX + parentWidth + 2);
        childWindow.setY(parentY-parentHeight/2+childWindowOffsetY);
        childWindowOffsetY += 180;

        childWindow.show();
        updateInfoLabel();
    }

    // 更新信息显示标签和父窗体的总点击次数
    private void updateInfoLabel() {
        StringBuilder sb = new StringBuilder();
        int totalClickCount = 0;
        for (ChildWindow childWindow : childWindows) {
            sb.append("子窗体").append(childWindow.getName()).append(": ").append(childWindow.getClickCount()).append("次点击\n");
            totalClickCount += childWindow.getClickCount();
        }
        sb.append("总点击次数: ").append(totalClickCount);

        Platform.runLater(() -> infoLabel.setText("已创建子窗体信息:\n" + sb));
    }

    // 子窗体类
    private static class ChildWindow extends Stage {
        private final String name;
        private int clickCount = 0;

        public ChildWindow(String name, ParentWindow parentWindow) {
            this.name = name;
            setTitle("Child Window " + name);

            // 创建点击按钮
            Button clickButton = new Button("点击");
            clickButton.setOnAction(e -> {
                clickCount++;
                parentWindow.updateInfoLabel();
            });

            // 创建子窗体布局
            VBox childLayout = new VBox(10);
            childLayout.setAlignment(Pos.CENTER);
            childLayout.setPadding(new Insets(10));
            childLayout.getChildren().addAll(clickButton);

            setScene(new Scene(childLayout, 250, 180));
        }

        // 获取子窗体名称
        public String getName() {
            return name;
        }

        // 获取子窗体的点击次数
        public int getClickCount() {
            return clickCount;
        }
    }
}

4. 双向实时通讯

java 复制代码
package com.example.text13;

import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

    private static Main instance; // 单例实例
    private int progress = 0; // 进度值
    private final Object lock = new Object(); // 同步锁对象
    private Label progressLabel; // 主窗体的进度文本标签
    private PauseTransition increaseTimer; // 增加定时器
    private PauseTransition decreaseTimer; // 减少定时器

    public static Main getInstance() {
        return instance;
    }

    public int getProgress() {
        return progress;
    }

    public Object getLock() {
        return lock;
    }

    public void increaseProgress() {
        if (progress < 100) {
            progress++;
        }
    }

    public void decreaseProgress() {
        if (progress > 0) {
            progress--;
        }
    }

    @Override
    public void start(Stage primaryStage) {
        instance = this; // 设置单例实例

        // 创建主窗体
        primaryStage.setTitle("主窗体");
        progressLabel = new Label("已完成了 0%");
        progressLabel.setAlignment(Pos.CENTER);

        Button increaseButton = new Button("增加");
        Button decreaseButton = new Button("减少");

        increaseButton.setOnAction(e -> {
            increaseProgress();
            updateProgressLabel();
        });

        decreaseButton.setOnAction(e -> {
            decreaseProgress();
            updateProgressLabel();
        });

        increaseButton.setOnMousePressed(e -> increaseTimer.playFromStart());

        increaseButton.setOnMouseReleased(e -> increaseTimer.stop());

        decreaseButton.setOnMousePressed(e -> decreaseTimer.playFromStart());

        decreaseButton.setOnMouseReleased(e -> decreaseTimer.stop());

        increaseTimer = createTimer(increaseButton, true);
        decreaseTimer = createTimer(decreaseButton, false);

        HBox buttonLayout = new HBox(10);
        buttonLayout.setAlignment(Pos.CENTER);
        buttonLayout.getChildren().addAll(increaseButton, decreaseButton);

        VBox mainLayout = new VBox(10);
        mainLayout.setAlignment(Pos.CENTER);
        mainLayout.getChildren().addAll(progressLabel, buttonLayout);
        Scene mainScene = new Scene(mainLayout, 450, 300);
        primaryStage.setScene(mainScene);
        primaryStage.show();

        // 创建从窗体
        Thread syncThread = getThread(primaryStage);
        syncThread.start();
    }

    private Thread getThread(Stage primaryStage) {
        ProgressBarWindow progressBarWindow = new ProgressBarWindow();
        Stage secondaryStage = getStage(primaryStage, progressBarWindow);
        secondaryStage.show();

        // 同步主窗体和从窗体的进度
        Thread syncThread = new Thread(() -> {
            try {
                while (true) {
                    synchronized (lock) {
                        Platform.runLater(() -> {
                            progressBarWindow.updateProgress(progress);
                            progressBarWindow.updatePercentage(progress);
                            updateProgressLabel();
                        });
                        lock.wait(100);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        syncThread.setDaemon(true);
        return syncThread;
    }

    private static Stage getStage(Stage primaryStage, ProgressBarWindow progressBarWindow) {
        Stage secondaryStage = new Stage();
        secondaryStage.setTitle("从窗体");
        Scene secondaryScene = new Scene(progressBarWindow.getLayout(), 250, 180);
        secondaryStage.setScene(secondaryScene);

        double primaryX = primaryStage.getX();
        double primaryY = primaryStage.getY();
        double primaryWidth = primaryStage.getWidth();
        double primaryHeight = primaryStage.getHeight();
        secondaryStage.setX(primaryX + primaryWidth + 2);
        secondaryStage.setY((primaryY+primaryHeight)/2);
        return secondaryStage;
    }

    private void updateProgressLabel() {
        progressLabel.setText("已完成了 " + progress + "%");
    }

    private PauseTransition createTimer(Button button, boolean increase) {
        PauseTransition timer = new PauseTransition(Duration.millis(100));
        timer.setOnFinished(e -> {
            synchronized (lock) {
                if (increase) {
                    increaseProgress();
                } else {
                    decreaseProgress();
                }
                updateProgressLabel();
            }
            timer.playFromStart();
        });
        button.setOnMouseClicked(e -> {
            if (e.getClickCount() > 1) {
                timer.stop();
            }
        });
        return timer;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

class ProgressBarWindow {
    private final VBox layout;
    private final ProgressBar progressBar;
    private final Label percentageLabel;

    public ProgressBarWindow() {
        progressBar = new ProgressBar(0);
        percentageLabel = new Label("0%");

        VBox.setMargin(progressBar, new javafx.geometry.Insets(10));
        VBox.setMargin(percentageLabel, new javafx.geometry.Insets(10));

        Button increaseButton = new Button("增加");
        Button decreaseButton = new Button("减少");
        increaseButton.setOnAction(e -> {
            synchronized (Main.getInstance().getLock()) {
                Main.getInstance().increaseProgress();
                updateProgress(Main.getInstance().getProgress());
                updatePercentage(Main.getInstance().getProgress());
            }
        });
        decreaseButton.setOnAction(e -> {
            synchronized (Main.getInstance().getLock()) {
                Main.getInstance().decreaseProgress();
                updateProgress(Main.getInstance().getProgress());
                updatePercentage(Main.getInstance().getProgress());
            }
        });

        HBox buttonLayout = new HBox(10);
        buttonLayout.setAlignment(Pos.CENTER);
        buttonLayout.getChildren().addAll(increaseButton, decreaseButton);

        layout = new VBox(10);
        layout.setAlignment(Pos.CENTER);
        layout.getChildren().addAll(progressBar, percentageLabel, buttonLayout);
    }

    public VBox getLayout() {
        return layout;
    }

    public void updateProgress(int progress) {
        progressBar.setProgress(progress / 100.0);
    }

    public void updatePercentage(int progress) {
        percentageLabel.setText(progress + "%");
    }
}

5.微信群模拟

java 复制代码
package com.example.test14;

import javafx.scene.control.Alert;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;

public class WeChatGroupSimulation extends Application {
    private static List<GroupChatMember> groupChatMembers; // 存储群聊成员
    private double childWindowOffsetY = 0; // 用来调节新窗体位置

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        groupChatMembers = new ArrayList<>();//创建一个空的ArrayList对象,用于存储群聊成员。
        // 创建主窗体
        createMainWindow(primaryStage);
        primaryStage.setTitle("WeChat Group Simulation");
        primaryStage.show();
    }

    private void createMainWindow(Stage primaryStage) {
        VBox root = new VBox();//垂直布局
        root.setAlignment(Pos.CENTER); // 居中对齐
        root.setSpacing(10); // 垂直间距10像素
        root.setPadding(new Insets(10)); // 内边距10像素

        Button addButton1 = new Button("加入1群");
        addButton1.setOnAction(event -> createGroupChatMember("1群", Color.RED, primaryStage));
        root.getChildren().add(addButton1);

        Button addButton2 = new Button("加入2群");
        addButton2.setOnAction(event -> createGroupChatMember("2群", Color.GREEN, primaryStage));
        root.getChildren().add(addButton2);

        // 加入群组3的按钮
        Button addButton3 = new Button("加入3群");
        addButton3.setOnAction(event -> createGroupChatMember("3群", Color.BLUE, primaryStage));
        root.getChildren().add(addButton3);

        Scene scene = new Scene(root, 300, 200);
        primaryStage.setScene(scene);
    }

    // 创建群聊成员窗口
    private void createGroupChatMember(String groupName, Color backgroundColor, Stage parentStageStage) {
        GroupChatMember member = new GroupChatMember(groupName);

        // 将已存在的群聊成员的历史消息合并到新成员的历史消息中
        for (GroupChatMember existingMember : groupChatMembers) {
            if (existingMember.getGroupName().equals(groupName)) {
                member.getHistory().addAll(existingMember.getHistory());
                break;
            }
        }
        Stage stage = new Stage();
        stage.setTitle(groupName);

        VBox root = new VBox();
        root.setStyle("-fx-background-color: " + toRGBCode(backgroundColor)); // 背景颜色
        root.setSpacing(10);
        root.setPadding(new Insets(10));

        TextArea historyArea = new TextArea(); // 创建文本区域用于显示历史消息
        historyArea.setPrefHeight(500);
        historyArea.setEditable(false);

        ListView<String> messageList = new ListView<>(); // 创建列表视图用于显示消息列表

        TextArea inputArea = new TextArea(); // 创建文本区域作为输入框
        inputArea.setPromptText("Enter your message..."); // 输入框提示文本
        inputArea.setPrefHeight(60);

        root.getChildren().addAll(historyArea, messageList, inputArea); // 将历史消息区域、消息列表和输入框添加到root中

        Scene scene = new Scene(root, 300, 400);

        // 新窗口初始位置(主要是为了自己方便一点,懒得动鼠标)
        double primaryX = parentStageStage.getX();
        double primaryY = parentStageStage.getY();
        double primaryWidth = parentStageStage.getWidth();
        double primaryHeight = parentStageStage.getHeight();
        stage.setX(primaryX + primaryWidth );
        stage.setY(primaryY-primaryHeight/2+ childWindowOffsetY);
        childWindowOffsetY += 100;

        stage.setScene(scene);

        // 模拟发送消息
        inputArea.setOnKeyPressed(event -> {
            if (event.getCode() == KeyCode.ENTER) {
                String message = inputArea.getText().trim();
                inputArea.clear();
                if (!message.isEmpty()) {
                    member.sendMessage(message); // 发送消息给成员对象
                    broadcastMessage(member, message); // 通过当前成员对象,广播消息给其他成员
                    messageList.scrollTo(messageList.getItems().size() - 1); // 聚焦到最后一条消息
                } else {
                    showErrorAlert();
                }
            }
        });

        // 监听新消息
        member.setOnMessageReceived(new MessageReceivedListener() {
            @Override
            public void onMessageReceived(String message) {
                // 更新消息列表
                Platform.runLater(() -> messageList.getItems().add(message));
            }
            @Override
            public void onHistoryUpdated(String historyText) {
                // 更新历史消息
                Platform.runLater(() -> historyArea.setText(historyText));
            }
        });

        groupChatMembers.add(member);

        stage.show();
    }

    // 错误提示窗口
    private void showErrorAlert() {
        Alert alert = new Alert(Alert.AlertType.ERROR);
        alert.setTitle("Error");
        alert.setHeaderText(null);
        alert.setContentText("Message cannot be empty");
        alert.showAndWait();
    }

    // 广播消息给同一群组的其他成员,也就是其他成员获得sender的message
    private void broadcastMessage(GroupChatMember sender, String message) {
        for (GroupChatMember member : groupChatMembers) {
            if (member != sender && member.getGroupName().equals(sender.getGroupName())) {
                member.receiveMessage(sender.getUsername(), message);
            }
        }
    }

    // 颜色转换:RGB
    private String toRGBCode(Color color) {
        int r = (int) (color.getRed() * 255);
        int g = (int) (color.getGreen() * 255);
        int b = (int) (color.getBlue() * 255);
        return String.format("#%02x%02x%02x", r, g, b);
    }
}

// 群聊成员类
class GroupChatMember {
    private static int memberID = 0;
    private final String groupName;
    private final String username;
    private final List<String> history;
    private MessageReceivedListener listener;

    public GroupChatMember(String groupName) {
        this.groupName = groupName;
        this.username = "成员" + getNextMemberID();
        this.history = new ArrayList<>();
    }

    private static synchronized int getNextMemberID() {
        return ++memberID;
    }

    public String getGroupName() {
        return groupName;
    }
    public String getUsername() {
        return username;
    }
    public List<String> getHistory() {
        return history;
    }
    public void setOnMessageReceived(MessageReceivedListener listener) {
        this.listener = listener;
        updateHistory();
    }

    public void sendMessage(String message) {
        history.add(username + ": " + message);
        if (listener != null) {
            listener.onMessageReceived(username + ": " + message);
            updateHistory();
        }
    }

    public void receiveMessage(String sender, String message) {
        history.add(sender +": "+ message);
        if (listener != null) {
            listener.onMessageReceived(sender +": "+ message);
            updateHistory();
        }
    }

    private void updateHistory() {
        StringBuilder builder = new StringBuilder();
        for (String message : history) {
            builder.append(message).append("\n");
        }
        if (listener != null) {
            listener.onHistoryUpdated(builder.toString());
        }
    }
}

// 监听消息接收和历史消息更新的接口
interface MessageReceivedListener {
    void onMessageReceived(String message);
    void onHistoryUpdated(String historyText);
}
相关推荐
老猿讲编程27 分钟前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk1 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*1 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue1 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man1 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
测开小菜鸟2 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity2 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天3 小时前
java的threadlocal为何内存泄漏
java
caridle3 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
萧鼎3 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步