JavaFX TableView列适合内容 [英] JavaFX TableView columns fit content

查看:85
本文介绍了JavaFX TableView列适合内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想调整一些 TableView 列的大小,因为javafx缺少实现此目的的方法,我设法找到在 MainApp中公开的解决方案。 GUIUtil.fitColumns(TableView tableView)

我的问题是:这个解决方案在用户操作调用时工作正常,但我无法找到一种方法来运行此方法在进行任何用户干预之前启动。

我希望在表格显示的情况下显示列为soos的表格。

如您所见,我拦截了 Exception 导致我头痛(PersonTableController.setMainApp第32行),打印堆栈跟踪,然后让程序继续证明fit方法在给用户控制后工作。

如果显示tableview,我怎样才能按代码调整列大小?

I want to resize some TableView columns, since a method to achieve this is missing from javafx i managed to find a solution exposed in MainApp.GUIUtil.fitColumns(TableView tableView).
My problem is: this solution works fine when called by a user action, but i can't find a way to run this method at startup before any user intervention is made.
I want to present the table with the column fitted as soos as the table is shown.
As you can see I intercept the Exception which is causing me headaches (PersonTableController.setMainApp line 32), print the stacktrace and then let the program continue to prove the fit method works after control is given to the user.
How can I fit the columns sizes by code as soon as the tableview is shown?

    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

这是我的代码:

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文件:

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

我的想法是在最后调用该方法渲染,所以我尝试使用此解决方案:在JavaFX中发布渲染事件,但没有任何事情发生如果我这样做。

My idea was to call that method at the end of the rendering so i tried with this solution: Post render event in JavaFX, but nothing happends if do I it.

推荐答案

所以不同之处在于你添加了

So, the difference is that you have added

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

in setMainApp 方法你的控制器。
正如 James_D 指出的那样,抛出空指针异常,因为皮肤没有已安装在那一点。

in setMainApp method of your controller. As it was pointed out by James_D, the null pointer exception is being thrown because the skin has not been installed at that point.

您可以使用控制器中的更新 setMainApp 方法解决此问题: / p>

You can workaround this with for example update setMainApp method in the controller as:

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

这将检查您的应用程序的阶段正在显示,如果是,则它适合列。如果它没有显示,它会将一个监听器附加到 stage showsProperty ,因此只要<$ c显示$ c> Stage ,将调用 fitColumns 方法。

This will check that the Stage of the your Application is showing, and if so, it fits the columns. If it is not showing, it attached a listener to the showingProperty of the Stage therefore as soon as the Stage is being shown, the fitColumns method will be called.

这篇关于JavaFX TableView列适合内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆