Javafx: get a TableView string


How do I get a string, knowing its number, and set its style (or add a class)?
For example, in a table of 10 rows, I need to change the style in 3 (for example, the background of this row).

You need to select a row not when creating a table, but after, when the table is already ready. I click on the button, and the 3rd line is highlighted in red.

Author: Regent, 2016-07-29

2 answers

Here are two possible options in one( the second one works only at the time of execution, so if you want to use it, you need to put it on some listener ):

public class Main2 extends Application {

    public static final int STYLING_ROW_INDEX = 3;

    @Override
    public void start(Stage primaryStage) throws Exception {
        File folder = new File( "/" );
        TableColumn<File,String> fileColumn = new TableColumn<File,String>( "Files" );
        TableView<File> table = new TableView<File>();
        table.getColumns().add( fileColumn );
        fileColumn.setCellValueFactory( new PropertyValueFactory<File,String>( "name" ) );

        // вариант 1:
        table.setRowFactory( new StyleRowFactory<File>() );

        table.getItems().addAll(folder.listFiles());
        primaryStage.setScene( new Scene(table));
        primaryStage.show();

        // вариант 2( ломается при scroll'е ):
/*
        for ( Node n: table.lookupAll( "TableRow" ) ) {
            if ( n instanceof TableRow ) {
                TableRow row = (TableRow)n;
                if ( row.getIndex() == STYLING_ROW_INDEX ) {
                    row.setStyle( "-fx-background-color: red;" );
                    break;
                }
            }
        }
*/
    }

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


}

class StyleRowFactory<T> implements Callback<TableView<T>, TableRow<T>> {

//    private final int stylingRowIndex;

//    public StyleRowFactory( int stylingRowIndex ) {
//        this.stylingRowIndex = stylingRowIndex;
//    }

    @Override
    public TableRow<T> call(TableView<T> tableView) {
        return new TableRow<T>() {
            @Override
            protected void updateItem( T paramT, boolean b ) {
                if ( getIndex() == Main2.STYLING_ROW_INDEX ) {
//              if ( tableView.getItems().get( Main2.STYLING_ROW_INDEX ) == paramT ) {
                    setStyle( "-fx-background-color: red;" );
                } else {
                    setStyle( null );
                }
                super.updateItem(paramT, b);
            }
        };
    }

}

Result:

result

UPDATE: Advanced option( as @DimXenon advised ):

public class Main extends Application {

    @Override
    public void start( Stage primaryStage ) throws Exception {
        ObservableList<Person> persons = FXCollections.<Person>observableArrayList(
            new Person( "q" ),
            new Person( "w" ),
            new Person( "e" ),
            new Person( "r" ),
            new Person( "t" ),
            new Person( "y" ),
            new Person( "u" ),
            new Person( "i" )
        );

        TableColumn<Person,String> nameColumn = new TableColumn<Person,String>( "Человеки" );
        nameColumn.setCellValueFactory( cellData -> cellData.getValue().nameProperty );
        TableView<Person> table = new TableView<Person>();
        table.getColumns().add( nameColumn );
        table.getItems().setAll( persons );
        table.setRowFactory( new StyleRowFactory() );
        VBox.setVgrow( table, Priority.ALWAYS );

        Button button = new Button( "qwer" );
        button.setOnAction( ae -> {
            persons.get( 3 ).setHighlight( true );
// грязный хак, чтобы спровоцировать обновление
            nameColumn.setVisible( false );
            nameColumn.setVisible( true );
        } );

        primaryStage.setScene( new Scene( new VBox( button, table ) ));
        primaryStage.show();
    }

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

class StyleRowFactory implements Callback<TableView<Person>, TableRow<Person>> {
    @Override
    public TableRow<Person> call(TableView<Person> tableView) {
        return new TableRow<Person>() {
            @Override
            protected void updateItem( Person person, boolean b ) {
                super.updateItem( person, b );
                if ( person == null )
                    return;
                if ( person.isHighlight() ) {
                    setStyle( "-fx-background-color: red;" );
                } else {
                    setStyle( null );
                }
            }
        };
    }
}

class Person {
    public final StringProperty nameProperty;
    private final BooleanProperty highlightProperty = new SimpleBooleanProperty( false );
    public Person( String name ) {
        nameProperty = new SimpleStringProperty( name );
    }
    public void setHighlight( boolean value ) {
        highlightProperty.set( value );
    }
    public boolean isHighlight() {
        return highlightProperty.get();
    }
}
 2
Author: Andrey M, 2016-07-29 13:50:26

Add a logical "Highlighted" field to the data model. Change this flag in the model whenever you want, and in the renderer, set the listener for the event of changing the value of this logical field in the constructor. When an event occurs, let the style of the cell containing the data instance change.

Here is the code of two classes: the first class is our data, with a certain flag "highlighted"; the second class is the cell renderer.

    private class TableItem {

        private final BooleanProperty active;
        private final StringProperty content;

        public TableItem(String val) {
            this.active = new SimpleBooleanProperty(false);
            this.content = new SimpleStringProperty(val);
        }

        public void setActive(boolean val) {
            this.active.setValue(val);
        }

        public BooleanProperty getActive() {
            return this.active;
        }

        public void setContent(String val) {
            this.content.setValue(val);
        }

        public StringProperty getContent() {
            return this.content;
        }
    }

    private static class NiceTableCell extends TableCell<String, TableItem> {

        public NiceTableCell() {
            super();
            BooleanProperty active = this.getItem().getActive();
            active.addListener((Observable c) -> {
                this.updateStyles(this.getItem());
            });
        }

        @Override
        protected void updateItem(final TableItem item, final boolean empty) {
            super.updateItem(item, empty);
            setText(empty ? "" : item.getContent().getValue());
            this.setStyle("-fx-background-color: rgba(255, 255, 255, .5);");
            updateStyles(empty ? null : item);
        }

        private void updateStyles(TableItem item) {
            if (item == null) {
                return;
            }
            if(item.getActive().getValue()){
                this.setStyle("-fx-background-color: rgba(255, 0, 0, .5);");
            }
        }
    }

After creating ObservableList<TableItem>, you will be able to change it for elements of the property value active and the cells containing them in the table, which are rendered as NiceTableCell will be colored red.

 0
Author: DimXenon, 2016-07-29 14:08:16