Я пытаюсь прочитать из CSV-файла в одном классе, который перебирает содержимое CSV-файла, который принимает форму номера студента в столбце 1 и вопрос 1 для вопроса xAmount в столбцах и создает объект из строк в CSV-файл. В другом классе я создаю таблицу и пытаюсь динамически заполнить таблицу, используя содержимое файла CSV.
До сих пор я настраивал его так, чтобы столбцы динамически заполнялись на основе заголовков в файле CSV, однако всякий раз, когда дело доходит до строк, выдается ошибка: «ПРЕДУПРЕЖДЕНИЕ: не удается получить свойство« номер студента »в PropertyValueFactory: javafx. scene.control.cell.PropertyValueFactory@76afc271 с предоставленным типом класса: class java.lang.String" и делает это для каждого столбца в файле CSV. В любом случае я могу динамически заполнять строки?
Вот код для класса StudentCsv:
public class StudentCsv {
private int[] marks;
private String studentNumber;
public StudentCsv(String studentNumber, int[] marks) {
this.studentNumber=studentNumber;
this.marks = marks;
}
}
А вот код класса tableView:
public class tableViewTest implements Initializable {
@FXML
private TableView tableView;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
ArrayList<StudentCsv> testStudents = new ArrayList<>();
StudentCsv studentCsv1 = new StudentCsv("40236387", new int[]{2, 3, 4, 5, 6});
StudentCsv studentCsv2 = new StudentCsv("40236388", new int[]{7, 8, 9, 10, 11});
StudentCsv studentCsv3 = new StudentCsv("40236388", new int[]{12, 13, 14, 15, 16});
testStudents.add(studentCsv1);
testStudents.add(studentCsv2);
testStudents.add(studentCsv3);
String[] columnNames = {"Student number", "q1", "q2", "q3", "q4", "q5"};
ObservableList<StudentCsv> studentData = FXCollections.observableArrayList();
for (int i = 0; i < testStudents.size(); i++) {
studentData.add(testStudents.get(i));
}
tableView.setItems(studentData);
for (int i = 0; i < columnNames.length; i++) {
TableColumn<StudentCsv, String> column = new TableColumn<>(columnNames[i]);
column.setCellValueFactory(param ->
new ReadOnlyObjectWrapper<>(param.getValue()).asString());
column.setPrefWidth(75);
tableView.getColumns().add(column);
}
}
}
public class Main extends Application {
@Override
public void start(Stage stage) throws IOException {
try{
Parent root = FXMLLoader.load(getClass().getResource("tableViewTest.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
launch();
}
}
<?xml version = "1.0" encoding = "UTF-8"?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight = "400.0" prefWidth = "600.0" xmlns = "http://javafx.com/javafx/19" xmlns:fx = "http://javafx.com/fxml/1" fx:controller = "com.example.testfx.tableViewTest">
<children>
<TableView fx:id = "tableView" layoutX = "43.0" layoutY = "76.0" prefHeight = "286.0" prefWidth = "505.0" />
</children>
</AnchorPane>
Когда таблица заполняется, она заполняется как
Я думаю, что Джеймс заметил эту проблему в вашем коде и закрыл ее на основе этого. Ссылка, которой я поделился, должна дать вам некоторые идеи о том, как решить вашу проблему. Кроме того, похоже, что вы не используете библиотеку для анализа файла CSV
. Я думаю тебе надо.
В ответ на @ SedJ601 я перешел по этой ссылке, и теперь мои столбцы настроены по-другому. Однако есть новая проблема, когда мои строки заполняются правильным количеством строк, которые находятся в CSV-файле, но проблема заключается в том, что строки заполняются значениями имени столбца. то есть номер студента появляется в столбце, а затем 4 раза в строках ниже.
Как это не исправление? Вам необходимо предоставить обратный вызов, который принимает каждый экземпляр модели строки (ваш StudentCsv
объект) и возвращает ObservableValue
обертку значения, которое будет отображаться в столбце. Очевидно, что у вас не может быть свойства под названием «номер студента», так как это даже недопустимое имя свойства.
Вероятный дубликат заполнения TableView из студенческого CSV.
Я предоставил минимальный воспроизводимый пример в соответствии с запросом, это было сделано в другом сообщении, но поскольку оно было удалено, могу ли я попросить повторно открыть вопрос?
Продолжая мой предыдущий комментарий : кажется, что класс tableViewTest
— это ваш класс контроллера FXML, но вы не опубликовали FXML.
Ваша проблема в параметре, который вы передаете setCellValueFactory
. Вы возвращаете объект StudentCsv
, а не один из его атрибутов. И результат, который вы видите, вероятно, потому, что класс StudentCsv
не переопределяет метод toString.
файл fxml - это просто таблица с fxid tableView, я не думал, что это необходимо. Есть ли рекомендуемое решение этой проблемы?
повторяя предыдущий комментарий @Abra. Вы возвращаете объект StudentCsv, а не один из его атрибутов - это ответ на строковое представление в ячейке. Пожалуйста, ознакомьтесь с руководством по использованию TableView. И в отношении: файл fxml - это просто таблица с fxid tableView. Я не думал, что это необходимо при условии, что это не минимально воспроизводимый пример, а просто фрагмент кода, бесполезный для воспроизведения проблемы без изменений (как это должно быть, и уже упоминалось в нескольких комментариях;)
В предыдущем посте один из участников Stack Overflow сказал мне, что fxml не понадобится. Я сейчас отредактировал его, чтобы все было внутри.
.. и начните исправлять эти нарушения именования - они режут глаз ;)
хорошо, спасибо за редактирование :) но тогда @Abra был достаточно любезен, чтобы просмотреть ваш код и зорким взглядом заметил ошибку, исправил ее и был счастлив. Обязательно прочитайте и поймите javadoc CellDataFeatures (== тип параметра, переданный фабрике)
Я рад, что @Abra заметил, где я ошибаюсь, но не уверен, почему вы должны постоянно комментировать снисходительные комментарии к моим сообщениям, лол. Я рад, если кто-то скажет мне, где я ошибаюсь или где моему посту не хватает глубины. Только не надо снисходительных замечаний. Спасибо.
Фабрика значений ячеек для столбца — это функция, которая берет объект, представляющий строку (это StudentCsv
, что является ужасным названием для класса), и возвращает ObservableValue
, содержащее значение, которое будет отображаться в этом столбце для этой строки (т. е. значение в каждой ячейке столбца). Функция применяется к каждой видимой строке таблицы, чтобы определить, что отображать в ячейках столбца.
Таким образом, ваша фабрика значений ячеек должна быть функцией, которая принимает Student
и возвращает ObservableValue
обертку значения для этого столбца. Фабрика значений ячеек первого столбца должна возвращать ObservableValue
, содержащую studentNumber
. Остальные фабрики значений ячеек столбцов должны возвращать ObservableNumber
, содержащий соответствующий mark
.
Итак, вам нужно начать с методов доступа для studentNumber
и marks
. Минимум:
public class Student {
private int[] marks;
private String studentNumber;
public Student(String studentNumber, int[] marks) {
this.studentNumber=studentNumber;
this.marks = marks;
}
public String getStudentNumber() {
return studentNumber;
}
public int[] getMarks() {
return marks;
}
}
Теперь ваши фабрики значений ячеек могут возвращать соответствующие значения для каждого столбца. Я исправил часть уродливого кода здесь. Я не уверен, почему у вас есть поле с именем studentNumber
, которое является String
(а не каким-то числовым типом), но я оставил его на случай, если для этого есть веская причина.
public class TableViewTest implements Initializable {
@FXML
private TableView<Student> tableView;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
ArrayList<Student> testStudents = new ArrayList<>();
Student student1 = new Student("40236387", new int[]{2, 3, 4, 5, 6});
Student student2 = new Student("40236388", new int[]{7, 8, 9, 10, 11});
Student student3 = new Student("40236388", new int[]{12, 13, 14, 15, 16});
testStudents.add(student1);
testStudents.add(student2);
testStudents.add(student3);
String[] columnNames = {"Student number", "q1", "q2", "q3", "q4", "q5"};
ObservableList<Student> studentData = FXCollections.observableArrayList();
studentData.addAll(testStudents);
tableView.setItems(studentData);
TableColumn<Student, String> studentNumberColumn = new TableColumn<>("Student number");
studentNumberColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getStudentNumber()));
tableView.getColumns().add(studentNumberColumn);
for (int i = 1; i < columnNames.length; i++) {
TableColumn<Student, Number> column = new TableColumn<>(columnNames[i]);
final int marksIndex = i-1 ;
column.setCellValueFactory(cellData ->
new SimpleIntegerProperty<>(cellData.getValue().getMarks()[marksIndex]));
column.setPrefWidth(75);
tableView.getColumns().add(column);
}
}
}
Это не проверено, поэтому могут быть опечатки.
Спасибо, Джеймс, я думаю, это тоже сработает. Мне тоже удалось решить проблему, но по-другому. Раньше это не позволяло мне опубликовать ответ, поэтому я тоже опубликую свой. Я ценю, что вы нашли время, чтобы помочь :)
Посмотрите, может ли stackoverflow.com/questions/56462624/… помочь.