javafx CheckBoxTableCell始终未选中

时间:2016-06-07 06:39:06

标签: generics javafx-8

我是javafx的新手。我尝试显示一个CheckBoxTableCell但它总是未经检查忽略Datamodel。这就是我创建列的方式:

@SuppressWarnings("unchecked")
private static <S, T> TableColumn<S, T> createTableColumn(Class<T> type, String fieldName, String index, String columnHeader) {
    TableColumn<S, T> col = new TableColumn<S, T>(columnHeader);
    col.setCellValueFactory(cellData -> {
        try {
            Object o = ReflectionUtils.getValue(fieldName, cellData.getValue());
            // Erzeuge eine Property, die das Attribut enthält
            SimpleObjectProperty<T> property = new SimpleObjectProperty<T>((T) o);
            return property;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    });
    if (type.equals(Boolean.TYPE))
        ((TableColumn<S, Boolean>) col).setCellFactory(CheckBoxTableCell.forTableColumn((TableColumn<S, Boolean>) col));

    col.setId(index);
    return col;
}

我查看了CheckBoxTableCell并发现我正在使用的factoryFunction转换为

    public static <S> Callback<TableColumn<S,Boolean>, TableCell<S,Boolean>> forTableColumn(
        final TableColumn<S, Boolean> column) {
    return forTableColumn(null, null);
}

所以我知道为什么这个功能不起作用,但我不知道现在使用哪种方式。 我希望你能帮助我。

最小的可执行示例: 我的TableGenerator:

package company.viewfx.tables;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.beanutils.BeanUtilsBean;

import company.viewfx.annotations.AsTableColumn;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;

/**
 *         Wrapperklasse, die die Benutzung des JavaFX TableView erleichtern soll
 * @param <S> Die Klasse, die in der Tabelle dargestellt werden soll
 */
@Log4j2
public class GTableView<S> extends TableView<S> {
    /**
     * Enthält eine Listen von Attributen aus <S> die in der Tabelle dargestellt werden sollen (optional)
     */
    @Setter
    private String[] attributes = new String[0];
    /**
     * Die Klasse die dargestellt werden soll
     */
    private Class<S> clazz;

    /**
     * @param clazz Die Klasse die dargestellt werden soll
     * @param items eine ObservableList<S> von Datenelementen
     */
    public GTableView(Class<S> clazz, ObservableList<S> items) {
        super(items);
        this.clazz = clazz;
        initialize();
    }

    /**
     * Fügt die Spalten + Überschrift und Inhalt zu der rohen Tabelle hinzu
     */
    private void initialize() {
        getColumns().addAll(process(attributes, "", "", this.clazz));
        // Spalten nach Id sortieren
        getColumns().sort(new Comparator<TableColumn<S, ?>>() {
            @Override
            public int compare(TableColumn<S, ?> o1, TableColumn<S, ?> o2) {
                return o1.getId().compareTo(o2.getId());
            }
        });
    }

    /**
     * Process the model class.
     * For the fields declared which have annotation AsTableColumn, create a TableColumn<T,S>
     * instance for it with the detected field type.
     * 
     * @param attrList Eine Liste mit Attributen die angezeigt werden sollen (kann auch null sein, dann standard)
     * @param containerName Entscheidet in welchem Komplexen Attribut nach den Spalten gesucht wird
     * @param containerIndex Der index des entsprechenden Wurzelobjektes
     * @param clazz Die Klasse des Attributes, das in dieser Spalte dargestellt werden soll
     * @return Eine Listen von TableColumns für die mit @AsColumn in this.clazz markierten Attribute
     */
    public static <S> List<TableColumn<S, ? extends Object>> process(String[] attrList, String containerName, String containerIndex,
            Class<?> clazz) {
        // Der Rückgabenwert
        List<TableColumn<S, ? extends Object>> columns = new ArrayList<>();
        // Wenn der Index nicht leer ist hänge einen Punkt an
        containerIndex += !containerIndex.equals("") ? "." : "";
        // Wenn der ContainerName nicht leer ist hänge einen Punkt an
        containerName += !containerName.equals("") ? "." : "";
        // Wenn die StandardSpalten verwendet werden sollen
        if (attrList.length == 0) {
            // gehe erst alle Felder durch
            for (Field field : clazz.getDeclaredFields()) {
                // Wenn das Attribut als Feld angezeigt werden soll
                if (field.isAnnotationPresent(AsTableColumn.class)) {
                    AsTableColumn anno = field.getAnnotation(AsTableColumn.class);
                    columns.add(createTableColumn(field.getType(), containerName + field.getName(), containerIndex + anno.index(),
                            anno.text()));
                }
            }
        }
        return columns;
    }

    /**
     * @param type Der Typ des Attributes, das in der Spalte stehen soll
     * @param fieldName Das Attribut, das in dieser Spalte dargestellt werden soll
     * @param columnHeader Die Spaltenüberschrift
     * @param index Der index der Spalte (entscheidet über ihre Reihenfolge)
     * @return TableColumn
     */
    // Das ist hier erlaubt da immer eine Typprüfung mit type.equals durchgeführt wird
    @SuppressWarnings("unchecked")
    private static <S, T> TableColumn<S, T> createTableColumn(Class<T> type, String fieldName, String index, String columnHeader) {
        TableColumn<S, T> col = new TableColumn<S, T>(columnHeader);
        col.setCellValueFactory(cellData -> {
            try {
                Object o = null;
                try {
                    o = BeanUtilsBean.getInstance().getPropertyUtils().getNestedProperty(o, fieldName);
                } catch (Exception e) {
                    log.warn(String.format("Can not reach attribute %s in %s", fieldName, cellData.getValue()), e);
                }
                // Erzeuge eine Property, die das Attribut enthält
                SimpleObjectProperty<T> property = new SimpleObjectProperty<T>((T) o);
                return property;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        if (type.equals(Boolean.TYPE))
            ((TableColumn<S, Boolean>) col).setCellFactory(CheckBoxTableCell.forTableColumn((TableColumn<S, Boolean>) col));
        col.setId(index);
        return col;
    }
}

注释

package company.viewfx.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD,ElementType.METHOD})
    /**
     * Mit dieser Annotation markierte Attribute werden in GTableView automatisch angezeigt, sofern keine anders lautenden
     * Parameter übergeben werden.
     * 
     */
    public @interface AsTableColumn {
        /**
         * @return Die Überschrift, die im Spaltenkopf angezeigt werden soll
         */
        String text() default "";

        /**
         * @return Die Stelle an der Die Spalte stehen soll
         */
        int index() default Integer.MAX_VALUE;
    }

TestDataModel:

package company.viewfx.tables.demo;

import company.viewfx.annotations.AsTableColumn;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@SuppressWarnings("javadoc")
@AllArgsConstructor
public class Person {
@Getter
@Setter
@AsTableColumn(index=1,text="Alive")
private boolean alive;
}

TestApplication:

package company.viewfx.tables.demo;

import company.viewfx.tables.GTableView;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 *         Dient der Vorführung dem Test von GTabelView
 */
public class TableTest extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        // initialize Testdata
        ObservableList<Person> data = FXCollections.observableArrayList(
                new Person(true),
                new Person(false));
        stage.setScene(new Scene(new GTableView<Person>(Person.class, data)));
        stage.show();
    }

    @SuppressWarnings("javadoc")
    public static void main(String[] args) {
        launch(args);
    }
}

的build.gradle

apply plugin: 'java'

// In this section you declare where to find the dependencies of your project
repositories {
    jcenter()
}

configurations {
    provided {
        dependencies.all { dep ->
            configurations.default.exclude group: dep.group, module: dep.name
        }
    }
    compile.extendsFrom provided
}

// In this section you declare the dependencies for your production and test code
dependencies {
    compile 'org.slf4j:slf4j-api:1.7.12'
    provided 'org.projectlombok:lombok:1.12.6'
    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.6'
    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.6'
    compile group: 'commons-beanutils', name: 'commons-beanutils', version: '1.8.3'
    compile 'org.apache.commons:commons-lang3:3.4'
    compile group: 'org.springframework', name: 'spring-core', version: '2.5.6'
    compile group: 'org.eclipse.osgi', name: 'org.eclipse.osgi', version: '3.7.1'
    testCompile 'junit:junit:4.12'
}

1 个答案:

答案 0 :(得分:0)

FXML用户将此作为附加列来呈现复选框。

>>> res
{(3, 4, 6), (3, 8, 10), (1, 2, 8), (2, 6, 9), (3, 4, 7), (1, 2, 9), (4, 6, 9), (2, 6, 8), (1, 8, 9), (4, 6, 8), (1, 4, 6), (3, 6, 8), (4, 8, 10), (3, 6, 9), (1, 6, 8), (4, 6, 10), (4, 8, 9), (1, 6, 9), (3, 9, 10), (1, 3, 4), (2, 8, 9), (4, 7, 8), (2, 7, 8), (1, 3, 9), (2, 4, 7), (3, 4, 8), (2, 7, 9), (1, 3, 8), (2, 4, 6), (2, 8, 10), (3, 4, 9), (2, 7, 10), (3, 4, 10), (1, 2, 4), (2, 3, 4), (2, 9, 10), (2, 3, 8), (2, 4, 9), (2, 3, 9), (3, 7, 9), (2, 4, 10), (2, 4, 8), (1, 4, 8), (3, 7, 8), (1, 7, 8), (3, 8, 9), (1, 8, 10), (3, 7, 10), (4, 6, 7)}