0

Ich bin der Aufbau einen Multi-Screen JavaFX App mit Daten aus einer SQL-Datenbank ObservableLists und angezeigt in der Schnittstelle über Tableview gezogen werden. Wegen der Multiscreen-Natur der App versuche ich, die Daten von der ObservableList über den Controller zur Tabellenansicht zu initialisieren. Der SQL-Pull zu ObservableList erfolgt über eine Aufgabe in einem neuen Thread. Als ich die sqlCSEditTbl.itemsProperty include(). SetValue ((ObservableList) csSQLList) in der Task-Methode nichts im Tableview angezeigt, wenn ich das Programm auszuführen. Wenn ich den Code außerhalb der Task-Methode platziere, wird der betreffende Bildschirm nicht angezeigt. Ich weiß nicht, was mir hier fehlt, um die Daten auf dem jeweiligen Bildschirm anzeigen zu können. Ich habe das SQL zu ObservableList debugged und die Daten werden ordnungsgemäß in der ObservableList gespeichert. Das Problem besteht darin, es von der ObservableList zur Tableview-Schnittstelle zu bekommen. Jede Hilfe würde sehr geschätzt werden. Vielen Dank!JavaFX ObservableList toTableview über die Task-Thema

App Edit Screen Screenshot

SQLCalcScript Array Modell

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 Code:

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 Klasse Code:

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 Klasse Code:

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 Haupt App-Code:

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); 
    } 
} 

Antwort

1

Wenn Sie anrufen

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

Sie die Benutzeroberfläche aktualisieren (durch Aktualisierung der Elemente in der Tabelle angezeigt). Wie (? Fast) alle UI-Toolkits ist JavaFX Single-Thread: Aktualisierungen der Benutzeroberfläche nur auf dem FX Anwendung Faden passieren kann. Dadurch in den Task, die auf einem Hintergrund-Thread ausgeführt wird, wird ein IllegalStateException werfen; Daher wird Ihre Aufrufmethode nie abgeschlossen und Sie sehen nie die Aktualisierung der Tabelle.

Der üblicher Weg, dies zu tun ist, um die Daten von Ihrer call Methode zurückzukehren:

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

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

      return data; 
     } 
    }; 

, wenn die Aufgabe abgeschlossen ist, die value Eigenschaft auf den Wert aus der call Methode zurückgegeben, so können Sie jetzt tun:

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

Es ist wahrscheinlich eine gute Idee, alle Ausnahmen zu protokollieren, die mit

auftreten 0

Dann starten Sie nach wie vor die Aufgabe, mit

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

Dank James_D! Das hilft sehr. –