Use objects in Checked ComboBox controls FX - java

I have a combobox in my application that selects data fetched from a database but the problem is i need to make that combobox select multiple values .
I looked into this question on stackoverflow
Selecting multiple items from combobox
Taking into Consideration the comments i have changed the app to use java8 and checkedCombobox of ControlsFX.
But how to acheive the keyvalue pair association in this combobox is it possible.
As we could use setCellfactory in normal combobox.
My checked ComboBox
Class
/*
Added for Application Lov
*/
package businesstier;
/**
*
* #author rahul_singh41
*/
public class KeyValuePair {
private final String key;
private final String value;
public String getKey() {
return key;
}
public String getValue() {
return value;
}
public KeyValuePair(String key, String value) {
this.key = key;
this.value = value;
}
#Override
public String toString() {
return key;
}
}
Method
public static ObservableList<KeyValuePair> getKeyValue(Connection conFrom) throws SQLException{
ObservableList<KeyValuePair> data = FXCollections.observableArrayList();
//data.add(new KeyValuePair("Select Application Name", null));
KeyValuePair keyValuePair;
String query = "select application_name,application_id from apps.fnd_application_vl";
PreparedStatement ps = null;
ResultSet rs = null;
ps = conFrom.prepareStatement(query);
rs = ps.executeQuery();
while(rs.next()){
//System.out.println("Key"+rs.getString(1)+"value"+rs.getString(2));
keyValuePair = new KeyValuePair(rs.getString(1), rs.getString(2));
data.add(keyValuePair);
}
//System.out.println("KeyValue pair"+data);
return data;
}
#FXML
private CheckComboBox<KeyValuePair> applicationCombo = new CheckComboBox<KeyValuePair>();
applicationCombo.getItems().addAll((AOLMethods.getKeyValue(connFrom)));

Related

How to load the data to tableview from database using javafx

i am beginner of javafx. i just use way java jtable like load the data but i couldn't load the data to tableview what i tried so far i attached below.how to load the data to tableview
#FXML
private TableColumn<?, ?> table1;
public void table_load()
{
int c;
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost/addressbook", "root","");
pst = con.prepareStatement("select * from records");
ResultSet rs = pst.executeQuery();
ResultSetMetaData rd = rs.getMetaData();
c = rd.getColumnCount();
df = (DefaultTableModel)table1.getCellData(0);
df.setRowCount(0);
while (rs.next())
{
Vector v = new Vector();
for (int i=1; i<=c; i++)
{
v.add(rs.getString("id"));
v.add(rs.getString("name"));
v.add(rs.getString("address"));
v.add(rs.getString("phone"));
}
df.addRow(v);
}
} catch (SQLException ex) {
} catch (ClassNotFoundException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
Usually you don't add the data to a TableColumn directly. The usual way would be to have objects of a type you can add. Let's assume your result set would contain objects of type Customer and you could extract one or many customer objects from your result set. Then you would rather work with the following (need to be defined in the fxml file:
A superordinate table like TableView <Customer> customerView
a number of table columns like:
TableColumn<Customer, String> idColumn
TableColumn<Customer, String> nameColumn
TableColumn<Customer, String> addressColumn
TableColumn<Customer, String> phoneColumn
You need to set the value factory for the columns to make clear which attribute is to be displayed.
idColumn.setCellValueFactory(new PropertyValueFactory<>("[ATTRIBUTE NAME IN CUSTOMER CLASS]"));
like
idColumn.setCellValueFactory(new PropertyValueFactory<>("id"));
The last step should be to fill the table view with data:
customerView.setItems(observableCustomers);
where observableCustomers is a list of type ObservableList<Customer>. javafx.collections.FXCollections will help you here to create a corresponding object.
It should be similar to this:
#FXML
TableView <Customer> customerView;
#FXML
TableColumn<Customer, String> idColumn;
#FXML
TableColumn<Customer, String> nameColumn;
#FXML
TableColumn<Customer, String> addressColumn;
#FXML
TableColumn<Customer, String> phoneColumn;
ObservableList<Customer> observableCustomers;
// init method or constructor, whatever suits your needs
private void initTable() {
observableCustomers = FXCollections.observableArrayList();
idColumn.setCellValueFactory(new PropertyValueFactory<>("id"));
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
addressColumn.setCellValueFactory(new PropertyValueFactory<>("address"));
phoneColumn.setCellValueFactory(new PropertyValueFactory<>("phone"));
}
public void table_load()
{
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost/addressbook", "root","");
pst = con.prepareStatement("select * from records");
ResultSet rs = pst.executeQuery();
ResultSetMetaData rd = rs.getMetaData();
// CAST/TRANSFORMATION TO BE DONE BY YOU
List<Customer> customerList = ((List<Customer>) rs.toList());
// only if necessary
observableCustomers.clear();
// add customers
observableCustomers.addAll(customerList);
} catch (SQLException ex) {
} catch (ClassNotFoundException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
Unlike in Swing, a JavaFX TableView does not use a separate model. Instead, the data is the model. You pass this data to the TableView using the TableView’s setItems method.
This means you need to create a class to hold your data. Since your table is called records, I would name the data class Record.
If you look at the documentation of JavaFX classes, you should notice a pattern. Bean properties are encapsulated attributes, which consist of three methods:
A read method, which always starts with get followed by a capital letter.¹
A write method, which always starts with set followed by a capital letter.²
A property method, whose name always ends with Property.
For instance, consider the javafx.stage.Window class. It has an “opacity” property, which is represented by these methods:
double getOpacity()
void setOpacity(double)
DoubleProperty opacityProperty()
Your data class needs to follow the same pattern:
public class Record {
private final StringProperty id;
private final StringProperty name;
private final StringProperty address;
private final StringProperty phone;
public Record() {
id = new SimpleStringProperty(this, "id");
name = new SimpleStringProperty(this, "name");
address = new SimpleStringProperty(this, "address");
phone = new SimpleStringProperty(this, "phone");
}
public StringProperty idProperty() { return id; }
public String getId() { return id.get(); }
public void setId(String newId) { id.set(newId); }
public StringProperty nameProperty() { return name; }
public String getName() { return name.get(); }
public void setName(String newName) { name.set(newName); }
public StringProperty addressProperty() { return address; }
public String getAddress() { return address.get(); }
public void setAddress(String newAddress) { address.set(newAddress); }
public StringProperty phoneProperty() { return phone; }
public String getPhone() { return phone.get(); }
public void setPhone(String newPhone) { phone.set(newPhone); }
#Override
public String toString() {
return String.format("%s[id=%s, name=%s]",
getClass().getName(), getId(), getName());
}
}
Creating these objects is straightforward:
#FXML
private TableView<Record> table;
#FXML
private TableColumn<Record, String> idColumn;
#FXML
private TableColumn<Record, String> nameColumn;
#FXML
private TableColumn<Record, String> addressColumn;
#FXML
private TableColumn<Record, String> phoneColumn;
// ...
ObservableList<Record> records = FXCollections.observableArrayList();
try (ResultSet rs = pst.executeQuery()) {
while (rs.next())
{
Record record = new Record();
record.setId(rs.getString("id"));
record.setName(rs.getString("name"));
record.setAddress(rs.getString("address"));
record.setPhone(rs.getString("phone"));
records.add(record);
}
}
table.setItems(records);
Instead of a table model, you must instead tell each table column which data it should display:
idColumn.setCellValueFactory(f -> f.getValue().idProperty());
nameColumn.setCellValueFactory(f -> f.getValue().nameProperty());
addressColumn.setCellValueFactory(f -> f.getValue().addressProperty());
phoneColumn.setCellValueFactory(f -> f.getValue().phoneProperty());
¹ Read methods whose return type is primitive boolean may use is instead of get.
² Write methods are not needed for read-only properties.

Why toString method won't get the selected item in JComboBox?

I bind my values from database to JComboBox using ArrayList and converted each array using StringBuilder because StringBuilder accepts any data types so I think this is the most efficient way.
while(rs.next())
{
departmentId = rs.getInt(1);
departmentTypeList = rs.getString(2);
ArrayList<DepartmentList> listDepartment = new ArrayList<DepartmentList>();
listDepartment.add(new DepartmentList(departmentId,departmentTypeList));
StringBuilder builder = new StringBuilder();
for(DepartmentList s : listDepartment)
{
builder.append(s);
}
cbDepartmentType.addItem(builder.toString());
}
private class DepartmentList
{
private int id;
private String department;
private DepartmentList(int id,String department)
{
this.id = id;
this.department = department;
}
private int getId()
{
return id;
}
#Override
public String toString() //Converting to String the (departmentId,departmentTypeList)
{
return department;
}
}
I added a listener on my JComboBox to listen what item is selected. I already converted my class to Object but when I click the JComboBox it gives me a exception java.lang.String Any ways to solve this problem?
if(e.getSource() == cbDepartmentType)
{
DepartmentList item = (DepartmentList) cbDepartmentType.getSelectedItem();
System.out.println("id "+(item.getId()));
}
StackTrace:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.String cannot be cast to position.AddPosition$DepartmentList
at position.AddPosition$ItemHandler.actionPerformed(AddPosition.java:295)
at javax.swing.JComboBox.fireActionEvent(JComboBox.java:1258)
at javax.swing.JComboBox.setSelectedItem(JComboBox.java:586)
at javax.swing.JComboBox.setSelectedIndex(JComboBox.java:622)
Update:
while(rs.next())
{
departmentId = rs.getInt(1);
departmentTypeList = rs.getString(2);
ArrayList<DepartmentList> listDepartment = new ArrayList<DepartmentList>();
listDepartment.add(new DepartmentList(departmentId,departmentTypeList));
cbDepartmentType.addItem(listDepartment.toString());
}
You are adding String to the Combobox
cbDepartmentType.addItem(builder.toString());
And you try to cast the selected item into a DepartementList
DepartmentList item = (DepartmentList) cbDepartmentType.getSelectedItem();
But you get a String. So something like this is try to run.
DepartmentList item = (DepartmentList) "A string";
You can add DepartmentList to the comboxbox directly.
cbDepartmentType.addItem(departement);
This will use the implementation of toString() of DepartementList to print the text in the component.
With this, the selectedItem will be an instance of DepartementList.
Here is the official tutorial of How to use Combo Boxes
EDIT :
Your code should look like :
while(rs.next())
{
departmentId = rs.getInt(1);
departmentTypeList = rs.getString(2);
DepartmentList dep = new DepartmentList(departmentId,departmentTypeList); //Create a department
cbDepartmentType.addItem(dep ); //insert into the combo
}
In your original code, you were using a List to store the instance then recover this instance to parse it into a StringBuilder then insert this represention (a String) into the combobox.
My logic
Department -> Combobox
Yours
List > Departemnt > StringBuilder > Combobox
Try to understand the while loop you had, you will see this was not logic at all.

Avoid Duplicate Literals Sonar Error

I'm using SonarQube to verify and inspect my Java code, and i've encountered an issue with Avoid Duplicate Literals in an Enum class type, here is an exemple :
public enum Products {
A ("Product A"),
C ("Product A"),
D ("Product B"),
P ("Product B");
private String name = "";
Products (String name){
this.name = name;
}
public String toString(){
return name;
}
}
Sonar is telling me to declare the Strings 'Product A' and 'Product B' as a constant field, but you can't declare variables in Enum type class.
You can declare the constant outside of the enum:
private static final String TYPE_A_NAME = "Type A";
public enum Type {
TYPEA(TYPE_A_NAME), TYPEB("B");
private String value;
Type(String value) {
}
}
Create Prefix (private static final Sting PREFIX = Product.class.getSimpleName()+ "."
and A("A"), etc...
you return a string, you can use a MessageFormatter to internationalize your string in a properties file
Product.A=Product A, etc...
and the constructor is private
you can make a getter like
`
public static String getI18NString(String key){
return Internationalizer.getI18String(PREFIX + key);
}
public class Internationalizer {
/** The logger of this class. */
private static final Log LOGGER = LogFactory.getLog(Internationalizer.class);
/** */
private static ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
/**
* Get the internationalized String form properties files
*
* #param key
* #return
*/
public static String getI18String(final String key) {
String message = "";
try {
message = resourceBundleMessageSource.getMessage(key, null, Locale.getDefault());
} catch (NoSuchMessageException e) {
LOGGER.info("Key not internationalized : " + key);
message = key;
}
return message;
}
/**
* Set the bundles for internationalization Injected by Spring
*
* #param bundles
*/
public void setBundles(final List<String> bundles) {
String[] bundlesArrays = new String[bundles.size()];
for (int i = 0; i < bundles.size(); i++) {
bundlesArrays[i] = bundles.get(i);
}
resourceBundleMessageSource.setBasenames(bundlesArrays);
}
}
`

Java - String NullPointerException

I'm making a mysql database connector with java to show all the data.
When I run the code, I get an NullPointerException in my getData() function.
here is my code.
public String[][] getData() {
String values[][];
try {
rs = st.executeQuery("SELECT * FROM adresses");
int i = 0;
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String adress = rs.getString("email_adress");
String catagory = rs.getString("catarogy");
values[i][0] = id;
values[i][1] = name;
values[i][2] = adress;
values[i][3] = catagory;
i++;
}
return values;
} catch (SQLException e) {
e.printStackTrace();
return values;
}
}
When the value of the String values is nothing I get The error. But if I give the String allready a value it says nothing .
public String[][] getData() {
String values[][] = {{"","","",""},
{"","","",""},
{"","","",""},};
try {
rs = st.executeQuery("SELECT * FROM adresses");
int i = 0;
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String adress = rs.getString("email_adress");
String catagory = rs.getString("catarogy");
values[i][0] = id;
values[i][1] = name;
values[i][2] = adress;
values[i][3] = catagory;
i++;
}
return values;
} catch (SQLException e) {
e.printStackTrace();
return values;
}
}
I want more data than that in my data String. how can I let it automatically do that??
Tnx.
PS.
The function is called in my class FrameGUI and has to change to Object
public class FrameGUI extends JFrame {
public JTable dataHolder;
Mysql mysql = new Mysql();
public String[] columnNames = {
"ID", "Name", "Adress", "Catagory"
};
-> public Object[][] data = mysql.getData();
public FrameGUI() {
init();
mysql.getData();
}
}
You do not initialize String values[][] so it is null. You either need to initialize it first or use a more appropriate datastructure like a List.
You should define a class and use a List (e.g. the ArrayList) instead.
e.g. if you want to call it User -
public class User {
private String id;
private String name;
//...
}
and a list
List<User> users = new ArrayList<User>();
and then instantiate the User class for each row and add the new instance to the list -
User currUser = new User();
users.add(currUser);
//set values from result set
The list can grow automatically when needed and the code is much more readable than using the array.
You get an index out of bounds in the first example because a String[][] (or String Matrix) gets initialized as a zero-length array.
In the second instance, you initialized the array to a size of 3x4 - that works so long as you only get 3 results back.
What you really need is a data structure with a dynamic size. Arrays aren't automatically sized dynamically. Try using a collection implementation like ArrayList or LinkedList or Vector.
Also, instead of saving your values to a String[], try creating a bean class that can hold your result. Create a new instance of it for each result that you get back instead of initializing a new array.
Because you didn't initialized your array, that is why you get NPE. Actually I suggest you to use List for your purposes:
public ArrayList<ArrayList<String>> getData() {
ArrayList<ArrayList<String>> values = new ArrayList<>();
try {
rs = st.executeQuery("SELECT * FROM adresses");
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String adress = rs.getString("email_adress");
String catagory = rs.getString("catarogy");
ArrayList<String> list = new ArrayList<>();
list.add(id);
list.add(name);
list.add(adress);
list.add(catagory);
values.add(list);
}
return values;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
The main problem in you code is you are using arrays to save variable number of data. Arrays is fixed sized after they are created so you can't add (or remove) elements to them dynamically.
Instead of using arrays you should use an ArrayList object which have methods to add more elements. Also instead of creating a multidimensional array it looks like a better idea to create a class for the data you get from you database.
So lets first create a Address class:
public class Address {
public String id, name, adress, catagory;
public Address(String id, String name, String adress, String catagory) {
this.id = id;
this.name = name;
this.adress = adress;
this.catagory = catagory;
}
}
Now you can write you code as:
public List<Address> getData() {
List<Address> values = new ArrayList<Address>();
try {
rs = st.executeQuery("SELECT * FROM adresses");
int i = 0;
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String adress = rs.getString("email_adress");
String catagory = rs.getString("catarogy");
values.add(new Address(id, name, adress, catagory));
}
return values;
} catch (SQLException e) {
e.printStackTrace();
return values;
}
}
The returned list will contain a list of Address objects which have the values from you database. Also, the size of the list is always the same as the content you put into it.

ParameterizedRowMapper That Maps Object List to Object

I am trying to set the Parent List in a ParameterizedRowMapper how is this written or approached. I have two Objects one for parent and one for children however children contains a ListThe parents for each child are stored in a separate table in the database and the mapping is 1 - many.
The select for the records for the parents will be done in a separate ResultSet. Will the mapping have to be done separately (separate ParameterizedRowMapper), if so how will i have to write the ParameterizedRowMapper this is the major concern how ParameterizedRowMapper is written to accommodate a list items.
ParameterizedRowMapper
public static class ChildrenMapper implements ParameterizedRowMapper<Children>{
public Children mapRow(ResultSet rs, int rowNum) throws SQLException {
Children child = new Children();
child.setFirstName(rs.getString("firstName"));
child.setLastName(rs.getString("lastName"));
//a child can have many Parents or gaurdians
child.setParent(List<Parent>);
return child;
}
}
Based on my research i have found that i need to use ResultSetExtractor, however i have a questions on the use of that. Do i integrate it into the class at the point of setting the Parent? Can someone guide me on how it can be done the correct way
Children.java
Public class Children(){
int cid;
String firstName;
String lastName;
List<Parent>parents;
..
//getters/setters
}
Parent.java
Public class Parent(){
int pid;
String firstName;
String lastName;
..
//setters/getters
}
I will show how to do this for a canonical 1-to-many example, you can adapt it to your vo class / table.
Order class
public class Order {
private Long orderId;
private String user;
private List<LineItem> items;
// Getter / setter omitted
}
Item class
public class LineItem {
private Long lineItemId;
private String product;
private int quantity;
// Getter / setter omitted
}
Use two rowmappers one for each class and then use a result set extractor to convert multiple rows into one order + line items
OrderRepository
public final static RowMapper<Order> orderMapper = ParameterizedBeanPropertyRowMapper.newInstance(Order.class);
public final static RowMapper<LineItem> lineItemMapper = ParameterizedBeanPropertyRowMapper.newInstance(LineItem.class);
public Order findOrderWithItems(Long orderId) {
return jdbcTemplate.query("select * from orders, line_item "
+ " where orders.order_id = line_item.order_id and orders.order_id = ?",
new ResultSetExtractor<Order>() {
public Order extractData(ResultSet rs) throws SQLException, DataAccessException {
Order order = null;
int row = 0;
while (rs.next()) {
if (order == null) {
order = orderMapper.mapRow(rs, row);
}
order.addItem(lineItemMapper.mapRow(rs, row));
row++;
}
return order;
}
}, orderId);
}
public List<Order> findAllOrderWithItmes() {
return jdbcTemplate.query("select * from orders, line_item "
+ " where orders.order_id = line_item.order_id order by orders.order_id",
new ResultSetExtractor<List<Order>>() {
public List<Order> extractData(ResultSet rs) throws SQLException, DataAccessException {
List<Order> orders = new ArrayList<Order>();
Long orderId = null;
Order currentOrder = null;
int orderIdx = 0;
int itemIdx = 0;
while (rs.next()) {
// first row or when order changes
if (currentOrder == null || !orderId.equals(rs.getLong("order_id"))) {
orderId = rs.getLong("order_id");
currentOrder = orderMapper.mapRow(rs, orderIdx++);
itemIdx = 0;
orders.add(currentOrder);
}
currentOrder.addItem(lineItemMapper.mapRow(rs, itemIdx++));
}
return orders;
}
});
}

Categories