Два дня я пытался заставить ячейки TableView обновлять свое содержимое при добавлении новых данных в базовую модель данных.
Это простое приложение, которое отображает информацию о контактах в TableView. Список контактов представляет собой ObservableList , который хранится в файле XML.
Модель контактных данных использует JavaFX properties для своих полей.
Новые контакты добавляются путем нажатия пункта меню «Добавить» на панели инструментов ( showAddContactDialog () ). Откроется диалоговое окно, где мы можем ввести контактную информацию. Затем контакт сохраняется в списке контактов, а затем сохраняется в XML-файле, который будет загружен при следующем запуске приложения. При запуске приложения контакты корректно отображаются в табличном представлении, но когда я добавляю новое, оно не добавляется в табличное представление, а сохраняется только в списке контактов и в XML-файле.
Не знаю, чего мне не хватает, нужна помощь, пожалуйста?
Я перепробовал много решений для stackoverflow и других, но ни одно из них не было успешным.
Ниже приведен код для класса контактов:
public class Contact {
private SimpleStringProperty mFirstName;
private SimpleStringProperty mLastName;
private SimpleStringProperty mPhoneNumber;
private SimpleStringProperty mNotes;
public Contact(){...}
public Contact(String firstName, String lastName, String phoneNumber, String notes){
this.mFirstName = new SimpleStringProperty(firstName);
this.mLastName = new SimpleStringProperty(lastName);
this.mPhoneNumber = new SimpleStringProperty(phoneNumber);
this.mNotes = new SimpleStringProperty(notes);
}
String getFirstName() { return mFirstName.get(); }
public SimpleStringProperty mFirstNameProperty() { return mFirstName; }
void setFirstName(String value) { mFirstName.set(value); }
String getLastName() { return mLastName.get(); }
public SimpleStringProperty mLastNameProperty() { return mLastName; }
void setLastName(String value) { mLastName.set(value); }
String getPhoneNumber() { return mPhoneNumber.get(); }
public SimpleStringProperty mPhoneNumberProperty() { return mPhoneNumber; }
void setPhoneNumber(String value) { mPhoneNumber.set(value); }
String getNotes() { return mNotes.get(); }
public SimpleStringProperty mNotesProperty() { return mNotes;}
void setNotes(String value) { mNotes.set(value); }
Ниже приведен код для класса ContactData , который отвечает за загрузку и сохранение контактов из файла XML и за операции добавления и удаления контактов из списка:
public class ContactData {
private static final String CONTACTS_FILE = "contacts.xml";
private static final String CONTACT = "contact";
private static final String FIRST_NAME = "first_name";
private static final String LAST_NAME = "last_name";
private static final String PHONE_NUMBER = "phone_number";
private static final String NOTES = "notes";
private ObservableList<Contact> contacts;
public ContactData() {
contacts = FXCollections.observableArrayList();
loadContacts();
}
public void addContact(Contact newContact){
contacts.add(newContact);
saveContacts();
}
public void deleteContact(Contact contact){
contacts.remove(contact);
saveContacts();
}
public ObservableList<Contact> getContacts() {
return FXCollections.observableList(contacts);
}
public void loadContacts() {
try {
// First, create a new XMLInputFactory
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
// Setup a new eventReader
InputStream in = new FileInputStream(CONTACTS_FILE);
XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
// read the XML document
Contact contact = null;
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
// If we have a contact item, we create a new contact
if (startElement.getName().getLocalPart().equals(CONTACT)) {
contact = new Contact();
continue;
}
if (event.isStartElement()) {
if (event.asStartElement().getName().getLocalPart()
.equals(FIRST_NAME)) {
event = eventReader.nextEvent();
contact.setFirstName(event.asCharacters().getData());
continue;
}
}
if (event.asStartElement().getName().getLocalPart()
.equals(LAST_NAME)) {
event = eventReader.nextEvent();
contact.setLastName(event.asCharacters().getData());
continue;
}
if (event.asStartElement().getName().getLocalPart()
.equals(PHONE_NUMBER)) {
event = eventReader.nextEvent();
contact.setPhoneNumber(event.asCharacters().getData());
continue;
}
if (event.asStartElement().getName().getLocalPart()
.equals(NOTES)) {
event = eventReader.nextEvent();
contact.setNotes(event.asCharacters().getData());
continue;
}
}
// If we reach the end of a contact element, we add it to the list
if (event.isEndElement()) {
EndElement endElement = event.asEndElement();
if (endElement.getName().getLocalPart().equals(CONTACT)) {
contacts.add(contact);
}
}
}
}
catch (FileNotFoundException e) {
//e.printStackTrace();
}
catch (XMLStreamException e) {
e.printStackTrace();
}
}
public void saveContacts() {
try {
// create an XMLOutputFactory
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
// create XMLEventWriter
XMLEventWriter eventWriter = outputFactory
.createXMLEventWriter(new FileOutputStream(CONTACTS_FILE));
// create an EventFactory
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
XMLEvent end = eventFactory.createDTD("\n");
// create and write Start Tag
StartDocument startDocument = eventFactory.createStartDocument();
eventWriter.add(startDocument);
eventWriter.add(end);
StartElement contactsStartElement = eventFactory.createStartElement("",
"", "contacts");
eventWriter.add(contactsStartElement);
eventWriter.add(end);
for (Contact contact: contacts) {
saveContact(eventWriter, eventFactory, contact);
}
eventWriter.add(eventFactory.createEndElement("", "", "contacts"));
eventWriter.add(end);
eventWriter.add(eventFactory.createEndDocument());
eventWriter.close();
}
catch (FileNotFoundException e) {
System.out.println("Problem with Contacts file: " + e.getMessage());
e.printStackTrace();
}
catch (XMLStreamException e) {
System.out.println("Problem writing contact: " + e.getMessage());
e.printStackTrace();
}
}
private void saveContact(XMLEventWriter eventWriter, XMLEventFactory eventFactory, Contact contact)
throws FileNotFoundException, XMLStreamException {
XMLEvent end = eventFactory.createDTD("\n");
// create contact open tag
StartElement configStartElement = eventFactory.createStartElement("",
"", CONTACT);
eventWriter.add(configStartElement);
eventWriter.add(end);
// Write the different nodes
createNode(eventWriter, FIRST_NAME, contact.getFirstName());
createNode(eventWriter, LAST_NAME, contact.getLastName());
createNode(eventWriter, PHONE_NUMBER, contact.getPhoneNumber());
createNode(eventWriter, NOTES, contact.getNotes());
eventWriter.add(eventFactory.createEndElement("", "", CONTACT));
eventWriter.add(end);
}
private void createNode(XMLEventWriter eventWriter, String name,
String value) throws XMLStreamException {
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
XMLEvent end = eventFactory.createDTD("\n");
XMLEvent tab = eventFactory.createDTD("\t");
// create Start node
StartElement sElement = eventFactory.createStartElement("", "", name);
eventWriter.add(tab);
eventWriter.add(sElement);
// create Content
Characters characters = eventFactory.createCharacters(value);
eventWriter.add(characters);
// create End node
EndElement eElement = eventFactory.createEndElement("", "", name);
eventWriter.add(eElement);
eventWriter.add(end);
}
}
Ниже приведен код для класса Controller:
public class Controller {
@FXML
private TableView<Contact> mContactsTableView;
@FXML
private BorderPane mMainWindow;
private ContactData mContactData;
private ObservableList<Contact> mContactsList;
public void initialize(){
mContactData = new ContactData();
mContactsList = mContactData.getContacts();
mContactsTableView.setItems(mContactsList);
//Initializing the columns of the TableView
TableColumn<Contact, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setCellValueFactory(param -> param.getValue().mFirstNameProperty());
TableColumn<Contact, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setCellValueFactory(new PropertyValueFactory<Contact, String>("mLastName"));
TableColumn<Contact, String> phoneCol = new TableColumn<>("Phone Number");
phoneCol.setCellValueFactory(new PropertyValueFactory<Contact, String>("mPhoneNumber"));
TableColumn<Contact, String> notesCol = new TableColumn<>("Notes");
notesCol.setCellValueFactory(new PropertyValueFactory<Contact, String>("mNotes"));
mContactsTableView.getColumns().setAll(firstNameCol, lastNameCol, phoneCol, notesCol);
}
@FXML
private void showAddContactDialog(){
Dialog<ButtonType> dialog = new Dialog<>();
dialog.initOwner(mMainWindow.getScene().getWindow());
dialog.setTitle("ADD NEW CONTACT");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass()
.getResource("AddContactDialog.fxml"));
try {
dialog.getDialogPane().setContent(fxmlLoader.load());
} catch (IOException e) {
System.out.println("Couldn't load the dialog");
e.printStackTrace();
}
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
Optional<ButtonType> result = dialog.showAndWait();
if (result.isPresent() && result.get() == ButtonType.OK){
AddContactDialogController dialogController = fxmlLoader.getController();
Contact newContact = dialogController.addContact();
}
Ниже приведен код для класса AddContactDialogController:
public class AddContactDialogController {
@FXML
private TextField firstNameField;
@FXML
private TextField lastNameField;
@FXML
private TextField phoneNumberField;
@FXML
private TextField notesField;
public Contact addContact(){
String firstName = firstNameField.getText().trim();
String lastName = lastNameField.getText().trim();
String phoneNumber = phoneNumberField.getText().trim();
String notes = notesField.getText().trim();
Contact newContact = new Contact(firstName, lastName, phoneNumber, notes);
ContactData contactData = new ContactData();
contactData.addContact(newContact);
return newContact;
}
}
Ниже приведен файл mainLayout.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane fx:id="mMainWindow" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<top>
<MenuBar>
<menus>
<Menu text="Contacts">
<items>
<MenuItem onAction="#showAddContactDialog" text="Add" />
<MenuItem onAction="#handleEditContact" text="Edit" />
<MenuItem onAction="#handleDeleteContact" text="Delete" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<TableView fx:id="mContactsTableView" />
</center>
</BorderPane>
Ниже приведен файл AddContactDialog.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.text.Text?>
<DialogPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="sample.AddContactDialogController">
<header>
<Text text="Add a New Contact"/>
</header>
<content>
<GridPane vgap="10" hgap="10">
<Label text="First Name" GridPane.rowIndex="0" GridPane.columnIndex="0"/>
<TextField fx:id="firstNameField" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
<Label text="Last Name" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
<TextField fx:id="lastNameField" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
<Label text="Phone Number" GridPane.rowIndex="2" GridPane.columnIndex="0"/>
<TextField fx:id="phoneNumberField" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
<Label text="Notes" GridPane.rowIndex="3" GridPane.columnIndex="0"/>
<TextField fx:id="notesField" GridPane.rowIndex="3" GridPane.columnIndex="1"/>
</GridPane>
</content>
</DialogPane>