Проблема с подключением объектов TableColumn к настраиваемому классу - PullRequest
0 голосов
/ 03 августа 2020

Я пытался понять, почему эта сцена продолжает выдавать ошибку, когда я пытаюсь добавить строки в ее TableView. Я просматривал руководство по адресу https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/table-view.htm#sthref109, но не смог понять, что я делаю неправильно. Я уверен, что могу запросить данные и поместить их в свой объект ObservableList, потому что потом я могу распечатать значения.

Кажется, что-то не так с тем, как я подключаю TableColumns к пользовательскому Класс CropCrow, который я использую.

Как я могу заставить TableColumns принимать значения моих настраиваемых классов?

Типы получаемых мной предупреждений:

WARNING: Can not retrieve property 'speciesName' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory@5e065707 with provided class type: class main.gui.CropsController$CropRow

Комментарии эта строка удаляет предупреждение, но я не могу добавлять строки без него.

this.cropTable.getItems().addAll(data);

Мой код:

package main.gui;

import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import main.GardenersApp;
import main.database.Database;

import java.sql.ResultSet;
import java.sql.SQLException;

public final class CropsController extends SuperController {

    private static final ObservableList<CropRow> data = FXCollections.observableArrayList();

    @FXML
    private TableView<CropRow> cropTable;

    @FXML
    private TableColumn<CropRow, String> speciesCol;

    @FXML
    private TableColumn<CropRow, String> varietyCol;

    @FXML
    private TableColumn<CropRow, String> typeCol;

    @FXML
    private TableColumn<CropRow, String> soilTempCol;

    @FXML
    private TableColumn<CropRow, String> weeklyWaterCol;

    @FXML
    private TableColumn<CropRow, String> sunlightCol;

    @FXML
    private TableColumn<CropRow, String> pHCol;

    @FXML
    private Button addCrop;

    @FXML
    private Button deleteCrop;

    @FXML
    private Button returnToMain;

    /**
     * Called immediately when this scene is shown.
     * Retrieves relevant data from the database and displays it in the
     */
    @FXML
    private void initialize() throws SQLException {
        Database.connect();

        ResultSet cropTable = Database.runQuery(
                "SELECT SpeciesName, VarietyName, CropTypeName, SoilTemperatureMin, SoilTemperatureMax, SunlightNeededMin, SunlightNeededMax, WaterNeededMin, WaterNeededMax, PHMin, PHMax \n" +
                        "    FROM CropSpecies CROSS JOIN CropVariety CROSS JOIN CropType \n" +
                        "    ON CropSpecies.SpeciesNumber = CropVariety.SpeciesNumber \n" +
                        "        AND CropType.CropTypeNumber = CropVariety.CropTypeNumber \n" +
                        "    GROUP BY SpeciesName, VarietyName, CropTypeName, SoilTemperatureMin, SoilTemperatureMax, SunlightNeededMin, SunlightNeededMax, WaterNeededMin, WaterNeededMax, PHMin, PHMax");

        while (cropTable.next()) {

            String speciesName = cropTable.getString("SpeciesName");
            String varietyName = cropTable.getString("VarietyName");
            String cropTypeName = cropTable.getString("CropTypeName");
            String soilTemperatureMin = cropTable.getString("SoilTemperatureMin");
            String soilTemperatureMax = cropTable.getString("SoilTemperatureMax");
            String sunlightNeededMin = cropTable.getString("SunlightNeededMin");
            String sunlightNeededMax = cropTable.getString("SunlightNeededMax");
            String waterNeededMin = cropTable.getString("WaterNeededMin");
            String waterNeededMax = cropTable.getString("WaterNeededMax");
            String pHMin = cropTable.getString("PHMin");
            String pHMax = cropTable.getString("PHMax");

            String soilTemperatureRange = soilTemperatureMin+ " - " + soilTemperatureMax + " F";
            String sunlightNeededRange = sunlightNeededMin + " - " + sunlightNeededMax + " Hours";
            String waterNeededRange = waterNeededMin + " - " + waterNeededMax + " inches";
            String pHRange = pHMin + " - " + pHMax;

            CropRow cropRow = new CropRow(speciesName, varietyName, cropTypeName, soilTemperatureRange, sunlightNeededRange, waterNeededRange, pHRange);
            data.add(cropRow);
        }

        this.speciesCol.setCellValueFactory(
                new PropertyValueFactory<CropRow, String>("speciesName"));

        this.varietyCol.setCellValueFactory(
                new PropertyValueFactory<CropRow, String>("varietyName"));

        this.typeCol.setCellValueFactory(
                new PropertyValueFactory<CropRow, String>("cropTypeName"));

        this.soilTempCol.setCellValueFactory(
                new PropertyValueFactory<CropRow, String>("soilTemperature"));

        this.weeklyWaterCol.setCellValueFactory(
                new PropertyValueFactory<CropRow, String>("waterNeeded"));

        this.sunlightCol.setCellValueFactory(
                new PropertyValueFactory<CropRow, String>("sunlightNeeded"));

        this.pHCol.setCellValueFactory(
                new PropertyValueFactory<CropRow, String>("pH"));

        for(CropRow cr : data) {
            System.out.println(cr.printCrop());
        }

        this.cropTable.setItems(data);

        Database.disconnect();
    }

    @FXML
    private void addCropAction() { }

    @FXML
    private void deleteCropAction() { }

    /**
     * Returns to the title screen when the returnToMain Button is clicked.
     */
    @FXML
    private void returnToMainAction() {
        GardenersApp gApp = GetG_app();

        gApp.switchScreen(Page.TITLE);
    }

    /**
     * Holds data on a row in the cropTable TableView object.
     */
    private static class CropRow {

        private final SimpleStringProperty speciesName;
        private final SimpleStringProperty varietyName;
        private final SimpleStringProperty cropTypeName;
        private final SimpleStringProperty soilTemperature;
        private final SimpleStringProperty waterNeeded;
        private final SimpleStringProperty sunlightNeeded;
        private final SimpleStringProperty pH;

        private CropRow(String species, String variety, String cropType, String soilTemp, String water, String sunlight, String pH) {

            this.speciesName = new SimpleStringProperty(species);
            this.varietyName = new SimpleStringProperty(variety);
            this.cropTypeName = new SimpleStringProperty(cropType);
            this.soilTemperature = new SimpleStringProperty(soilTemp);
            this.waterNeeded = new SimpleStringProperty(water);
            this.sunlightNeeded = new SimpleStringProperty(sunlight);
            this.pH = new SimpleStringProperty(pH);
        }

        public String getSpeciesName() {
            return speciesName.get();
        }

        public void setSpeciesName(String speciesName) {
            this.speciesName.set(speciesName);
        }

        public String getVarietyName() {
            return varietyName.get();
        }

        public void setVarietyName(String varietyName) {
            this.varietyName.set(varietyName);
        }

        public String getCropTypeName() {
            return cropTypeName.get();
        }

        public void setCropTypeName(String cropTypeName) {
            this.cropTypeName.set(cropTypeName);
        }

        public String getSoilTemperature() {
            return soilTemperature.get();
        }

        public void setSoilTemperature(String soilTemperature) {
            this.soilTemperature.set(soilTemperature);
        }

        public String getWaterNeeded() {
            return waterNeeded.get();
        }

        public void setWaterNeeded(String waterNeeded) {
            this.waterNeeded.set(waterNeeded);
        }

        public String getSunlightNeeded() {
            return sunlightNeeded.get();
        }

        public void setSunlightNeeded(String sunlightNeeded) {
            this.sunlightNeeded.set(sunlightNeeded);
        }

        public String getpH() {
            return pH.get();
        }

        public void setpH(String pH) {
            this.pH.set(pH);
        }

        public String printCrop() {
            return this.speciesName.get() + " | " + this.cropTypeName.get() + " | " + this.varietyName.get();
        }
    }
}

Файл F XML:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="720.0" prefWidth="1280.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.gui.CropsController">
   <children>
      <HBox prefHeight="720.0" prefWidth="1280.0">
         <children>
            <VBox prefHeight="720.0" prefWidth="200.0" spacing="15.0">
               <padding>
                  <Insets bottom="25.0" left="25.0" top="25.0" />
               </padding>
               <children>
                  <Button fx:id="addCrop" mnemonicParsing="false" onAction="#addCropAction" text="Add Crop" />
                  <Button fx:id="deleteCrop" layoutX="35.0" layoutY="35.0" mnemonicParsing="false" onAction="#deleteCropAction" text="Delete Crop" />
                  <Button fx:id="returnToMain" layoutX="35.0" layoutY="75.0" mnemonicParsing="false" onAction="#returnToMainAction" text="Return to Main" />
               </children>
            </VBox>
            <TableView fx:id="cropTable" prefHeight="200.0" prefWidth="1080.0">
              <columns>
                <TableColumn fx:id="speciesCol" prefWidth="102.0" text="Species" />
                <TableColumn fx:id="varietyCol" prefWidth="168.0" text="Variety" />
                  <TableColumn fx:id="typeCol" prefWidth="115.0" text="Type" />
                  <TableColumn fx:id="soilTempCol" prefWidth="119.0" text="Soil Temperature" />
                  <TableColumn fx:id="weeklyWaterCol" prefWidth="118.0" text="Weekly Water" />
                  <TableColumn fx:id="sunlightCol" prefWidth="98.0" text="Sunlight" />
                  <TableColumn fx:id="pHCol" minWidth="0.0" prefWidth="69.0" text="pH" />
              </columns>
               <HBox.margin>
                  <Insets />
               </HBox.margin>
            </TableView>
         </children>
      </HBox>
   </children>
</AnchorPane>

1 Ответ

1 голос
/ 03 августа 2020

Из документации для PropertyValueFactory: :

Пример использования этого класса:

TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name"); 
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("firstName"));   

В этом примере Person - это тип класса списка TableView элементов. Класс Person должен быть объявлен publi c.

(выделено мной).

Ваш код не работает, потому что ваш класс модели CropRow объявлен private: вам нужно сделать его public, если вы хотите использовать PropertyValueFactory.

Обратите внимание, что PropertyValueFactory - это что-то вроде устаревшего класса, который был введен исключительно для того, чтобы избежать большого количества шаблонного кода, который был бы необходим для создания фабрики значений ячеек до Java 8. У него есть несколько недостатков (наиболее важно, что он полагается на отображение строк в имена методов, которые нельзя проверить во время компиляции; но также, как вы обнаружили, требуется полный доступ к классу модели).

С появлением улучшенного вывода типов во время компиляции и лямбда-выражений в Java 8 и более поздних версиях PropertyValueFactory действительно не требуется подробнее.

Добавьте «методы доступа к свойствам» в класс модели (согласно документации, указанной выше, это хорошая идея, даже если вы все еще используете PropertyValueFactory):

private static class CropRow {

    private final StringProperty speciesName;

    private CropRow(String species /* etc... */) {

        this.speciesName = new SimpleStringProperty(species);
        // ...

    }

    public StringProperty speciesNameProperty() {
        return speciesName ;
    }

    public final String getSpeciesName() {
        return speciesNameProperty.get();
    }

    public final void setSpeciesName(String speciesName) {
       speciesNameProperty().set(speciesName);
    }

    // similarly for other properties...

}

и тогда вам просто нужно:

this.speciesCol.setCellValueFactory(cellData -> 
    cellData.getValue().speciesNameProperty());
...