使用通用Object类型的TableColumn的CellValueFactory?

时间:2017-03-21 16:52:34

标签: java generics javafx tableview treetableview

错误:类型不匹配:无法从SimpleStringProperty转换为ObservableValue<Object>

我正在尝试使用管理各种数据类型的列创建TreeTableView。这意味着每行可以使用三种类型的数据之一(StringintStringPropertyObjectProperty< LocalDate >

鉴于我的数据类型是&#34;对象&#34;然后setCellValueFactory( cellDataFeatures -> { return ...; })需要ObservableValue< Object >。我无法尝试从CellValueFactory回调的属性中获取所需的ObservableValue。 :(

This post建议使用ReadOnlyStringWrapper,但我希望保持值可编辑(在大多数情况下)。我还发现了#asObject()方法的建议,这在StringProperty中是不可用的。

        /*-------------------------+------------+ 
         | columnPeople            | columnData |
         +-------------------------+------------+ 
         |                         |            |
         | + Bob Rozz ============ | 33 ======= |
         |   + SKILLS              |            |
         |     + testskill 1       | 0.7        |
         |                         | 3/14/2017  |
         |     + testskill 2       |            |
         |                         | 0.9        |
         |                         | 3/11/2017  |
         |                         |            |
         | + Bob Dilly =========== | 34 ======= |
         |   + SKILLS              |            |
         |     + testskill 1       | 0.6        |
         |                         | 3/10/2017  |
         |     + testskill 2       |            |
         |                         | 0.5        |
         |                         | 3/17/2017  |
         +-------------------------+------------+ 
        */

注1 :尚未处理setCellFactory(...)

Note2 :如上所述,我意识到这个例子不切实际。它与我的项目完全分开,作为所需功能的一个例子。

package testGenericTableTreeColumn;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import javafx.application.Platform;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TextFieldTreeTableCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Pair;
import javafx.util.converter.DefaultStringConverter;



public class testGenericTableTreeColumn extends javafx.application.Application {

    class Skill {

        private StringProperty        name = new SimpleStringProperty( "" );
        public  final String          getName(){ return this.name.get();         }
        public  final void            setName( String v ){ name.set(v); return;  }
        public  StringProperty        nameProperty(){ return this.name;          }

        private SimpleFloatProperty   value = new SimpleFloatProperty( 0f );
        public  final String          getValue(){ return this.name.get();        }
        public  final void            setValue( String v ){ name.set(v); return; }
        public  StringProperty        valueProperty(){ return this.name;         }

        private SimpleObjectProperty< LocalDate > date = new SimpleObjectProperty< LocalDate >( LocalDate.now() );//LocalDate date  = LocalDate.now();
        public  final String          getDate(){ return this.name.get();         }
        public  final void            setDate( String v ){ name.set(v); return;  }
        public  StringProperty        dateProperty(){ return this.name;          }

        public Skill( String name ){
            java.util.Random r = new java.util.Random();
            this.name  .set( name );                        //this.name  = name;
            this.value .set( 100 * ( r.nextFloat() ));      //this.value = 100 * ( r.nextFloat() );
            this.date  .get().minusWeeks( r.nextInt(10) );  //date.minusWeeks( r.nextInt(10) );
            return;
        }
    }
    class Person {

        private StringProperty  name = new SimpleStringProperty( "" );
        public final String     getName()          { return this.name.get(); }
        public final void       setName( String v ){ name.set(v); return;    }
        public StringProperty   nameProperty()     { return this.name;       }

        private IntegerProperty age = new SimpleIntegerProperty( 0 );
        public final int        getAge()           { return this.age.get();  }
        public final void       setAge( int v )    { age.set(v); return;     }
        public IntegerProperty  ageProperty()      { return this.age;        }

        public  List< Skill >   skills = new ArrayList<>();

        public Person( String name, int age ){
            this.name .set( name );
            this.age  .set( age  );
            skills.add( new Skill( "testskill 1" ));
            skills.add( new Skill( "testskill 2" ));
            return;
        }
    }

    public TreeTableView< Pair< Object, Object >> table = new TreeTableView<>();

    @Override public void start( Stage primaryStage ){

        TreeItem< Pair< Object, Object >> itemRoot = new TreeItem<>( new Pair<>( "PEOPLE", null ));
        this.table.setRoot( itemRoot );

        Person person1 = new Person( "Bob Rozz"  ,33 );
        Person person2 = new Person( "Bob Dilly" ,34 );

        List< Person > people = new ArrayList<>();
        people.add( person1 );
        people.add( person2 );

        /*-------------------------+------------+ 
         | columnPeople            | columnData |
         +-------------------------+------------+ 
         |                         |            |
         | + Bob Rozz ============ | 33 ======= |
         |   + SKILLS              |            |
         |     + testskill 1       | 0.7        |
         |                         | 3/14/2017  |
         |     + testskill 2       |            |
         |                         | 0.9        |
         |                         | 3/11/2017  |
         |                         |            |
         | + Bob Dilly =========== | 34 ======= |
         |   + SKILLS              |            |
         |     + testskill 1       | 0.6        |
         |                         | 3/10/2017  |
         |     + testskill 2       |            |
         |                         | 0.5        |
         |                         | 3/17/2017  |
         +-------------------------+------------+ 
        */

        for ( Person person : people ){

            TreeItem< Pair< Object, Object >> treeItemPerson = new TreeItem<>( new Pair< Object, Object >( person.nameProperty(), person.ageProperty() ));
            TreeItem< Pair< Object, Object >> treeItemSkills = new TreeItem<>( new Pair< Object, Object >( "Skills"             , null ));

            itemRoot       .getChildren().add( treeItemPerson );
            treeItemPerson .getChildren().add( treeItemSkills );

            for ( Skill skill : person.skills ){

                TreeItem< Pair< Object, Object >> treeItemSkillName  = new TreeItem<>( new Pair< Object, Object >( null, skill.nameProperty  () ));
                TreeItem< Pair< Object, Object >> treeItemSkillValue = new TreeItem<>( new Pair< Object, Object >( null, skill.valueProperty () ));
                TreeItem< Pair< Object, Object >> treeItemSkillDate  = new TreeItem<>( new Pair< Object, Object >( null, skill.dateProperty  () ));

                treeItemSkills    .getChildren().add( treeItemSkillName  );
                treeItemSkillName .getChildren().add( treeItemSkillDate  );
                treeItemSkillName .getChildren().add( treeItemSkillValue );
            }
        }

        TreeTableColumn< Pair< Object, Object>, String > colName = new TreeTableColumn<>("People"); colName.setMinWidth(100);
        colName.setCellValueFactory( cellDataFeatures -> {

            // Could be a String, StringProperty, or ObjectProperty< LocalDate >
            Object item   = cellDataFeatures.getValue().getValue().getKey();

            //String
            if ( item instanceof String ){
                /* ERROR */ return ( String ) item; //ERROR: Type mismatch: cannot convert from SimpleStringProperty to ObservableValue< Object >
            }

            //StringProperty
            if ( item instanceof StringProperty ){
                /* ERROR */ return (( StringProperty ) item ); //ERROR: Type mismatch: cannot convert from SimpleStringProperty to ObservableValue< Object >
            }
        });

        TreeTableColumn< Pair< Object, Object>, Object > colData = new TreeTableColumn<>("Skills"); colData.setMinWidth(200);
        colData.setCellValueFactory( cellDataFeatures -> {

            //itemKey : Could be a String, IntegerProperty, StringProperty, or ObjectProperty< LocalDate >
            Object item = cellDataFeatures.getValue().getValue().getValue();

            //String
            if ( item instanceof String ){
                /* ERROR */ return (String) item; //ERROR: Type mismatch: cannot convert from SimpleStringProperty to ObservableValue< Object >
            }

            //IntegerProperty
            if ( item instanceof IntegerProperty ){
                /* ERROR */ return (( IntegerProperty ) item ); //ERROR: Type mismatch: cannot convert from SimpleIntegerProperty to ObservableValue< Object >
            }

            //StringProperty
            if ( item instanceof StringProperty ){
                /* ERROR */ return (( StringProperty ) item ); //ERROR: Type mismatch: cannot convert from SimpleStringProperty to ObservableValue< Object >
            }

            //ObjectProperty< LocalDate >
            if ( item instanceof ObjectProperty< ? >){
                Object value = (( ObjectProperty<?> ) item ).getBean();
                if ( value instanceof LocalDate ){
                    //@TODO LocalDate cell
                }
            }
        });

        /*
        //colData.setCellFactory( new Callback< TreeTableColumn< Person, Object >, TreeTableCell< Person, Object >>());
        colData.setCellFactory( column -> {

            TreeTableCell< Object, Object > cell = new TreeTableCell< Object, Object >(){
                @Override protected void updateItem( Object newValue, boolean empty ){

                    this.setEditable( false );

                    super.updateItem( newValue, empty );
                    if ( empty || newValue == null ){
                        setText    ( null );
                        setGraphic ( null );
                        return;
                    }

                    if ( newValue instanceof String ){
                        return;
                    }

                    this.setEditable( true );

                    if ( newValue instanceof LocalDate ){
                        return;
                    }

                    return;
                }   // updateItem( ... );
            };
        });
        // */

        // Type safety: A generic array of Table... is created for a varargs
        // parameter
        // -> @SuppressWarnings("unchecked") to start method!
        table.getColumns().addAll( colName, colData );

        // Output in console the selected table view's cell value/class to check
        // that the data type is correct.
        //  SystemOutTreeTableViewSelectedCell.set(tableView);
        /*
        // To check that table view is correctly refreshed on data changed..
        final Button agePlusOneButton = new Button("Age +1");
        agePlusOneButton.setOnAction((ActionEvent e) -> {
            Person<?> person = tableView.getSelectionModel().getSelectedItem();
            try {
                person.setAge(person.getAge() + 1);
            } catch (NullPointerException npe ){
                //
            }
        });
        */

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll( table );

        Scene scene = new Scene(new Group());
        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        primaryStage.setWidth(600);
        primaryStage.setHeight(750);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

错误:

Description Resource    Path    Location    Type
Type mismatch: cannot convert from IntegerProperty to ObservableValue<Object>   testGenericTableTreeColumn.java /testGenericTableTreeColumn/src/testGenericTableTreeColumn  line 300    Java Problem
Type mismatch: cannot convert from String to ObservableValue<Object>    testGenericTableTreeColumn.java /testGenericTableTreeColumn/src/testGenericTableTreeColumn  line 295    Java Problem
Type mismatch: cannot convert from String to ObservableValue<String>    testGenericTableTreeColumn.java /testGenericTableTreeColumn/src/testGenericTableTreeColumn  line 278    Java Problem
Type mismatch: cannot convert from StringProperty to ObservableValue<Object>    testGenericTableTreeColumn.java /testGenericTableTreeColumn/src/testGenericTableTreeColumn  line 305    Java Problem

Java版本:

java version "1.8.0_121" Java(TM)
SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)

1 个答案:

答案 0 :(得分:2)

对于TreeTableColumn<S,T>cellValueFactory的类型为Callback<CellDataFeatures<S,T>, ObservableValue<S,T>>,它本质上是一个以[{1}}为例并返回CellDataFeatures<S,T>的函数。

您的ObservableValue<S,T>colName,因此TreeTableColumn<Pair<Object, Object>, String>SPair<Object, Object>T。因此,String的{​​{1}}是一个功能,可以使用cellValueFactory个实例(您调用colName)并返回CellDataFeatures<Pair<Object, Object>>

您的实施存在多个问题。第一个是,如果声明为cellDataFeatures的{​​{1}}不是ObservableValue<String>item的实例,那么代码实际上永远不会达到{{1}声明。所以这甚至不是一个有效的lambda表达式。

第二个问题是,如果ObjectString个实例(第一个StringProperty语句),则会返回return,而不是item ,所以你回错了类型。

所以至少要编译的实现是

String

同样,对于if,您的代码路径永远不会到达return语句,因此您尚未定义有效的lambda表达式。在这种情况下,StringObservableValue<String>,因此 TreeTableColumn< Pair< Object, Object>, String > colName = new TreeTableColumn<>("People"); colName.setMinWidth(100); colName.setCellValueFactory( cellDataFeatures -> { // Could be a String, StringProperty, or ObjectProperty< LocalDate > Object item = cellDataFeatures.getValue().getValue().getKey(); //String if ( item instanceof String ){ return new SimpleStringProperty(( String ) item); } //StringProperty if ( item instanceof StringProperty ){ return (( StringProperty ) item ); } // must return something: you probably don't want to return null though, so you should fix this as needed. return null ; }); colData,返回类型必须为colData。您的各种TreeTableColumn<Pair<Object, Object>, Object>阻止尝试返回TObjectObservableValue<Object>,(或某些待确定的内容),而这些都不是if的实例。

实际编译的实现是

String