基于java的通讯录管理系统(含基于javafx的可视化界面)

项目简介:

基于java 的通讯录管理系统。
使用javafx进行界面开发设计,程序包含添加和删除分组、个人主页(含图片等个人信息等等)、增删改查个人信息、模糊搜索、打开xml文件、打开csv(有格式要求)文件、打开vCard(有格式要求)文件、导出为xml文件、导出为csv文件、导出为vCard文件以及基本的新建保存文件功能,是一个小练习。
本程序采用Intellij IDEA 2024.1平台进行开发,使用JavaFX Scene Builder 2.0辅助界面设计,jdk版本为1.8.0_281。
另外,程序中导入了pinyin4j-2.5.0.jar包以及ez-vcard-0.12.1.jar包,如果出现找不到包的问题可以自行导入。

本程序参考学习了以下内容:

JavaFX 教程 (中文) | code.makery.ch

项目结构:

699b162a6e3245b6a40d3159b1cc9ae5.png

项目类图:

17fc4ec6c5564ac5b10ea8fd109c02b4.png

项目代码:

1.model包:

Person

package model;

import java.io.File;
import java.time.LocalDate;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import util.LocalDateAdapter;

public class Person {

    private final StringProperty groupName;//所属组
    private final StringProperty personName;//名字
    private final StringProperty homeAddress;//家庭地址
    private final IntegerProperty postalCode;//邮编
    private final StringProperty workAddress;//工作地址&&单位
    private final ObjectProperty<LocalDate> birthday;//生日
    private final StringProperty phonenumber;//电话号码
    private final StringProperty emailadd;//邮箱
    private final StringProperty extralting;//备注
    private String personimage;//图片(URL)

    public Person() {
        this(null, null);
    }
    //设置一些初始数据
    public Person(String groupName, String personName) {
        this.groupName = new SimpleStringProperty(groupName);
        this.personName = new SimpleStringProperty(personName);
        this.homeAddress = new SimpleStringProperty("泰山区学牲宿舍");
        this.postalCode = new SimpleIntegerProperty(1234);
        this.workAddress = new SimpleStringProperty("SCAU");
        this.birthday = new SimpleObjectProperty<LocalDate>(LocalDate.of(2000, 2, 4));
        this.phonenumber = new SimpleStringProperty("1145145178");
        this.emailadd = new SimpleStringProperty("11111@163.com");
        this.extralting = new SimpleStringProperty("圆神糕首");
        File file = new File("src\\resources\\images\\man.png");
        String s = file.toURI().toString();
        this.personimage = s;
    }

    public String getgroupName() {
        return groupName.get();
    }

    public void setgroupName(String groupName) {
        this.groupName.set(groupName);
    }

    public StringProperty groupNameProperty() {
        return groupName;
    }

    public String getPersonName() {
        return personName.get();
    }

    public void setPersonName(String personName) {
        this.personName.set(personName);
    }

    public StringProperty personNameProperty() {
        return personName;
    }

    public String getHomeAddress() {
        return homeAddress.get();
    }

    public void setHomeAddress(String homeAddress) {
        this.homeAddress.set(homeAddress);
    }

    public StringProperty homeAddressProperty() {
        return homeAddress;
    }

    public int getPostalCode() {
        return postalCode.get();
    }

    public void setPostalCode(int postalCode) {
        this.postalCode.set(postalCode);
    }

    public IntegerProperty postalCodeProperty() {
        return postalCode;
    }

    public String getWorkAddress() {
        return workAddress.get();
    }

    public void setWorkAddress(String workAddress) {
        this.workAddress.set(workAddress);
    }

    public StringProperty workAddressProperty() {
        return workAddress;
    }

    public void setPhonenumber(String phonenumber) {this.phonenumber.set(phonenumber);}

    public String getPhonenumber() {return phonenumber.get();}

    public StringProperty phonenumberProperty() {return phonenumber;}

    public String getEmailadd() {return emailadd.get();}

    public void setEmailadd(String emailadd) {this.emailadd.set(emailadd);}

    public StringProperty emailaddProperty() {return emailadd;}

    public String getExtralting() {return extralting.get();}

    public void setExtralting(String extralting) {this.extralting.set(extralting);}

    public StringProperty extraltingProperty() {return extralting;}

    public String getPersonimage() {return personimage;}

    public void setPersonimage(String personimage) {this.personimage=personimage;}

    @XmlJavaTypeAdapter(LocalDateAdapter.class)
    public LocalDate getBirthday() {
        return birthday.get();
    }

    public void setBirthday(LocalDate birthday) {
        this.birthday.set(birthday);
    }

    public ObjectProperty<LocalDate> birthdayProperty() {
        return birthday;
    }
}

PersonListWrapper

package model;

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
//读取xml文件
@XmlRootElement(name = "persons")
public class PersonListWrapper {

    private List<Person> persons;

    @XmlElement(name = "person")
    public List<Person> getPersons() {
        return persons;
    }

    public void setPersons(List<Person> persons) {
        this.persons = persons;
    }
}

resources包:存资源图片

util包:

DateUtil

package util;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;


public class DateUtil {
    //设置生日格式
    private static final String DATE_PATTERN = "yyyy.MM.dd";

    private static final DateTimeFormatter DATE_FORMATTER =
            DateTimeFormatter.ofPattern(DATE_PATTERN);

    public static String format(LocalDate date) {
        if (date == null) {
            return null;
        }
        return DATE_FORMATTER.format(date);
    }

    public static LocalDate parse(String dateString) {
        try {
            return DATE_FORMATTER.parse(dateString, LocalDate::from);
        } catch (DateTimeParseException e) {
            return null;
        }
    }

    public static boolean validDate(String dateString) {
        return DateUtil.parse(dateString) != null;
    }
}

LocalDateAdapter

package util;

import java.time.LocalDate;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class LocalDateAdapter extends XmlAdapter<String, LocalDate> {
    @Override
    public LocalDate unmarshal(String v) throws Exception {
        return LocalDate.parse(v);
    }

    @Override
    public String marshal(LocalDate v) throws Exception {
        return v.toString();
    }
}

view包:

ChangeHanziToPinyin

package view;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;

public class ChangeHanziToPinyin {
    public static String getPinYin(String src) {
        String t4 = "";
        if (src != null) {
            char[] t1 = src.toCharArray();
            String[] t2 = new String[t1.length];
            // 设置汉字拼音输出的格式
            HanyuPinyinOutputFormat t3 = new HanyuPinyinOutputFormat();
            t3.setCaseType(HanyuPinyinCaseType.LOWERCASE);
            t3.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
            t3.setVCharType(HanyuPinyinVCharType.WITH_V);
            int t0 = t1.length;
            try {
                for (int i = 0; i < t0; i++) {
                    // 判断是否为汉字字符
                    if (Character.toString(t1[i]).matches("[\\u4E00-\\u9FA5]+")) {
                        // 将汉字的几种全拼都存到t2数组中
                        t2 = PinyinHelper.toHanyuPinyinStringArray(t1[i], t3);
                        // 取出该汉字全拼的第一种读音并连接到字符串t4后
                        t4 += t2[0];
                    } else {
                        // 如果不是汉字字符,直接取出字符并连接到字符串t4后
                        t4 += Character.toString(t1[i]);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (t4 != null && !"".equals(t4)) {
                t4 = t4.toLowerCase();
            }
        }
        return t4.toLowerCase();
    }

}

MainApp

package view;

import java.io.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.prefs.Preferences;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;
import javafx.stage.Stage;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import model.Person;
import model.PersonListWrapper;

public class MainApp extends Application {

    private Stage primaryStage;//程序主页面
    private BorderPane rootLayout;//背景页面、菜单

    private ObservableList<Person> personData = FXCollections.observableArrayList();//运用一个集合类来存储每个联系人的数据
    private List<String> personGroup = new ArrayList<>();//用一个list来存储分组数据
    private String mainlygroup = " ";//当前选择的分组
    private String searchNamestring ="";//当前想要查找的名字字符
    private String searchPhonestring ="";//当前想要查找的电话号码字符
    private boolean firststart = false;

    public MainApp () {}
    //将当前分组数据更新到分组list中
    public void setPersonGroup(ObservableList<Person> personData){
        for (Person person : personData) {
            if(personGroup.isEmpty()&&!person.getgroupName().equals("None")){
                personGroup.add(person.getgroupName());
            }else{
                if(!personGroup.contains(person.getgroupName())&&!person.getgroupName().equals("None")){
                    personGroup.add(person.getgroupName());
                }
            }
        }
    }
    //清除分组数据
    public void clearPersonGroup(){this.personGroup.clear();}
    //添加分组
    public void addPersonGroup(String groupName){this.personGroup.add(groupName);}
    //删除分组
    public void deletePersonGroup(String groupName){
        for(Person person : rtPersonData()){
            if(person.getgroupName().equals(groupName)){
                person.setgroupName("None");
            }
        }
        personGroup.clear();
        setPersonGroup(rtPersonData());
    }
    //获得分组数据
    public List<String> getPersonGroup(){return personGroup;}
    //设置当前分组
    public void setMainlygroup(String mainlygroup){this.mainlygroup = mainlygroup;}
    //获取当前分组
    public String getMainlygroup(){return mainlygroup;}
    //获取当前程序中读取的联系人数据(副本)
    public ObservableList<Person> getPersonData() {
        if(mainlygroup.equals("all")&& searchNamestring.isEmpty() && searchPhonestring.isEmpty()){
            return personData;
        }
        ObservableList<Person> personData1 = FXCollections.observableArrayList();
        for(Person person : personData) {
            if(searchNamestring.isEmpty() && searchPhonestring.isEmpty()){
                if(person.getgroupName().equals(mainlygroup)) {
                    personData1.add(person);
                }
            }else if(searchPhonestring.isEmpty()){
                if(cmp(ChangeHanziToPinyin.getPinYin(searchNamestring),ChangeHanziToPinyin.getPinYin(person.getPersonName()))){
                    personData1.add(person);
                }
            }else if(searchNamestring.isEmpty()){
                if(cmp(searchPhonestring,person.getPhonenumber())){
                    personData1.add(person);
                }
            }else{
                if(cmp(searchPhonestring,person.getPhonenumber())&&cmp(ChangeHanziToPinyin.getPinYin(searchNamestring),ChangeHanziToPinyin.getPinYin(person.getPersonName()))){
                    personData1.add(person);
                }
            }
        }
        return personData1;
    }
    //获取当前程序中读取的数据,可改变
    public ObservableList<Person> rtPersonData(){return personData;}
    //字符串对比方法,用于实现搜索功能
    public boolean cmp(String searchstring, String thisname){
        char [] arr = searchstring.toCharArray();
        int res=0;
        for(char ch : thisname.toCharArray()) {
            for(char ch2 : arr) {
                if(ch == ch2) {
                    ++res;
                }
            }
        }
        if(res == 0){
            return false;
        }else {
            return true;
        }
    }
    //设置搜索名字
    public void setSearchNamestring(String searchNamestring){this.searchNamestring = searchNamestring;}
    //设置搜索电话号码
    public void setSearchPhonestring(String searchPhonestring){this.searchPhonestring = searchPhonestring;}
    //获取搜索名字
    public String getSearchNamestring(){return searchNamestring;}

    //程序启动
    @Override
    public void start(Stage primaryStage) {
        this.primaryStage = primaryStage;
        this.primaryStage.setTitle("通讯录管理APP");
        this.primaryStage.getIcons().add(new Image("File:src\\view\\app.png"));
        //设置背景、菜单
        initRootLayout();
        //设置程序主界面
        showPersonOverview();
    }
    //设置菜单和背景界面
    public void initRootLayout() {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("RootLayout.fxml"));//读取fxml文件,存储了可视化界面的代码
            rootLayout = (BorderPane) loader.load();
            if(!firststart) {
                File file = getPersonFilePath();
                if (file != null) {
                    if(file.getPath().endsWith(".xml")){
                        loadPersonDataFromFile(file);
                    }
                    else if(file.getPath().endsWith(".csv")){
                        loadPersonDataFromCSVFile(file);
                    }
                    else if(file.getPath().endsWith(".vcf")){
                        loadPersonDataFromvCardFile(file);
                    }
                }
                firststart = true;
            }


            Scene scene = new Scene(rootLayout);
            primaryStage.setScene(scene);

            RootLayoutController controller = loader.getController();
            controller.setMainApp(this);
            setPersonGroup(personData);//初始化组菜单
            controller.initMenuItem(getPersonGroup());
            primaryStage.show();//呈现在舞台中
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    //设置用户主界面
    public void showPersonOverview() {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("PersonOverview.fxml"));
            AnchorPane personOverview = (AnchorPane) loader.load();

            rootLayout.setCenter(personOverview);//将该界面设置在背景的中心

            PersonOverviewController controller = loader.getController();
            controller.setMainApp(this);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //呈现个人信息编辑界面
    public boolean showPersonEditDialog(Person person) {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("PersonEditDialog.fxml"));
            AnchorPane page = (AnchorPane) loader.load();

            Stage dialogStage = new Stage();
            dialogStage.setTitle("Edit Person");
            dialogStage.initModality(Modality.WINDOW_MODAL);
            dialogStage.initOwner(primaryStage);
            Scene scene = new Scene(page);
            dialogStage.setScene(scene);

            PersonEditDialogController controller = loader.getController();
            controller.setDialogStage(dialogStage);
            controller.setPerson(person);

            dialogStage.getIcons().add(new Image("file:src\\resources\\images\\edit.png"));

            dialogStage.showAndWait();

            return controller.isOkClicked();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    //呈现分组信息编辑界面
    public boolean showPersonGroupEditDialog() {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("PersonGroupEditDialog.fxml"));
            AnchorPane page = (AnchorPane) loader.load();

            Stage dialogStage = new Stage();
            dialogStage.setTitle("New PersonGroup");
            dialogStage.initModality(Modality.WINDOW_MODAL);
            dialogStage.initOwner(primaryStage);
            Scene scene = new Scene(page);
            dialogStage.setScene(scene);

            PersonGroupEditDialogController controller = loader.getController();
            controller.setDialogStage(dialogStage);
            controller.setMainApp(this);

            dialogStage.getIcons().add(new Image("file:src\\resources\\images\\edit.png"));

            dialogStage.showAndWait();

            return controller.isOkClicked();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    //呈现分组信息删除界面
    public boolean showPersonGroupDeleteDialog() {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("PersonGroupDelete.fxml"));
            AnchorPane page = (AnchorPane) loader.load();

            Stage dialogStage = new Stage();
            dialogStage.setTitle("Delete PersonGroup");
            dialogStage.initModality(Modality.WINDOW_MODAL);
            dialogStage.initOwner(primaryStage);
            Scene scene = new Scene(page);
            dialogStage.setScene(scene);

            PersonGroupDeleteController controller = loader.getController();
            controller.setDialogStage(dialogStage);
            controller.setMainApp(this);

            dialogStage.getIcons().add(new Image("file:src\\resources\\images\\edit.png"));

            dialogStage.showAndWait();

            return controller.isOkClicked();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    //呈现搜索界面
    public boolean showPersonNameSearchDialog() {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("PersonSearchDialog.fxml"));
            AnchorPane page = (AnchorPane) loader.load();

            Stage dialogStage = new Stage();
            dialogStage.setTitle("Search Person");
            dialogStage.initModality(Modality.WINDOW_MODAL);
            dialogStage.initOwner(primaryStage);
            Scene scene = new Scene(page);
            dialogStage.setScene(scene);

            PersonSearchDialogController controller = loader.getController();
            controller.setDialogStage(dialogStage);
            controller.setMainApp(this);

            dialogStage.getIcons().add(new Image("file:src\\resources\\images\\edit.png"));

            dialogStage.showAndWait();

            return controller.isOkClicked();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
    //获取文件地址(上一个)
    public File getPersonFilePath() {
        Preferences prefs = Preferences.userNodeForPackage(MainApp.class);
        String filePath = prefs.get("filePath", null);
        if (filePath != null) {
            return new File(filePath);
        } else {
            return null;
        }
    }
    //设置文件地址
    public void setPersonFilePath(File file) {
        Preferences prefs = Preferences.userNodeForPackage(MainApp.class);
        if (file != null) {
            prefs.put("filePath", file.getPath());

            primaryStage.setTitle("*通讯录管理系统* - " + file.getName());
        } else {
            prefs.remove("filePath");

            primaryStage.setTitle("*通讯录管理系统*");
        }
    }

    //读取文件
    public void loadPersonDataFromFile(File file) {
        try {
            JAXBContext context = JAXBContext.newInstance(PersonListWrapper.class);
            Unmarshaller um = context.createUnmarshaller();

            PersonListWrapper wrapper = (PersonListWrapper) um.unmarshal(file);

            personData.clear();
            personData.addAll(wrapper.getPersons());
            setPersonGroup(personData);
            setPersonFilePath(file);
        } catch (Exception e) {
            e.printStackTrace();
            Alert alert = new Alert(AlertType.ERROR);
            alert.setTitle("Error");
            alert.setHeaderText("Could not load data");
            alert.setContentText("Could not load data from file:\n" + file.getPath());

            alert.showAndWait();
        }
    }
    //保存
    public void savePersonDataToFile(File file) {
        try {
            JAXBContext context = JAXBContext
                    .newInstance(PersonListWrapper.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            PersonListWrapper wrapper = new PersonListWrapper();
            wrapper.setPersons(personData);

            m.marshal(wrapper, file);

            setPersonFilePath(file);
        } catch (Exception e) {
            Alert alert = new Alert(AlertType.ERROR);
            alert.setTitle("Error");
            alert.setHeaderText("Could not save data");
            alert.setContentText("Could not save data to file:\n" + file.getPath());

            alert.showAndWait();
        }
    }

    //读取文件
    public void loadPersonDataFromCSVFile(File csvFile) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader(csvFile.getPath()));
            personData.clear();
            // 读取CSV文件内容
            String line;
            line = reader.readLine();
            while ((line = reader.readLine()) != null) {
                // 按逗号分割行内容
                String[] fields = line.split(",");
                Person person = new Person();
                // 打印每一行的数据
                int i=0;
                for (String field : fields) {
                    switch (i){
                        case 0:
                            person.setgroupName(field);
                            break;
                        case 1:
                            person.setPersonName(field);
                            break;
                        case 2:
                            person.setEmailadd(field);
                            break;
                        case 3:
                            person.setBirthday(LocalDate.parse(field));
                            break;
                        case 4:
                            person.setHomeAddress(field);
                            break;
                        case 5:
                            person.setWorkAddress(field);
                            break;
                        case 6:
                            person.setPhonenumber(field);
                            break;
                        case 7:
                            person.setPostalCode(Integer.parseInt(field));
                            break;
                        case 8:
                            person.setExtralting(field);
                            break;
                        case 9:
                            person.setPersonimage(field);
                            break;
                    }
                    ++i;
                }
                personData.add(person);
            }
            reader.close();
            setPersonGroup(personData);
            setPersonFilePath(csvFile);
            // 关闭读取流

        } catch (Exception e) {
            e.printStackTrace();
            Alert alert = new Alert(AlertType.ERROR);
            alert.setTitle("Error");
            alert.setHeaderText("Could not load data");
            alert.setContentText("Could not load data from file:\n" + csvFile.getPath());

            alert.showAndWait();
        }
    }
    //导出为CSV
    public void creatCSV(File file){
        try {
            // 创建CSV文件写入流
            FileWriter writer = new FileWriter(file);

            // 写入CSV文件头部
            writer.append("GroupName,PersonName,Email,Birthday,homeAddress,workAddress,phoneNumber,postalCode,extralting,personimage");
            writer.append("\n");

            // 写入数据
            for(Person person : personData){
                writer.append(person.getgroupName()).append(",").append(person.getPersonName()).append(",").append(person.getEmailadd()).append(",").append(person.getBirthday().toString()).append(",").append(person.getHomeAddress()).append(",").append(person.getWorkAddress()).append(",").append(person.getPhonenumber()).append(",").append(Integer.toString(person.getPostalCode())).append(",").append(person.getExtralting()).append(",").append(person.getPersonimage());
                writer.append("\n");
            }

            // 关闭写入流
            writer.flush();
            writer.close();

            System.out.println("CSV文件已创建成功!");
        } catch (IOException e) {
            System.out.println("创建CSV文件时出错:" + e.getMessage());
        }
    }

    public void loadPersonDataFromvCardFile(File file) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader(file.getPath()));
            personData.clear();
            // 读取vCard文件内容
            String line;
            int i=0;
            Person person = new Person();
            while ((line = reader.readLine()) != null) {
                // 读取每一行的数据
                if(i==0){
                    Person person1 = new Person();
                    person = person1;
                }
                String field = "";
                if(i!=11){
                    String[] fields = line.split(":");
                    int j=0;
                    for(String f:fields){
                        ++j;
                        if(j==2){
                            field = f;
                            break;
                        }
                    }
                }else{
                    field = line.substring(6);
                }

                    switch (i){
                        case 3:
                            person.setPersonName(field);
                            break;
                        case 4:
                            person.setgroupName(field);
                            break;
                        case 5:
                            person.setEmailadd(field);
                            break;
                        case 6:
                            person.setPhonenumber(field);
                            break;
                        case 7:
                            person.setBirthday(LocalDate.parse(field));
                            break;
                        case 8:
                            person.setHomeAddress(field);
                            break;
                        case 9:
                            person.setWorkAddress(field);
                            break;
                        case 10:
                            person.setExtralting(field);
                            break;
                        case 11:
                            person.setPersonimage(field);
                            break;
                        case 12:
                            person.setPostalCode(Integer.parseInt(field));
                            break;
                    }
                    ++i;
                    if(i==13){
                        personData.add(person);
                    }
                    if(i==14){
                        i=0;
                    }
            }

            // 关闭读取流
            reader.close();
            setPersonGroup(personData);
            setPersonFilePath(file);
        } catch (Exception e) {
            Alert alert = new Alert(AlertType.ERROR);
            alert.setTitle("Error");
            alert.setHeaderText("Could not load data");
            alert.setContentText("Could not load data from file:\n" + file.getPath());

            alert.showAndWait();
        }
    }
    //导出为vCard
    public void creatvCard(File file){
        try {
            // 创建vCard文件写入流
            FileWriter writer = new FileWriter(file);

            // 写入示例vCard数据
            for(Person person : personData){
                writer.write("BEGIN:VCARD\n");
                writer.write("VERSION:3.0\n");
                writer.write("PRODID:ez-vcard 0.10.6");
                writer.write("FN:"+person.getPersonName()+"\n");
                writer.write("N:"+person.getPersonName()+"\n");
                writer.write("GROUP:"+person.getgroupName()+"\n");
                writer.write("EMAIL:"+person.getEmailadd()+"\n");
                writer.write("TEL:"+person.getPhonenumber()+"\n");
                writer.write("BDAY:"+person.getBirthday().toString()+"\n");
                writer.write("ADR:"+person.getHomeAddress()+"\n");
                writer.write("ADR:"+person.getWorkAddress()+"\n");
                writer.write("NOTE:"+person.getExtralting()+"\n");
                writer.write("PHOTO:"+person.getPersonimage()+"\n");
                writer.write("POST:"+person.getPostalCode()+"\n");
                writer.write("END:VCARD\n");

            }
            // 关闭写入流
            writer.flush();
            writer.close();

            System.out.println("vCard文件已创建成功!");
        } catch (IOException e) {
            System.out.println("创建vCard文件时出错:" + e.getMessage());
        }
    }

    public Stage getPrimaryStage() {
        return primaryStage;
    }

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

PersonEditDialog.fxml

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

<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="410.0" prefWidth="520.0" styleClass="background" stylesheets="" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.PersonEditDialogController">
   <children>
      <GridPane layoutX="10.0" layoutY="44.0" prefHeight="296.0" prefWidth="419.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="44.0">
        <columnConstraints>
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="218.0" minWidth="10.0" prefWidth="111.0" />
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="316.0" minWidth="10.0" prefWidth="261.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <Label text="组别" />
            <Label text="姓名" GridPane.rowIndex="1" />
            <Label text="家庭地址" GridPane.rowIndex="2" />
            <Label text="工作单位" GridPane.rowIndex="3" />
            <Label text="邮编" GridPane.rowIndex="4" />
            <TextField fx:id="groupNameField" GridPane.columnIndex="1" />
            <TextField fx:id="personNameField" GridPane.columnIndex="1" GridPane.rowIndex="1" />
            <TextField GridPane.columnIndex="1" GridPane.rowIndex="2" />
            <TextField fx:id="homeAddressField" GridPane.columnIndex="1" GridPane.rowIndex="2" />
            <TextField fx:id="workAddressField" GridPane.columnIndex="1" GridPane.rowIndex="3" />
            <TextField fx:id="postalCodeField" GridPane.columnIndex="1" GridPane.rowIndex="4" />
            <TextField fx:id="birthdayField" GridPane.columnIndex="1" GridPane.rowIndex="5" />
            <Label text="生日" GridPane.rowIndex="5" />
            <Label text="电话号码" GridPane.rowIndex="6" />
            <Label text="邮箱" GridPane.rowIndex="7" />
            <Label text="备注" GridPane.rowIndex="8" />
            <TextField fx:id="phonenumberField" GridPane.columnIndex="1" GridPane.rowIndex="6" />
            <TextField fx:id="emailaddField" GridPane.columnIndex="1" GridPane.rowIndex="7" />
            <TextField fx:id="extralingField" GridPane.columnIndex="1" GridPane.rowIndex="8" />
         </children>
      </GridPane>
      <ButtonBar layoutX="176.0" layoutY="233.0" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0">
        <buttons>
            <Button defaultButton="true" mnemonicParsing="false" onAction="#handleOk" text="OK" />
          <Button mnemonicParsing="false" onAction="#handleCancel" prefWidth="120.0" text="Cancel" />
        </buttons>
      </ButtonBar>
   </children>
</AnchorPane>

PersonEditDialogController

package view;

import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import model.Person;
import util.DateUtil;

public class PersonEditDialogController {

    @FXML
    private TextField groupNameField;
    @FXML
    private TextField personNameField;
    @FXML
    private TextField homeAddressField;
    @FXML
    private TextField postalCodeField;
    @FXML
    private TextField workAddressField;
    @FXML
    private TextField birthdayField;
    @FXML
    private TextField phonenumberField;
    @FXML
    private TextField emailaddField;
    @FXML
    private TextField extralingField;


    private Stage dialogStage;
    private Person person;
    private boolean okClicked = false;

    @FXML
    private void initialize() {
    }
    //设置舞台
    public void setDialogStage(Stage dialogStage) {
        this.dialogStage = dialogStage;
        this.dialogStage.getIcons().add(new Image("file:src\\resources\\images\\edit.png"));
    }
    //将原本的信息呈现在编辑框中
    public void setPerson(Person person) {
        this.person = person;

        groupNameField.setText(person.getgroupName());
        personNameField.setText(person.getPersonName());
        homeAddressField.setText(person.getHomeAddress());
        postalCodeField.setText(Integer.toString(person.getPostalCode()));
        workAddressField.setText(person.getWorkAddress());
        birthdayField.setText(DateUtil.format(person.getBirthday()));
        birthdayField.setPromptText("dd.mm.yyyy");
        phonenumberField.setText(person.getPhonenumber());
        emailaddField.setText(person.getEmailadd());
        extralingField.setText(person.getExtralting());
    }
    //判断是否点击确定
    public boolean isOkClicked() {
        return okClicked;
    }

    //OK按钮事件
    @FXML
    private void handleOk() {
        if (isInputValid()) {
            person.setgroupName(groupNameField.getText());
            person.setPersonName(personNameField.getText());
            person.setHomeAddress(homeAddressField.getText());
            person.setPostalCode(Integer.parseInt(postalCodeField.getText()));
            person.setWorkAddress(workAddressField.getText());
            person.setBirthday(DateUtil.parse(birthdayField.getText()));
            person.setPhonenumber(phonenumberField.getText());
            person.setEmailadd(emailaddField.getText());
            person.setExtralting(extralingField.getText());
            okClicked = true;
            dialogStage.close();
        }
    }

    //取消按钮事件
    @FXML
    private void handleCancel() {
        dialogStage.close();
    }

    //是否输入
    private boolean isInputValid() {
        String errorMessage = "";

        if (groupNameField.getText() == null || groupNameField.getText().length() == 0) {
            errorMessage += "No valid group name!\n";
        }
        if (personNameField.getText() == null || personNameField.getText().length() == 0) {
            errorMessage += "No valid person name!\n";
        }
        if (homeAddressField.getText() == null || homeAddressField.getText().length() == 0) {
            errorMessage += "No valid home address!\n";
        }

        if (postalCodeField.getText() == null || postalCodeField.getText().length() == 0) {
            errorMessage += "No valid postal code!\n";
        }
        if (phonenumberField.getText() == null || phonenumberField.getText().length() == 0) {
            errorMessage += "No valid phone number!\n";
        }
        if (emailaddField.getText() == null || emailaddField.getText().length() == 0) {
            errorMessage += "No valid email address!\n";
        }
        if (extralingField.getText() == null || extralingField.getText().length() == 0) {
            errorMessage += "No valid extral word!\n";
        }else {
            try {
                Integer.parseInt(postalCodeField.getText());
            } catch (NumberFormatException e) {
                errorMessage += "No valid postal code (must be an integer)!\n";
            }
        }

        if (workAddressField.getText() == null || workAddressField.getText().length() == 0) {
            errorMessage += "No valid work address!\n";
        }

        if (birthdayField.getText() == null || birthdayField.getText().length() == 0) {
            errorMessage += "No valid birthday!\n";
        } else {
            if (!DateUtil.validDate(birthdayField.getText())) {
                errorMessage += "No valid birthday. Use the format yyyy.mm.dd!\n";
            }
        }

        if (errorMessage.length() == 0) {
            return true;
        } else {
            Alert alert = new Alert(AlertType.ERROR);
            alert.initOwner(dialogStage);
            alert.setTitle("Invalid Fields");
            alert.setHeaderText("Please correct invalid fields");
            alert.setContentText(errorMessage);

            alert.showAndWait();

            return false;
        }
    }
}

PersonGroupDelete.fxml

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.PersonGroupDeleteController">
   <children>
      <GridPane layoutX="123.0" layoutY="155.0" prefHeight="53.0" prefWidth="349.0">
        <columnConstraints>
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
          <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <Label prefHeight="36.0" prefWidth="108.0" text="需要删除的分组:" />
            <TextField fx:id="groupNameField" prefHeight="43.0" prefWidth="174.0" GridPane.columnIndex="1" />
         </children>
      </GridPane>
      <Button layoutX="150.0" layoutY="295.0" mnemonicParsing="false" onAction="#handleOk" prefHeight="53.0" prefWidth="120.0" text="确定" />
      <Button layoutX="309.0" layoutY="295.0" mnemonicParsing="false" onAction="#handleCancel" prefHeight="53.0" prefWidth="120.0" text="取消" />
   </children>
</AnchorPane>

PersonGroupDeleteController

package view;

import java.io.File;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import model.Person;

public class PersonGroupDeleteController {
    @FXML
    private TextField groupNameField;

    private Stage groupdialogStage;
    private String groupName;
    private MainApp mainApp;
    private boolean okClicked = false;

    @FXML
    private void initialize() {
    }
    //设置舞台
    public void setDialogStage(Stage dialogStage) {
        this.groupdialogStage = dialogStage;
        this.groupdialogStage.getIcons().add(new Image("file:src\\resources\\images\\edit.png"));
    }
    //设置组名
    public void setGroupName(String groupName) {this.groupName = groupName;}
    //将mainAPP传入,用于调用一些方法以及修改变量
    public void setMainApp(MainApp mainApp) {this.mainApp = mainApp;}
    //返回是否按下确定按钮
    public boolean isOkClicked() {
        return okClicked;
    }

    //确定按钮事件
    @FXML
    private void handleOk() {
        if (isInputValid()) {
            mainApp.deletePersonGroup(groupNameField.getText());
            okClicked = true;
            groupdialogStage.close();
        }
    }

    //取消按钮事件
    @FXML
    private void handleCancel() {
        groupdialogStage.close();
    }

    //判断输入合法性
    private boolean isInputValid() {
        String errorMessage = "";

        if (groupNameField.getText().isEmpty()) {
            errorMessage += "No valid group name!\n";
        }
        if (errorMessage.length()==0) {
            return true;
        } else {
            // Show the error message.
            Alert alert = new Alert(AlertType.ERROR);
            alert.initOwner(groupdialogStage);
            alert.setTitle("Invalid Fields");
            alert.setHeaderText("Please correct invalid fields");
            alert.setContentText(errorMessage);

            alert.showAndWait();

            return false;
        }
    }
}

PersonGroupEditDialog.fxml

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>


<AnchorPane prefHeight="212.0" prefWidth="445.0" styleClass="background" stylesheets="" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.PersonGroupEditDialogController">
   <children>
      <GridPane layoutX="40.0" layoutY="36.0" prefHeight="66.0" prefWidth="368.0">
        <columnConstraints>
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="186.0" minWidth="10.0" prefWidth="103.0" />
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="265.0" minWidth="10.0" prefWidth="265.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <Label prefHeight="44.0" prefWidth="93.0" styleClass="label-bright" stylesheets="" text="新增分组" />
            <TextField fx:id="groupNameField" prefHeight="66.0" prefWidth="211.0" GridPane.columnIndex="1" />
         </children>
      </GridPane>
      <Button layoutX="99.0" layoutY="147.0" mnemonicParsing="false" onAction="#handleOk" text="确定" />
      <Button layoutX="254.0" layoutY="147.0" mnemonicParsing="false" onAction="#handleCancel" text="取消" />
   </children>
</AnchorPane>

PersonGroupEditDialogController

package view;

import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.stage.Stage;

public class PersonGroupEditDialogController {
    @FXML
    private TextField groupNameField;

    private Stage groupdialogStage;
    private String groupName;
    private MainApp mainApp;
    private boolean okClicked = false;

    @FXML
    private void initialize() {
    }
    //设置舞台
    public void setDialogStage(Stage dialogStage) {
        this.groupdialogStage = dialogStage;
        this.groupdialogStage.getIcons().add(new Image("file:src\\resources\\images\\edit.png"));
    }
    //设置组名
    public void setGroupName(String groupName) {this.groupName = groupName;}
    //将mainAPP传入,用于调用一些方法以及修改变量
    public void setMainApp(MainApp mainApp) {this.mainApp = mainApp;}
    //返回是否按下确定按钮
    public boolean isOkClicked() {
        return okClicked;
    }

    //确定按钮事件
    @FXML
    private void handleOk() {
        if (isInputValid()) {
            mainApp.addPersonGroup(groupNameField.getText());
            okClicked = true;
            groupdialogStage.close();
        }
    }

    //取消按钮事件
    @FXML
    private void handleCancel() {
        groupdialogStage.close();
    }

    //判断输入合法性
    private boolean isInputValid() {
        String errorMessage = "";

        if (groupNameField.getText() == null || groupNameField.getText().length() == 0) {
            errorMessage += "No valid group name!\n";
        }
        if (errorMessage.length() == 0) {
            return true;
        } else {
            // Show the error message.
            Alert alert = new Alert(AlertType.ERROR);
            alert.initOwner(groupdialogStage);
            alert.setTitle("Invalid Fields");
            alert.setHeaderText("Please correct invalid fields");
            alert.setContentText(errorMessage);

            alert.showAndWait();

            return false;
        }
    }

}

PersonOverview.fxml

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

<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="900.0" prefWidth="1500.0" stylesheets="" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.PersonOverviewController">
   <children>
      <SplitPane dividerPositions="0.4126984126984127" layoutX="153.0" layoutY="70.0" prefHeight="300.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <items>
          <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
               <children>
                  <TableView fx:id="personTable" layoutX="-12.0" layoutY="49.0" prefHeight="298.0" prefWidth="175.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
                    <columns>
                      <TableColumn fx:id="groupColumn" prefWidth="75.0" text="组别" />
                      <TableColumn fx:id="personNameColumn" prefWidth="75.0" text="姓名" />
                    </columns>
                     <columnResizePolicy>
                        <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
                     </columnResizePolicy>
                  </TableView>
               </children>
            </AnchorPane>
          <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="900.0" prefWidth="1500.0" styleClass="background">
               <children>
                  <Label layoutX="33.0" layoutY="8.0" prefHeight="34.0" prefWidth="266.0" styleClass="label-header" text="Person Details" AnchorPane.leftAnchor="33.0" AnchorPane.topAnchor="8.0" />
                  <GridPane layoutX="14.0" layoutY="293.0" prefHeight="313.0" prefWidth="867.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="-4.0" AnchorPane.topAnchor="293.0">
                    <columnConstraints>
                      <ColumnConstraints hgrow="SOMETIMES" maxWidth="196.0" minWidth="10.0" prefWidth="142.0" />
                      <ColumnConstraints hgrow="SOMETIMES" maxWidth="251.0" minWidth="10.0" prefWidth="251.0" />
                    </columnConstraints>
                    <rowConstraints>
                      <RowConstraints maxHeight="26.0" minHeight="10.0" prefHeight="26.0" vgrow="SOMETIMES" />
                      <RowConstraints maxHeight="36.0" minHeight="10.0" prefHeight="31.0" vgrow="SOMETIMES" />
                        <RowConstraints maxHeight="34.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                        <RowConstraints maxHeight="39.0" minHeight="10.0" prefHeight="29.0" vgrow="SOMETIMES" />
                        <RowConstraints maxHeight="40.0" minHeight="10.0" prefHeight="33.0" vgrow="SOMETIMES" />
                      <RowConstraints maxHeight="44.0" minHeight="10.0" prefHeight="37.0" vgrow="SOMETIMES" />
                        <RowConstraints maxHeight="48.0" minHeight="20.0" prefHeight="41.0" />
                        <RowConstraints maxHeight="41.0" minHeight="6.0" prefHeight="32.0" />
                        <RowConstraints maxHeight="42.0" minHeight="7.0" prefHeight="42.0" />
                    </rowConstraints>
                     <children>
                        <Label text="组别" />
                        <Label text="姓名" GridPane.rowIndex="1" />
                        <Label text="家庭地址" GridPane.rowIndex="2" />
                        <Label text="工作单位" GridPane.rowIndex="3" />
                        <Label text="邮编" GridPane.rowIndex="4" />
                        <Label text="生日" GridPane.rowIndex="5" />
                         <Label text="电话" GridPane.rowIndex="6" />
                         <Label text="邮箱" GridPane.rowIndex="7" />
                         <Label text="备注" GridPane.rowIndex="8" />
                        <Label fx:id="groupNameLabel" styleClass="label-bright" text="Label" GridPane.columnIndex="1" />
                        <Label fx:id="personNameLabel" styleClass="label-bright" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="1" />
                        <Label fx:id="streetLabel" styleClass="label-bright" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="2" />
                        <Label fx:id="cityLabel" styleClass="label-bright" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="3" />
                        <Label fx:id="postalCodeLabel" styleClass="label-bright" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="4" />
                        <Label fx:id="birthdayLabel" styleClass="label-bright" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="5" />
                        <Label fx:id="phonenumberLabel" prefHeight="21.0" prefWidth="179.0" styleClass="label-bright" text="111" GridPane.columnIndex="1" GridPane.rowIndex="6" />
                        <Label fx:id="emailaddLabel" prefHeight="21.0" prefWidth="215.0" styleClass="label-bright" text="222" GridPane.columnIndex="1" GridPane.rowIndex="7" />
                        <Label fx:id="extraltingLabel" prefHeight="21.0" prefWidth="193.0" styleClass="label-bright" text="333" GridPane.columnIndex="1" GridPane.rowIndex="8" />
                     </children>
                  </GridPane>
                  <ButtonBar layoutX="54.0" layoutY="250.0" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0">
                    <buttons>
                      <Button mnemonicParsing="false" onAction="#handleNewPerson" text="New..." />
                        <Button mnemonicParsing="false" onAction="#handleEditPerson" text="Edit..." />
                        <Button mnemonicParsing="false" onAction="#handleDeletePerson" text="Delete" />
                        <Button mnemonicParsing="false" onAction="#handleSearchPerson" text="Search" />
                        <Button mnemonicParsing="false" onAction="#handleResetSearch" text="ResetSearch" />
                        <Button mnemonicParsing="false" onAction="#handleEditImage" text="EditImage" />
                    </buttons>
                  </ButtonBar>
                  <ImageView fx:id="personImage" fitHeight="179.0" fitWidth="266.0" layoutX="47.0" layoutY="89.0" pickOnBounds="true" preserveRatio="true" />
               </children>
            </AnchorPane>
        </items>
      </SplitPane>
   </children>
</AnchorPane>

PersonOverviewController

package view;

import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.FileChooser;
import model.Person;
import util.DateUtil;

import java.io.File;

public class PersonOverviewController {
    private String group;//用于分组
    @FXML
    private TableView<Person> personTable;
    @FXML
    private TableColumn<Person, String> groupColumn;
    @FXML
    private TableColumn<Person, String> personNameColumn;

    @FXML
    private ImageView personImage;


    @FXML
    private Label groupNameLabel;
    @FXML
    private Label personNameLabel;
    @FXML
    private Label streetLabel;
    @FXML
    private Label postalCodeLabel;
    @FXML
    private Label cityLabel;
    @FXML
    private Label birthdayLabel;
    @FXML
    private Label phonenumberLabel;
    @FXML
    private Label emailaddLabel;
    @FXML
    private Label extraltingLabel;

    private MainApp mainApp;

    public String getGroup() {return group;}

    public void setGroup(String group) {this.group = group;}

    //设置组为所有(默认)
    public PersonOverviewController() {
        this.group="all";
    }

    //用户界面初始化
    @FXML
    private void initialize() {
        groupColumn.setCellValueFactory(cellData -> cellData.getValue().groupNameProperty());
        personNameColumn.setCellValueFactory(cellData -> cellData.getValue().personNameProperty());

        showPersonDetails(null);

        personTable.getSelectionModel().selectedItemProperty().addListener(
                (observable, oldValue, newValue) -> showPersonDetails(newValue));
    }

    //传入mainapp,用于刷新以及初始化
    public void setMainApp(MainApp mainApp) {
        this.mainApp = mainApp;
        personTable.setItems(mainApp.getPersonData());
    }

    //当选择表中的联系人时,将联系人的信息呈现在个人主页中
    private void showPersonDetails(Person person) {
        if(person != null) {
                groupNameLabel.setText(person.getgroupName());
                personNameLabel.setText(person.getPersonName());
                streetLabel.setText(person.getHomeAddress());
                postalCodeLabel.setText(Integer.toString(person.getPostalCode()));
                cityLabel.setText(person.getWorkAddress());
                birthdayLabel.setText(DateUtil.format(person.getBirthday()));
                phonenumberLabel.setText(person.getPhonenumber());
                emailaddLabel.setText(person.getEmailadd());
                extraltingLabel.setText(person.getExtralting());
                Image image = new Image(person.getPersonimage());
                personImage.setImage(image);
        }else {
            groupNameLabel.setText("");
            personNameLabel.setText("");
            streetLabel.setText("");
            postalCodeLabel.setText("");
            cityLabel.setText("");
            birthdayLabel.setText("");
            phonenumberLabel.setText("");
            emailaddLabel.setText("");
            extraltingLabel.setText("");
        }

    }

    //删除按钮事件
    @FXML
    private void handleDeletePerson() {
        int selectedIndex = personTable.getSelectionModel().getSelectedIndex();//用于判断是否选择了一个联系人
        if (selectedIndex >= 0) {
            mainApp.rtPersonData().remove(selectedIndex);
            personTable.getItems().remove(selectedIndex);
        } else {
            Alert alert = new Alert(AlertType.WARNING);
            alert.initOwner(mainApp.getPrimaryStage());
            alert.setTitle("No Selection");
            alert.setHeaderText("No Person Selected");
            alert.setContentText("Please select a person in the table.");

            alert.showAndWait();
        }
    }

    //新增联系人按钮事件
    @FXML
    private void handleNewPerson() {
        Person tempPerson = new Person();
        boolean okClicked = mainApp.showPersonEditDialog(tempPerson);//判断是否按下确定
        if (okClicked) {
            mainApp.rtPersonData().add(tempPerson);
            mainApp.setPersonGroup(mainApp.getPersonData());
            mainApp.showPersonOverview();
        }
    }

    //搜索按钮事件
    @FXML
    private void handleSearchPerson() {
        boolean okClicked = mainApp.showPersonNameSearchDialog();
        if (okClicked) {
            mainApp.showPersonOverview();
        }
    }

    //搜索功能复位案件事件
    @FXML
    private void handleResetSearch() {
        mainApp.setSearchNamestring("");
        mainApp.setSearchPhonestring("");
        mainApp.showPersonOverview();

    }

    //编辑功能按钮事件
    @FXML
    private void handleEditPerson() {
        Person selectedPerson = personTable.getSelectionModel().getSelectedItem();
        if (selectedPerson != null) {
            boolean okClicked = mainApp.showPersonEditDialog(selectedPerson);
            if (okClicked) {
                mainApp.setPersonGroup(mainApp.getPersonData());
                mainApp.showPersonOverview();
            }

        } else {
            Alert alert = new Alert(AlertType.WARNING);
            alert.initOwner(mainApp.getPrimaryStage());
            alert.setTitle("No Selection");
            alert.setHeaderText("No Person Selected");
            alert.setContentText("Please select a person in the table.");

            alert.showAndWait();
        }
    }

    //编辑图片按钮事件
    @FXML
    private void handleEditImage() {
        Person selectedPerson = personTable.getSelectionModel().getSelectedItem();
        if (selectedPerson != null) {
            FileChooser fileChooser = new FileChooser();

            FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("PNG files", "*.png");
            FileChooser.ExtensionFilter extFilter1 = new FileChooser.ExtensionFilter("JPG files", "*.jpg");
            FileChooser.ExtensionFilter extFilter2 = new FileChooser.ExtensionFilter("JPEG files", "*.jpeg");
            fileChooser.getExtensionFilters().add(extFilter);
            fileChooser.getExtensionFilters().add(extFilter1);
            fileChooser.getExtensionFilters().add(extFilter2);
            File file = fileChooser.showOpenDialog(mainApp.getPrimaryStage());
            String s = file.toURI().toString();
            selectedPerson.setPersonimage(s);
            mainApp.showPersonOverview();
            showPersonDetails(selectedPerson);
        } else {
            Alert alert = new Alert(AlertType.WARNING);
            alert.initOwner(mainApp.getPrimaryStage());
            alert.setTitle("No Selection");
            alert.setHeaderText("No Person Selected");
            alert.setContentText("Please select a person in the table.");
            alert.showAndWait();
        }
    }
}

PersonSearchDialog.fxml

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane prefHeight="238.0" prefWidth="442.0" styleClass="background" stylesheets="" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.PersonSearchDialogController">
   <children>
      <GridPane layoutX="50.0" layoutY="35.0" prefHeight="101.0" prefWidth="334.0">
        <columnConstraints>
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="162.0" minWidth="10.0" prefWidth="102.0" />
          <ColumnConstraints hgrow="SOMETIMES" maxWidth="232.0" minWidth="10.0" prefWidth="232.0" />
        </columnConstraints>
        <rowConstraints>
          <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
         <children>
            <Label prefHeight="21.0" prefWidth="86.0" styleClass="label-bright" stylesheets="" text="名字:" />
            <TextField fx:id="searchNameTextField" GridPane.columnIndex="1" />
            <Label text="电话号码:" GridPane.rowIndex="1" />
            <TextField fx:id="searchNumTextField1" GridPane.columnIndex="1" GridPane.rowIndex="1" />
         </children>
      </GridPane>
      <Button layoutX="109.0" layoutY="163.0" mnemonicParsing="false" onAction="#handleOk" prefHeight="23.0" prefWidth="78.0" text="确定" />
      <Button layoutX="248.0" layoutY="163.0" mnemonicParsing="false" onAction="#handleCancel" prefHeight="23.0" prefWidth="78.0" text="取消" />
   </children>
</AnchorPane>

PersonSearchDialogController

package view;

import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.stage.Stage;


public class PersonSearchDialogController {
    @FXML
    private TextField searchNameTextField;

    @FXML
    private TextField searchNumTextField1;

    private Stage groupdialogStage;
    private String personName;
    private MainApp mainApp;
    private boolean okClicked = false;

    @FXML
    private void initialize() {
    }

    public void setDialogStage(Stage dialogStage) {
        this.groupdialogStage = dialogStage;
        this.groupdialogStage.getIcons().add(new Image("file:src\\resources\\images\\edit.png"));
    }

    public void setPersonName(String personName) {this.personName = personName;}

    public void setMainApp(MainApp mainApp) {this.mainApp = mainApp;}

    public boolean isOkClicked() {
        return okClicked;
    }

    //确定按钮事件,按下后调用mainapp中的搜索方法
    @FXML
    private void handleOk() {
        if (isInputValid()) {
            mainApp.setSearchNamestring(searchNameTextField.getText());
            mainApp.setSearchPhonestring(searchNumTextField1.getText());
            okClicked = true;
            groupdialogStage.close();
        }
    }

    @FXML
    private void handleCancel() {
        groupdialogStage.close();
    }

    private boolean isInputValid() {
        String errorMessage = "";

        if (searchNameTextField.getText() == null && searchNumTextField1.getText() == null) {
            errorMessage += "No input!";
        }
        if (errorMessage.length() == 0) {
            return true;
        } else {
            Alert alert = new Alert(AlertType.ERROR);
            alert.initOwner(groupdialogStage);
            alert.setTitle("Invalid Fields");
            alert.setHeaderText("Please correct invalid fields");
            alert.setContentText(errorMessage);

            alert.showAndWait();

            return false;
        }
    }
}

RootLayout.fxml

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

<?import javafx.scene.input.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>

<BorderPane prefHeight="1000.0" prefWidth="1600.0" stylesheets="" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.RootLayoutController">
   <top>
      <MenuBar BorderPane.alignment="CENTER">
        <menus>
          <Menu mnemonicParsing="false" text="File">
               <items>
                  <MenuItem mnemonicParsing="false" onAction="#handleNew" text="New">
                     <accelerator>
                        <KeyCodeCombination alt="UP" code="N" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
                     </accelerator>
                  </MenuItem>

                  <MenuItem mnemonicParsing="false" onAction="#handleSave" text="Save">
                     <accelerator>
                        <KeyCodeCombination alt="UP" code="S" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
                     </accelerator>
                  </MenuItem>
                   <MenuItem mnemonicParsing="false" onAction="#handleOpenXML" text="OpenXML">
                   </MenuItem>
                   <MenuItem mnemonicParsing="false" onAction="#handleOpenCSV" text="OpenCSV"/>
                   <MenuItem mnemonicParsing="false" onAction="#handleOpenvCard" text="OpenvCard"/>
                  <MenuItem mnemonicParsing="false" onAction="#handleSaveAs" text="Save AsXML" />
                   <MenuItem mnemonicParsing="false" onAction="#handleSaveAsCSV" text="Save AsCSV" />
                   <MenuItem mnemonicParsing="false" onAction="#handleSaveASvCard" text="Save AsvCard" />
                  <MenuItem mnemonicParsing="false" onAction="#handleExit" text="Exit" />
               </items>
          </Menu>
          <Menu mnemonicParsing="false" text="Help">
            <items>
              <MenuItem mnemonicParsing="false" onAction="#handleAbout" text="About" />
            </items>
          </Menu>
            <Menu fx:id="Group" mnemonicParsing="false" text="Group">
               <items>
                  <MenuItem fx:id="Newgroup" mnemonicParsing="false" onAction="#handleNewgroup" text="NewGroup" />
                   <MenuItem fx:id="Deleteroup" mnemonicParsing="false" onAction="#handleDeletegroup" text="DeleteGroup" />
                  <MenuItem fx:id="ALlgroup" mnemonicParsing="false" onAction="#handleAllgroup" text="ALL" />
               </items>
            </Menu>
        </menus>
      </MenuBar>
   </top>
</BorderPane>

RootLayoutController

package view;

import java.io.File;
import java.util.List;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.stage.FileChooser;
import model.Person;

public class RootLayoutController {

    private MainApp mainApp;

    @FXML
    private Menu Group;

    @FXML
    private MenuItem Newgroup;

    @FXML
    private MenuItem ALlgroup;

    public void setMainApp(MainApp mainApp) {
        this.mainApp = mainApp;
    }

    public void initMenuItem(List<String> personGroup){
        for(String group : personGroup){
            MenuItem item = new MenuItem(group);
            item.setOnAction(event -> {
                MenuItemaction(group);
            });
            Group.getItems().add(item);
        }
    }

    public void MenuItemaction(String group){
        mainApp.setMainlygroup(group);
        mainApp.showPersonOverview();
    }

    @FXML
    private void handleNew() {
        String group = "null";
        mainApp.getPersonData().clear();//清空联系人数据
        mainApp.clearPersonGroup();//新建一个文件后清空分组数据
        mainApp.setPersonFilePath(null);
        mainApp.initRootLayout();
        mainApp.showPersonOverview();
    }

    @FXML
    private void handleOpenXML() {
        FileChooser fileChooser = new FileChooser();

        //设置打开的文件的后缀
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("XML files (*.xml)", "*.xml");
        fileChooser.getExtensionFilters().add(extFilter);

        File file = fileChooser.showOpenDialog(mainApp.getPrimaryStage());

        if (file != null) {
            mainApp.loadPersonDataFromFile(file);
            mainApp.initRootLayout();
            mainApp.showPersonOverview();
        }
    }

    @FXML
    private void handleOpenCSV() {
        FileChooser fileChooser = new FileChooser();

        //设置打开的文件的后缀
        FileChooser.ExtensionFilter extFilter1 = new FileChooser.ExtensionFilter("CSV files (*.CSV)", "*.CSV");
        fileChooser.getExtensionFilters().add(extFilter1);

        File file = fileChooser.showOpenDialog(mainApp.getPrimaryStage());

        if (file != null) {
            mainApp.loadPersonDataFromCSVFile(file);
            mainApp.initRootLayout();
            mainApp.showPersonOverview();
        }
    }

    @FXML
    private void handleOpenvCard() {
        FileChooser fileChooser = new FileChooser();

        //设置打开的文件的后缀
        FileChooser.ExtensionFilter extFilter2 = new FileChooser.ExtensionFilter("vCard files (*.vcf)", "*.vcf");
        fileChooser.getExtensionFilters().add(extFilter2);

        File file = fileChooser.showOpenDialog(mainApp.getPrimaryStage());

        if (file != null) {
            mainApp.loadPersonDataFromvCardFile(file);
            mainApp.initRootLayout();
            mainApp.showPersonOverview();
        }
    }

    @FXML
    private void handleSave() {
        File personFile = mainApp.getPersonFilePath();
        if (personFile != null) {
            mainApp.savePersonDataToFile(personFile);
        } else {
            handleSaveAs();
        }
    }

    //导出为csv
    @FXML
    private void handleSaveAsCSV() {
        FileChooser fileChooser = new FileChooser();

        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("CSV files", "*.csv");
        fileChooser.getExtensionFilters().add(extFilter);
        File file = fileChooser.showSaveDialog(mainApp.getPrimaryStage());
        if (file != null) {
            if (!file.getPath().endsWith(".csv")) {
                file = new File(file.getPath() + ".csv");
            }
            mainApp.creatCSV(file);
        }
    }

    //导出为vcard
    @FXML
    private void handleSaveASvCard() {
        FileChooser fileChooser = new FileChooser();
        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("vCard files", "*.vcf");
        fileChooser.getExtensionFilters().add(extFilter);
        File file = fileChooser.showSaveDialog(mainApp.getPrimaryStage());

        if (file != null) {
            if (!file.getPath().endsWith(".vcf")) {
                file = new File(file.getPath() + ".vcf");
            }
            mainApp.creatvCard(file);
        }
    }

    //另存为xml
    @FXML
    private void handleSaveAs() {
        FileChooser fileChooser = new FileChooser();

        FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("XML files (*.xml)", "*.xml");
        fileChooser.getExtensionFilters().add(extFilter);
        File file = fileChooser.showSaveDialog(mainApp.getPrimaryStage());

        if (file != null) {
            if (!file.getPath().endsWith(".xml")) {
                file = new File(file.getPath() + ".xml");
            }
            mainApp.savePersonDataToFile(file);
        }
    }

    @FXML
    private void handleAbout() {
        Alert alert = new Alert(AlertType.INFORMATION);
        alert.setTitle("*通讯录管理系统*");
        alert.setHeaderText("About");
        alert.setContentText("Made by mika.");

        alert.showAndWait();
    }

    @FXML
    private void handleAllgroup() {
        mainApp.setMainlygroup("all");
        mainApp.showPersonOverview();
    }

    @FXML
    private void handleNewgroup() {
            boolean okClicked = mainApp.showPersonGroupEditDialog();
            if (okClicked) {
                mainApp.initRootLayout();
                mainApp.showPersonOverview();
        }
    }

    @FXML
    private void handleDeletegroup() {
        boolean okClicked = mainApp.showPersonGroupDeleteDialog();
        if (okClicked) {
            mainApp.initRootLayout();
            mainApp.showPersonOverview();
        }
    }

    @FXML
    private void handleExit() {
        System.exit(0);
    }

}

 

 

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mika的瑞士卷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值