1

I created a table view using fx which displays information from a database and whenever I search through the database and display the results, for some reason it will display the last value retrieved times the amount of results found but what it should do is display every item in the observableList. What am I doing wrong?

enter image description here

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.ArrayList;


/**
 * Created by user on 02/06/2016.
 */
public class Main extends Application {
    TableView<TableViewData> table;
    ObservableList<TableViewData> itemList = FXCollections.observableArrayList();

    public static void main(String[] args) {

        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Welcome");
        primaryStage.setResizable(false);

        TableColumn<TableViewData, String> nameColumn = new TableColumn<>("Name");
        nameColumn.setMinWidth(200);
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));

        TableColumn<TableViewData, String> brandColumn = new TableColumn<>("Brand");
        nameColumn.setMinWidth(200);
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("brand"));

        TableColumn<TableViewData, Integer> quantityColumn = new TableColumn<>("Quantity");
        nameColumn.setMinWidth(200);
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("quantity"));

        TableColumn<TableViewData, Double> priceColumn = new TableColumn<>("Price");
        nameColumn.setMinWidth(200);
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("price"));

        TableColumn<TableViewData, String> typeColumn = new TableColumn<>("Type");
        nameColumn.setMinWidth(200);
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("type"));

        table = new TableView<>();
        table.getColumns().addAll(nameColumn, quantityColumn, priceColumn, typeColumn, brandColumn);

        TextField query = new TextField();
        query.setPromptText("Search");

        ComboBox column = new ComboBox();
        //adds the optons for the combo box
        column.getItems().addAll(
                "Name",
                "Price",
                "Item Type",
                "Brand",
                "Details"
        );

        Button searchButton = new Button("Search");

        searchButton.setOnAction(e -> {
            try {
                itemList = DatabaseHandling.search(column.getValue().toString(), query.getText());
                table.getItems().addAll(itemList);
            } catch (Exception ex) {
                Errors.error("Please select a an option from the box", "error");
            }

        });


        HBox searchBox = new HBox();
        searchBox.getChildren().addAll(query, column, searchButton);
        searchBox.setPadding(new Insets(10, 10, 10, 10));
        searchBox.setSpacing(10);

        Button createItem = new Button("Create");
        createItem.setOnAction(e -> MainFunctions.createItem());
        Button deleteItem = new Button("Delete");
        Button editItem = new Button("Edit");
        editItem.setOnAction(e -> MainFunctions.editItem());

        HBox itemManipulationBox = new HBox();
        itemManipulationBox.getChildren().addAll(createItem, deleteItem, editItem);
        itemManipulationBox.setPadding(new Insets(10, 10, 10, 10));
        itemManipulationBox.setSpacing(10);


        VBox layout = new VBox();
        layout.getChildren().addAll(table, searchBox, itemManipulationBox);
        Scene scene = new Scene(layout);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

Here is the search function the search button calls:

public static ObservableList<TableViewData> search(String column, String query){

        String name=null;
        String brand = null;
        String type=null;
        int quantity=0;
        double price =0.00;
       String newQuery = query.replace(" ","_");
        String s = "SELECT * FROM ITEM " +
                "WHERE "+column+" LIKE '%"+newQuery+"%';";
        Connection con =db_connectionHandler.connect();
        ObservableList<TableViewData> items = FXCollections.observableArrayList();
        items.clear();
        try{

            Statement st=con.createStatement();
            st.executeUpdate(s);
            ResultSet rs=st.executeQuery(s);
            while(rs.next()){
               items.add(new TableViewData(rs.getString("NAME"),rs.getInt("QUANTITY"),rs.getDouble("PRICE"),rs.getString("TYPE"),rs.getString("BRAND")));


            }
            for(TableViewData i: items) {
                System.out.println();
            }

            db_connectionHandler.endConnect(con,st,rs);
            return items;
        }
        catch(SQLException e){
            System.out.print("error: "+e.getMessage());
        }
        db_connectionHandler.endConnect(con,null,null);
        return items;
    }

Class for the TableViewData object:

public class TableViewData {
    private static SimpleStringProperty name;
    private static SimpleStringProperty brand;
    private static int quantity;
    private static double price;
    private static SimpleStringProperty type;
//constructor for item object

    public TableViewData(String Fname, int Fquantity, double Fprice, String Ftype, String Fbrand ){
        TableViewData.name=new SimpleStringProperty(Fname);
        TableViewData.quantity= new Integer(Fquantity);
        TableViewData.price= new Double(Fprice);
        TableViewData.type=new SimpleStringProperty(Ftype);
        TableViewData.brand=new SimpleStringProperty(Fbrand);
    }

    public static String getName() {
        return name.get();
    }

    public static void setName(String name) {
        TableViewData.name.set(name.replace(" ","_"));
    }

    public static String getBrand() {
        return brand.get();
    }

    public static void setBrand(String brand) {
        TableViewData.brand.set(brand.replace(" ","_"));
    }

    public static int getQuantity() {
        return quantity;
    }

    public static void setQuantity(int quantity) {
        TableViewData.quantity = quantity;
    }

    public static double getPrice() {
        return price;
    }

    public static void setPrice(double price) {
        TableViewData.price = price;
    }

    public static  String getType() {
        return type.get();
    }

    public static void setType(String type) {
        TableViewData.type.set(type.replace(" ","_"));
    }
}
Fabian Fagerholm
  • 4,099
  • 1
  • 35
  • 45
JScott
  • 109
  • 10
  • 2
    You're using static fields, obviously the data will all be the same. That's what static means. Get rid of all the static in TableViewData. – brian Jun 05 '16 at 01:48
  • changing the table to non static hasn't changed anything, any other ideas? – JScott Jun 05 '16 at 02:58
  • i manage to get the array to correctly store the objects however when i display the array it will only show values from the type column, but display them in the first column – JScott Jun 05 '16 at 03:40
  • Possible duplicate of [Why does my ArrayList contain N copies of the last item added to the list?](http://stackoverflow.com/questions/19843506/why-does-my-arraylist-contain-n-copies-of-the-last-item-added-to-the-list) – fabian Jun 05 '16 at 07:39
  • i fixed the first problem now but i still can't get it to display information on the table properly – JScott Jun 05 '16 at 08:58
  • 1
    You have all the columns using the variable nameColumn. Use the right variable names. – brian Jun 05 '16 at 14:51
  • You can still use observable properties for double and int so the table will update automatically. They're called SimpleDoubleProperty etc.. – brian Jun 05 '16 at 14:55

2 Answers2

1

There are 2 key issues here (as others have already identified in the comments):


Table not displaying complete item information:

Look closely at your code here:

TableColumn<TableViewData, String> nameColumn = new TableColumn<>("Name");
nameColumn.setMinWidth(200);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));

TableColumn<TableViewData, String> brandColumn = new TableColumn<>("Brand");
nameColumn.setMinWidth(200);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("brand"));

TableColumn<TableViewData, Integer> quantityColumn = new TableColumn<>("Quantity");
nameColumn.setMinWidth(200);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("quantity"));

TableColumn<TableViewData, Double> priceColumn = new TableColumn<>("Price");
nameColumn.setMinWidth(200);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("price"));

TableColumn<TableViewData, String> typeColumn = new TableColumn<>("Type");
nameColumn.setMinWidth(200);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("type"));

You're only ever modifying nameColumn. You can fix this by changing the names to reflect the code groupings you've set up
E.g where you set up typeColumn, you should be setting the typeColumn width and cellValueFactory, not nameColumn as this was done above

With these changes your table will look something like this:

enter image description here

i manage to get the array to correctly store the objects however when i display the array it will only show values from the type column, but display them in the first column

This was also due to only the nameColumn being modified, the last modification was:

nameColumn.setCellValueFactory(new PropertyValueFactory<>("type"));

which overwrote the initial value of:

nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));

Meaning that it was populating from type instead of name
Following this step should correct that issue also


Duplicated rows:

From the last image, the columns are now populating but the rows are the same. This is due to the TableViewData fields being declared as static

It might be best to read up on other answers for more clarity around this such as:

My attempt at describing it (for this scenario) would be:


Each of your objects are no longer unique when all of their fields are static. Upon creation they will all reference the same value, so when you create a new instance, each instance you've created will then reflect that instance's value. This is visible in the image above as that was the last item I added to my list.

To fix this you can:

  1. Remove the static key word from your variable declarations
  2. Remove replace TableViewData.someVariableName with this.someVariableName

Using this will look within the object's variables for a match, which will prevent conflicts when the method parameter has the same name. This post should provide more detail: Using the this Keyword

With these changes the table should now look something like this:

enter image description here

Community
  • 1
  • 1
Peter
  • 1,592
  • 13
  • 20
0

Hi You need to correct the following code

nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));

. . .

to

nameColumn.setCellValueFactory(new PropertyValueFactory<TableViewData,SimpleStringProperty>("name"));

. . .

Please change all the columns accordingly