0

Я создаю многоэкранное приложение JavaFX с данными, извлекаемыми из базы данных SQL в ObservableLists и отображаемыми в интерфейсе через Tableview. Из-за многоэкранного характера приложения я пытаюсь инициализировать данные из ObservableList в Tableview через контроллер. SQL pull to ObservableList выполняется через Task в новом потоке. Когда я включаю sqlCSEditTbl.itemsProperty(). SetValue ((ObservableList) csSQLList) в методе задачи ничего ничего не отображается в TableView при запуске программы. Если я поместил код за пределы метода «Задача», конкретный экран не будет отображаться. Я не знаю, чего мне здесь не хватает, чтобы получить данные для отображения на конкретном экране. Я отлаживал SQL для ObservableList, и данные правильно хранятся в ObservableList. Проблема заключается в получении его из ObservableList в интерфейс Tableview. Любая помощь будет принята с благодарностью. Спасибо!JavaFX ObservableList toTableview через задачу Thread

App Edit Screen Screenshot

SQLCalcScript Массив Модель

package model.calcs; 

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

/** 
* Created by jdsmith on 2/17/2016. 
*/ 
public class SQLCalcScripts { 

    private final IntegerProperty calcScriptID; 
    private final IntegerProperty calcScriptIndex; 
    private final StringProperty calcScriptName; 
    private final StringProperty calcScriptServer; 
    private final StringProperty calcScriptApp; 
    private final StringProperty calcScriptGroup; 

    public SQLCalcScripts() { 
     this(null, null, null, null, null, null); 
    } 

    public SQLCalcScripts(Integer calcScriptID, Integer calcScriptIndex, String calcScriptName, String calcScriptServer, String calcScriptApp, String calcScriptGroup) { 
     this.calcScriptID = new SimpleIntegerProperty(calcScriptID); 
     this.calcScriptIndex = new SimpleIntegerProperty(calcScriptIndex); 
     this.calcScriptName = new SimpleStringProperty(calcScriptName); 
     this.calcScriptServer = new SimpleStringProperty(calcScriptServer); 
     this.calcScriptApp = new SimpleStringProperty(calcScriptApp); 
     this.calcScriptGroup = new SimpleStringProperty(calcScriptGroup); 

     this.calcScriptID.addListener((e) -> System.out.println("ID changed to " + this.calcScriptID.get())); 
     this.calcScriptIndex.addListener((e) -> System.out.println("ID changed to " + this.calcScriptIndex.get())); 
     this.calcScriptName.addListener((e) -> System.out.println("ID changed to " + this.calcScriptName.get())); 
     this.calcScriptServer.addListener((e) -> System.out.println("ID changed to " + this.calcScriptServer.get())); 
     this.calcScriptApp.addListener((e) -> System.out.println("ID changed to " + this.calcScriptApp.get())); 
     this.calcScriptGroup.addListener((e) -> System.out.println("ID changed to " + this.calcScriptGroup.get())); 
    } 

    // Getters and Setters for Calc Script 
    public Integer getCalcScriptID() { 
     return calcScriptID.get(); 
    } 

    public void setCalcScriptID(Integer calcScriptID) { 
     this.calcScriptID.set(calcScriptID); 
    } 

    public IntegerProperty calcScriptIDProperty() { 
     return calcScriptID; 
    } 


    public Integer getCalcScriptIndex() { 
     return calcScriptIndex.get(); 
    } 

    public void setCalcScriptIndex(Integer calcScriptIndex) { 
     this.calcScriptIndex.set(calcScriptIndex); 
    } 

    public IntegerProperty calcScriptIndexProperty() { 
     return calcScriptIndex; 
    } 


    public String getCalcScriptName() { 
     return calcScriptName.get(); 
    } 

    public void setCalcScriptName(String calcScriptName) { 
     this.calcScriptName.set(calcScriptName); 
    } 

    public StringProperty calcScriptNameProperty() { 
     return calcScriptName; 
    } 


    public String getCalcScriptServer() { 
     return calcScriptServer.get(); 
    } 

    public void setCalcScriptServer(String calcScriptServer) { 
     this.calcScriptServer.set(calcScriptServer); 
    } 

    public StringProperty calcScriptServerProperty() { 
     return calcScriptServer; 
    } 


    public String getCalcScriptApp() { 
     return calcScriptApp.get(); 
    } 

    public void setCalcScriptApp(String calcScriptApp) { 
     this.calcScriptApp.set(calcScriptApp); 
    } 

    public StringProperty calcScriptAppProperty() { 
     return calcScriptApp; 
    } 


    public String getCalcScriptGroup() { 
     return calcScriptGroup.get(); 
    } 

    public void setCalcScriptGroup(String calcScriptGroup) { 
     this.calcScriptGroup.set(calcScriptGroup); 
    } 

    public StringProperty calcScriptGroupProperty() { 
     return calcScriptGroup; 
    } 
} 

csEditInterface.fxml

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

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

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="1080.0" prefWidth="1920.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="essapp.csEditController"> 
    <children> 
     <VBox alignment="TOP_CENTER" prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> 
     <children> 
      <Label alignment="CENTER" contentDisplay="CENTER" text="Calculation Script Editor"> 
       <font> 
        <Font name="System Bold" size="36.0" /> 
       </font> 
      </Label> 
      <ScrollPane fitToHeight="true" fitToWidth="true" pannable="true" prefHeight="800.0" prefWidth="717.0"> 
       <content> 
        <AnchorPane prefHeight="200.0" prefWidth="717.0"> 
        <children> 
         <TableView editable="true" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> 
          <columns> 
          <TableColumn fx:id="csEditID" editable="false" prefWidth="100.0" sortable="false" text="ID" /> 
          <TableColumn fx:id="csEditIndex" prefWidth="100.0" text="Index" /> 
           <TableColumn fx:id="csEditName" prefWidth="250.0" sortable="false" text="Name" /> 
           <TableColumn fx:id="csEditServer" editable="false" prefWidth="300.0" sortable="false" text="Server" /> 
           <TableColumn fx:id="csEditApp" editable="false" prefWidth="250.0" sortable="false" text="Application" /> 
           <TableColumn fx:id="csEditGroup" prefWidth="400.0" sortable="false" text="Calc Group" /> 
          </columns> 
         </TableView> 
        </children> 
        </AnchorPane> 
       </content> 
       <VBox.margin> 
        <Insets left="50.0" right="50.0" top="50.0" /> 
       </VBox.margin> 
      </ScrollPane> 
      <Button fx:id="csEditOkBtn" defaultButton="true" mnemonicParsing="false" onAction="#createTbl" prefHeight="25.0" prefWidth="151.0" text="Commit Changes"> 
       <VBox.margin> 
        <Insets top="50.0" /> 
       </VBox.margin> 
      </Button> 
      <Button fx:id="csEditExitBtn" cancelButton="true" mnemonicParsing="false" onAction="#goToCSInt" prefHeight="25.0" prefWidth="150.0" text="Cancel"> 
       <VBox.margin> 
        <Insets top="25.0" /> 
       </VBox.margin> 
      </Button> 
     </children> 
     </VBox> 
    </children> 
</AnchorPane> 

csEditController Код:

package essapp; 

import com.sun.javafx.tk.Toolkit; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.concurrent.Task; 
import javafx.event.ActionEvent; 
import javafx.fxml.FXML; 
import javafx.fxml.Initializable; 
import javafx.scene.control.*; 
import javafx.scene.control.cell.ComboBoxTableCell; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.util.StringConverter; 
import javafx.util.converter.DefaultStringConverter; 
import model.calcs.*; 

import java.net.URL; 
import java.util.Map; 
import java.util.ResourceBundle; 

import static javafx.scene.input.KeyCode.T; 

@SuppressWarnings("Duplicates") 
public class csEditController implements Initializable, ControlledScreen { 

    ScreensController myController; 
    ObservableList<SQLCalcScripts> csEditCSList = FXCollections.observableArrayList(); 
    ObservableList<CalcScripts> csEditEssSQL = FXCollections.observableArrayList(); 
    /** 
    * Initializes the controller class. 
    */ 
    @Override 
    public void initialize(URL url, ResourceBundle rb) { 

     //Add SQL data to TableView 
     Task task = new Task<Void>() { 
      @Override 
      public Void call() throws Exception { 

       SQL2CalcScripts csSQLList = new SQL2CalcScripts(); 
       csSQLList.sqlCalc("http://TEST-HYPRPT01:13080/aps/JAPI","GNLESB",csEditCSList); 
       sqlCSEditTbl.itemsProperty().setValue((ObservableList<SQLCalcScripts>) csSQLList); 

       return null; 
      } 
     }; 
//  sqlCSEditTbl.itemsProperty().bind(task.valueProperty()); 
//  sqlCSEditTbl.setItems(csEditCSList); 
     new Thread(task).start(); 

     // Initialize table with columns 
     csEditID.setCellValueFactory(cellData -> cellData.getValue().calcScriptIDProperty().asObject()); 
     csEditIndex.setCellValueFactory(cellData -> cellData.getValue().calcScriptIndexProperty().asObject()); 
     csEditName.setCellValueFactory(cellData -> cellData.getValue().calcScriptNameProperty()); 
     csEditServer.setCellValueFactory(cellData -> cellData.getValue().calcScriptServerProperty()); 
     csEditApp.setCellValueFactory(cellData -> cellData.getValue().calcScriptAppProperty()); 
     csEditGroup.setCellValueFactory(cellData -> cellData.getValue().calcScriptGroupProperty()); 

     // TableView Calc Group ComboBox 
     ObservableList<String> csGroupList = FXCollections.observableArrayList("Supplement", "Wrapper", "Board Book"); 
     csEditGroup.setCellFactory(ComboBoxTableCell.forTableColumn(new DefaultStringConverter(), csGroupList)); 
     csEditGroup.setOnEditCommit(
       (TableColumn.CellEditEvent<SQLCalcScripts,String> cb) -> { 
        ((SQLCalcScripts) cb.getTableView().getItems().get(
          cb.getTablePosition().getRow() 
        )).setCalcScriptGroup(cb.getNewValue()); 
       } 
     ); 
    } 

    public void setScreenParent(ScreensController screenParent){ 
     myController = screenParent; 
    } 

    @FXML // ResourceBundle that was given to the FXMLLoader 
    private ResourceBundle resources; 

    @FXML // URL location of the FXML file that was given to the FXMLLoader 
    private URL location; 

    @FXML // fx:id="sqlCSEditTbl" 
    private TableView<SQLCalcScripts> sqlCSEditTbl; // Value injected by FXMLLoader 

    @FXML // fx:id="csEditGroup" 
    private TableColumn<SQLCalcScripts, String> csEditGroup; // Value injected by FXMLLoader 

    @FXML // fx:id="csEditExitBtn" 
    private Button csEditExitBtn; // Value injected by FXMLLoader 

    @FXML // fx:id="csEditServer" 
    private TableColumn<SQLCalcScripts, String> csEditServer; // Value injected by FXMLLoader 

    @FXML // fx:id="csEditID" 
    private TableColumn<SQLCalcScripts, Integer> csEditID; // Value injected by FXMLLoader 

    @FXML // fx:id="csEditIndex" 
    private TableColumn<SQLCalcScripts, Integer> csEditIndex; // Value injected by FXMLLoader 

    @FXML // fx:id="csEditOkBtn" 
    private Button csEditOkBtn; // Value injected by FXMLLoader 

    @FXML // fx:id="csEditApp" 
    private TableColumn<SQLCalcScripts, String> csEditApp; // Value injected by FXMLLoader 

    @FXML // fx:id="csEditName" 
    private TableColumn<SQLCalcScripts, String> csEditName; // Value injected by FXMLLoader 

    @FXML 
    private void goToCSInt(ActionEvent event){ 
     myController.setScreen(ScreensFramework.calcScriptInterfaceID); 
    } 

// @FXML 
// private void createTbl(ActionEvent event) { 
//  sqlCSEditTbl.setItems(csEditCSList); 
// } 
} 

Controll edScreen класс Код:

package sample; 

/** 
* Created by jdsmith on 4/21/2016. 
*/ 
public interface ControlledScreen { 
    //This method will allow the injection of the Parent ScreenPane 
    public void setScreenParent(ScreensController screenPage); 
} 

ScreensController класс Код:

package essapp; 

import java.util.HashMap; 
import javafx.animation.KeyFrame; 
import javafx.animation.KeyValue; 
import javafx.animation.Timeline; 
import javafx.beans.property.DoubleProperty; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Node; 
import javafx.scene.Parent; 
import javafx.scene.layout.StackPane; 
import javafx.util.Duration; 

/** 
* Created by jdsmith on 1/7/2016. 
*/ 
public class ScreensController extends StackPane { 
    //Holds the screens to be displayed 

    private HashMap<String, Node> screens = new HashMap<>(); 

    public ScreensController() { 
     super(); 
    } 

    //Add the screen to the collection 
    public void addScreen(String name, Node screen) { 
     screens.put(name, screen); 
    } 

    //Returns the Node with the appropriate name 
    public Node getScreen(String name) { 
     return screens.get(name); 
    } 

    //Loads the fxml file, add the screen to the screens collection and 
    //finally injects the screenPane to the controller. 
    public boolean loadScreen(String name, String resource) { 
     try { 
      FXMLLoader myLoader = new FXMLLoader(getClass().getResource(resource)); 
      Parent loadScreen = (Parent) myLoader.load(); 
      ControlledScreen myScreenControler = ((ControlledScreen) myLoader.getController()); 
      myScreenControler.setScreenParent(this); 
      addScreen(name, loadScreen); 
      return true; 
     } catch (Exception e) { 
      System.out.println(e.getMessage()); 
      return false; 
     } 
    } 

    //This method tries to displayed the screen with a predefined name. 
    //First it makes sure the screen has been already loaded. Then if there is more than 
    //one screen the new screen is been added second, and then the current screen is removed. 
    // If there isn't any screen being displayed, the new screen is just added to the root. 
    public boolean setScreen(final String name) { 
     if (screens.get(name) != null) { //screen loaded 
      final DoubleProperty opacity = opacityProperty(); 

      if (!getChildren().isEmpty()) { //if there is more than one screen 
       Timeline fade = new Timeline(
         new KeyFrame(Duration.ZERO, new KeyValue(opacity, 1.0)), 
         new KeyFrame(new Duration(1000), new EventHandler<ActionEvent>() { 
          @Override 
          public void handle(ActionEvent t) { 
           getChildren().remove(0);     //remove the displayed screen 
           getChildren().add(0, screens.get(name));  //add the screen 
           Timeline fadeIn = new Timeline(
             new KeyFrame(Duration.ZERO, new KeyValue(opacity, 0.0)), 
             new KeyFrame(new Duration(800), new KeyValue(opacity, 1.0))); 
           fadeIn.play(); 
          } 
         }, new KeyValue(opacity, 0.0))); 
       fade.play(); 

      } else { 
       setOpacity(0.0); 
       getChildren().add(screens.get(name));  //no one else been displayed, then just show 
       Timeline fadeIn = new Timeline(
         new KeyFrame(Duration.ZERO, new KeyValue(opacity, 0.0)), 
         new KeyFrame(new Duration(2500), new KeyValue(opacity, 1.0))); 
       fadeIn.play(); 
      } 
      return true; 
     } else { 
      System.out.println("screen hasn't been loaded!!! \n"); 
      return false; 
     } 

     /*Node screenToRemove; 
     if(screens.get(name) != null){ //screen loaded 
     if(!getChildren().isEmpty()){ //if there is more than one screen 
     getChildren().add(0, screens.get(name));  //add the screen 
     screenToRemove = getChildren().get(1); 
     getChildren().remove(1);     //remove the displayed screen 
     }else{ 
     getChildren().add(screens.get(name));  //no one else been displayed, then just show 
     } 
     return true; 
     }else { 
     System.out.println("screen hasn't been loaded!!! \n"); 
     return false; 
     }*/ 
    } 

    //This method will remove the screen with the given name from the collection of screens 
    public boolean unloadScreen(String name) { 
     if (screens.remove(name) == null) { 
      System.out.println("Screen didn't exist"); 
      return false; 
     } else { 
      return true; 
     } 
    } 
} 

ScreensFramework Main App Код:

package essapp; 

import javafx.application.Application; 
import javafx.geometry.Rectangle2D; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.stage.Screen; 
import javafx.stage.Stage; 

public class ScreensFramework extends Application { 

    public static String mainInterfaceID = "main"; 
    public static String mainInterfaceFile = "mainInterface.fxml"; 

    public static String msaInterfaceID = "msa"; 
    public static String msaInterfaceFile = "msaInterface.fxml"; 

    public static String creditRatingInterfaceID = "credit"; 
    public static String creditRatingInterfaceFile = "creditRatingInterface.fxml"; 

    public static String calcScriptEditID = "csEdit"; 
    public static String calcScriptEditFile = "csEditInterface.fxml"; 

    public static String calcScriptInterfaceID = "calc"; 
    public static String calcScriptInterfaceFile = "calcScriptInterface.fxml"; 

    public static String subVarInterfaceID = "subvar"; 
    public static String subVarInterfaceFile = "subVarInterface.fxml"; 

    @Override 
    public void start(Stage primaryStage) { 

     ScreensController mainContainer = new ScreensController(); 
     mainContainer.loadScreen(ScreensFramework.mainInterfaceID, ScreensFramework.mainInterfaceFile); 
     mainContainer.loadScreen(ScreensFramework.calcScriptInterfaceID, ScreensFramework.calcScriptInterfaceFile); 
     mainContainer.loadScreen(ScreensFramework.calcScriptEditID, ScreensFramework.calcScriptEditFile); 
     mainContainer.loadScreen(ScreensFramework.subVarInterfaceID, ScreensFramework.subVarInterfaceFile); 
     mainContainer.loadScreen(ScreensFramework.msaInterfaceID, ScreensFramework.msaInterfaceFile); 
     mainContainer.loadScreen(ScreensFramework.creditRatingInterfaceID, ScreensFramework.creditRatingInterfaceFile); 

     mainContainer.setScreen(ScreensFramework.mainInterfaceID); 

     mainContainer.prefHeightProperty().bind(primaryStage.heightProperty()); 
     mainContainer.prefWidthProperty().bind(primaryStage.widthProperty()); 
     mainContainer.setCenterShape(true); 
     mainContainer.setScaleShape(true); 

     Group root = new Group(); 
     root.getChildren().addAll(mainContainer); 
     Scene scene = new Scene(root); 

     Screen screen = Screen.getPrimary(); 
     Rectangle2D bounds = screen.getVisualBounds(); 

     primaryStage.setWidth(bounds.getWidth()); 
     primaryStage.setHeight(bounds.getHeight()); 

     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

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

ответ

1

Когда вы звоните

sqlCSEditTbl.itemsProperty().setValue(...); 

вы обновляете интерфейс (путем обновления элементы, отображаемые в таблице). Как (почти?) Все инструментальные средства UI, JavaFX однопоточен: обновления для пользовательского интерфейса могут возникать только в потоке приложения FX. Выполнение этого в Task, которое выполняется в фоновом потоке, выдает IllegalStateException; поэтому ваш метод вызова никогда не завершается, и вы никогда не увидите обновление к таблице.

Обычный способ сделать это, чтобы вернуть данные из call метода:

Task<List<SQLCalcScripts>> task = new Task<List<SQLCalcScripts>>() { 
     @Override 
     public List<SQLCalcScripts> call() throws Exception { 

      List<SQLCalcScripts> data = /* get data.... */ ; 

      return data; 
     } 
    }; 

после завершения задачи, свойство value устанавливается на значение, возвращаемого метода call, так что вы можете теперь делать:

task.setOnSucceeded(e -> sqlCSEditTbl.getItems().setAll(task.getValue())); 

Это, вероятно, хорошая идея, чтобы войти каких-либо исключений, которые происходят с

task.setOnFailed(e -> task.getException().printStackTrace()); 

Затем, перед запуском задачи с

new Thread(task).start(); 
+0

Спасибо James_D! Это очень помогает. –