2016-08-31 9 views
1

Ich möchte einige TableView Spalten Größe ändern, da eine Methode, um dies zu erreichen fehlt von javafx ich habe es geschafft, eine Lösung in MainApp.GUIUtil.fitColumns(TableView tableView) ausgesetzt zu finden.
Mein Problem ist: Diese Lösung funktioniert gut, wenn sie von einer Benutzeraktion aufgerufen wird, aber ich kann keine Methode finden, diese Methode beim Start auszuführen, bevor Benutzereingriffe vorgenommen werden.
Ich möchte die Tabelle mit der Spalte als soos wie die Tabelle dargestellt dargestellt.
Wie Sie sehen können ich die Exception abfangen, die mir Kopfweh (PersonTableController.setMainApp Zeile 32) verursacht, drucken Sie den StackTrace und lassen Sie dann das Programm weiterhin beweisen, dass die Fit-Methode funktioniert, nachdem die Kontrolle an den Benutzer gegeben wurde.
Wie kann ich die Spaltengrößen per Code anpassen, sobald die Tabellenansicht angezeigt wird?JavaFX TableView Spalten passen Inhalt

Exception in Application start method 
java.lang.reflect.InvocationTargetException 
    ... 
Caused by: java.lang.RuntimeException: Exception in Application start method 
    ... 
Caused by: java.lang.NullPointerException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at columnstofit.MainApp$GUIUtil.fitColumns(MainApp.java:120) 
    at columnstofit.PersonTableController.setMainApp(PersonTableController.java:35) 
    at columnstofit.MainApp.showPersonTable(MainApp.java:79) 
    at columnstofit.MainApp.start(MainApp.java:65) 
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863) 
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326) 
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294) 
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) 
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191) 
    ... 1 more 
Exception running application columnstofit.MainApp 

Hier ist mein Code:

package columnstofit; 

import com.sun.javafx.scene.control.skin.TableViewSkin; 
import java.awt.AWTException; 
import java.io.IOException; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Scene; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.layout.AnchorPane; 
import javafx.stage.Stage; 

public class MainApp extends Application { 

    private  PersonTableController controller; 
    public static Stage     primaryStage; 
        AnchorPane   personTable; 

    private ObservableList<Person> personData = FXCollections.observableArrayList(); 

    /** 
    * Constructor 
    */ 
    public MainApp() { 
     // i am entering this name just to force the resizing of the column 
     personData.add(new Person("Hansgggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg", "Muster")); 
     personData.add(new Person("Ruth", "Mueller")); 
     personData.add(new Person("Heinz", "Kurz")); 
     personData.add(new Person("Cornelia", "Meier")); 
     personData.add(new Person("Werner", "Meyer")); 
     personData.add(new Person("Lydia", "Kunz")); 
     personData.add(new Person("Anna", "Best")); 
     personData.add(new Person("Stefan", "Meier")); 
    } 

    /** 
    * Returns the data as an observable list of Persons. 
    * @return 
    */ 
    public ObservableList<Person> getPersonData() { 
     return personData; 
    } 

    @Override 
    public void start(Stage primaryStage) throws AWTException { 

     this.primaryStage = primaryStage; 
     this.primaryStage.setTitle("Names Table"); 

     showPersonTable(); 
    } 

    public void showPersonTable() throws AWTException { 

     try 
     { 
      // Load root layout from fxml file. 
      FXMLLoader loader = new FXMLLoader(); 
      loader.setLocation(MainApp.class.getResource("PersonTable.fxml")); 
      personTable = (AnchorPane) loader.load(); 

      // Give the controller access to the main app. 
      controller = loader.getController(); 
      controller.setMainApp(this); 

      Scene scene = new Scene(personTable); 
      primaryStage.setScene(scene); 
      primaryStage.show(); 
     } 
     catch (IOException e) { e.printStackTrace(); } 
    } 

    /** 
    * Returns the main stage. 
    * @return 
    */ 
    public Stage getPrimaryStage() { 
     return primaryStage; 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     launch(args); 
    } 


    public static class GUIUtil { 
     private static Method columnToFitMethod; 

     static 
     { 
      try 
      { 
       columnToFitMethod = TableViewSkin.class.getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class); 
       columnToFitMethod.setAccessible(true); 
      } 
      catch (NoSuchMethodException e) {e.printStackTrace();} 
     } 

     public static void fitColumns(TableView tableView) { 
      for (Object column : tableView.getColumns()) 
      { 
       try { columnToFitMethod.invoke(tableView.getSkin(), column, -1); } 
       catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } 
      } 
     } 
    } 

    public class Person { 
     private final StringProperty firstName; 
     private final StringProperty lastName; 

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

     public Person(String firstName, String lastName) { 
      this.firstName = new SimpleStringProperty(firstName); 
      this.lastName = new SimpleStringProperty(lastName); 
     } 

     public String getFirstName() { 
      return firstName.get(); 
     } 

     public void setFirstName(String firstName) { 
      this.firstName.set(firstName); 
     } 

     public StringProperty firstNameProperty() { 
      return firstName; 
     } 

     public String getLastName() { 
      return lastName.get(); 
     } 

     public void setLastName(String lastName) { 
      this.lastName.set(lastName); 
     } 

     public StringProperty lastNameProperty() { 
      return lastName; 
     } 
    } 
} 

Und hier ist die FXML Datei:

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

<?import javafx.scene.control.TableColumn?> 
<?import javafx.scene.control.TableView?> 
<?import javafx.scene.layout.AnchorPane?> 

<AnchorPane id="AnchorPane" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="columnstofit.PersonTableController"> 
    <TableView fx:id="tableView" layoutX="-39.0" layoutY="39.0" onKeyPressed="#fitColumns" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> 
        <columns> 
         <TableColumn fx:id="firstNameColumn" editable="false" minWidth="-1.0" prefWidth="-1.0" text="First Name" /> 
         <TableColumn fx:id="lastNameColumn" editable="false" minWidth="-1.0" prefWidth="-1.0" text="Last Name" /> 
        </columns> 
        <columnResizePolicy> 
         <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> 
        </columnResizePolicy> 
        </TableView> 
</AnchorPane> 

Mit seinem jeweiligen Controller:

package columnstofit; 

import java.awt.AWTException; 
import javafx.fxml.FXML; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 

    /** 
    * FXML Controller class 
    */ 
    public class PersonTableController { 

     // Reference to the main application. 
     private MainApp mainApp; 

     @FXML 
     private TableColumn<MainApp.Person, String> firstNameColumn; 
     @FXML 
     private TableColumn<MainApp.Person, String> lastNameColumn; 
     @FXML 
     private TableView       tableView; 

     public PersonTableController() { 
     } 

     public void setMainApp(MainApp mainApp) throws AWTException { 
      this.mainApp = mainApp; 
      // Add observable list data to the table 
      tableView.setItems(mainApp.getPersonData()); 
      try 
      { 
       fitColumns(); 
      } 
      catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 

     @FXML 
     private void initialize() throws AWTException { 
      // Initialize the person table with the two columns. 
      firstNameColumn.setCellValueFactory(
        cellData -> cellData.getValue().firstNameProperty()); 
      lastNameColumn.setCellValueFactory(
        cellData -> cellData.getValue().lastNameProperty()); 
     } 

     @FXML 
     private void fitColumns() { 
      MainApp.GUIUtil.fitColumns(tableView); 
     } 
    } 

Meine Idee zu nennen war diese Methode am Ende des Renderings, also versuchte ich wi th diese Lösung: Post render event in JavaFX, aber nichts passiert, wenn ich es mache.

+0

Funktioniert gut für mich. – DVarga

+0

Die Nullzeiger-Ausnahme ist, weil die Skin zu diesem Zeitpunkt nicht installiert wurde. Um das zu erreichen, müssen Sie mindestens die Tabelle als Teil einer Szene verwenden und CSS anwenden (was Sie mit 'table.applyCSS()' erzwingen können); Ich kann es immer noch nicht zur Arbeit bringen, auch nicht mit dem. –

+0

@DVarga Es tut mir leid, meine Frage war nicht ganz klar, der Code, den ich gepostet habe, warf die Ausnahme nicht. Ich habe es korrigiert. –

Antwort

0

So ist der Unterschied, dass Sie

try 
{ 
    fitColumns(); 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 

in setMainApp Methode des Controllers hinzugefügt haben. Wie es von James_D hingewiesen wurde, wird die Nullzeigerausnahme ausgelöst, da die Skin zu diesem Zeitpunkt nicht installiert wurde.

Sie können diese Problemumgehung mit zum Beispiel aktualisieren setMainApp Methode in der Steuerung als:

public void setMainApp(MainApp mainApp) { 
    this.mainApp = mainApp; 
    tableView.setItems(mainApp.getPersonData()); 
    if(mainApp.primaryStage.isShowing()) 
     fitColumns(); 
    else { 
     mainApp.primaryStage.showingProperty().addListener((obs, oldVal, newVal) -> { 
      if(newVal) 
       fitColumns(); 
     }); 
    } 
} 

Dies wird prüfen, ob die Stage des Ihre Application angezeigt wird, und wenn ja, passt es die Spalten. Wenn es nicht angezeigt wird, wurde ein Listener an die showingProperty der Stage angeschlossen, daher wird die fitColumns-Methode aufgerufen, sobald die Stage angezeigt wird.

+0

Ihre Lösung funktioniert super, danke @DVarga :) –

+0

... aber meine Probleme sind nicht vorbei. Wenn ich PersonTable in ein Parent-Layout (RootLayout) einfügte, tauchte das Problem erneut auf. Ich habe bereits eine Frage [hier] (http://stackoverflow.com/questions/39327969/programmatic-resize-tablecolumns-in-javafx) geschrieben. Jede Hilfe ist dankbar, danke :) –