javafx : get the name of the column

user3776738

How do I get the name of the column of a textfield inside a javaFX table? I need this to check the value of the cells only in the "text2" column. I tried it with textfield.parent() but I didn't get a useful result.Edit: I just removed some unnessary log, which was not helpful for understanding.Now it is more convenient. Here is my Code:

import java.util.ArrayList;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TextArea;
import javafx.util.Callback;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;


/*interface inside_table
{
    public String get_column_name
}*/

public class Supermain extends Application {

    @Override
    public void start(Stage primaryStage) {

        ArrayList myindizes=new ArrayList();



        final TableView<myTextRow> table = new TableView<>();
        table.setEditable(true);
        table.setStyle("-fx-text-wrap: true;");

        //Table columns
        TableColumn<myTextRow, String> clmID = new TableColumn<>("ID");
        clmID.setMinWidth(160);
        clmID.setCellValueFactory(new PropertyValueFactory<>("ID"));

        TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
        clmtext.setMinWidth(160);
        clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
        clmtext.setCellFactory(new TextFieldCellFactory());

        TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
        clmtext2.setMinWidth(160);
        clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
        clmtext2.setCellFactory(new TextFieldCellFactory());

        //Add data
        final ObservableList<myTextRow> data = FXCollections.observableArrayList(
                new myTextRow(5, "Lorem","bla"),
                new myTextRow(2, "Ipsum","bla")
        );

        table.getColumns().addAll(clmID, clmtext,clmtext2);
        table.setItems(data);

        HBox hBox = new HBox();
        hBox.setSpacing(5.0);
        hBox.setPadding(new Insets(5, 5, 5, 5));

        Button btn = new Button();
        btn.setText("Get Data");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                for (myTextRow data1 : data) {
                    System.out.println("data:" + data1.getText2());
                }
            }
        });

        hBox.getChildren().add(btn);

        BorderPane pane = new BorderPane();
        pane.setTop(hBox);
        pane.setCenter(table);
        primaryStage.setScene(new Scene(pane, 640, 480));
        primaryStage.show();


    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }


    public static class TextFieldCellFactory
            implements Callback<TableColumn<myTextRow, String>, TableCell<myTextRow, String>> {

        @Override
        public TableCell<myTextRow, String> call(TableColumn<myTextRow, String> param) {
            TextFieldCell textFieldCell = new TextFieldCell();
            return textFieldCell;

        }

        public static class TextFieldCell extends TableCell<myTextRow, String> {

            private TextArea textField;
            private StringProperty boundToCurrently = null;
            private String last_text;


            public TextFieldCell() {

                textField = new TextArea();
                textField.setWrapText(true);
                textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
                last_text="";



                this.setGraphic(textField);

                textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> { 
//only if textfield is in the text2 column
                    if(isNowFocused){last_text=textField.getText();  System.out.println("NOW focus "+last_text);}
                    if (! isNowFocused && ! isValid(textField.getText())) { 
                        textField.setText(last_text);
                        textField.selectAll();
                        System.out.println("blur");

                    }

                });

            }

            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                if (!empty) {
                    // Show the Text Field
                    this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);


                   // myindizes.add(getIndex());

                    // Retrieve the actual String Property that should be bound to the TextField
                    // If the TextField is currently bound to a different StringProperty
                    // Unbind the old property and rebind to the new one
                    ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
                    SimpleStringProperty sp = (SimpleStringProperty) ov;

                    if (this.boundToCurrently == null) {
                        this.boundToCurrently = sp;
                        this.textField.textProperty().bindBidirectional(sp);
                    } else if (this.boundToCurrently != sp) {
                        this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
                        this.boundToCurrently = sp;
                        this.textField.textProperty().bindBidirectional(this.boundToCurrently);
                    }

                    double height = real_lines_height(textField.getText(), this.getWidth(), 30, 22);
                    textField.setPrefHeight(height);
                    textField.setMaxHeight(height);

                    textField.setMaxHeight(Double.MAX_VALUE);
                    // if height bigger than the biggest height in the row
                    //-> change all heights of the row(textfields ()typeof textarea) to this height
                    // else leave the height as it is


                    //System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
                    //this.textField.setText(item);  // No longer need this!!!
                } else {
                    this.setContentDisplay(ContentDisplay.TEXT_ONLY);
                }
            }//update

            private boolean isValid(String s){

                if(s.length()<7){return true;}
                return false;  


            }

        }

    }

    public class myTextRow {

        private final SimpleIntegerProperty ID;

        private final SimpleStringProperty text;
        private final SimpleStringProperty text2;

        public myTextRow(int ID, String text,String text2) {

            this.ID = new SimpleIntegerProperty(ID);
            this.text = new SimpleStringProperty(text);
            this.text2 = new SimpleStringProperty(text2);


        }


        //setter
        public void setID(int id) {
            this.ID.set(id);
        }

        public void setText(String text) {
            this.text.set(text);
        }

        public void setText2(String text) {         
            this.text2.set(text);         
        }

       //getter
        public int getID() {
            return ID.get();
        }

        public String getText() {
            return text.get();
        }

        public String getText2() {
            return text2.get();
        }

        //properties
        public StringProperty textProperty() {
        return text;

        }

        public StringProperty text2Property() {
        return text2;

        }

    public IntegerProperty IDProperty() {
        return ID;
    }

    }

    private static double real_lines_height(String s, double width, double heightCorrector, double widthCorrector) {
        HBox h = new HBox();
        Label l = new Label("Text");
        h.getChildren().add(l);
        Scene sc = new Scene(h);
        l.applyCss();
        double line_height = l.prefHeight(-1);

        int new_lines = s.replaceAll("[^\r\n|\r|\n]", "").length();
        //  System.out.println("new lines= "+new_lines);
        String[] lines = s.split("\r\n|\r|\n");
        //  System.out.println("line count func= "+ lines.length);
        int count = 0;
        //double rest=0;
        for (int i = 0; i < lines.length; i++) {
            double text_width = get_text_width(lines[i]);
            double plus_lines = Math.ceil(text_width / (width - widthCorrector));
            if (plus_lines > 1) {
                count += plus_lines;
                //rest+= (text_width / (width-widthCorrector)) - plus_lines;
            } else {
                count += 1;
            }

        }
        //count+=(int) Math.ceil(rest);
        count += new_lines - lines.length;

        return count * line_height + heightCorrector;
    }

    private static double get_text_width(String s) {
        HBox h = new HBox();
        Label l = new Label(s);
        l.setWrapText(false);
        h.getChildren().add(l);
        Scene sc = new Scene(h);
        l.applyCss();

        return l.prefWidth(-1);

    }

}
James_D

There are probably (way) better ways to organize this, but probably the cleanest fix is just to define a boolean validate parameter to the constructor of your cell implementation. (You really don't want the logic to be "if the title of the column is equal to some specific text, then validate". You would be utterly screwed when your boss came in to the office and asked you to internationalize the application, or even just change the title of the column, for example.)

Using an entire inner class just to implement the callback seems completely redundant, but keeping that you would have to pass the parameter through it:

public static class TextFieldCellFactory
        implements Callback<TableColumn<myTextRow, String>, TableCell<myTextRow, String>> {

    private final boolean validate ;

    public TextFieldCellFactory(boolean validate) {
        this.validate = validate ;
    }

    @Override
    public TableCell<myTextRow, String> call(TableColumn<myTextRow, String> param) {
        TextFieldCell textFieldCell = new TextFieldCell(validate);
        return textFieldCell;

    }

    public static class TextFieldCell extends TableCell<myTextRow, String> {

        private TextArea textField;
        private StringProperty boundToCurrently = null;
        private String last_text;

        public TextFieldCell(boolean validate) {

            textField = new TextArea();
            textField.setWrapText(true);
            textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
            last_text="";



            this.setGraphic(textField);

            if (validate) {
                textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> { 
//only if textfield is in the text2 column
                    if(isNowFocused){last_text=textField.getText();  System.out.println("NOW focus "+last_text);}
                    if (! isNowFocused && ! isValid(textField.getText())) { 
                        textField.setText(last_text);
                        textField.selectAll();
                        System.out.println("blur");

                    }

                });
            }

        }

      // ...

}

Then of course you just do

TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
clmtext.setCellFactory(new TextFieldCellFactory(false));

TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
clmtext2.setMinWidth(160);
clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
clmtext2.setCellFactory(new TextFieldCellFactory(true));

(To properly answer your question, you can get the text of the column from within the cell to which it is attached with getTableColumn().getText(), but as I pointed out, actually basing the logic on the value displayed in a column header will make your code completely unmaintainable.)

And I guess for completeness, I should also mention that your TextFieldCellFactory class looks like it is not really serving any purpose. I would remove it entirely and just have the TextFieldCell class, and do

TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
clmtext.setCellFactory(c -> new TextFieldCell(false));

TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
clmtext2.setMinWidth(160);
clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
clmtext2.setCellFactory(c -> new TextFieldCell(true));

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related