2016-08-31 9 views
1

TableViewの列のサイズを変更したいのですが、これを達成する方法がjavafxから見つからないため、MainApp.GUIUtil.fitColumns(TableView tableView)で解決された解決策を見つけることができました。
私の問題は:このソリューションは、ユーザーの操作で呼び出されたときに正常に動作しますが、ユーザーの操作が行われる前に起動時にこのメソッドを実行する方法を見つけることができません。
テーブルが表示されているように、スモールとしてフィッティングされたカラムでテーブルを提示したいと思います。
私は頭痛(PersonTableController.setMainApp 32行目)の原因となっているExceptionを傍受し、スタックトレースを印刷して、ユーザーにコントロールが与えられた後にプログラムがフィットメソッドを動作させ続けるようにします。
tableviewが表示されるとすぐにコードサイズで列サイズを調整できますか?ここでJavaFX TableViewの列が内容に合う

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 

は私のコードです:彼のそれぞれのコントローラで

<?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> 

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

そしてここでは、FXMLファイルです

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

私の考えを呼び出すことでしたレンダリングの最後にそのメソッドを使用してみましたこの解決策:Post render event in JavaFXしかし、私はそれを行う場合は何も起こりません。

+0

私にとってうまく動作します。 – DVarga

+0

ヌルポインタ例外は、その時点でスキンがインストールされていないためです。それが起こるには、少なくともテーブルがシーンの一部であり、CSSが適用されている必要があります(これは 'table.applyCSS()'で強制できます)。しかし、それでも私はそれを働かせることはできません。 –

+0

@DVarga私の質問は完全にはっきりしていませんでした。申し訳ありませんが、私が投稿したコードは例外を投げかけませんでした。私はそれを修正しました。 –

答えて

0

だから、違いは、あなたのコントローラのsetMainApp方法で

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

が追加されていることです。 James_Dで指摘されているように、その時点でスキンがインストールされていないため、NULLポインタ例外がスローされています。

あなたは、コントローラにsetMainApp方法を更新たとえばでこれを回避することができます

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

これはあなたのApplicationStageが表示されていることを確認し、もしそうなら、それは列にフィットします。表示されていない場合は、Stageが表示されるとすぐにStageshowingPropertyにリスナーを添付して、fitColumnsメソッドが呼び出されます。

+0

あなたのソリューションは素晴らしいです、@DVargaありがとう:) –

+0

...しかし、私のトラブルは終わっていません。 PersonTableをParentレイアウト(RootLayout)にラップすると、同じ問題が再現されました。私は既に質問[ここ](http://stackoverflow.com/questions/39327969/programmatically-resize-tablecolumns-in-javafx)を投稿しました。どんな助けも感謝しています:) –

関連する問題