0
votes

In MS Access a 'ListBox' can hide the first 'column' of a 2 column ResultSet - it's great for hiding 'IDs' which are easily accessible when the user selects an item from the list.

If possible I want to do the same in JavaFX with a ListView so I can populate a second ListView based on the selection from the first ListView.

This is how I populate the ListView : menuList1.setItems(MenuUtilities.getDivisions()); from

public static ObservableList getDivisions() {

    ObservableList divisionListRow = FXCollections.observableArrayList();
    try {
        Connection conn;
        conn = Connect_db.getConnection();
        String query = "SELECT ID, Division FROM tbl_ref_employee_divisions";
        PreparedStatement prestate = conn.prepareStatement(query);
        ResultSet divsResult = prestate.executeQuery();
        while (divsResult.next()) {

            for (int i = 1; i <= divsResult.getMetaData().getColumnCount(); i++) {
                divisionListRow.add(divsResult.getString(i));
            }
        }
        prestate.close();
        divsResult.close();
        conn.close();

    } catch (SQLException ex) {
        ex.printStackTrace();
    }
    return divisionListRow;
}

the listview displays : see image of List View Output

From the image I get the impression a listView cannot format an array. If so, am I better using a single column TableView? And if so how do I display one string column from the ObservableList and access the integer ID of the selected item in code.

many thanks

1
..perhaps I should read my ResultSet into a 2 field class and pass one field (as a single String type) to the ObservableList..but it still begs the question - using best practice - how do I get to my ID? Clearly I'm a noob.. - Rod Wenban
..I have a not-elegant solution which is to use the list view, populate with 'Division' only (no duplicates) and just use the selected Division as a parameter back to the dbase to get the id...yuk but it will do until I learn a bit more. - Rod Wenban

1 Answers

1
votes

You access the ResultSet in a way that for each row you add an element for each of the columns. You need to add a single item for each row you want to display in the ListView, i.e. in this case a single item per row in the ResultSet.

Since you want the ID to be accessible, you should create a custom type containing the values for both rows (or use an existing class like Pair) and use a cellFactory to choose the data to display.

public class EmployeeDivision {
    private final long id; // or maybe String/int as type?
    private final String name;

    public EmployeeDivision (long id, String name) {
        this.id = id;
        this.name = name;
    }

    /* getters */

}
ListView<EmployeeDivision> menuList1;
menuList1.setCellFactory(lv -> new ListCell<EmployeeDivision>() {
    @Override
    protected void updateItem(EmployeeDivision item, boolean empty) {
        super.updateItem(item, empty);
        setText(empty || item == null ? "" : item.getName());
    }
});
while (divsResult.next()) {
    divisionListRow.add(new EmployeeDivision(divsResult.getLong(1), divsResult.getString(2)));
}

This allows you to access the id of the selected item like this:

EmployeeDivision selectedItem = menuList1.getSelectionModel().getSelectedItem();
if (selectedItem != null) {
    System.out.println("id = " + selectedItem.getId());
} else {
    System.out.println("no item selected");
}

BTW: I recommend specifying type parameters unless you've got a really good reason to use the raw type. This allows the compiler to do some checks that could result in issues that are hard to spot, if the raw type was used.