0

How can I set value at selected row in TableColumn JavaFX. Early I did it in Swing with table.setValueAt, but now I do it in JavaFX and have some problem with doing it. I'm doing Database App. There are a three fields for ID, first name and last name. And a three buttons: Add, Update, Delete.

I need to replace old values to new values after click Update button. I've done Select method, now I need to make Update method. Here's my full code.

Controller class

package com.cascado.application.application;

import static com.cascado.application.common.Constants.REGEX;
import com.cascado.application.common.Constants;

import com.cascado.application.common.User;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import java.net.URL;
import javafx.scene.input.MouseEvent;
import java.util.ResourceBundle;

public class Controller implements Initializable {

    @FXML
    private TableView<User> table;
    @FXML
    private TableColumn<User, String> idColumn;
    @FXML
    private TableColumn<User, String> firstNameColumn;
    @FXML
    private TableColumn<User, String> lastNameColumn;
    @FXML
    private TextField firstNameField;
    @FXML
    private TextField lastNameField;
    @FXML
    private TextField idField;
    private ObservableList<User> users;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        idColumn.setCellValueFactory(new PropertyValueFactory<User, String>("ID"));
        firstNameColumn.setCellValueFactory(new PropertyValueFactory<User, String>("firstName"));
        lastNameColumn.setCellValueFactory(new PropertyValueFactory<User, String>("lastName"));
        users = table.getItems();
        table.setEditable(true);
        selectRow();
    }
    @FXML
    private void addButton(ActionEvent actionEvent) {
        users.add(newUser(Constants.ID, Constants.FIRST_NAME, Constants.LAST_NAME));
        table.setItems(users);
        clearFields();
    }

    private void selectRow(){
        table.setOnMouseClicked((MouseEvent event) -> {
            getTextFromSelectedRow();
        });
    }

    private void getTextFromSelectedRow(){
        User selectedUser = table.getSelectionModel().getSelectedItem();
        idField.setText(selectedUser.getID());
        firstNameField.setText(selectedUser.getFirstName());
        lastNameField.setText(selectedUser.getLastName());
    }

    @FXML
    private void updateButton(ActionEvent actionEvent) {
        if (table.getSelectionModel().getSelectedIndex() != -1) {
            setTextToSelectedRow();
        } else {
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION,
                    "Please select the row",
                    ButtonType.OK);
            alert.showAndWait();
        }
    }

    private void setTextToSelectedRow(){
//        int selectedUser = table.getSelectionModel().getSelectedIndex();
        idColumn.setCellValueFactory();
        firstNameColumn.setText(firstNameField.getText());
        lastNameColumn.setText(lastNameField.getText());
    }

    @FXML
    private void deleteButton(ActionEvent actionEvent) {
    }

    private String[] fieldsTextArray(){
        return (idField.getText() + REGEX + firstNameField.getText() + REGEX + lastNameField.getText()).split(REGEX);
    }

    private void clearFields(){
        firstNameField.clear();
        lastNameField.clear();
        idField.clear();
    }

    private User newUser(int id, int firstName, int lastName){
        // values in textfields message array
        return new User(fieldsTextArray()[id], fieldsTextArray()[firstName], fieldsTextArray()[lastName]);
    }

}

Application class

package com.cascado.application.application;

import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Application extends javafx.application.Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(this.getClass().getResource("/resources.fxml"));
        Parent parent = loader.load();
        Scene scene = new Scene(parent);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.setTitle("Database");
        primaryStage.show();
    }
}

Constants class

package com.cascado.application.common;

public class Constants {
    public static final String REGEX = "@#!#@";
    public static final int ID = 0;
    public static final int FIRST_NAME = 1;
    public static final int LAST_NAME = 2;
}

User class

package com.cascado.application.common;

public class User {

    private String firstName;
    private String lastName;
    private String ID;

    public User(String ID, String firstName, String lastName){
        this.ID = ID;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getID() {
        return ID;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void setID(String ID) {
        this.ID = ID;
    }
}
pilotUSA
  • 23
  • 4
  • 4
    _Here's my full code._ - please strip it down to a [mcve]: currently you seem to have a problem with update, so there is no need for code related to add :) On the other hand, the fxml is missing as is the description of the problem: what doesn't work as expected, exactly? BTW: this code doesn't even compile (there is no method `column.setCellValueFactory()`). Also, there is no need to repeatedly calling `table.setItems(users)` .. simply modify the list (look at the api doc of Observable/List to learn how), the update will happen automagically. – kleopatra Jul 07 '22 at 15:45
  • 4
    Use [JavaFX properties](https://docs.oracle.com/javafx/2/binding/jfxpub-binding.htm) in your `User` class, and [don't use `PropertyValueFactory`](https://stackoverflow.com/questions/72437983/why-should-i-avoid-using-propertyvaluefactory-in-javafx). If you set things up the correct way, simply calling `setXXX()` on the `User` object will automatically update the table. – James_D Jul 07 '22 at 16:06
  • sorry for my incompetence – pilotUSA Jul 07 '22 at 18:23
  • thank you all. a things with observablelist was right. it works. also i add ```table.refresh()``` after button clicked – pilotUSA Jul 07 '22 at 19:14
  • 4
    You should not use `table.refresh()`. That API was added for some corner-cases. If things are set up correctly, the table will automatically refresh when you change values or add new elements to the items list. – James_D Jul 07 '22 at 19:42
  • I'm not quite sure why you are now calling refresh. One reason might be that you are updating fields in the model and aren't seeing them shown in your table. If you don't use properties in your model and observe changes to them in the list using an [extractor](https://stackoverflow.com/questions/31687642/callback-and-extractors-for-javafx-observablelist) then the table won't be automatically refreshed when you modify a field of an item in the list. If that is the case for you (it may not be), then using properties and an extractor may be a preferred solution. – jewelsea Jul 07 '22 at 21:33
  • putting it stronger than @James_D: you __must not__ use refresh, if it appears to be needed there's something wrong in your setup. Find the error and fix it instead of painting it over (it'll come back and hit you later, anyway :) – kleopatra Jul 08 '22 at 10:39

0 Answers0