How to import database data into combo box in javafx - javafx

Using this code I Initialized Combo box
#FXML
private ComboBox category;
And get value using:
String Category = category.getValue().toString();
And inserted value to mysql database.
Now before inserting next value in category Combo box I need to import the values in the database to the drop down in Combo Box and value should be displayed in the combo box.

I recommend to read the values from the database and save it into a ObservableList, once you get all the values you can fill the combobox with:
combobox.setItems(myObservableList);
if your type of combobox is not "String" you should use a String converter, for example, if you wanna fill the combobox with the name of users, being "user" a class and name an attribute, you just have to:
myCombo.setConverter(new StringConverter<user>() {
#Override
public String toString(user object) {
return object.getName();
}
#Override
public user fromString(String string) {
// TODO Auto-generated method stub
return null;
}
});

Related

Accessing the Value of a CheckBox in TableView

I'm having trouble getting the boolean value of whether a checkbox in a tableView for JavaFX is selected or not.
(Link to Image)
https://i.imgur.com/pIWDcfI.png
For some reason the when I getCellObservableValue() to get the CheckBox at index 1, I get null as the result.
//From SceneBuilder/JavaFX file
<TableColumn fx:id="labelColumn" prefWidth="112.57145690917969" text="Use
as Label" />
//Setting Up Table, which displays everything correctly
TableColumn<Integer,CheckBox> labelColumn = (TableColumn<Integer,
CheckBox>) elements.get("labelColumn");
labelColumn.setCellFactory(data -> new CheckBoxTableCell<>());
monitorTable.setEditable(true);
//Trying to Access, which gives null pointer exception
CheckBox cb = (CheckBox) labelColumn.getCellObservableValue(1);
System.out.println(cb.isSelected());
That method returns null if there's no cellValueFactory set. Besides, you should really have a model to hold this state—a TableView is just a view. Unlike the TableViewSelectionModel, which represents which items are selected solely in the context of the TableView itself, a column containing CheckBoxes represents the "boolean state" of a property of the model. For example:
public class ToDoTask {
private final StringProperty name = new SimpleStringProperty(this, "name");
private final BooleanProperty complete = new SimpleBooleanProperty(this, "complete");
// constructors, getters, setters, and property-getters omitted for brevity
}
A TableView for displaying that class could be configured like the following:
TableView<ToDoTask> table = new TableView<>();
table.setItems(...);
TableColumn<ToDoTask, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(features -> features.getValue().nameProperty());
table.getColumns().add(nameCol);
TableColumn<ToDoTask, Boolean> completeCol = new TableColumn<>("Complete");
completeCol.setCellValueFactory(features -> features.getValue().completeProperty());
completeCol.setCellFactory(CheckBoxTableCell.forTableColumn(completeCol));
table.getColumns().add(completeCol);
You would then query if a task is complete by accessing the model:
table.getItems().get(...).isComplete();
Another option to setting the cellValueFactory is to register a Callback with the CheckBoxTableCells themselves. See CheckBoxTableCell#forTableColumn(Callback).
Also, note that getCellObservableValue() returns an ObservableValue. A CheckBox is not an ObservableValue. If you weren't receiving null you'd be getting a ClassCastException.

Map integer to string of custom class in combobox

I have a tabelview that displays a list of appointees. Each appointe has a group assigned to it, the id of that group is saved in the appointe class.
I want to display a combobox inside a tablecell that displays the selected group and all other groups that exist. I can set the items of the combobox in the cell factory but i cant set the selected value of the respective appointee.
I have a method that returns the Group from the observable list when i provide it with the id. Thats means i need the id in the cellfactory but i didnt find a way to do this. I also need to display the name of the group and not the refernce to the clas. Is there a way to do this, or should i change my approach?
The Appointee class
public class Appointee {
private SimpleIntegerProperty id;
private SimpleStringProperty firstname;
private SimpleStringProperty lastname;
private SimpleIntegerProperty group;
private SimpleIntegerProperty assigned;
public Appointee(int id, String firstname, String lastname, int group, int assigned){
this.id = new SimpleIntegerProperty(id);
this.firstname = new SimpleStringProperty(firstname);
this.lastname = new SimpleStringProperty(lastname);
this.group = new SimpleIntegerProperty(group);
this.assigned = new SimpleIntegerProperty(assigned);
}
The Group class
public class Group {
private IntegerProperty id;
private StringProperty name;
private IntegerProperty members;
private IntegerProperty assigned;
public Group(int id, String name, int members, int assigned) {
this.id = new SimpleIntegerProperty(id);
this.name = new SimpleStringProperty(name);
this.members = new SimpleIntegerProperty(members);
this.assigned = new SimpleIntegerProperty(assigned);
}
The appointe table view
public AppointeeTableView() {
// define table view
this.setPrefHeight(800);
this.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
this.setItems(MainController.appointeeObervableList);
this.setEditable(true);
// define columns
...
TableColumn groupCol = new TableColumn("Group"); // group
groupCol.setCellFactory(col -> {
TableCell<Group, StringProperty> c = new TableCell<>();
final ComboBox<String> comboBox = new ComboBox(MainController.groupObservableList);
c.graphicProperty().bind(Bindings.when(c.emptyProperty()).then((Node) null).otherwise(comboBox));
return c;
});
groupCol.setEditable(false);
...
}
Override the updateItem method of the TableCell to update the cell, make sure the new value is saved on a change of the TableCell value and use a cellValueFactory.
final Map<Integer, Group> groupById = ...
final ObservableList<Integer> groupIds = ...
TableColumn<Group, Number> groupCol = new TableColumn<>("Group");
groupCol.setCellValueFactory(cd -> cd.getValue().groupProperty());
class GroupCell extends ListCell<Integer> {
#Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
Group group = groupById.get(item);
if (empty || group == null) {
setText("");
} else {
setText(group.getName());
}
}
}
groupCol.setCellFactory(col -> new TableCell<Group, Integer>() {
private final ComboBox<Integer> comboBox = new ComboBox<>(groupIds);
private final ChangeListener<Integer> listener = (o, oldValue, newValue) -> {
Group group = (Group) getTableView().getItems().get(getIndex());
group.setGroup(newValue);
};
{
comboBox.setCellFactory(lv -> new GroupCell());
comboBox.setButtonCell(new GroupCell());
}
#Override
protected void updateItem(Number item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
} else {
comboBox.valueProperty().removeListener(listener);
setGraphic(comboBox);
comboBox.setValue((Integer) item);
comboBox.valueProperty().addListener(listener);
}
}
});
It's a bit hard to tell from only some small code snippets, but my general recommendation when working with frontends is to distinguish between the model and the rendering on each level. This applies to JavaFX, Swing and Angular applications alike.
The appointee TableView should likely be TableView<Appointee>.
For the appointee.group property you have two options: either use Group or (e.g. when this would generate too many duplicate data when de-/serializing from/ to JSON) then use a business key. The first option is usually easier to implement and work with. With the second option you'll need some service / code to convert back to a Group and have to think about where/ at what level exactly you want to do the conversion.
Let's go on here with the second option as you currently have specified appointee.group to be an integer.
In this case the group column should be TableColum<Appointee, Integer>.
The group cell then should be TableCell<Appointee, Integer>.
So far we've only talked about the model, not about rendering except that we want to display the appointees in a table.
I recommend to do this also on the next level.
Don't use a ComboBox<String> for a groups comboBox but a ComboBox<Group>. String is how you want to render the group inside the comboBox but the Group is the model. Also ComboBox<Integer>, the type of the business key, is a bit misleading (as you want a Groups comboBox, not an integer comboBox) and limits the flexibility of your code.
Use the converting service / code I've mentioned when pre-selecting a value in the comboBox.
The group cell should have the type ListCell<Group> and in the updateItem method, which concerns about how to render a Group, you could e.g. use the name property to get the String representation.
Of course there are variations of this approach, but make sure that on each level you know what the model of the control is and what the renderer of the control is. Always design your code using the model and use the rendering types only at the lowest rendering level.

How do I automatically trigger enter key in Javafx

Nowadays I am working on raspberry pi and I write some programs in java , javafx platforms.I just would like to inform you that I am simply beginner on javafx.
According to that I just would like to trigger ENTER key after changing my textfield.Working principle of my program is like this;
1)I have created one masterform fxml and it is directing all other pages with one textfield.
2)I created main method that let me to use keyboard to enter some specific String values to assign them to textfield for page alteration.
3)I have a bridge java page, it includes global variables to use everywhere in project.So Firstly I set value from keyboard to these global variables.These global variables are created as stringproperty for adding actionlistener for any change.
4)Then I set these global variables to textfield.
5)Textfield indicates relevant values from keyboard.But Unfortunately I can not forward the pages without pressing to enter key.In this case ı would like to trigger this textfield.But unfortunately ı have no idea how to trigger texfield without pressing enter key.Therefore I decided to make auto trigger to enter key for this textfield.
I simply used robot method;
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_ENTER);
But it didn't work.Because After I set the global variable to textfield for first time.It does not define the value of the textfield is changed.It determines after pressing the enter key.
So how can I trigger this textfield after getting value of my global variables.I would like to pass how to set pages, I will show you how my program works.
Example of my code is;
Main method
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
for (String strBarcode = scanner.nextLine(); !strBarcode.isEmpty();
strBarcode = scanner.nextLine()) {
if (strBarcode.equals("distribution")){
Global.G_MOD.set("distribution");
System.out.println(Global.G_MOD.get());
}
}}
GlobalVariables.java(bridge page)
public class Global{
public static StringProperty G_MOD = new SimpleStringProperty("");
}
My MasterController Page for javafx
public class masterformController implements Initializable {
#FXML
public TextField tbxBarcode;
#FXML
void onchangetbxBarcode(ActionEvent event) {
if(Global.G_MOD.get().equals("distribution")){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/puttolightfx/fxml/page1.fxml"));
Parent rootpage1 = (Parent)loader.load();
pnPages.getChildren().clear();
pnPages.getChildren().add(rootpage1);
} catch (IOException ex) {
Logger.getLogger(masterformController.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
Global.G_MOD.addListener(new ChangeListener(){
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
String Newvalue = (String)newValue;
tbxBarcode.setText(Global.G_MOD.get());}
});
}
}
So Everything is working, just I have to trigger textfield when the global value : Global.G_MOD is indicated on texfield.Then it will pass to another page according to global value of Global.G_MOD : "distribution".
SOLUTION(SOLVED):
I solved my problem using thread on listener of the textfield.I gave up to trigger enter key automatically and focused on textfield change.
I simply decided to use thread to change .fxml pages in textfield listener.
Platform.runLater(new Runnable() {
#Override
public void run() {
//if you change the UI, do it here !
}
});
EDITED CODE :
tbxBarcode.textProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
String Newvalue=(String)newValue;
System.out.println(tbxBarcode.getText());
Platform.runLater(new Runnable() {
#Override
public void run() {
if(Global.G_MOD.get().equals("distribution")){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/puttolightfx/fxml/page1.fxml"));
Parent rootpage1 = (Parent)loader.load();
pnPages.getChildren().clear();
pnPages.getChildren().add(rootpage1);
} catch (IOException ex) {
Logger.getLogger(masterformController.class.getName()).log(Level.SEVERE, null, ex);
}
}
// }
}
});
});
Try using
textField.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.ENTER, true, true, true, true));
According to the docs
public KeyEvent(EventType<KeyEvent> eventType,
String character,
String text,
KeyCode code,
boolean shiftDown,
boolean controlDown,
boolean altDown,
boolean metaDown)
Constructs new KeyEvent event with null source and target and KeyCode object directly specified.
Parameters:
eventType - The type of the event.
character - The character or sequence of characters associated with the event
text - A String describing the key code
code - The integer key code
shiftDown - true if shift modifier was pressed.
controlDown - true if control modifier was pressed.
altDown - true if alt modifier was pressed.
metaDown - true if meta modifier was pressed.
Since:
JavaFX 8.0
You can refer https://docs.oracle.com/javase/8/javafx/api/javafx/scene/input/KeyEvent.html
Edit 1
You need to identify the moment when Enter key event must be triggered.
For example:
If your textfield allows a limited number of characters, then you can add the above mentioned code in the following way:
txtField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
if (newValue.length()>30) {
txtField.setText(oldValue);
txtField.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED, "", "", KeyCode.ENTER, true, true, true, true));
}
}
});
This is just an example. It can fire your event multiple times, so you need to write the code to fire the event just once.

Dynamically Adding context menu items to tableview columns

I have the following controller that is instantiated many times on my gui. The reason is beacause it has a tableview that gets filled with different kind of data. Looks like this
class Controller {
#FXML
TableView<Map<String, String> myTable;
private Manager manager;
//Each TableView has different ammount of columns with different names that get dynamically added to the table view using this function
public void setUpColumns(List<TableColumn<Map<String, String>, String>> columns){
myTable.getColumns().addAll(columns);
addContextMenuToColumnHeaders();
}
private addContextMenuToColumnHeaders(){
for (TableColumn<Map<String, String>, ?> tc : myTable.getColumns()){
ContextMenu addToGraphContextMenu = createAddToGraphContextMenu(tc);
tc.setContextMenu(addToGraphContextMenu);
}
}
private ContextMenu createAddToGraphContextMenu(TableColumn<Map<String, String> String> tc){
for (MangerHandledObject mHO : manager.getHandledObjects()){
MenuItem menuItem = new MenuItem(mHO.getName());
menuItem.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event){
//I want each menu item to have access to the column that is added to get the name of the column. Even after dynamically adding new menuItems
manager.callMethod(tc.getName());
}
});
}
}
}
The manager handled objects are not static. So the are added and deleted from the list that the manager keeps. I tried this
contextMenu.setOnShowing(......)
and before showing it will always check for the list from the manager and re-make the context menu items. But the problems is that when this executes I don't have access to the columns anymore. Is there any way to bypass this? Should I implement my own context menu to have a field of the column Name?
It worked. But I had to add at least one dummy MenuItem on my context menu in order for it to appear.

Update field on valuechange

I have two fields binded with a fieldgroup. I need to make the second field change when the first field loses focus.
What I have so far:
class MyBean {
private String first;
private String second;
//getters, setters
}
class MasterData extends CustomComponent{
private TextField first;
private TextField second;
//add to layout, other tasks
}
//the calling code
FieldGroup fieldgroup = new FieldGroup(new MyBean());
fieldgroup.bindMemberFields(new MasterData());
((AbstractComponent)fg.getField("first")).setImmediate(true);
fg.getField("first").addValueChangeListener(new ValueChangeListener() {
#Override
public void valueChange(ValueChangeEvent event) {
MyBean bean = fg.getItemDataSource().getBean();
bean.setSecond((String) event.getProperty().getValue());
try {
fg.commit();
} catch (CommitException e) { }
}
});
The value change event is called but the second field never gets updated on the screen. How canI force the fieldgroup to repaint its field?
You might want to take a look at BlurListener.
Also, I think you need to update the value of the TextField "manually". Changing it in the bean might no update the TextField. When you call commit() on the FieldGroup it commits the values in the field to the bean, not the other way around. So in the listener's implementation, it might look something like this:
second.setValue(event.getProperty().getValue());
try {
fg.commit();
} catch (CommitException e) { }

Resources