javaFX+CSS+外用包开发东北大学2020级暑期实训项目——东大颐养中心

东北大学2020级暑期实训项目——东大颐养中心

前言

项目名称:东北大学2020级暑期实训项目——东大颐养中心
开发语言:java
开发者:杨富超
使用工具:IDEA2020、SceneBuilder8.0、javaFX8.0、JFoenix库等

架构:MVC
任何疑问,欢迎留言,
尊重劳动成果,期待一键三连

链接JFoenix库 SceneBuilder8.5

系统展示

超级管理员登录界面及其添加普通管理人员的操作界面
javaFX+CSS+外用包开发东北大学2020级暑期实训项目——东大颐养中心
部分代码结构太长放不下
javaFX+CSS+外用包开发东北大学2020级暑期实训项目——东大颐养中心
部分UI图
javaFX+CSS+外用包开发东北大学2020级暑期实训项目——东大颐养中心
javaFX+CSS+外用包开发东北大学2020级暑期实训项目——东大颐养中心

项目思路分享

项目分层:

javaFX+CSS+外用包开发东北大学2020级暑期实训项目——东大颐养中心
实训项目一共分为四层:用户管理、评估管理、楼宇管理、职工管理。
我们可以用MVC架构来做,Model:放工具类,放文件,放职工、房屋、模板等实体类;view:放各个界面的UI类,fxml,css;Controller:用来放每个FXMl图的控件管理类,比如HouseController、TemplateController等

思路

简单来说,不要重复造*,要提高代码的复用率,造一个*demo就行,其他类直接粘贴复制demo的结构,改改参数,数据就行了。这样项目做起来会很快。根据老师发的文件,其实需要做的模板就几个,一个是增删改查,一个是评估模板类,一个是菜单界面类。我的代码里面Controller下面的类结构就是根据两到三中模板重复使用写出来的。view下面的类是通过一个模板写出来的,几乎一样。为了view界面每个界面都有小化、关闭等操作,我创建了一个window父类

window父类

package View;

import javafx.scene.Cursor;
import javafx.scene.Parent;
import javafx.scene.image.Image;
import javafx.stage.Stage;
/*父类Stage  window*/
/**
 * 所有窗口的父类
 * created by 杨富超
 */
public abstract class window extends Stage {

    Parent root;
    private double xOffset;
    private double yOffset;
    /**
     * 窗口移动方法
     */
    public void setIcon(){

        //getIcons().add(new Image(getClass().getResourceAsStream("/View/Fxml/CSS/Image/icon.png")));

    }
    public void move() {
        root.setOnMousePressed(event -> {
            xOffset = getX() - event.getScreenX();
            yOffset = getY() - event.getScreenY();
            getRoot().setCursor(Cursor.CLOSED_HAND);
        });
        root.setOnMouseDragged(event -> {

            setX(event.getScreenX() + xOffset);
            setY(event.getScreenY() + yOffset);
        });
        root.setOnMouseReleased(event -> {
            root.setCursor(Cursor.DEFAULT);

        });
    }

    /**
     * 抽象方法  窗口退出操作
     */
    abstract public void quit();

    /**
     * 最小化
     */
    abstract public void minimiser();

    /**
     * 获取root
     *
     * @return
     */
    public Parent getRoot() {
        return root;
    }

    /**
     * 选择界面元素
     * @param id
     * @return
     */
    public Object $(String id) {
        return (Object) root.lookup("#" + id);
    }

}

一、楼宇管理()

模块分析

功能总的来说增删改查,单选框,多选框删除,用Tableview来做一个表格,需要几个不同的信息,就填加几个Column,记得一定要把每个Comlumn与对应的属性相绑定,不要绑定错误,绑定错误是没有信息出来的 nameColumn.setCellValueFactory(new PropertyValueFactory<Patient, String>(“name”));//id为person的属性`
还可以设置每个Column是可编辑的
> Callback<TableColumn<Patient, String>,
TableCell<Patient, String>> cellFactory
= (TableColumn<Patient, String> p) -> new EditingCell_patient();
//为每列设定cellFactory
nameColumn.setCellFactory(cellFactory);

这样方便修改,要有一个datalist用来保存Arraylist<House>的元素,
tableView.setItems(data);
tableView.setEditable(true);

data是表格中内容的list,houseArrayList是读取文件是保存House对象的类,两个类几乎同时在增减元素,tmp这个list是在查询时作为clone的list来操作的

FXML界面
javaFX+CSS+外用包开发东北大学2020级暑期实训项目——东大颐养中心

楼宇FXML代码

<?xml version="1.0" encoding="UTF-8"?>

<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXRadioButton?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.paint.RadialGradient?>
<?import javafx.scene.paint.Stop?>
<?import javafx.scene.text.Font?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="1200.0" stylesheets="@CSS/House.css" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.HouseController">
    <top>
        <AnchorPane prefHeight="169.0" prefWidth="1200.0" style="-fx-background-color: #7bbfea;" BorderPane.alignment="CENTER">
            <children>
                <ImageView fitHeight="170.0" fitWidth="514.0" layoutY="1.0" pickOnBounds="true" preserveRatio="true">
                    <image>
                        <Image url="@CSS/Image/neulabel.png" />
                    </image>
                </ImageView>
                <ImageView fitHeight="150.0" fitWidth="200.0" layoutX="723.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true" />
                <Label layoutX="723.0" layoutY="28.0" prefHeight="144.0" prefWidth="471.0" text="楼宇界面">
                    <font>
                        <Font name="System Bold" size="66.0" />
                    </font>
                </Label>
                <Button fx:id="minimiser1" layoutX="1120.0" layoutY="13.0" mnemonicParsing="false" stylesheets="@CSS/House.css" />
                <Button fx:id="quit1" layoutX="1154.0" layoutY="13.0" mnemonicParsing="false" stylesheets="@CSS/House.css" />
                <JFXButton fx:id="returnButton" buttonType="RAISED" layoutX="1056.0" layoutY="13.0" onAction="#returnButtonOnAction" style="-fx-background-color: #cde6c7;" text="返回" />
                <ImageView fitHeight="166.0" fitWidth="164.0" layoutX="505.0" layoutY="3.0" pickOnBounds="true" preserveRatio="true">
                    <image>
                        <Image url="@CSS/Image/Memuhospital.png" />
                    </image>
                </ImageView>
            </children>
        </AnchorPane>
    </top>
    <bottom>
        <AnchorPane fx:id="username" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
            <children>
                <Label fx:id="label" layoutX="270.0" layoutY="82.0" prefHeight="20.0" prefWidth="134.0" visible="false" />
                <JFXButton fx:id="addButton" buttonType="RAISED" layoutX="995.0" layoutY="97.0" onAction="#add" prefHeight="45.0" prefWidth="158.0" style="-fx-background-color: #cde6c7;" text="新增楼宇">
                    <font>
                        <Font name="System Bold" size="19.0" />
                    </font>
                </JFXButton>
                <JFXTextField fx:id="nametext" layoutX="23.0" layoutY="67.0" promptText="名称" />
                <JFXComboBox fx:id="numberComboBox" cache="true" layoutX="263.0" layoutY="32.0" prefHeight="30.0" prefWidth="202.0" promptText="楼号" style="-fx-background-color: #cde6c7;">
                    <focusColor>
                        <RadialGradient centerX="0.5" centerY="0.5" radius="0.5">
                            <stops>
                                <Stop color="#040814" />
                                <Stop color="WHITE" offset="1.0" />
                            </stops>
                        </RadialGradient>
                    </focusColor>
                </JFXComboBox>
            <JFXTextField fx:id="idtext" layoutX="23.0" layoutY="32.0" promptText="ID" />
            <JFXComboBox fx:id="floorComboBox" cache="true" layoutX="499.0" layoutY="32.0" prefHeight="30.0" prefWidth="202.0" promptText="楼层" style="-fx-background-color: #cde6c7;">
               <focusColor>
                  <RadialGradient centerX="0.5" centerY="0.5" radius="0.5">
                     <stops>
                        <Stop color="#040814" />
                        <Stop color="WHITE" offset="1.0" />
                     </stops>
                  </RadialGradient>
               </focusColor>
            </JFXComboBox>
            <JFXComboBox fx:id="roomComboBox" cache="true" layoutX="737.0" layoutY="32.0" prefHeight="30.0" prefWidth="202.0" promptText="房间" style="-fx-background-color: #cde6c7;">
               <focusColor>
                  <RadialGradient centerX="0.5" centerY="0.5" radius="0.5">
                     <stops>
                        <Stop color="#040814" />
                        <Stop color="WHITE" offset="1.0" />
                     </stops>
                  </RadialGradient>
               </focusColor>
            </JFXComboBox>
            <JFXRadioButton fx:id="noButton" layoutX="335.0" layoutY="138.0" onAction="#radio1Onaction" text="否" />
            <Label layoutX="263.0" layoutY="124.0" text="稀有房间" underline="true" />
            <JFXRadioButton fx:id="yesButton" layoutX="335.0" layoutY="109.0" onAction="#radioOnaction" text="是" />
            <JFXTextField fx:id="maxnumtext" layoutX="23.0" layoutY="126.0" promptText="最大容纳量" />
            <JFXComboBox fx:id="racetypeCombobox" cache="true" layoutX="489.0" layoutY="96.0" prefHeight="30.0" prefWidth="139.0" promptText="稀有类型" style="-fx-background-color: #cde6c7;" visible="false">
               <focusColor>
                  <RadialGradient centerX="0.5" centerY="0.5" radius="0.5">
                     <stops>
                        <Stop color="#040814" />
                        <Stop color="WHITE" offset="1.0" />
                     </stops>
                  </RadialGradient>
               </focusColor>
            </JFXComboBox>
            <JFXTextField fx:id="tmptext" layoutX="263.0" layoutY="77.0" prefHeight="30.0" prefWidth="36.0" visible="false" />
            <JFXTextField fx:id="informationtext" layoutX="737.0" layoutY="111.0" promptText="备注" />
            <JFXComboBox fx:id="roomidCombobox" layoutX="489.0" layoutY="141.0" prefHeight="30.0" prefWidth="140.0" promptText="床位号码" visible="false" />
            </children>
        </AnchorPane>
    </bottom>
    <center>
        <GridPane BorderPane.alignment="CENTER">
            <columnConstraints>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            </columnConstraints>
            <rowConstraints>
                <RowConstraints maxHeight="195.0" minHeight="10.0" prefHeight="96.0" vgrow="SOMETIMES" />
                <RowConstraints maxHeight="304.0" minHeight="10.0" prefHeight="304.0" vgrow="SOMETIMES" />
            </rowConstraints>
            <children>
                <TableView fx:id="tableView" prefHeight="380.0" prefWidth="1200.0" GridPane.rowIndex="1">
                    <columns>
                        <TableColumn fx:id="idColumn" prefWidth="105.0" text="ID" />
                        <TableColumn fx:id="nameColumn" prefWidth="117.0" text="名称" />
                        <TableColumn fx:id="numberColumn" minWidth="3.0" prefWidth="153.0" text="楼号" />
                        <TableColumn fx:id="floorColumn" prefWidth="164.0" text="楼层" />
                        <TableColumn fx:id="roomColumn" minWidth="0.0" prefWidth="148.0" text="房间" />
                        <TableColumn fx:id="maxnumColumn" minWidth="0.0" prefWidth="138.0" text="最大容纳量" />
                        <TableColumn fx:id="raceColumn" minWidth="0.0" prefWidth="55.0" text="稀有房间" />
                  <TableColumn fx:id="race_typeColumn" prefWidth="72.0" text="稀有类型" />
                  <TableColumn fx:id="informationColumn" prefWidth="261.0" text="备注" />
                        <TableColumn fx:id="selectColumn" prefWidth="136.0" text="选择" />
                    </columns>
               <cursor>
                  <Cursor fx:constant="SW_RESIZE" />
               </cursor>
               <columnResizePolicy>
                  <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
               </columnResizePolicy>
                </TableView>
                <AnchorPane prefHeight="78.0" prefWidth="1200.0">
                    <children>
                        <Label fx:id="label1" layoutX="439.0" layoutY="14.0" prefHeight="22.0" prefWidth="106.0" visible="false" />
                        <JFXButton fx:id="deleteButton" buttonType="RAISED" layoutX="1010.0" layoutY="22.0" onAction="#delete" prefHeight="76.0" prefWidth="152.0" style="-fx-background-color: #FF6A6A;" text="删   除">
                            <font>
                                <Font size="30.0" />
                            </font>
                        </JFXButton>
                    </children>
                </AnchorPane>
            </children>
        </GridPane>
    </center>
</BorderPane>

楼宇实体类代码

package Model.Entity;

import java.io.Serializable;

public class House implements Cloneable , Serializable {
    private String building_id;
    private String building_name;
    private String building_number;
    private String building_floor;
    private String building_room;
    private String maxnumber;
    private String race;
    private String roomname;
    private String information;
    private boolean selected;
    public House(String building_id,String building_name,String building_number,String building_floor,String building_room,String maxnumber,String rare,String roomname,String information)
    {
        this.building_id=building_id;
        this.building_name=building_name;
        this.building_number=building_number;
        this.building_floor=building_floor;
        this.building_room=building_room;
        this.maxnumber=maxnumber;
        this.race=rare;
        this.roomname=roomname;
        this.information=information;
    }

    public String getBuilding_name() {
        return building_name;
    }

    public void setBuilding_name(String building_name) {
        this.building_name = building_name;
    }

    public String getBuilding_number() {
        return building_number;
    }

    public void setBuilding_number(String building_number) {
        this.building_number = building_number;
    }

    public String getBuilding_floor() {
        return building_floor;
    }

    public void setBuilding_floor(String building_floor) {
        this.building_floor = building_floor;
    }

    public String getBuilding_room() {
        return building_room;
    }

    public void setBuilding_room(String building_room) {
        this.building_room = building_room;
    }

    public String getBuilding_id() {
        return building_id;
    }

    public void setBuilding_id(String building_id) {
        this.building_id = building_id;
    }

    public String getMaxnumber() {
        return maxnumber;
    }

    public void setMaxnumber(String maxnumber) {
        this.maxnumber = maxnumber;
    }

    public String getRace() {
        return race;
    }

    public void setRace(String rare) {
        this.race = rare;
    }

    public String getRare_type() {
        return roomname;
    }

    public void setRare_type(String rare_type) {
        this.roomname = rare_type;
    }

    public String getInformation() {
        return information;
    }

    public void setInformation(String information) {
        this.information = information;
    }

    public String getRoomname() {
        return roomname;
    }

    public void setRoomname(String roomname) {
        this.roomname = roomname;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }
    @Override
    public House clone() throws CloneNotSupportedException {
        return (House) super.clone();//克隆出一个对象
    }
    @Override
    public String toString() {
        return building_id+","+building_name+","+building_number+","+building_floor+","+building_number+","+maxnumber+","+race+","+roomname+","+information+"\n";
    }
}

楼宇view类代码

package View;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Tooltip;
import javafx.stage.StageStyle;
import java.io.IOException;
/*房屋UI*/
public class House extends window {
    public House() throws IOException {
        root = FXMLLoader.load(getClass().getResource("fxml/House.fxml"));
        initStyle(StageStyle.UNDECORATED);
        setScene(new Scene(root, 1200, 800));
        setResizable(false);
        move();
        quit();
        setIcon();
        minimiser();
        show();
    }
    @Override
    public void quit() {
        ((Button) $("quit1")).setTooltip(new Tooltip("关闭"));//当鼠标悬停在节点上时,它们通常用于在场景图中显示有关节点的附加信息。任何节点都可以显示工具提示。
        ((Button) $("quit1")).setOnAction(event -> {
            close();//关闭
        });//监听
    }

    @Override
    public void minimiser() {
        ((Button) $("minimiser1")).setTooltip(new Tooltip("最小化"));
        ((Button) $("minimiser1")).setOnAction(event -> {
            setIconified(true);//将此属性设置为true将隐藏舞台,但不显示它的图标。
        });
    }
}

楼宇控件管理类

package Controller;
import Model.CellFactory;
import Model.EditingCell_House;
import Model.Entity.House;
import Model.Entity.Question;
import Model.Tool.ioTool;
import View.Login;
import View.Memu;
import com.jfoenix.controls.*;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 控制层
 */
public class HouseController {
    @FXML
    private TableView<House> tableView;

    @FXML
    private TableColumn<House, String> idColumn;

    @FXML
    private TableColumn<House, String> nameColumn;

    @FXML
    private TableColumn<House, String> numberColumn;

    @FXML
    private TableColumn<House, String> floorColumn;
    @FXML
    private TableColumn<House, String> roomColumn;
    @FXML
    private TableColumn<House, String> maxnumColumn;
    @FXML
    private TableColumn<House, String> raceColumn;
    @FXML
    private TableColumn<House, String> race_typeColumn;
    @FXML
    private TableColumn<House, String> informationColumn;

    @FXML
    private TableColumn<House, Boolean> selectColumn;

    @FXML
    private JFXTextField idtext;

    @FXML
    private JFXTextField nametext;
    @FXML
    private JFXTextField maxnumtext;
    @FXML
    private JFXTextField tmptext;
    @FXML
    private JFXTextField informationtext;
    @FXML
    private JFXComboBox<String> numberComboBox;
    @FXML
    private JFXComboBox<String> floorComboBox;
    @FXML
    private JFXComboBox<String> roomComboBox;
    @FXML
    private JFXComboBox<String> racetypeCombobox;
    @FXML
    private JFXComboBox<String> roomidCombobox;
    @FXML
    private JFXButton returnButton;
    @FXML
    private JFXRadioButton yesButton;
    @FXML
    private JFXRadioButton noButton;

    private ioTool tool=new ioTool();
    //表格内容list
    private final ObservableList<House> data = FXCollections.observableArrayList();

    //文件目录
    private final Path path = Paths.get("src/Model/House.txt");

    //与表格内容同步的数据list
    private final List<House> employeeList = new ArrayList<>();
    private final List<House> tmp = new ArrayList<>();
    public HouseController()
    {

    }
    public void returnButtonOnAction(ActionEvent event) throws InterruptedException, IOException {
        Thread.sleep(300);
        Stage stage=(Stage) returnButton.getScene().getWindow();
        stage.close();
    }
    /**
     * 新增
     * @param event
     * @throws IOException
     */
    @FXML
    public void add(ActionEvent event) throws IOException {//需要更改
        if (idtext.getText() != null && nametext.getText() != null && maxnumtext.getText() != null && informationtext.getText() != null&&numberComboBox.getValue().toString() != null&& floorComboBox.getValue().toString() != null && roomComboBox.getValue().toString() != null) {
            //获得文本框的输入
            if (tmptext.getText().equals("是")){
                House person = new House(
                        idtext.getText(),
                        nametext.getText(),
                        numberComboBox.getValue().toString(),
                        floorComboBox.getValue().toString(),
                        roomComboBox.getValue().toString(),
                        maxnumtext.getText(),
                        tmptext.getText(),
                        racetypeCombobox.getValue().toString(),
                        informationtext.getText());
                data.add(person);
                employeeList.add(person);
            } else if (tmptext.getText().equals("否")) {
                House person = new House(
                        idtext.getText(),
                        nametext.getText(),
                        numberComboBox.getValue().toString(),
                        floorComboBox.getValue().toString(),
                        roomComboBox.getValue().toString(),
                        maxnumtext.getText(),
                        tmptext.getText(),
                        roomidCombobox.getValue().toString(),
                        informationtext.getText()
                );
                data.add(person);
                employeeList.add(person);
            }
        }
            //添加到表格中

            //同步添加到list
            System.out.println("[add]: " +nametext.getText() + " " + tmptext.getText() );

            //将list写入到文件中
           tool.WriteObject(employeeList,path.toString());

            //清空文本输入框//
            idtext.clear();
            nametext.clear();
            maxnumtext.clear();
            informationtext.clear();
        }
    /**
     * 单选框监听*/
    @FXML
    public void radioOnaction(ActionEvent event)
    {
        yesButton.setSelected(true);
        yesButton.requestFocus();
        noButton.setSelected(false);
        racetypeCombobox.setVisible(true);
        roomidCombobox.setVisible(false);
        tmptext.setText(yesButton.getText());
        System.out.println(tmptext.getText());
    }
    /**
     * 单选框监听*/
    @FXML
    public void radio1Onaction(ActionEvent event)
    {
        noButton.setSelected(true);
        noButton.requestFocus();
        yesButton.setSelected(false);
        racetypeCombobox.setVisible(false);
        roomidCombobox.setVisible(true);
        tmptext.setText(noButton.getText());
    }
    /**
     * 删除
     * @param event
     * @throws IOException
     */
    @FXML
    void delete(ActionEvent event) throws IOException {
        deleteStudents();
    }

    private boolean deleteStudents() throws IOException {
        int size = data.size();
        if (size <= 0) {
            return false;
        }
        //遍历所选选项
        for (int i = size - 1; i >= 0; i--) {
            House p = data.get(i);
            if (p.isSelected()) {//被选中则删除

                //从list中移除
                employeeList.remove(p);
                //将list写入到文件中
                tool.WriteObject(employeeList,path.toString());
                //从表格中移除
                data.remove(p);
            }
        }
        return true;
    }

    @FXML
    private void initialize() throws IOException{
        //绑定每一列,需要添加
        numberComboBox.getItems().addAll("急诊楼","住院楼","手术楼");
        floorComboBox.getItems().addAll("第一层","第二层","第三层");
        roomComboBox.getItems().addAll("01","02","03");
        roomidCombobox.getItems().addAll("A","B","C");
        racetypeCombobox.getItems().addAll("浴室","娱乐室","棋牌室");

        idColumn.setCellValueFactory(new PropertyValueFactory<House, String>("building_id"));//id为person的属性
        nameColumn.setCellValueFactory(new PropertyValueFactory<House, String>("building_name"));
        numberColumn.setCellValueFactory(new PropertyValueFactory<House, String>("building_number"));
        floorColumn.setCellValueFactory(new PropertyValueFactory<House, String>("building_floor"));
        roomColumn.setCellValueFactory(new PropertyValueFactory<House, String>("building_room"));
        maxnumColumn.setCellValueFactory(new PropertyValueFactory<House, String>("maxnumber"));
        raceColumn.setCellValueFactory(new PropertyValueFactory<House, String>("race"));
        race_typeColumn.setCellValueFactory(new PropertyValueFactory<House, String>("roomname"));
        informationColumn.setCellValueFactory(new PropertyValueFactory<House, String>("information"));
        selectColumn.setCellValueFactory(new PropertyValueFactory<House, Boolean>("selected"));
        //设定数据list
        tableView.setItems(data);
        tableView.setEditable(true);
        try {
            if(tool.ReadObject(path.toString())!=null)
                employeeList.addAll((Collection<? extends House>)tool.ReadObject(path.toString()));
        } catch (ClassNotFoundException e) {
            System.out.println("没用此文件!");
        }
        catch (IOException e)
        {
            System.out.println("文件为空");
        }
        data.addAll(employeeList);
        //初始化多选框,默认全为false,当为true则被选中
        selectColumn.setCellFactory(
                CellFactory.tableCheckBoxColumn(new Callback<Integer, ObservableValue<Boolean>>() {
                    @Override
                    public ObservableValue<Boolean> call(Integer index) {
                        final House employee = tableView.getItems().get(index);
                        ObservableValue<Boolean> ret =
                                new SimpleBooleanProperty(employee, "selected", employee.isSelected());//SimpleBooleanProperty(Object bean, String name, boolean initialValue)
                        ret.addListener(new ChangeListener<Boolean>() {
                            @Override
                            public void changed(
                                    ObservableValue<? extends Boolean> observable,
                                    Boolean oldValue, Boolean newValue) {
                                employee.setSelected(newValue);
                            }
                        });
                        return ret;
                    }
                }));

        /**
         * 单元格都可修改,但暂时未能保存到文件中,为后续优化功能
         */
        //每个单元格都可编辑
        Callback<TableColumn<House, String>,
                TableCell<House, String>> cellFactory
                = (TableColumn<House, String> p) -> new EditingCell_House();

        //为每列设定cellFactory
        idColumn.setCellFactory(cellFactory);
        /*  selectedColumn.setCellFactory(cellFactory);*/
        nameColumn.setCellFactory(cellFactory);
        numberColumn.setCellFactory(cellFactory);
        floorColumn.setCellFactory(cellFactory);
        roomColumn.setCellFactory(cellFactory);
        maxnumColumn.setCellFactory(cellFactory);
        raceColumn.setCellFactory(cellFactory);
        race_typeColumn.setCellFactory(cellFactory);
        informationColumn.setCellFactory(cellFactory);
        System.out.println("[initialize]: ");
    }
}

工具类

序列化,反序列化代码,得到年龄的代码,设置多选框代码

package Model.Tool;
import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

public class ioTool {

    public ioTool() {

    }
    //反序列化,返回一个数组,未给出泛型的数组
    public Object ReadObject(String path) throws IOException, ClassNotFoundException {
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
                ArrayList arrayliast = (ArrayList) ois.readObject();
                return arrayliast;
    }
    public Object ReadObject_string(String path) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        String arrayliast = (String) ois.readObject();
        return arrayliast;
    }
    public Object ReadObject_Object(String path) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        Object arrayliast = (Object) ois.readObject();
        return arrayliast;
    }
    //序列化
    public void WriteObject(Object object, String path) throws IOException {

                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
                oos.writeObject(object);
                oos.flush();
                oos.close();
    }
    //得到时间差
    public  long getTimeDifferenceAboutSecond(Date beginTime, Date endTime) throws ParseException {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String begin = df.format(beginTime);
        String end = df.format(endTime);
        Calendar now = Calendar.getInstance();
        Calendar birthday = Calendar.getInstance();
        now.setTime(df.parse(end));
        birthday.setTime(df.parse(begin));
        int age = now.get(Calendar.YEAR) - birthday.get(Calendar.YEAR);
        if (now.get(Calendar.DAY_OF_YEAR) < birthday.get(Calendar.DAY_OF_YEAR)) {
            age -= 1;
        }
        return age;
    }
}


工厂类,负责表格每一列的初始化对应

package Model;

import javafx.beans.value.ObservableValue;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.util.Callback;
import javafx.util.StringConverter;

/**
 * 工厂类,负责表格每一列的初始化对应
 */
public class CellFactory {

    public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> tableCheckBoxColumn(
            Callback<Integer, ObservableValue<Boolean>> paramCallback) {
        return tableCheckBoxColumn(paramCallback, null);
    }

    public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> tableCheckBoxColumn(
            final Callback<Integer, ObservableValue<Boolean>> getSelectedProperty,
            final StringConverter<T> converter) {
        return new Callback<TableColumn<S, T>, TableCell<S, T>>() {
            @Override
            public TableCell<S, T> call(TableColumn<S, T> paramTableColumn) {
                return new CheckBoxTableCell<S, T>(getSelectedProperty, converter);
            }
        };
    }
}

单元格都可修改,可自己写个save函数保存,
/**
* 保存*/
@FXML
public void save(ActionEvent event) throws IOException {
tool.WriteObject(questionList,path.toString());
}

package Model;
import Model.Entity.Employee;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
/**
 * 表格单元格修改类
 * 单元格都可修改,但暂时未能保存到文件中,为后续优化功能
 */
public class EditingCell extends TableCell<Employee, String> {

    private TextField textField;

    public EditingCell() {
    }

    @Override
    public void startEdit() {
        if (!isEmpty()) {
            super.startEdit();
            createTextField();
            setText(null);
            setGraphic(textField);
            textField.selectAll();
        }
    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setText((String) getItem());
        setGraphic(null);
    }

    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);

        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
            if (isEditing()) {
                if (textField != null) {
                    textField.setText(getString());
                }
                setText(null);
                setGraphic(textField);
            } else {
                setText(getString());
                setGraphic(null);
            }
        }
    }

    private void createTextField() {
        textField = new TextField(getString());
        textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
        textField.focusedProperty().addListener(
                (ObservableValue<? extends Boolean> arg0,
                 Boolean arg1, Boolean arg2) -> {
                    if (!arg2) {
                        commitEdit(textField.getText());
                    }
                });
    }

    private String getString() {
        return getItem() == null ? "" : getItem().toString();
    }
}


二、评估管理

模块分析

分为问题增删改查,模板的增删改查,评估界面的创建,
评估界面因为是三个固定的问题,所以只用创建三个面板,加入单选框按钮就行

Contreller控件代码

package Controller;
import Model.CellFactory;
import Model.Entity.Assess;
import Model.Tool.ioTool;
import View.Question;
import View.Template;
import com.jfoenix.controls.*;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 控制层:评估界面的控件
 */
public class AssessController {
    @FXML
    private TableView<Assess> tableView;
    @FXML
    private TableColumn<Assess, String> nameColumn;
    @FXML
    private TableColumn<Assess, String> sexColumn;
    @FXML
    private TableColumn<Assess, String> templatenameColumn;
    @FXML
    private TableColumn<Assess, String> templatetypeColumn;
    @FXML
    private TableColumn<Assess, String>datetimeColumn;
    @FXML
    private TableColumn<Assess, String> assesspersonColumn;
    @FXML
    private TableColumn<Assess, String>suggestColumn;
    @FXML
    private TableColumn<Assess, Boolean> selectColumn;
    @FXML
    private JFXTextField idsearch;
    @FXML
    private JFXComboBox<String> assessCombobox;
    @FXML
    private JFXButton returnButton;
    private ioTool tool=new ioTool();
    //表格内容list
    private final ObservableList<Assess> data = FXCollections.observableArrayList();
    //文件目录
    private final Path path = Paths.get("src/Model/Assess.txt");

    //与表格内容同步的数据list
    private final List<Assess> assessArrayList = new ArrayList<>();
    private final List<Assess> tmp = new ArrayList<>();
    public AssessController()
    {

    }
    public void templateButtonOnaction(ActionEvent event) throws IOException {
        new Template();
    }
    public void QuestionButtonOnaction(ActionEvent event){
        try {
            new Question();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void returnButtonOnAction(ActionEvent event) throws InterruptedException {
        Thread.sleep(300);
        Stage stage=(Stage) returnButton.getScene().getWindow();
        stage.close();

    }
    /*
     * 下拉框,搜索旁边的combobox*/
    @FXML
    void assessComboboxOnaction(ActionEvent event) throws CloneNotSupportedException {

        for (Assess p : assessArrayList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(assessArrayList);
        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Assess p : assessArrayList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getTemplate_type().equals(assessCombobox.getValue().toString())) {
                data.add(p);
            }
        }
    }
    /**
     * 删除
     *
     * @param event
     * @throws IOException
     */
    @FXML
    void delete(ActionEvent event) throws IOException {
        deleteStudents();
    }
    public boolean deleteStudents()throws IOException {
        int size = data.size();
        if (size <= 0) {
            return false;
        }
        //遍历所选选项
        for (int i = size - 1; i >= 0; i--) {
            Assess p = data.get(i);
            if (p.isSelected()) {//被选中则删除
                //从list中移除
                assessArrayList.remove(p);
                //将list写入到文件中
                tool.WriteObject(assessArrayList,path.toString());
                //从表格中移除
                data.remove(p);
            }
        }
        return true;
    }
    /**保存修改
     * */
    @FXML
    public void save(ActionEvent event) throws IOException {
        tool.WriteObject(assessArrayList,path.toString());
    }
    /**
     * 查找,仅支持通过id或name查找
     * @param event
     * @throws CloneNotSupportedException
     */
    @FXML
    void search(ActionEvent event) throws CloneNotSupportedException {
        for (Assess p : assessArrayList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(assessArrayList);

        String name = idsearch.getText();

        //若为空时,则添加回所有数据
        if (name.equals("")) {
            data.addAll(assessArrayList);
        }

        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Assess p : assessArrayList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getName().equals(name)) {
                data.add(p);
            }
        }
        idsearch.clear();
    }

    @FXML
    private void initialize() throws IOException {
        //绑定每一列,需要添加
        assessCombobox.getItems().addAll("A","B","C");
        nameColumn.setCellValueFactory(new PropertyValueFactory<Assess, String>("name"));
        sexColumn.setCellValueFactory(new PropertyValueFactory<Assess, String>("sex"));
        templatenameColumn.setCellValueFactory(new PropertyValueFactory<Assess, String>("template_name"));
        templatetypeColumn.setCellValueFactory(new PropertyValueFactory<Assess, String>("template_type"));
        datetimeColumn.setCellValueFactory(new PropertyValueFactory<Assess, String>("datetime"));
        assesspersonColumn.setCellValueFactory(new PropertyValueFactory<Assess, String>("assessperson"));
        suggestColumn.setCellValueFactory(new PropertyValueFactory<Assess, String>("suggest"));
        selectColumn.setCellValueFactory(new PropertyValueFactory<Assess, Boolean>("selected"));
        //设定数据list
        tableView.setItems(data);
        tableView.setEditable(true);

        //按行读取文件,存入list中
        try{
            if(tool.ReadObject(path.toString())!=null)
                assessArrayList.addAll((Collection<? extends Assess>)tool.ReadObject(path.toString()));
            data.addAll(assessArrayList);
        } catch (ClassNotFoundException e) {
            System.out.println("没用此文件!");
        }
        catch (IOException e)
        {
            System.out.println("文件为空");
        }
        for (Assess assess:assessArrayList)
        {
            System.out.println(assess.getName()+","+assess.getSex()+","+assess.getTemplate_name());
        }
        //初始化多选框,默认全为false,当为true则被选中
        try {
            selectColumn.setCellFactory(
                    CellFactory.tableCheckBoxColumn(new Callback<Integer, ObservableValue<Boolean>>() {
                        @Override
                        public ObservableValue<Boolean> call(Integer index) {
                            final Assess employee = tableView.getItems().get(index);
                            ObservableValue<Boolean> ret =
                                    new SimpleBooleanProperty(employee, "selected", employee.isSelected());//SimpleBooleanProperty(Object bean, String name, boolean initialValue)
                            ret.addListener(new ChangeListener<Boolean>() {
                                @Override
                                public void changed(
                                        ObservableValue<? extends Boolean> observable,
                                        Boolean oldValue, Boolean newValue) {
                                    employee.setSelected(newValue);
                                }
                            });
                            return ret;
                        }
                    }));
        }
        catch (Exception e)
        {
            e.printStackTrace();

        }
        System.out.println("[initialize]: " );
    }
}

package Controller;
import Model.CellFactory;
import Model.EditingCell_patient;
import Model.Entity.Assess;
import Model.Entity.Patient;
import Model.Entity.Template;
import Model.Tool.ioTool;
import com.jfoenix.controls.*;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * 控制层:问卷界面的控件
 */
public class AssessfinalController {
    @FXML
    private Label onelabel;
    @FXML
    private Label twolabel;
    @FXML
    private Label threelabel;
    @FXML
    private Label oneanswer;
    @FXML
    private Label twoanswer;
    @FXML
    private Label threeanswer;
    @FXML
    private JFXRadioButton oneoneradio;
    @FXML
    private JFXRadioButton onetworadio;
    @FXML
    private JFXRadioButton onethreeradio;
    @FXML
    private JFXRadioButton twooneradio;
    @FXML
    private JFXRadioButton twotworadio;
    @FXML
    private JFXRadioButton twothreeradio;
    @FXML
    private JFXRadioButton threeoneradio;
    @FXML
    private JFXRadioButton threetworadio;
    @FXML
    private JFXRadioButton threethreeradio;
    @FXML
    private JFXComboBox  templateCombobox;
    @FXML
    private Label loginnamelabel;
    @FXML
    private JFXButton addButton;
    private String assesspersonnme;
    private Patient patient;
    private ioTool tool=new ioTool();
    //表格内容list
    private final ObservableList<Template> data = FXCollections.observableArrayList();

    //文件目录
    private final Path path_template = Paths.get("src/Model/Template.txt");
    private final Path path_assess = Paths.get("src/Model/Assess.txt");

    //与表格内容同步的数据list
    private final List<Template> templateArrayList = new ArrayList<>();
    private final List<Assess> assessArrayList = new ArrayList<>();
    private final List<Template> tmp = new ArrayList<>();
    public  AssessfinalController()
    {

    }
    /**
     * 单选框监听
     * */
    @FXML
    public void oneoneradioOnaction(ActionEvent event)
    {
        oneoneradio.setSelected(true);
        oneoneradio.requestFocus();
        onetworadio.setSelected(false);
        onethreeradio.setSelected(false);
        oneanswer.setText(oneoneradio.getText());
        System.out.println(oneoneradio.getText());
    }
    @FXML
    public void onetworadioOnaction(ActionEvent event)
    {
        onetworadio.setSelected(true);
        onetworadio.requestFocus();
        onethreeradio.setSelected(false);
        oneoneradio.setSelected(false);
        oneanswer.setText(onetworadio.getText());
    }
    @FXML
    public void onethreeradioOnaction(ActionEvent event)
    {
        onethreeradio.setSelected(true);
        onethreeradio.requestFocus();
        onetworadio.setSelected(false);
        oneoneradio.setSelected(false);
        oneanswer.setText(onethreeradio.getText());
    }
    @FXML
    public void twooneradioOnaction(ActionEvent event)
    {
        twooneradio.setSelected(true);
        twooneradio.requestFocus();
        twotworadio.setSelected(false);
        twothreeradio.setSelected(false);
        twoanswer.setText(twooneradio.getText());
    }
    @FXML
    public void twotworadioOnaction(ActionEvent event)
    {
        twotworadio.setSelected(true);
        twotworadio.requestFocus();
        twooneradio.setSelected(false);
        twothreeradio.setSelected(false);
        twoanswer.setText(twotworadio.getText());
    }
    @FXML
    public void twothreeradioOnaction(ActionEvent event)
    {
        twothreeradio.setSelected(true);
        twothreeradio.requestFocus();
        twotworadio.setSelected(false);
        twooneradio.setSelected(false);
        twoanswer.setText(twothreeradio.getText());
    }
    @FXML
    public void threeoneradioOnaction(ActionEvent event)
    {
        threeoneradio.setSelected(true);
        threeoneradio.requestFocus();
        threetworadio.setSelected(false);
        threethreeradio.setSelected(false);
        threeanswer.setText(threeoneradio.getText());
    }

    @FXML
    public void threetworadioOnaction(ActionEvent event)
    {
        threetworadio.setSelected(true);
        threetworadio.requestFocus();
        threeoneradio.setSelected(false);
        threethreeradio.setSelected(false);
        threeanswer.setText(threetworadio.getText());
    }

    @FXML
    public void threethreeradioOnaction(ActionEvent event)
    {
        threethreeradio.setSelected(true);
        threethreeradio.requestFocus();
        threeoneradio.setSelected(false);
        threetworadio.setSelected(false);
        threeanswer.setText(threethreeradio.getText());
    }
    /**
     * 新增
     * @param event
     * @throws IOException
     */
    @FXML
    public void add(ActionEvent event) throws IOException {//需要更改
        if (oneanswer.getText() != null && twoanswer.getText() != null && threeanswer.getText() != null){
            //获得文本框的输入
            String type="";
            for(Template ssss:templateArrayList)
            {
                if(ssss.getTemplate_name().equals( templateCombobox.getValue().toString()))
                    type=ssss.getTemplate_type();
            }
            Assess person = new Assess(
                    patient.getName(),
                    patient.getSex(),
                    templateCombobox.getValue().toString(),
                    type,
                    new Date(),
                    assesspersonnme,
                    "合格"
            );
            System.out.println("[add]: ");
            assessArrayList.add(person);
            //将list写入到文件中
            tool.WriteObject(assessArrayList,path_assess.toString());
        }
    }
    /*
     * 下拉框,搜索旁边的combobox*/
    @FXML
    void templateComboboxOnaction(ActionEvent event) throws CloneNotSupportedException {

        for (Template p : templateArrayList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(templateArrayList);
        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Template p : templateArrayList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getTemplate_name().equals(templateCombobox.getValue().toString())) {
                onelabel.setText(p.getQuestion().get(0).getQuestion_name());
                twolabel.setText(p.getQuestion().get(1).getQuestion_name());
                threelabel.setText(p.getQuestion().get(2).getQuestion_name());
                oneoneradio.setText(p.getQuestion().get(0).getAnswer_one());
                onetworadio.setText(p.getQuestion().get(0).getAnswer_two());
                onethreeradio.setText(p.getQuestion().get(0).getAnswer_three());
                twooneradio.setText(p.getQuestion().get(1).getAnswer_one());
                twotworadio.setText(p.getQuestion().get(1).getAnswer_two());
                twothreeradio.setText(p.getQuestion().get(1).getAnswer_three());
                threeoneradio.setText(p.getQuestion().get(2).getAnswer_one());
                threetworadio.setText(p.getQuestion().get(2).getAnswer_two());
                threethreeradio.setText(p.getQuestion().get(2).getAnswer_three());
            }
        }
    }
    @FXML
    private void initialize() throws IOException, ClassNotFoundException {
        try {
        if(tool.ReadObject(path_template.toString())!=null)
            templateArrayList.addAll((Collection<? extends Template>)tool.ReadObject(path_template.toString()));
        if(tool.ReadObject_string("src/Model/Login.txt")!=null)
                assesspersonnme= (String) tool.ReadObject_string("src/Model/Login.txt");
        if(tool.ReadObject_Object("src/Model/patient_tmp.txt")!=null)
                patient= (Patient) tool.ReadObject_Object("src/Model/patient_tmp.txt");
        if(tool.ReadObject("src/Model/Assess.txt")!=null)
            assessArrayList.addAll((Collection<? extends Assess>)tool.ReadObject("src/Model/Assess.txt"));
        if(tool.ReadObject_string("src/Model/Login.txt")!=null)
            loginnamelabel.setText((String)tool.ReadObject_string("src/Model/Login.txt"));
    } catch (ClassNotFoundException e) {
        System.out.println("没用此文件!");
    }
        catch (IOException e)
    {
        System.out.println("文件为空");
    }
        for (Template a:templateArrayList)
        {
            templateCombobox.getItems().add(a.getTemplate_name());
        }
        //初始化多选框,默认全为false,当为true则被选中
        System.out.println("[initialize]: ");
    }
}

package Controller;
import Main.Main;
import Model.CellFactory_question;
import Model.EditingCell_Template;
import Model.Entity.*;
import Model.Tool.ioTool;
import View.Assess;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXComboBox;
import com.jfoenix.controls.JFXTextField;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Callback;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * 控制层:模板类控件
 */
public class TemplateController {
    @FXML
    private TableView<Template> tableView;
    @FXML
    private TableColumn<Template, String> IDColumn;
    @FXML
    private TableColumn<Template, String> templatename;
    @FXML
    private TableColumn<Template, String> templatetypeColumn;
    @FXML
    private TableColumn<Template, Boolean> selectColumn;
    @FXML
    private JFXComboBox<String> typeComboBox;
    @FXML
    private JFXComboBox<String> templatetypeComboBox;
    @FXML
    private JFXComboBox<String> oneCombobox;
    @FXML
    private JFXComboBox<String> twoCombobox;
    @FXML
    private JFXComboBox<String> threeCombobox;
    @FXML
    private JFXButton informationButton;
    @FXML
    private JFXTextField idsearch;
    @FXML
    protected JFXTextField idtext;
    @FXML
    protected JFXTextField nametext;
    @FXML
    protected JFXTextField onetext;
    @FXML
    protected JFXTextField twotext;
    @FXML
    protected JFXTextField threetext;
    @FXML
    protected JFXButton returnButton;
    @FXML
    private TableColumn<Question, String> questionidColumn;
    @FXML
    private TableColumn<Question, String> questionnameC0lumn;
    @FXML
    private TableColumn<Question, Boolean> selectColumnpreview;
    @FXML
    private JFXButton returnButtonpreview;
    @FXML
    private JFXButton addButton;
    private Stage stage;
    private ioTool tool = new ioTool();
    //表格内容list
    private final ObservableList<Template> data = FXCollections.observableArrayList();
    private final ObservableList<Question> dataquestion = FXCollections.observableArrayList();
    //文件目录
    private final Path path_question = Paths.get("src/Model/Question.txt");
    private final Path path_Template = Paths.get("src/Model/Template.txt");

    //与表格内容同步的数据list
    private final List<Template> templateArrayList = new ArrayList<>();
    private final List<Template> tmp = new ArrayList<>();
    private final List<Question> questionArrayList = new ArrayList<>();

    private final List<String> tmp_template = new ArrayList<>();

    public TemplateController() {

    }

    /**
     * @param
     * @return
     */
    public void informationOnaction() {
    }

    public void returnButtonOnAction(ActionEvent event) throws InterruptedException, IOException {
        Thread.sleep(300);
        Stage stage = (Stage) returnButton.getScene().getWindow();
        stage.close();
        new Assess();
    }

    /**
     * 转换函数
     */
    public Question exchange(String name) {
        for (Question q : questionArrayList) {
            if (name.equals(q.getQuestion_name())) {
                return q;
            }
        }
        return null;
    }

    /**
     * 新增函数
     */
    public void add() throws IOException {
        if (idtext.getText() != null && nametext.getText() != null && typeComboBox.getValue().toString() != null && oneCombobox.getValue().toString() != null && twoCombobox.getValue().toString() != null && threeCombobox.getValue().toString() != null) {
            ArrayList<Question> question = new ArrayList<Question>();
            question.add(exchange(oneCombobox.getValue().toString()));
            question.add(exchange(twoCombobox.getValue().toString()));
            question.add(exchange(threeCombobox.getValue().toString()));
            Template tm = new Template(
                    idtext.getText(),
                    nametext.getText(),
                    typeComboBox.getValue().toString(),
                    question
            );
            templateArrayList.add(tm);
            data.add(tm);
            System.out.println("[add]: ");
            //将list写入到文件中
            tool.WriteObject(templateArrayList,path_Template.toString());
        }
    }

    /**
     * 预览框函数
     */
    @FXML
    void informationOnaction(ActionEvent event)
    {

    }
   /**
     下拉框,搜索旁边的combobox
     */
    @FXML
    void combobox1(ActionEvent event) throws CloneNotSupportedException {

        for (Template p : templateArrayList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(templateArrayList);
        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Template p : templateArrayList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getTemplate_type().equals(templatetypeComboBox.getValue().toString())) {
                data.add(p);
            }
        }
        idsearch.clear();
    }
    /**
     * 删除
     *
     * @param event
     * @throws IOException
     */
    @FXML
    void delete(ActionEvent event) throws IOException {
        deleteStudents();
    }
    private boolean deleteStudents() throws IOException {
        int size = data.size();
        if (size <= 0) {
            return false;
        }
        //遍历所选选项
        for (int i = size - 1; i >= 0; i--) {
            Template p = data.get(i);
            if (p.isSelected()) {//被选中则删除

/*
                System.out.println("[Delete]: " + p.getId() + " " + p.getName() + " " + p.getPhone() + " " + p.getEmail());//显示删除的信息
*/
                //从list中移除
                templateArrayList.remove(p);
                //将list写入到文件中
                tool.WriteObject(templateArrayList,path_Template.toString());
                //从表格中移除
                data.remove(p);
            }
        }
        return true;
    }

    /**
     * 查找,仅支持通过id或name查找
     * @param event
     * @throws CloneNotSupportedException
     */
    @FXML
    void search(ActionEvent event) throws CloneNotSupportedException {
        for (Template p : templateArrayList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(templateArrayList);

        String id =idsearch.getText();

        //若为空时,则添加回所有数据
        if (id.equals("")) {
            data.addAll(templateArrayList);
        }

        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Template p : templateArrayList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getId().equals(id)) {
                data.add(p);
            }
        }
        idsearch.clear();
    }

    @FXML
    private void initialize() throws IOException {
        //绑定每一列,需要添加
        templatetypeComboBox.getItems().addAll("A","B","C");
        typeComboBox.getItems().addAll("A","B","C");
        IDColumn.setCellValueFactory(new PropertyValueFactory<Template, String>("id"));//id为person的属性
        templatename.setCellValueFactory(new PropertyValueFactory<Template, String>("template_name"));
        templatetypeColumn.setCellValueFactory(new PropertyValueFactory<Template, String>("template_type"));
        selectColumn.setCellValueFactory(new PropertyValueFactory<Template, Boolean>("selected"));
        //设定数据list
        tableView.setItems(data);
        tableView.setEditable(true);
        try{
            if(tool.ReadObject(path_Template.toString())!=null)
                templateArrayList.addAll((Collection<? extends Template>)tool.ReadObject(path_Template.toString()));
            data.addAll(templateArrayList);
        } catch (ClassNotFoundException e) {
            System.out.println("没用此文件!");
        }
        catch (IOException e)
        {
            System.out.println("文件为空");
        }
        /**读入问题题目
        * du*/
        try{
        if(tool.ReadObject(path_question.toString())!=null)
            questionArrayList.addAll((Collection<? extends Question>)tool.ReadObject(path_question.toString()));
        for (Question a: questionArrayList)
        {
            oneCombobox.getItems().add(a.getQuestion_name());
            twoCombobox.getItems().add(a.getQuestion_name());
            threeCombobox.getItems().add(a.getQuestion_name());
        }
        }catch (ClassNotFoundException e) {
            System.out.println("没用此文件!");
        }
        catch (IOException e)
        {
            System.out.println("文件为空");
        }
        //初始化多选框,默认全为false,当为true则被选中
        selectColumn.setCellFactory(
                CellFactory_question.tableCheckBoxColumn(new Callback<Integer, ObservableValue<Boolean>>() {
                    @Override
                    public ObservableValue<Boolean> call(Integer index) {
                        final Template employee = tableView.getItems().get(index);
                        ObservableValue<Boolean> ret =
                                new SimpleBooleanProperty(employee, "selected", employee.isSelected());//SimpleBooleanProperty(Object bean, String name, boolean initialValue)
                        ret.addListener(new ChangeListener<Boolean>() {
                            @Override
                            public void changed(
                                    ObservableValue<? extends Boolean> observable,
                                    Boolean oldValue, Boolean newValue) {
                                employee.setSelected(newValue);
                            }
                        });
                        return ret;
                    }
                }));

        /**
         * 单元格都可修改,但暂时未能保存到文件中,为后续优化功能
         */
        //每个单元格都可编辑
        Callback<TableColumn<Template, String>,
                TableCell<Template, String>> cellFactory
                = (TableColumn<Template, String> p) -> new EditingCell_Template();

        //为每列设定cellFactory
        IDColumn.setCellFactory(cellFactory);
        templatename.setCellFactory(cellFactory);
        templatetypeColumn.setCellFactory(cellFactory);
        //设置每个单元格可修改,还需要新添加
        IDColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Template, String> t) -> {
                    ((Template) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setId(t.getNewValue());
                });
        //设置每个单元格可修改
        templatename.setOnEditCommit(
                (TableColumn.CellEditEvent<Template, String> t) -> {
                    ((Template) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setTemplate_name(t.getNewValue());
                });
        //设置每个单元格可修改
        templatetypeColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Template, String> t) -> {
                    ((Template) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setTemplate_type(t.getNewValue());
                });
    }
}

package Controller;
import Model.CellFactory_question;
import Model.EditingCell_question;
import Model.Entity.Bed;
import Model.Entity.Question;
import Model.Tool.ioTool;
import View.Assess;
import com.jfoenix.controls.*;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 控制层:问题界面控件
 */
public class QuestionController {
    @FXML
    private TableView<Question> tableView;

    @FXML
    private TableColumn<Question, String> IDColumn;

    @FXML
    private TableColumn<Question, String> questionColumn;

    @FXML
    private TableColumn<Question, String> questiontypeColumn;

    @FXML
    private TableColumn<Question, String>oneColumn;
    @FXML
    private TableColumn<Question, String>twoColumn;
    @FXML
    private TableColumn<Question, String>threeColumn;
    @FXML
    private TableColumn<Question, Boolean> selectColumn;

    @FXML
    private JFXTextField idtext;

    @FXML
    private JFXTextField nametext;

    @FXML
    private JFXTextField onetext;

    @FXML
    private JFXTextField twotext;

    @FXML
    private JFXTextField threetext;
    @FXML
    private JFXComboBox<String> typeComboBox;
    @FXML
    private JFXComboBox<String> type1ComboBox;
    @FXML
    private JFXButton informationButton;
    @FXML
    private JFXTextField idsearch;
    @FXML
    private JFXButton returnButton;

    private ioTool tool=new ioTool();

    private boolean index = false;

    //表格内容list
    private final ObservableList<Question> data = FXCollections.observableArrayList();

    //文件目录
    private final Path path = Paths.get("src/Model/Question.txt");

    //与表格内容同步的数据list
    private final List<Question> questionList = new ArrayList<>();
    private final List<Question> tmp = new ArrayList<>();
    public QuestionController()
    {

    }

    public void returnButtonOnAction(ActionEvent event) throws InterruptedException, IOException {
        Thread.sleep(300);
        Stage stage=(Stage) returnButton.getScene().getWindow();
        stage.close();
        new Assess();
    }
    /**
     *  Question information
    * */
    public void information(ActionEvent event)
    {
        if(!oneColumn.isVisible())
        oneColumn.setVisible(true);
        else
            oneColumn.setVisible(false);
        if(!twoColumn.isVisible())
        twoColumn.setVisible(true);
        else
            twoColumn.setVisible(false);
        if(!threeColumn.isVisible())
        threeColumn.setVisible(true);
        else
            threeColumn.setVisible(false);
    }
    /**
     * 保存*/
    @FXML
    public void save(ActionEvent event) throws IOException {
        tool.WriteObject(questionList,path.toString());
    }

    /**
     * 新增
     * @param event
     * @throws IOException
     */
    @FXML
    public void add(ActionEvent event) throws IOException {//需要更改
        if (nametext.getText() != null && idtext.getText() != null && onetext.getText() != null && typeComboBox.getValue() != null&& twotext.getText() != null&& threetext.getText()!=null){
            //获得文本框的输入
            Question person = new Question(
            String.valueOf(Integer.parseInt(idtext.getText())+1),
                    nametext.getText(),
                    typeComboBox.getValue().toString(),
                    onetext.getText(),
                    twotext.getText(),
                    threetext.getText());
            //添加到表格中
            data.add(person);
            //同步添加到list中
            questionList.add(person);

            System.out.println("[add]: " +nametext.getText() + " " + idtext.getText() );

            //将list写入到文件中
           tool.WriteObject(questionList,path.toString());

            //清空文本输入框//
            idtext.clear();
            nametext.clear();
            nametext.clear();
            onetext.clear();
            twotext.clear();
            threetext.clear();
        }
    }

    /*
     * 下拉框监听事件
     * */
    @FXML
    void combobox(ActionEvent event)
    {
        typeComboBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldValue, Object newValue) {
                System.out.println("成功选中");
            }
        });
    }
    /*
     * 下拉框,搜索旁边的combobox*/
    @FXML
    void combobox1(ActionEvent event) throws CloneNotSupportedException {

        for (Question p : questionList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(questionList);
        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Question p : questionList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getQuestion_type().equals(type1ComboBox.getValue().toString())) {
                data.add(p);
            }
        }
        idsearch.clear();
    }
    /**
     * 删除
     *
     * @param event
     * @throws IOException
     */
    @FXML
    void delete(ActionEvent event) throws IOException {
        deleteStudents();
    }

    private boolean deleteStudents() throws IOException {
        int size = data.size();
        if (size <= 0) {
            return false;
        }
        //遍历所选选项
        for (int i = size - 1; i >= 0; i--) {
            Question p = data.get(i);
            if (p.isSelected()) {//被选中则删除

/*
                System.out.println("[Delete]: " + p.getId() + " " + p.getName() + " " + p.getPhone() + " " + p.getEmail());//显示删除的信息
*/
                //从list中移除
                questionList.remove(p);
                //将list写入到文件中
                tool.WriteObject(questionList,path.toString());
                //从表格中移除
                data.remove(p);
            }
        }
        return true;
    }
/*

    */
/**
     * 修改
     * @param event
     * @throws IOException
     *//*

    @FXML
    void modify(ActionEvent event) throws IOException {
        boolean flag = false;
        if (nametext.getText() != null && idtext.getText() != null && onetext.getText() != null && typeComboBox.getValue() != null&& twotext.getText() != null&& threetext.getText()!=null){
            //遍历list,判断是否有同将要修改姓名一致的元素
            for (Question p : questionList) {//姓名
                if (p.getQuestion_id().equals(idtext.getText())) {//通过id来查
                    flag = true;
                    //先移除列表所有数据
                    data.removeAll(questionList);//先清空,再显示要显示的
                    //更新改行数据
                    p.setQuestion_id(idtext.getText());
                    p.setQuestion_type(typeComboBox.getValue().toString());
                    p.setBirthday(birthdaytext.getText());
                    p.setGoodat(goodattext.getText());
                    p.setTelephone(telephonetext.getText());
                    p.setIdcrad(idcradtext.getText());
                    System.out.println("[modify]: " + p.getUsername() + " " + p.getName() + " ");
                }
            }
            //如果有更新,则添加全部数据回表格
            if (flag) {
                data.addAll(questionList);
            }

            Files.write(path, listToBytes(questionList));
            usernametext.clear();
            passwordtext.clear();
            nametext.clear();
            birthdaytext.clear();
            goodattext.clear();
            telephonetext.clear();
            idcradtext.clear();
        }
    }
*/

    /**
     * 查找,仅支持通过id或name查找
     * @param event
     * @throws CloneNotSupportedException
     */
    @FXML
    void search(ActionEvent event) throws CloneNotSupportedException {
        for (Question p : questionList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(questionList);

        String id =idsearch.getText();

        //若为空时,则添加回所有数据
        if (id.equals("")) {
            data.addAll(questionList);
        }

        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Question p : questionList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getQuestion_id().equals(id)) {
                data.add(p);
            }
        }
        idsearch.clear();
    }

    @FXML
    private void initialize() throws IOException, ClassNotFoundException {
        //绑定每一列,需要添加
        typeComboBox.getItems().addAll("A","B","C");
        type1ComboBox.getItems().addAll("A","B","C");
        IDColumn.setCellValueFactory(new PropertyValueFactory<Question, String>("question_id"));//id为person的属性
        questionColumn.setCellValueFactory(new PropertyValueFactory<Question, String>("question_name"));
        questiontypeColumn.setCellValueFactory(new PropertyValueFactory<Question, String>("question_type"));
        oneColumn.setCellValueFactory(new PropertyValueFactory<Question, String>("answer_one"));
        twoColumn.setCellValueFactory(new PropertyValueFactory<Question, String>("answer_two"));
        threeColumn.setCellValueFactory(new PropertyValueFactory<Question, String>("answer_three"));
        selectColumn.setCellValueFactory(new PropertyValueFactory<Question, Boolean>("selected"));
        //设定数据list
        tableView.setItems(data);
        tableView.setEditable(true);
        try{
            if(tool.ReadObject(path.toString())!=null)
                questionList.addAll((Collection<? extends Question>)tool.ReadObject(path.toString()));
            data.addAll(questionList);
        } catch (ClassNotFoundException e) {
            System.out.println("没用此文件!");
        }
        catch (IOException e)
        {
            System.out.println("文件为空");
        }
       /* //按行读取文件,存入list中
        List<String> lines = Files.readAllLines(path);
        //根据分隔符拆分文件每一行数据,存入person对象中,并添加到fx表格中
        for (String line : lines) {
            String[] tmp = line.split(",");//分割得到字符串数组
            questionList.add(new Question(tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5]));//几个属性添加几个
            //不能通过匿名对象创建,会导致无法remove掉元素
            data.add(questionList.get(questionList.size() - 1));//添加最新的对象
        }
*/
        //初始化多选框,默认全为false,当为true则被选中
        selectColumn.setCellFactory(
                CellFactory_question.tableCheckBoxColumn(new Callback<Integer, ObservableValue<Boolean>>() {
                    @Override
                    public ObservableValue<Boolean> call(Integer index) {
                        final Question employee = tableView.getItems().get(index);
                        ObservableValue<Boolean> ret =
                                new SimpleBooleanProperty(employee, "selected", employee.isSelected());//SimpleBooleanProperty(Object bean, String name, boolean initialValue)
                        ret.addListener(new ChangeListener<Boolean>() {
                            @Override
                            public void changed(
                                    ObservableValue<? extends Boolean> observable,
                                    Boolean oldValue, Boolean newValue) {
                                employee.setSelected(newValue);
                            }
                        });
                        return ret;
                    }
                }));

        /**
         * 单元格都可修改,但暂时未能保存到文件中,为后续优化功能
         */
        //每个单元格都可编辑
        Callback<TableColumn<Question, String>,
                TableCell<Question, String>> cellFactory
                = (TableColumn<Question, String> p) -> new EditingCell_question();
        //为每列设定cellFactory
        IDColumn.setCellFactory(cellFactory);
        questionColumn.setCellFactory(cellFactory);
        questiontypeColumn.setCellFactory(cellFactory);
        oneColumn.setCellFactory(cellFactory);
        twoColumn.setCellFactory(cellFactory);
        threeColumn.setCellFactory(cellFactory);
        //设置每个单元格可修改,还需要新添加
        IDColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Question, String> t) -> {
                    ((Question) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setQuestion_id(t.getNewValue());
                });
        //设置每个单元格可修改
        questionColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Question, String> t) -> {
                    ((Question) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setQuestion_name(t.getNewValue());
                });
        //设置每个单元格可修改
        questiontypeColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Question, String> t) -> {
                    ((Question) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setQuestion_type(t.getNewValue());
                });
        //设置每个单元格可修改
        oneColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Question, String> t) -> {
                    ((Question) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setAnswer_one(t.getNewValue());
                });
        //设置每个单元格可修改
        twoColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Question, String> t) -> {
                    ((Question) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setAnswer_two(t.getNewValue());
                });
        //设置每个单元格可修改
        threeColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Question, String> t) -> {
                    ((Question) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setAnswer_three(t.getNewValue());
                });
        System.out.println("[initialize]: " + idtext.getText() + " " + nametext.getText() + " ");
    }
}

三、用户管理

模块分析

分三个方面病患管理,床位管理,稀有设备管理。一样是增删改查,只是会有数据的联系,比如床位管理的入住,在入住人哪里,是通过读取patien(病患)文件来得到的病患对象及其姓名,即这个单选框Combobox的数据是根据patient的数据来改变的,而不是不变的。而且在时间方面用的JAVAFX的组件JFXDatePicker,我这里举一个病患管理的例子。

Controller类:

package Controller;
import Model.CellFactory;
import Model.EditingCell_patient;
import Model.Entity.Assess;
import Model.Entity.Patient;
import Model.Tool.ioTool;
import View.Assessfinal;
import com.jfoenix.controls.*;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * 控制层:病患类的控制层
 */
public class PatientController {
    @FXML
    private TableView<Patient> tableView;

    @FXML
    private TableColumn<Patient, String> nameColumn;

    @FXML
    private TableColumn<Patient, String> sexColumn;

    @FXML
    private TableColumn<Patient, String> birthdayColumn;

    @FXML
    private TableColumn<Patient, String>idcradColumn;
    @FXML
    private TableColumn<Patient, String>telephoneColumn;
    @FXML
    private TableColumn<Patient, String>emergencynameColumn;
    @FXML
    private TableColumn<Patient, String>emergencytelephoneColumn;
    @FXML
    private TableColumn<Patient, Boolean> selectColumn;

    @FXML
    private JFXTextField nametext;

    @FXML
    private JFXTextField birthdaytext;

    @FXML
    private JFXTextField idcradtext;

    @FXML
    private JFXTextField telephonetext;

    @FXML
    private JFXTextField emergencytext;
    @FXML
    private JFXTextField emergencytelephonetext;
    @FXML
    private JFXComboBox<String> sexCombobox;
    @FXML
    private JFXTextField nameSearch;
    @FXML
    private JFXTextField tmptext;
    @FXML
    private JFXDatePicker birthdaydatePicker;
    @FXML
    private JFXRadioButton rb1;
    @FXML
    private JFXRadioButton rb2;
    @FXML
    private JFXButton returnButton;
    private ioTool tool=new ioTool();
    //表格内容list
    private final ObservableList<Patient> data = FXCollections.observableArrayList();

    //文件目录
    private final Path path = Paths.get("src/Model/Patient.txt");

    //与表格内容同步的数据list
    private final List<Patient> patientArrayList = new ArrayList<>();
    private final List<Patient> tmp = new ArrayList<>();
    public PatientController ()
    {

    }
    public void returnButtonOnAction(ActionEvent event) throws InterruptedException, IOException {
        Thread.sleep(300);
        Stage stage=(Stage) returnButton.getScene().getWindow();
        stage.close();
    }
    /**
     * 单选框监听
     * */
    @FXML
    public void radioOnaction(ActionEvent event)
    {
          rb1.setSelected(true);
          rb1.requestFocus();
          rb2.setSelected(false);
          tmptext.setText(rb1.getText());
        System.out.println(tmptext.getText());
    }
    /**
     * 单选框监听*/
    @FXML
    public void radio1Onaction(ActionEvent event)
    {
        rb2.setSelected(true);
        rb2.requestFocus();
        rb1.setSelected(false);
        tmptext.setText(rb2.getText());
    }
    /**
     * 新增
     * @param event
     * @throws IOException
     */
    @FXML
    public void add(ActionEvent event) throws IOException {//需要更改
        if (nametext.getText() != null && birthdaydatePicker.getValue() != null && idcradtext.getText() != null && telephonetext.getText() != null&& emergencytelephonetext.getText() != null&& emergencytext.getText() != null){
            //获得文本框的输入
            Patient person = new Patient(
                    nametext.getText(),
                    tmptext.getText(),
                    Date.from(birthdaydatePicker.getValue().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()),
                    idcradtext.getText(),
                    telephonetext.getText(),
                    emergencytext.getText(),
                    emergencytelephonetext.getText()
                   );
            //添加到表格中
            data.add(person);
            //同步添加到list中
            patientArrayList.add(person);

            System.out.println("[add]: " +nametext.getText() + " " +telephonetext.getText() );

            //将list写入到文件中
            tool.WriteObject(patientArrayList,path.toString());

            //清空文本输入框//
            nametext.clear();
            emergencytelephonetext.clear();
            telephonetext.clear();
            idcradtext.clear();
            idcradtext.clear();
            emergencytext.getText();
        }
    }
    /*
     * 下拉框,搜索旁边的combobox*/
    @FXML
    void combobox1(ActionEvent event) throws CloneNotSupportedException {

        for (Patient p : patientArrayList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(patientArrayList);
        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Patient p : patientArrayList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getSex().equals(sexCombobox.getValue().toString())) {
                data.add(p);
            }
        }
        nameSearch.clear();
    }
    /**
     * 删除
     *
     * @param event
     * @throws IOException
     */
    @FXML
    void delete(ActionEvent event) throws IOException {
        deleteStudents();
    }

    private boolean deleteStudents() throws IOException {
        int size = data.size();
        if (size <= 0) {
            return false;
        }
        //遍历所选选项
        for (int i = size - 1; i >= 0; i--) {
            Patient p = data.get(i);
            if (p.isSelected()) {//被选中则删除

/*
                System.out.println("[Delete]: " + p.getId() + " " + p.getName() + " " + p.getPhone() + " " + p.getEmail());//显示删除的信息
*/
                //从list中移除
                patientArrayList.remove(p);
                //将list写入到文件中
                tool.WriteObject(patientArrayList,path.toString());
                //从表格中移除
                data.remove(p);
            }
        }
        return true;
    }
    /**
     * 查找,仅支持通过id或name查找
     * @param event
     * @throws CloneNotSupportedException
     */
    @FXML
    void search(ActionEvent event) throws CloneNotSupportedException {
        for (Patient p : patientArrayList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(patientArrayList);

        String name = nameSearch.getText();

        //若为空时,则添加回所有数据
        if (name.equals("")) {
            data.addAll(patientArrayList);
        }

        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Patient p : patientArrayList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getName().equals(name)) {
                data.add(p);
            }
        }
        nameSearch.clear();
    }
    /**
     * 修改
     * @param event
     * @throws IOException
     */
    @FXML
    void modify(ActionEvent event) throws IOException {
        boolean flag = false;
        if (nametext.getText() != null && birthdaytext.getText() != null && idcradtext.getText() != null && telephonetext.getText() != null&& emergencytelephonetext.getText() != null&& emergencytext.getText() != null){
            //遍历list,判断是否有同将要修改姓名一致的元素
            for (Patient p : patientArrayList) {//姓名
                if (p.getName().equals(nametext.getText())) {//通过id来查
                    flag = true;
                    //先移除列表所有数据
                    data.removeAll(patientArrayList);//先清空,再显示要显示的
                    //更新改行数据
                    p.setName(nametext.getText());
                    p.setSex(tmptext.getText());
                    p.setBirthday(Date.from(birthdaydatePicker.getValue().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
                    p.setIdcrad(idcradtext.getText());
                    p.setEmergency_name(emergencytext.getText());
                    p.setEmergency_telephone(emergencytelephonetext.getText());
                    System.out.println("[modify]: " + p.getName() + " " + p.getSex() + " ");
                }
            }
            //如果有更新,则添加全部数据回表格
            if (flag) {
                data.addAll(patientArrayList);
            }

            tool.WriteObject(patientArrayList,path.toString());
            nametext.clear();
            birthdaytext.clear();
            emergencytelephonetext.clear();
            telephonetext.clear();
            idcradtext.clear();
            idcradtext.clear();
            emergencytext.getText();
        }
    }
    @FXML
    private void assessOnaction() throws IOException {

        int size = data.size();
        if (size <= 0) {
            return;
        }
        //遍历所选选项
        for (int i = size - 1; i >= 0; i--) {
            Patient p = data.get(i);
            if (p.isSelected()) {//被选中则删除
                //将list写入到文件中
                tool.WriteObject(p,"src/Model/patient_tmp.txt");
                 new Assessfinal();
            }
        }
    }
    @FXML
    private void initialize() throws IOException, ClassNotFoundException {
        //绑定每一列,需要添加
        sexCombobox.getItems().addAll("男","女");
        rb1.setUserData("男");
        rb2.setUserData("女");
        nameColumn.setCellValueFactory(new PropertyValueFactory<Patient, String>("name"));//id为person的属性
        sexColumn.setCellValueFactory(new PropertyValueFactory<Patient, String>("sex"));
        birthdayColumn.setCellValueFactory(new PropertyValueFactory<Patient, String>("birthday"));
        idcradColumn.setCellValueFactory(new PropertyValueFactory<Patient, String>("idcrad"));
        telephoneColumn.setCellValueFactory(new PropertyValueFactory<Patient, String>("telephone"));
        emergencynameColumn.setCellValueFactory(new PropertyValueFactory<Patient, String>("emergency_name"));
        emergencytelephoneColumn.setCellValueFactory(new PropertyValueFactory<Patient, String>("emergency_telephone"));
        selectColumn.setCellValueFactory(new PropertyValueFactory<Patient, Boolean>("selected"));
        //设定数据list
        tableView.setItems(data);
        tableView.setEditable(true);
        try {
        if(tool.ReadObject(path.toString())!=null)
            patientArrayList.addAll((Collection<? extends Patient>)tool.ReadObject(path.toString()));
        data.addAll(patientArrayList);
    } catch (ClassNotFoundException e) {
        System.out.println("没用此文件!");
    }
        catch (IOException e)
    {
        System.out.println("文件为空");
    }
        //初始化多选框,默认全为false,当为true则被选中
        selectColumn.setCellFactory(
                CellFactory.tableCheckBoxColumn(new Callback<Integer, ObservableValue<Boolean>>() {
                    @Override
                    public ObservableValue<Boolean> call(Integer index) {
                        final Patient employee = tableView.getItems().get(index);
                        ObservableValue<Boolean> ret =
                                new SimpleBooleanProperty(employee, "selected", employee.isSelected());//SimpleBooleanProperty(Object bean, String name, boolean initialValue)
                        ret.addListener(new ChangeListener<Boolean>() {
                            @Override
                            public void changed(
                                    ObservableValue<? extends Boolean> observable,
                                    Boolean oldValue, Boolean newValue) {
                                employee.setSelected(newValue);
                            }
                        });
                        return ret;
                    }
                }));
        /**
         * 单元格都可修改,但暂时未能保存到文件中,为后续优化功能
         */
        //每个单元格都可编辑
        Callback<TableColumn<Patient, String>,
                TableCell<Patient, String>> cellFactory
                = (TableColumn<Patient, String> p) -> new EditingCell_patient();
        //为每列设定cellFactory
        nameColumn.setCellFactory(cellFactory);
        /*  selectedColumn.setCellFactory(cellFactory);*/
        sexColumn.setCellFactory(cellFactory);
        /*birthdayColumn.setCellFactory(cellFactory);*/
        idcradColumn.setCellFactory(cellFactory);
        telephoneColumn.setCellFactory(cellFactory);
        emergencynameColumn.setCellFactory(cellFactory);
        emergencytelephoneColumn.setCellFactory(cellFactory);
        //设置每个单元格可修改,还需要新添加
        nameColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Patient, String> t) -> {
                    ((Patient) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setName(t.getNewValue());
                });
        //设置每个单元格可修改
        sexColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Patient, String> t) -> {
                    ((Patient) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setSex(t.getNewValue());
                });
        //设置每个单元格可修改
        idcradColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Patient, String> t) -> {
                    ((Patient) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setIdcrad(t.getNewValue());
                });
        //设置每个单元格可修改
        telephoneColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Patient, String> t) -> {
                    ((Patient) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setTelephone(t.getNewValue());
                });
        //设置每个单元格可修改
        emergencynameColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Patient, String> t) -> {
                    ((Patient) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setEmergency_name(t.getNewValue());
                });
        emergencytelephoneColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Patient, String> t) -> {
                    ((Patient) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setEmergency_telephone(t.getNewValue());
                });

        System.out.println("[initialize]: " + nametext.getText() + " " + telephonetext.getText() + " ");
    }
}

实体类:

package Model.Entity;
import java.io.Serializable;
import java.util.Date;

/*
 * 职工管理
 * 各个属性
 * */
public class Patient implements Cloneable , Serializable {
    private String name;//姓名
    private String sex;//性别
    private Date birthday;//出生日期
    private String idcrad;//身份证号码
    private String telephone;//电话号码
    private String emergency_name;//紧急联系人
    private String emergency_telephone;//紧急联系人电话
    private boolean selected;
    public Patient()
    {
    }
    public Patient(String name, String sex, Date birthday, String idcrad, String telephone, String emergency_name, String emergency_telephone) {
        this.name=name;
        this.sex=sex;
        this.birthday=birthday;
        this.idcrad=idcrad;
        this.telephone=telephone;
        this.emergency_name=emergency_name;
        this.emergency_telephone=emergency_telephone;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getIdcrad() {
        return idcrad;
    }

    public void setIdcrad(String idcrad) {
        this.idcrad = idcrad;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getEmergency_name() {
        return emergency_name;
    }

    public void setEmergency_name(String emergency_name) {
        this.emergency_name = emergency_name;
    }

    public String getEmergency_telephone() {
        return emergency_telephone;
    }

    public void setEmergency_telephone(String emergency_telephone) {
        this.emergency_telephone = emergency_telephone;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }

    @Override
    public Patient clone() throws CloneNotSupportedException {
        return (Patient) super.clone();//克隆出一个对象
    }
    @Override
    public String toString() {
        return name+","+sex+","+birthday+","+idcrad+","+telephone+","+emergency_name+","+emergency_telephone+"\n";
    }
}

界面类:

package View;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Tooltip;
import javafx.stage.StageStyle;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/*病患UI*/
public class Patient extends window {
    public Patient() throws IOException {
        root = FXMLLoader.load(getClass().getResource("fxml/Patient.fxml"));
        initStyle(StageStyle.UNDECORATED);
        setScene(new Scene(root, 1200, 800));
        setResizable(false);
        move();
        quit();
        setIcon();
        minimiser();
        show();
    }
    @Override
    public void quit() {
        ((Button) $("quit1")).setTooltip(new Tooltip("关闭"));//当鼠标悬停在节点上时,它们通常用于在场景图中显示有关节点的附加信息。任何节点都可以显示工具提示。
        ((Button) $("quit1")).setOnAction(event -> {
            close();//关闭
        });//监听
    }

    @Override
    public void minimiser() {
        ((Button) $("minimiser1")).setTooltip(new Tooltip("最小化"));
        ((Button) $("minimiser1")).setOnAction(event -> {
            setIconified(true);//将此属性设置为true将隐藏舞台,但不显示它的图标。
        });
    }
}

病患的fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXDatePicker?>
<?import com.jfoenix.controls.JFXRadioButton?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.paint.RadialGradient?>
<?import javafx.scene.paint.Stop?>
<?import javafx.scene.text.Font?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="1200.0" stylesheets="@CSS/Patient.css" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.PatientController">
   <top>
      <AnchorPane prefHeight="169.0" prefWidth="1200.0" style="-fx-background-color: #7bbfea;" BorderPane.alignment="CENTER">
         <children>
            <ImageView fitHeight="170.0" fitWidth="514.0" layoutY="1.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@CSS/Image/neulabel.png" />
               </image>
            </ImageView>
            <ImageView fitHeight="150.0" fitWidth="200.0" layoutX="723.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true" />
            <Label layoutX="713.0" layoutY="17.0" prefHeight="144.0" prefWidth="487.0" text="病患人员界面">
               <font>
                  <Font name="System Bold" size="66.0" />
               </font>
            </Label>
            <Button fx:id="minimiser1" layoutX="1120.0" layoutY="13.0" mnemonicParsing="false" />
            <Button fx:id="quit1" layoutX="1154.0" layoutY="13.0" mnemonicParsing="false" />
            <JFXButton fx:id="returnButton" buttonType="RAISED" layoutX="1017.0" layoutY="13.0" onAction="#returnButtonOnAction" style="-fx-background-color: #cde6c7;" text="返回" />
            <ImageView fitHeight="206.0" fitWidth="164.0" layoutX="514.0" layoutY="3.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@CSS/Image/patient.jpg" />
               </image>
            </ImageView>
         </children>
      </AnchorPane>
   </top>
   <bottom>
      <AnchorPane fx:id="username" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
         <children>
            <Label fx:id="label" layoutX="270.0" layoutY="82.0" prefHeight="20.0" prefWidth="134.0" visible="false" />
            <JFXButton fx:id="addButton" buttonType="RAISED" layoutX="993.0" layoutY="119.0" onAction="#add" prefHeight="45.0" prefWidth="158.0" style="-fx-background-color: #cde6c7;" text="新增患者">
               <font>
                  <Font name="System Bold" size="19.0" />
               </font>
            </JFXButton>
            <JFXTextField fx:id="nametext" layoutX="23.0" layoutY="32.0" promptText="姓名" />
            <JFXTextField fx:id="idcradtext" layoutX="736.0" layoutY="32.0" promptText="身份证号码" />
            <JFXTextField fx:id="emergencytext" layoutX="272.0" layoutY="111.0" promptText="紧急联系人" />
            <JFXTextField fx:id="telephonetext" layoutX="23.0" layoutY="111.0" promptText="手机号码" />
            <JFXTextField fx:id="emergencytelephonetext" layoutX="505.0" layoutY="111.0" promptText="紧急联系人号码" />
            <JFXRadioButton fx:id="rb1" layoutX="295.0" layoutY="23.0" onAction="#radioOnaction" text="男" />
            <JFXRadioButton fx:id="rb2" layoutX="295.0" layoutY="58.0" onAction="#radio1Onaction" prefHeight="18.0" prefWidth="59.0" text="女" />
            <JFXTextField fx:id="tmptext" layoutX="354.0" layoutY="32.0" prefHeight="26.0" prefWidth="65.0" visible="false" />
            <JFXButton fx:id="addButton1" buttonType="RAISED" layoutX="987.0" layoutY="36.0" onAction="#add" prefHeight="45.0" prefWidth="158.0" style="-fx-background-color: #cde6c7;" text="修改患者信息">
               <font>
                  <Font name="System Bold" size="19.0" />
               </font>
            </JFXButton>
            <JFXDatePicker fx:id="birthdaydatePicker" layoutX="457.0" layoutY="32.0" promptText="出生年月日" />
            <Label layoutX="235.0" layoutY="44.0" prefHeight="23.0" prefWidth="60.0" text="性别" />
         </children>
      </AnchorPane>
   </bottom>
   <center>
      <GridPane BorderPane.alignment="CENTER">
        <columnConstraints>
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints maxHeight="195.0" minHeight="10.0" prefHeight="96.0" vgrow="SOMETIMES" />
          <RowConstraints maxHeight="304.0" minHeight="10.0" prefHeight="304.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <TableView fx:id="tableView" prefHeight="380.0" prefWidth="1200.0" style="-fx-background-color: #cde6c7;" tableMenuButtonVisible="true" GridPane.rowIndex="1">
              <columns>
                <TableColumn fx:id="nameColumn" prefWidth="105.0" text="姓名" />
                <TableColumn fx:id="sexColumn" prefWidth="65.0" text="性别" />
                  <TableColumn fx:id="birthdayColumn" minWidth="3.0" prefWidth="101.0" text="出生日期" />
                  <TableColumn fx:id="idcradColumn" minWidth="0.0" prefWidth="140.0" text="身份证号码" />
                  <TableColumn fx:id="telephoneColumn" minWidth="0.0" prefWidth="296.0" text="手机号码" />
                  <TableColumn fx:id="emergencynameColumn" minWidth="0.0" prefWidth="108.0" text="紧急联系人" />
                  <TableColumn fx:id="emergencytelephoneColumn" prefWidth="141.0" text="紧急联系人电话" />
                  <TableColumn fx:id="selectColumn" prefWidth="133.0" text="选择" />
                  <TableColumn prefWidth="75.0" text="评估" />
              </columns>
               <columnResizePolicy>
                  <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
               </columnResizePolicy>
               <cursor>
                  <Cursor fx:constant="NW_RESIZE" />
               </cursor>
            </TableView>
            <AnchorPane prefHeight="200.0" prefWidth="200.0">
               <children>
                  <Label fx:id="label1" layoutX="439.0" layoutY="14.0" prefHeight="22.0" prefWidth="106.0" visible="false" />
                  <JFXTextField fx:id="nameSearch" layoutX="40.0" layoutY="43.0" promptText="姓名">
                     <font>
                        <Font name="System Bold" size="16.0" />
                     </font>
                  </JFXTextField>
                  <JFXButton fx:id="searcherButton" buttonType="RAISED" layoutX="265.0" layoutY="49.0" onAction="#search" prefHeight="30.0" prefWidth="94.0" ripplerFill="#280707" style="-fx-background-color: #cde6c7;" text="搜索姓名" textOverrun="WORD_ELLIPSIS">
                     <textFill>
                        <RadialGradient centerX="0.5" centerY="0.5" radius="0.5">
                           <stops>
                              <Stop color="#030303" />
                              <Stop color="#221e1e" offset="1.0" />
                           </stops>
                        </RadialGradient>
                     </textFill>
                  </JFXButton>
                  <JFXComboBox fx:id="sexCombobox" cache="true" layoutX="409.0" layoutY="49.0" onAction="#combobox1" prefHeight="30.0" prefWidth="119.0" promptText="性别筛选" style="-fx-background-color: #cde6c7;">
                     <focusColor>
                        <RadialGradient centerX="0.5" centerY="0.5" radius="0.5">
                           <stops>
                              <Stop color="#040814" />
                              <Stop color="WHITE" offset="1.0" />
                           </stops>
                        </RadialGradient>
                     </focusColor>
                  </JFXComboBox>
                  <JFXButton fx:id="deleteButton" buttonType="RAISED" layoutX="1070.0" layoutY="39.0" onAction="#delete" prefHeight="42.0" prefWidth="92.0" style="-fx-background-color: #6f60aa;" text="删   除">
                     <font>
                        <Font size="17.0" />
                     </font>
                  </JFXButton>
                  <JFXButton layoutX="869.0" layoutY="42.0" onAction="#assessOnaction" prefHeight="32.0" prefWidth="129.0" text="评估" />
               </children>
            </AnchorPane>
         </children>
      </GridPane>
   </center>
</BorderPane>

四、职工管理

模块分析

对于员工的操作,增删改查,注意数据为序列化存储。

Controller

package Controller;
import Model.CellFactory;
import Model.EditingCell;
import Model.Entity.Bed;
import Model.Entity.Employee;
import Model.Tool.ioTool;
import View.Login;
import com.jfoenix.controls.*;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 控制层,超级管理员的界面控件
 */
public class AdministratorController {
    @FXML
    private TableView<Employee> tableView;

    @FXML
    private TableColumn<Employee, String> usernameColumn;

    @FXML
    private TableColumn<Employee, String> nameColumn;

    @FXML
    private TableColumn<Employee, String> workColumn;

    @FXML
    private TableColumn<Employee, String>birthdayColumn;
    @FXML
    private TableColumn<Employee, String>goodatColumn;
    @FXML
    private TableColumn<Employee, String>telephonenumberColumn;
    @FXML
    private TableColumn<Employee, String>idcradColumn;
    @FXML
    private TableColumn<Employee, Boolean> selectColumn;

    @FXML
    private JFXTextField nametext;

    @FXML
    private JFXTextField birthdaytext;

    @FXML
    private JFXTextField goodattext;

    @FXML
    private JFXTextField telephonetext;

    @FXML
    private JFXTextField idcradtext;
    @FXML
    private JFXTextField usernametext;
    @FXML
    private JFXComboBox<String> workComboBox;
    @FXML
    private JFXComboBox<String> work1ComboBox;
    @FXML
    private JFXPasswordField passwordtext;
    @FXML
    private JFXTextField nameSearch;
    @FXML
    private JFXButton returnButton;
    @FXML
    private Label AdministratorControllerLabel;
    private boolean index = false;
    private ioTool tool=new ioTool();
    //表格内容list
    private final ObservableList<Employee> data = FXCollections.observableArrayList();

    //文件目录
    private final Path path = Paths.get("src/Model/Employee.txt");

    //与表格内容同步的数据list
    private final List<Employee> employeeList = new ArrayList<>();
    private final List<Employee> tmp = new ArrayList<>();
   public AdministratorController()
   {

   }    /**
     * list转byte[]数组,用于存入文件中
     * @param
     * @return
     */
    public void returnButtonOnAction(ActionEvent event) throws InterruptedException, IOException {
        Thread.sleep(300);
        Stage stage=(Stage) returnButton.getScene().getWindow();
        stage.close();
        new Login();
    }
    /**
     * 新增
     * @param event
     * @throws IOException
     */
    @FXML
    public void add(ActionEvent event) throws IOException {//需要更改
        if (nametext.getText() != null && birthdaytext.getText() != null && goodattext.getText() != null && telephonetext.getText() != null&&idcradtext.getText() != null&& usernametext.getText() != null&& passwordtext.getText() != null){
            //获得文本框的输入
            Employee person = new Employee(
                    usernametext.getText(),
                    passwordtext.getText(),
                    nametext.getText(),
                    workComboBox.getValue().toString(),
                    birthdaytext.getText(),
                    goodattext.getText(),
                    telephonetext.getText(),
                    idcradtext.getText());
            //添加到表格中
            data.add(person);
            //同步添加到list中
            employeeList.add(person);

            System.out.println("[add]: " +usernametext.getText() + " " + passwordtext.getText() );

            //将list写入到文件中
            tool.WriteObject(employeeList,path.toString());


            //清空文本输入框//
            usernametext.clear();
            passwordtext.clear();
            nametext.clear();
            birthdaytext.clear();
            goodattext.clear();
            telephonetext.clear();
            idcradtext.clear();
        }
    }

/*
* 下拉框监听事件
* */
    @FXML
    void combobox(ActionEvent event)
    {
        workComboBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldValue, Object newValue) {
                System.out.println("成功选中");
            }
        });
    }
    /*
    * 下拉框,搜索旁边的combobox*/
    @FXML
    void combobox1(ActionEvent event) throws CloneNotSupportedException {

        for (Employee p : employeeList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(employeeList);
        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Employee p : employeeList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getWork().equals(work1ComboBox.getValue().toString())) {
                data.add(p);
            }
        }
        nameSearch.clear();
    }
    /**
     * 删除
     *
     * @param event
     * @throws IOException
     */
    @FXML
    void delete(ActionEvent event) throws IOException {
        deleteStudents();
    }
/**保存修改
* */
    @FXML
    public void save(ActionEvent event) throws IOException {
        tool.WriteObject(employeeList,path.toString());
    }
        private boolean deleteStudents() throws IOException {
        int size = data.size();
        if (size <= 0) {
            return false;
        }
        //遍历所选选项
        for (int i = size - 1; i >= 0; i--) {
            Employee p = data.get(i);
            if (p.isSelected()) {//被选中则删除

/*
                System.out.println("[Delete]: " + p.getId() + " " + p.getName() + " " + p.getPhone() + " " + p.getEmail());//显示删除的信息
*/
                //从list中移除
                employeeList.remove(p);
                //将list写入到文件中
                tool.WriteObject(employeeList,path.toString());
                //从表格中移除
                data.remove(p);
            }
        }
        return true;
    }

    /**
     * 修改
     * @param event
     * @throws IOException
     */
    @FXML
    void modify(ActionEvent event) throws IOException {
        boolean flag = false;
        if (nametext.getText() != null && birthdaytext.getText() != null && goodattext.getText() != null && telephonetext.getText() != null&&idcradtext.getText() != null&& usernametext.getText() != null&& passwordtext.getText() != null){
            //遍历list,判断是否有同将要修改姓名一致的元素
            for (Employee p : employeeList) {//姓名
                if (p.getName().equals(nametext.getText())) {//通过id来查
                    flag = true;
                    //先移除列表所有数据
                    data.removeAll(employeeList);//先清空,再显示要显示的
                    //更新改行数据
                    p.setName(nametext.getText());
                    p.setWork(workComboBox.getValue().toString());
                    p.setBirthday(birthdaytext.getText());
                    p.setGoodat(goodattext.getText());
                    p.setTelephone(telephonetext.getText());
                    p.setIdcrad(idcradtext.getText());
                    System.out.println("[modify]: " + p.getUsername() + " " + p.getName() + " ");
                }
            }
            //如果有更新,则添加全部数据回表格
            if (flag) {
                data.addAll(employeeList);
            }
            tool.WriteObject(employeeList,path.toString());
            usernametext.clear();
            passwordtext.clear();
            nametext.clear();
            birthdaytext.clear();
            goodattext.clear();
            telephonetext.clear();
            idcradtext.clear();
        }
    }

    /**
     * 查找,仅支持通过id或name查找
     * @param event
     * @throws CloneNotSupportedException
     */
    @FXML
    void search(ActionEvent event) throws CloneNotSupportedException {
        for (Employee p : employeeList) {
            tmp.add(p.clone());
        }
        //先清空表格所有数据
        data.removeAll(employeeList);

        String name = nameSearch.getText();

        //若为空时,则添加回所有数据
        if (name.equals("")) {
            data.addAll(employeeList);
        }

        //遍历list,若有与搜索条件相同的数据,则添加到表格中
        for (Employee p : employeeList) {//这里可以改成任意equals(getText);就可以变成搜索任意的关键字
            if (p.getName().equals(name)) {
                data.add(p);
            }
        }
        nameSearch.clear();
    }

    @FXML
    private void initialize() throws IOException {
        //绑定每一列,需要添加
        workComboBox.getItems().addAll("医生","护士","护工");
        work1ComboBox.getItems().addAll("医生","护士","护工");
        usernameColumn.setCellValueFactory(new PropertyValueFactory<Employee, String>("username"));//id为person的属性
        nameColumn.setCellValueFactory(new PropertyValueFactory<Employee, String>("name"));
        workColumn.setCellValueFactory(new PropertyValueFactory<Employee, String>("work"));
        birthdayColumn.setCellValueFactory(new PropertyValueFactory<Employee, String>("birthday"));
        goodatColumn.setCellValueFactory(new PropertyValueFactory<Employee, String>("goodat"));
        telephonenumberColumn.setCellValueFactory(new PropertyValueFactory<Employee, String>("telephone"));
        idcradColumn.setCellValueFactory(new PropertyValueFactory<Employee, String>("idcrad"));
        selectColumn.setCellValueFactory(new PropertyValueFactory<Employee, Boolean>("selected"));
        //设定数据list
        tableView.setItems(data);
        tableView.setEditable(true);

        //按行读取文件,存入list中
        try{
            if(tool.ReadObject(path.toString())!=null)
                employeeList.addAll((Collection<? extends Employee>)tool.ReadObject(path.toString()));
            data.addAll(employeeList);
            if(tool.ReadObject_string("src/Model/Login.txt")!=null)
                AdministratorControllerLabel.setText((String)tool.ReadObject_string("src/Model/Login.txt"));
        } catch (ClassNotFoundException e) {
            System.out.println("没用此文件!");
        }
        catch (IOException e)
        {
            System.out.println("文件为空");
        }

        //初始化多选框,默认全为false,当为true则被选中
        selectColumn.setCellFactory(
                CellFactory.tableCheckBoxColumn(new Callback<Integer, ObservableValue<Boolean>>() {
                    @Override
                    public ObservableValue<Boolean> call(Integer index) {
                        final Employee employee = tableView.getItems().get(index);
                        ObservableValue<Boolean> ret =
                                new SimpleBooleanProperty(employee, "selected", employee.isSelected());//SimpleBooleanProperty(Object bean, String name, boolean initialValue)
                        ret.addListener(new ChangeListener<Boolean>() {
                            @Override
                            public void changed(
                                    ObservableValue<? extends Boolean> observable,
                                    Boolean oldValue, Boolean newValue) {
                                employee.setSelected(newValue);
                            }
                        });
                        return ret;
                    }
                }));

        /**
         * 单元格都可修改,但暂时未能保存到文件中,为后续优化功能
         */
        //每个单元格都可编辑
        Callback<TableColumn<Employee, String>,
                TableCell<Employee, String>> cellFactory
                = (TableColumn<Employee, String> p) -> new EditingCell();

        //为每列设定cellFactory
        usernameColumn.setCellFactory(cellFactory);
      /*  selectedColumn.setCellFactory(cellFactory);*/
        nameColumn.setCellFactory(cellFactory);
        workColumn.setCellFactory(cellFactory);
        birthdayColumn.setCellFactory(cellFactory);
        goodatColumn.setCellFactory(cellFactory);
        telephonenumberColumn.setCellFactory(cellFactory);
        idcradColumn.setCellFactory(cellFactory);
        //设置每个单元格可修改,还需要新添加
        usernameColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Employee, String> t) -> {
                    ((Employee) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setUsername(t.getNewValue());
                });
        //设置每个单元格可修改
        nameColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Employee, String> t) -> {
                    ((Employee) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setName(t.getNewValue());
                });
        //设置每个单元格可修改
        workColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Employee, String> t) -> {
                    ((Employee) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setWork(t.getNewValue());
                });
        //设置每个单元格可修改
        birthdayColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Employee, String> t) -> {
                    ((Employee) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setBirthday(t.getNewValue());
                });
        //设置每个单元格可修改
        goodatColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Employee, String> t) -> {
                    ((Employee) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setGoodat(t.getNewValue());
                });
        //设置每个单元格可修改
        telephonenumberColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Employee, String> t) -> {
                    ((Employee) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setTelephone(t.getNewValue());
                });
        //设置每个单元格可修改
        idcradColumn.setOnEditCommit(
                (TableColumn.CellEditEvent<Employee, String> t) -> {
                    ((Employee) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setIdcrad(t.getNewValue());
                });

        System.out.println("[initialize]: " + usernametext.getText() + " " + nameColumn.getText() + " ");
    }
}

实体类

package Model.Entity;

import java.io.Serializable;

/*
* 职工管理
* 各个属性
* */
public class Employee implements Cloneable , Serializable {
    private String username;//用户名
    private String name;//姓名
    private String password;//密码
    private String work;//职称
    private String birthday;//出生日期
    private String goodat;//专长
    private String telephone;//电话号码
    private String idcrad;//身份证号码
    private boolean selected;
    public Employee(String username,String password,String name, String work,String birthday,String goodat,String telephone,String idcrad) {
        this.username=username;
        this.password=password;
        this.name=name;
        this.work=work;
        this.birthday=birthday;
        this.goodat=goodat;
        this.telephone=telephone;
        this.idcrad=idcrad;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getWork() {
        return work;
    }

    public void setWork(String work) {
        this.work = work;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public String getGoodat() {
        return goodat;
    }

    public void setGoodat(String goodat) {
        this.goodat = goodat;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getIdcrad() {
        return idcrad;
    }

    public void setIdcrad(String idcrad) {
        this.idcrad = idcrad;
    }
    public boolean isSelected() {
        return selected;
    }
    public void setSelected(boolean selected) {
        this.selected = selected;
    }
    @Override
    public Employee clone() throws CloneNotSupportedException {
        return (Employee) super.clone();//克隆出一个对象
    }
    @Override
    public String toString() {`在这里插入代码片`
        return username+","+name+","+password+","+work+","+birthday+","+goodat+","+telephone+","+idcrad+"\n";
    }
}

fXML文件

<?xml version="1.0" encoding="UTF-8"?>

<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXPasswordField?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.paint.RadialGradient?>
<?import javafx.scene.paint.Stop?>
<?import javafx.scene.text.Font?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="1200.0" stylesheets="@CSS/AdministratorController.css" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.AdministratorController">
   <top>
      <AnchorPane prefHeight="169.0" prefWidth="1200.0" style="-fx-background-color: #7bbfea;" BorderPane.alignment="CENTER">
         <children>
            <ImageView fitHeight="170.0" fitWidth="514.0" layoutY="1.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@CSS/Image/neulabel.png" />
               </image>
            </ImageView>
            <ImageView fitHeight="150.0" fitWidth="200.0" layoutX="723.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true" />
            <Label layoutX="713.0" layoutY="17.0" prefHeight="144.0" prefWidth="487.0" text="管理人员界面">
               <font>
                  <Font name="System Bold" size="66.0" />
               </font>
            </Label>
            <Button fx:id="minimiser1" layoutX="1120.0" layoutY="13.0" mnemonicParsing="false" />
            <Button fx:id="quit1" layoutX="1154.0" layoutY="13.0" mnemonicParsing="false" />
            <JFXButton fx:id="returnButton" buttonType="RAISED" layoutX="1103.0" layoutY="123.0" onAction="#returnButtonOnAction" style="-fx-background-color: #cde6c7;" text="退出登录" />
            <ImageView fitHeight="206.0" fitWidth="164.0" layoutX="514.0" layoutY="3.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@CSS/Image/guanli.jpg" />
               </image>
            </ImageView>
            <Label layoutX="949.0" layoutY="12.0" prefHeight="32.0" prefWidth="64.0" text="欢迎您:">
               <font>
                  <Font size="16.0" />
               </font>
            </Label>
            <Label fx:id="AdministratorControllerLabel" layoutX="1013.0" layoutY="18.0" prefHeight="20.0" prefWidth="66.0" text="管理员" />
         </children>
      </AnchorPane>
   </top>
   <bottom>
      <AnchorPane fx:id="username" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
         <children>
            <Label fx:id="label" layoutX="270.0" layoutY="82.0" prefHeight="20.0" prefWidth="134.0" visible="false" />
            <JFXButton fx:id="addButton" buttonType="RAISED" layoutX="992.0" layoutY="24.0" onAction="#add" prefHeight="45.0" prefWidth="158.0" style="-fx-background-color: #cde6c7;" text="新增工作人员">
               <font>
                  <Font name="System Bold" size="19.0" />
               </font>
            </JFXButton>
            <JFXButton fx:id="changeButton1" buttonType="RAISED" layoutX="992.0" layoutY="111.0" onAction="#modify" prefHeight="44.0" prefWidth="165.0" ripplerFill="#ddd3d3" style="-fx-background-color: #cde6c7;" text="修改工作人员">
               <font>
                  <Font name="System Bold" size="20.0" />
               </font>
            </JFXButton>
            <JFXTextField fx:id="nametext" layoutX="23.0" layoutY="32.0" promptText="姓名" />
            <JFXComboBox fx:id="workComboBox" cache="true" layoutX="263.0" layoutY="32.0" onAction="#combobox" prefHeight="30.0" prefWidth="202.0" promptText="职称" style="-fx-background-color: #cde6c7;">
               <focusColor>
                  <RadialGradient centerX="0.5" centerY="0.5" radius="0.5">
                     <stops>
                        <Stop color="#040814" />
                        <Stop color="WHITE" offset="1.0" />
                     </stops>
                  </RadialGradient>
               </focusColor>
            </JFXComboBox>
            <JFXTextField fx:id="birthdaytext" layoutX="505.0" layoutY="32.0" promptText="出生日期" />
            <JFXTextField fx:id="goodattext" layoutX="736.0" layoutY="32.0" promptText="专长" />
            <JFXTextField fx:id="idcradtext" layoutX="272.0" layoutY="111.0" promptText="身份证" />
            <JFXTextField fx:id="telephonetext" layoutX="23.0" layoutY="111.0" promptText="联系电话" />
            <JFXTextField fx:id="usernametext" layoutX="505.0" layoutY="111.0" promptText="用户名" />
            <JFXPasswordField fx:id="passwordtext" layoutX="755.0" layoutY="111.0" promptText="密码" />
         </children>
      </AnchorPane>
   </bottom>
   <center>
      <GridPane BorderPane.alignment="CENTER">
        <columnConstraints>
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints maxHeight="195.0" minHeight="10.0" prefHeight="96.0" vgrow="SOMETIMES" />
          <RowConstraints maxHeight="304.0" minHeight="10.0" prefHeight="304.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <TableView fx:id="tableView" prefHeight="380.0" prefWidth="1200.0" GridPane.rowIndex="1">
              <columns>
                <TableColumn fx:id="usernameColumn" prefWidth="105.0" text="用户名" />
                <TableColumn fx:id="nameColumn" prefWidth="117.0" text="姓名" />
                  <TableColumn fx:id="workColumn" minWidth="3.0" prefWidth="153.0" text="职称" />
                  <TableColumn fx:id="birthdayColumn" prefWidth="164.0" text="出生日期" />
                  <TableColumn fx:id="goodatColumn" minWidth="0.0" prefWidth="148.0" text="专长" />
                  <TableColumn fx:id="telephonenumberColumn" minWidth="0.0" prefWidth="169.0" text="联系电话" />
                  <TableColumn fx:id="idcradColumn" minWidth="0.0" prefWidth="207.0" text="身份证" />
                  <TableColumn fx:id="selectColumn" prefWidth="136.0" text="选择" />
              </columns>
            </TableView>
            <AnchorPane prefHeight="200.0" prefWidth="200.0">
               <children>
                  <Label fx:id="label1" layoutX="439.0" layoutY="14.0" prefHeight="22.0" prefWidth="106.0" visible="false" />
                  <JFXTextField fx:id="nameSearch" layoutX="40.0" layoutY="43.0" promptText="姓名">
                     <font>
                        <Font name="System Bold" size="16.0" />
                     </font>
                  </JFXTextField>
                  <JFXButton fx:id="searcherButton" buttonType="RAISED" layoutX="265.0" layoutY="49.0" onAction="#search" prefHeight="30.0" prefWidth="94.0" ripplerFill="#280707" style="-fx-background-color: #cde6c7;" text="搜索姓名" textOverrun="WORD_ELLIPSIS">
                     <textFill>
                        <RadialGradient centerX="0.5" centerY="0.5" radius="0.5">
                           <stops>
                              <Stop color="#030303" />
                              <Stop color="#221e1e" offset="1.0" />
                           </stops>
                        </RadialGradient>
                     </textFill>
                  </JFXButton>
                  <JFXComboBox fx:id="work1ComboBox" cache="true" layoutX="409.0" layoutY="49.0" onAction="#combobox1" prefHeight="30.0" prefWidth="119.0" promptText="职称" style="-fx-background-color: #cde6c7;">
                     <focusColor>
                        <RadialGradient centerX="0.5" centerY="0.5" radius="0.5">
                           <stops>
                              <Stop color="#040814" />
                              <Stop color="WHITE" offset="1.0" />
                           </stops>
                        </RadialGradient>
                     </focusColor>
                  </JFXComboBox>
                  <JFXButton fx:id="deleteButton" buttonType="RAISED" layoutX="1070.0" layoutY="39.0" onAction="#delete" prefHeight="42.0" prefWidth="92.0" style="-fx-background-color: #6f60aa;" text="删   除">
                     <font>
                        <Font size="17.0" />
                     </font>
                  </JFXButton>
               </children>
            </AnchorPane>
         </children>
      </GridPane>
   </center>
</BorderPane>

注意事项

1,UI图做的好看,在于布局(美感),图片(适当添加图片),CSS(样式美化)。
,2, 造模板是很重要的,一个模板衍生十多种类的事很多。
3,看清需求
4,我使用了JFoenix外部包的,组件比较好看,不平常。

后期优化方向

添加css样式,
模糊搜索
MD5加密
背景,图片修改

全部代码地址

csdn: 还没上传;
百度网盘:还没上传;
求求大噶给个1键3连吧,点赞+关注,上传代码更快哦。

上一篇:毕业设计写这个你就赢了《Netty + JavaFx 实战:仿桌面版微信聊天》


下一篇:JavaFx 百度翻译API