TableView не заполняется при получении ввода от пользователя, но заполняется при явном добавлении нового объекта
Это первый раз, когда я использую JavaFX и TableView. У меня есть приложение, которое пользователи вводят результаты игры в гольф, чтобы создать для них значение гандикапа.
У меня есть ArrayList, который я использую в качестве "базы данных":
public ArrayList<Score> scoreDB = new ArrayList<>();
С этим как метод, который добавляет значения:
public static Score scoreSubmit(DatePicker roundDate, TextField courseName, TextField courseRating, TextField courseSlope, TextField score)
{
Score temp = new Score();
//Wanted to use own Date class, must use this roundabout way to set the date correctly
LocalDate tempDate = roundDate.getValue();
temp.setRoundDate(tempDate.getMonthValue(), tempDate.getDayOfMonth(), tempDate.getYear());
temp.setCourseName(courseName.getText());
temp.setCourseRating(Double.valueOf(courseRating.getText()));
temp.setCourseSlope(Double.valueOf(courseSlope.getText()));
temp.setScore(Double.valueOf(score.getText()));
return temp;
}
примечание: я использовал свой собственный класс дат, который я создал.
Я проверил, действительно ли метод работает, и ArrayList действительно получает значение.
Вот моя конструкция TableView:
//Table columns
//Creating columns and setting the display to call the values from Score class
TableColumn<Score, String> courseNameColumn = new TableColumn<>("Course Name");
courseNameColumn.setMinWidth(100);
courseNameColumn.setCellValueFactory(new PropertyValueFactory<>("courseName"));
TableColumn<Score, Date> dateColumn = new TableColumn<>("Date");
dateColumn.setMinWidth(100);
dateColumn.setCellValueFactory(new PropertyValueFactory<>("roundDate"));
TableColumn<Score, Double> scoreColumn = new TableColumn<>("Score");
scoreColumn.setMinWidth(100);
scoreColumn.setCellValueFactory(new PropertyValueFactory<>("score"));
//This adds rating and slope under one column
TableColumn courseDataColumn = new TableColumn("Course Data");
TableColumn<Score, Double> courseRatingColumn = new TableColumn<>("Course Rating");
TableColumn<Score, Double> courseSlopeColumn = new TableColumn<>("Course Slope");
courseDataColumn.getColumns().addAll(courseRatingColumn, courseSlopeColumn);
courseDataColumn.setMinWidth(100);
courseRatingColumn.setCellValueFactory(new PropertyValueFactory<>("courseRating"));
courseSlopeColumn.setCellValueFactory(new PropertyValueFactory<>("courseSlope"));
scoreTable.getColumns().addAll(courseNameColumn, dateColumn, scoreColumn, courseDataColumn);
displayLayout.setCenter(displaySP);
displaySP.setBackground(new Background(new BackgroundFill(Paint.valueOf("#006400"), CornerRadii.EMPTY, Insets.EMPTY)));
displaySP.getChildren().add(scoreTable);
displayLayout.setBottom(displayHbox);
scoreTable.setItems(addScore());
Вот переменные из моего класса оценки:
private double score = 0.0;
private double courseRating = 0.0;
private double courseSlope = 0.0;
private String courseName = "";
private Date roundDate;
Вот мои получатели для класса очков (я читал, что они должны быть названы определенным образом, чтобы он работал):
public double getScore()
{
return score;
}
public String getCourseName()
{
return courseName;
}
public Double getCourseSlope()
{
return courseSlope;
}
public double getCourseRating()
{
return courseRating;
}
public Date getRoundDate()
{
return roundDate;
}
Вот метод возврата наблюдаемого списка:
public ObservableList<Score> addScore()
{
ObservableList<Score> scores = FXCollections.observableArrayList();
// scores.add(new Score());
for (int i = 0; i < scoreDB.size(); i++)
{
scores.add(scoreDB.get(i));
}
return scores;
}
Когда используется только закомментированный новый Score(), таблица заполняется этим значением по умолчанию. При использовании цикла for ничего не заполняется.
Любая помощь с благодарностью.
2 ответа
Для начала стоит обратить внимание на свою модель (класс Score). Хорошо (но не обязательно) работать с Properties
, Причина этого в том, что вы сможете редактировать значения, и изменения будут автоматически отражаться в представлении (TableView
). В противном случае вам нужно будет обновить его вручную, если вы внесете какие-либо изменения в уже добавленные данные, потому что PropertyValueFactory
будет генерировать свойство только для чтения.
public class Score {
private DoubleProperty score = new SimpleDoubleProperty(0.0);
private DoubleProperty courseRating = new SimpleDoubleProperty(0.0);
private DoubleProperty courseSlope = new SimpleDoubleProperty(0.0);
private StringProperty courseName = new SimpleStringProperty("");
private ObjectProperty<LocalDate> roundDate = new SimpleObjectProperty<>();
public double getScore() {
return score.get();
}
public DoubleProperty scoreProperty() {
return score;
}
public void setScore(double score) {
this.score.set(score);
}
public double getCourseRating() {
return courseRating.get();
}
public DoubleProperty courseRatingProperty() {
return courseRating;
}
public void setCourseRating(double courseRating) {
this.courseRating.set(courseRating);
}
public double getCourseSlope() {
return courseSlope.get();
}
public DoubleProperty courseSlopeProperty() {
return courseSlope;
}
public void setCourseSlope(double courseSlope) {
this.courseSlope.set(courseSlope);
}
public String getCourseName() {
return courseName.get();
}
public StringProperty courseNameProperty() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName.set(courseName);
}
public LocalDate getRoundDate() {
return roundDate.get();
}
public ObjectProperty<LocalDate> roundDateProperty() {
return roundDate;
}
public void setRoundDate(LocalDate roundDate) {
this.roundDate.set(roundDate);
}
}
Вы также должны изменить свою "базу данных". Вы должны использовать Observable
коллекция вместо равнины List
, Это позволит вам напрямую добавлять в него данные, и они автоматически появятся в таблице.
public ObservableList<Score> scoreDB = FXCollections.observableArrayList();
...
//scoreTable.setItems(addScore());
scoreTable.setItems(scoreDB);
...
public void scoreSubmit() {
Score temp = new Score();
temp.setRoundDate(roundDate.getValue());
temp.setCourseName(courseName.getText());
temp.setCourseRating(Double.valueOf(courseRating.getText()));
temp.setCourseSlope(Double.valueOf(courseSlope.getText()));
temp.setScore(Double.valueOf(score.getText()));
scoreDB.add(temp);
}
Обновить
Это рабочий пример, который использует почти всю структуру, которую вы показали. Ввод данных перегружен, и вы можете получить NumberFormatException
потому что Double#valueOf
звонки. Чтобы избежать этой проблемы, желательно использовать TextFormatter
public class Main extends Application {
private DatePicker roundDate = new DatePicker();
private TextField courseName = new TextField();
private TextField courseRating = new TextField();
private TextField courseSlope = new TextField();
private TextField score = new TextField();
private TableView<Score> scoreTable = new TableView<>();
public ObservableList<Score> scoreDB = FXCollections.observableArrayList();
@Override
public void start(Stage primaryStage) throws Exception{
//Table columns
//Creating columns and setting the display to call the values from Score class
TableColumn<Score, String> courseNameColumn = new TableColumn<>("Course Name");
courseNameColumn.setMinWidth(100);
courseNameColumn.setCellValueFactory(new PropertyValueFactory<>("courseName"));
TableColumn<Score, LocalDate> dateColumn = new TableColumn<>("Date");
dateColumn.setMinWidth(100);
dateColumn.setCellValueFactory(new PropertyValueFactory<>("roundDate"));
TableColumn<Score, Double> scoreColumn = new TableColumn<>("Score");
scoreColumn.setMinWidth(100);
scoreColumn.setCellValueFactory(new PropertyValueFactory<>("score"));
//This adds rating and slope under one column
TableColumn courseDataColumn = new TableColumn("Course Data");
TableColumn<Score, Double> courseRatingColumn = new TableColumn<>("Course Rating");
TableColumn<Score, Double> courseSlopeColumn = new TableColumn<>("Course Slope");
courseDataColumn.getColumns().addAll(courseRatingColumn, courseSlopeColumn);
courseDataColumn.setMinWidth(100);
courseRatingColumn.setCellValueFactory(new PropertyValueFactory<>("courseRating"));
courseSlopeColumn.setCellValueFactory(new PropertyValueFactory<>("courseSlope"));
scoreTable.getColumns().addAll(courseNameColumn, dateColumn, scoreColumn, courseDataColumn);
scoreTable.setItems(scoreDB);
Button addButton = new Button("Add");
addButton.setOnAction(e -> scoreSubmit());
HBox displayHbox = new HBox();
displayHbox.setSpacing(5);
displayHbox.getChildren().addAll(roundDate, courseName, courseRating, courseSlope, score, addButton);
BorderPane displayLayout = new BorderPane();
displayLayout.setCenter(scoreTable);
displayLayout.setBottom(displayHbox);
primaryStage.setScene(new Scene(displayLayout));
primaryStage.show();
}
public void scoreSubmit() {
Score temp = new Score();
temp.setRoundDate(roundDate.getValue());
temp.setCourseName(courseName.getText());
temp.setCourseRating(Double.valueOf(courseRating.getText()));
temp.setCourseSlope(Double.valueOf(courseSlope.getText()));
temp.setScore(Double.valueOf(score.getText()));
scoreDB.add(temp);
}
public static void main(String[] args) {
launch(args);
}
}
Я не уверен, что я сделал, но я, кажется, исправил это. Вот моя реализация метода ScoreSubmit ():
//Submit Button for score scene, implements method for setting Score Class variables
Button scoreSubmit = GHINAppMethods.submitButton();
scoreSubmit.defaultButtonProperty().bind(nameInput.focusedProperty());
scoreSubmit.setOnAction(e ->
{
//checks to make sure values are correct
switch (GHINAppMethods.checkScoreValues(courseRating, courseSlope, score))
{
//all values valid
case 0:
{
//adds score to a "database" that will eventually be used in ScoreHistory class
scoreDB.add(GHINAppMethods.scoreSubmit(roundDateTest, courseName, courseRating, courseSlope, score));
//ScoreIterator has no use at this point
System.out.println(scoreDB.get(scoreIterator));
scoreIterator++;
System.out.println(scoreIterator);
System.out.println(scoreDB.size());
GHINAppMethods.addAnotherScore(scoreTextFields, clearAll, displayScene, entryWindow, scoreTable, scores);
break;
}
//rating invalid
case 1:
{
courseRating.clear();
GHINAppMethods.ratingInvalid();
break;
}
//slope invalid
case 2:
{
courseSlope.clear();
GHINAppMethods.slopeInvalid();
break;
}
//score invalid
case 3:
{
score.clear();
GHINAppMethods.scoreInvalid();
break;
}
//Fatal System Error (shouldn't be used)
default:
{
GHINAppMethods.fatalError();
System.out.println("fatal error");
System.exit(0);
break;
}
}
});
Метод checkScoreValues () просто проверяет правильность значений (я все еще пропускаю исключения, но это помогает). checkScoreValues возвращает int, и оператор switch будет выполнен. ScoreDB.add(...) и addAnotherScore() - единственные используемые методы. Другие для проверки ошибок.