I wan't to populate a ChoiceBox from a List<Object>. My Object has a name field which i wan't to use that as the choice text.
Of course i need to know which object the user has selected in order to pass the correct data.
FXML Controller:
public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
UniversitiesService uniService = new UniversitiesServiceImpl();
List<University> uniList = uniService.getUniversitiesList();
//uniChoiceBox.setItems(); Need some guidance here
}
University Entity:
private String universityName;
private String universityURL;
private String[] universityDataNames;
//getters setters
Just do
uniChoiceBox.getItems().setAll(uniList);
If you need to configure the display (i.e. if the toString() method in University doesn't give the text you need), add a converter:
uniChoiceBox.setConverter(new StringConverter<University>() {
#Override
public String toString(University uni) {
return uni.getUniversityName();
}
#Override
// not used...
public University fromString(String s) {
return null ;
}
});
Related
Lets say I have a class:
public class Dummy {
private String name;
private String someOtherProperty;
public String getName() {
return name;
}
}
I have an ArrayList of this class ArrayList<Dummy> dummyList;
Can I create a JavaFX ComboBox with the Object name property as selection options without creating a new ArrayList<String> with the object names?
Pseudocode:
ObservableList<Dummy> dummyO = FXCollections.observableArrayList(dummyList);
final ComboBox combo = new ComboBox(dummyO); // -> here dummyO.name?
(Optional) Ideally, while the name should be displayed, when an option has been selected, the combo.getValue() should return me the reference of the selected Dummy and not only the name. Is that possible?
You can use a custom cellFactory to display the items in a way that suits your needs:
ComboBox<Dummy> comboBox = ...
Callback<ListView<Dummy>, ListCell<Dummy>> factory = lv -> new ListCell<Dummy>() {
#Override
protected void updateItem(Dummy item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? "" : item.getName());
}
};
comboBox.setCellFactory(factory);
comboBox.setButtonCell(factory.call(null));
I'm assuming the ComboBox you're referring to is this: http://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ComboBoxBase.html. As getValue() is public, you can do:
public class MyComboBox<T> extends ComboBox<T> {
private final Dummy dummy;
public MyComboBox(Dummy dummy) {
this.dummy = dummy;
}
public T getValue() {
return dummy.getName();
}
}
I am using a custom TextFieldTableCell in JavaFX 8 to allow users to edit the text field. When the user hits Enter, however, I want to check to see if the text field equals a certain value. If it does equal this certain value, I do not want the entry to save and for it to revert to the text it had before the user started editing. Is there a method I can override to produce this result? I cannot find one that fits what I am looking for.
Thank you in advance!
Since the model is bound to the cell's data, you can do the validation and reset part in the modell class, in your case in the Person class.
Here is a simple example how you can do it:
public class Controller implements Initializable {
#FXML
private TableColumn<Model, String> name;
#FXML
private TableView<Model> tableView;
#Override
public void initialize(URL location, ResourceBundle resources) {
name.setCellValueFactory(data -> data.getValue().nameProperty());
name.setCellFactory(cell -> new TextFieldTableCell<>(new StringConverter<String>() {
#Override
public String toString(String object) {
return object;
}
#Override
public String fromString(String string) {
return string;
}
}));
tableView.setEditable(true);
tableView.setItems(FXCollections.observableArrayList(new Model("Test")));
}
private class Model {
private StringProperty name;
ChangeListener<String> nameChangeListener = (observable, oldValue, newValue) -> {
if (!newValue.matches("[A-Z][a-zA-Z]*")) { // a validation example insert your here.
this.name.set(oldValue);
}
};
public Model(String name) {
this.name = new SimpleStringProperty(name);
this.name.addListener(nameChangeListener);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
}
}
From your description I assume that you are talking about an editable cell in a table view.
If that's the case, the following example should be working for you. You can use the .setOnEditCommit() method to add an event handler to the colum for which you would like to check the entered value.
//Create table
TableView<Person> table = new TableView<Person>();
table.setEditable(true);
//Create column
TableColumn<Person, String> column = new TableColumn<Person, String>("Full Name");
column.setCellValueFactory(new PropertyValueFactory<>("fullName"));
column.setCellFactory(TextFieldTableCell.<Person> forTableColumn());
column.setMinWidth(200);
column.setOnEditCommit(event -> {
//Get entered value
String newFullName = event.getNewValue();
//Get selected position
TablePosition<Person, String> pos = event.getTablePosition();
//Get row of position
int row = pos.getRow();
//Get data from selected row
Person person = event.getTableView().getItems().get(row);
//Check if text equals ...
if (newFullName.equals("Test")) {
person.setFullName(newFullName);
} else {
person.setFullName(event.getOldValue());
table.refresh();
}
});
I have used One-to-Many Mapping in my project. I have stored a list of clicks for every user.
But when I retrieve the list by calling getClicks() methodm Hibernate returns list in different format.
Something like this.
"[com.zednx.tech.persistence.Click#29df9a77]"
So I tried Reading Every value from the list and assign to a new List.
List<Click> clicks=new ArrayList<Click>();
for(Click c: e.getClicks()){
Click temp = new Click();
temp.setAff_source(c.getAff_source());
temp.setCb_to_award(c.getCb_to_award());
temp.setCb_type(c.getCb_type());
clicks.add(temp);
}
But when i print the items of new List it stills prints the same way.
I need to build a JSON from the resulting String of this list.
So if the list is returned in format, it wont help me.
I couldn't find anything regarding this except How to pretty print Hibernate query results?
I tried Arrays.ToString(Object o). But it doesn't work.
GSON builder part-
Gson gson = new GsonBuilder()
.registerTypeAdapter(Click.class, new MyTypeAdapter<Click>())
.create();
List<Click> clicks=new ArrayList<Click>();
for(Click c: e.getClicks()){
Click temp = new Click();
temp.setAff_source(c.getAff_source());
temp.setCb_to_award(c.getCb_to_award());
temp.setCb_type(c.getCb_type());
temp.setCom_to_recieve(c.getCom_to_recieve());
temp.setStore_name(c.getStore_name());
temp.setT_date(c.getT_date());
temp.setT_status(c.getT_status());
temp.setT_ticket(c.getT_ticket());
temp.setUid(c.getUid());
System.out.println(c.toString());
clicks.add(temp);
}
String json = gson.toJson(clicks, Click.class);
Click.java
#Entity
#Table(name="click")
public class Click {
#Id
#Column(name="t_ticket")
private String t_ticket;
#Column(name="uid",nullable=false)
private long uid;
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
#ManyToOne
#JoinColumn(name="uid",
insertable=false, updatable=false,
nullable=false)
private Earning earning;
#Column(name="store_name")
private String store_name;
#Column(name="t_status")
private String t_status;
#Column(name="aff_source")
private String aff_source;
#Column(name="com_to_recieve")
private float com_to_recieve;
#Column(name="t_date")
private Date t_date;
#Column(name="cb_to_award")
private float cb_to_award;
#Column(name="cb_type")
private String cb_type;
public String getT_ticket() {
return t_ticket;
}
public void setT_ticket(String t_ticket) {
this.t_ticket = t_ticket;
}
public Earning getEarning() {
return earning;
}
public void setEarning(Earning earning) {
this.earning = earning;
}
public String getStore_name() {
return store_name;
}
public void setStore_name(String store_name) {
this.store_name = store_name;
}
public String getT_status() {
return t_status;
}
public void setT_status(String t_status) {
this.t_status = t_status;
}
public String getAff_source() {
return aff_source;
}
public void setAff_source(String aff_source) {
this.aff_source = aff_source;
}
public float getCom_to_recieve() {
return com_to_recieve;
}
public void setCom_to_recieve(float com_to_recieve) {
this.com_to_recieve = com_to_recieve;
}
public Date getT_date() {
return t_date;
}
public void setT_date(Date t_date) {
this.t_date = t_date;
}
public float getCb_to_award() {
return cb_to_award;
}
public void setCb_to_award(float cb_to_award) {
this.cb_to_award = cb_to_award;
}
public String getCb_type() {
return cb_type;
}
public void setCb_type(String cb_type) {
this.cb_type = cb_type;
}
Any Help is appreciated.
You need to implement a toString method, as your current Click class likely doesn't have one, so it just prints as the name of the class and instance identifier.
Okay, I could solve my problem finally.
I made another POJO without any annotations and Mapped the List items to that POJO class.
I think the problem was with Annotation of mapping on another class which I had in original POJO.
Also getString() method only helps in changing format of identifier. So basically it has nothing to do with JSON building unless you format getString() in form of JSON.
Hope it helps. If anyone wants new temp POJO I made I can post it if requested.
Thanks.
I am newbie in building javafx MVVM app.
I've created a simple ViewModel:
public class PersonViewModel {
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty age = new SimpleIntegerProperty();
public PersonViewModel() {}
// getters and setters
}
and simple View:
public class PersonView implements Initializable {
#FXML
TextField name;
#FXML
TextField age;
#FXML
Button ok;
#Override
public void initialize(URL location, ResourceBundle resources) {
PersonViewModel viewModel = new PersonViewModel();
name.textProperty().bindBidirectional(viewModel.name);
age.textProperty().bindBidirectional(viewModel.age);
}
}
Can you give me any idea how to make age validation? F.e. I wanna not to allow user to put characters into age (TextField) except [a-zA-Z]. And the main idea of my question to make this validation in ViewModel) Help me pls.
P.S. I wanna make it not using not standard javafx components.
You can use a TextFormatter both to filter input in a text input control, and to convert the text into a value of a specific type. If you want the view model to define the validation rules, then define a method in there representing the validation, and delegate to that method in the filter definition for the TextFormatter. For example:
public class PersonViewModel {
private final StringProperty name = new SimpleStringProperty();
public StringProperty nameProperty() {
return name ;
}
public final String getName() {
return nameProperty().get();
}
public final void setName(String name) {
nameProperty.set(name);
}
private final IntegerProperty age = new SimpleIntegerProperty();
public IntegerProperty ageProperty() {
return age ;
}
public final int getAge() {
return ageProperty().get();
}
public final void setAge(int age) {
ageProperty.set(age);
}
public boolean validAgeInput(String input) {
// must support partial entry while editing, including empty string
// accept any integer from 0 - 135 (arbitrary upper bound example)
String regex = "([0-9]{0,2})|(1[0-2][0-9])|(13[0-5])";
return input.matches(regex);
}
}
Now you can do:
public class PersonView implements Initializable {
#FXML
TextField name;
#FXML
TextField age;
#FXML
Button ok;
#Override
public void initialize(URL location, ResourceBundle resources) {
PersonViewModel viewModel = new PersonViewModel();
UnaryOperator<Change> filter = change -> {
if (viewModel.validAgeInput(change.getControlNewText()) {
// accept
return change ;
} else {
// reject
return null ;
}
};
TextFormatter<Integer> ageFormatter = new TextFormatter<>(new IntegerStringConverter(), 0, filter);
age.setTextFormatter(ageFormatter);
ageFormatter.valueProperty().bindBidirectional(viewModel.ageProperty().asObject());
name.textProperty().bindBidirectional(viewModel.nameProperty());
}
}
The filter defined here will only accept input in the control if it matches the rule defined by the method in the PersonViewModel. The valueProperty() of the TextFormatter represents the text in the TextField after passing it to the IntegerStringConverter: this is bound bidirectionally to the ageProperty() in the model. (The call to asObject() effectively just converts between an IntegerProperty and an ObjectProperty<Integer>.)
I have a choiceBox which represents a list objects. When the name representing one of those objects is changed by another bit of code the name in the drop down list for the choice box does not change. For example if I have a choice box which is made up of list Test objects. The Code for Test is shown below:
class Test {
String name;
public Test(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return name;
}
}
Then have a choice Box as follows:
ChoiceBox<Test> chi = new ChoiceBox<>();
ObservableList<Test> items = FXCollections.observableArrayList();
chi.setItems(items);
items.addAll(new Test("ITEM1"),new Test("ITEM2"),new Test("ITEM3"));
The ChoiceBox will show the list ITEM1, ITEM2 and ITEM3
If I then change the name of one of the items via the following code:
items.get(1).setName("CHANGED");
The ChoiceBox will still show the list ITEM1, ITEM2 and ITEM3. How can I make it so the choiceBox will update and show the list ITEM1, CHANGED and ITEM3?
Just for completeness - in fx2 you are probably stuck with the replace approach as outlined in the other answer. Since fx8, there's a mechanism to tell the list to listen to changes of its contained items (precondition being, of course, that your item has properties and notifies listeners on change):
/** changed item to
* - use property and notify on change
* - not override toString (for visuals, use converter instead)
*/
class Test {
StringProperty name;
public Test(String name) {
setName(name);
}
public StringProperty nameProperty() {
if (name == null) name = new SimpleStringProperty(this, "name");
return name;
}
public void setName(String name) {
nameProperty().set(name);
}
public String getName() {
return nameProperty().get();
}
}
// use in collection with extractor
ObservableList<Test> items = FXCollections.observableList(
e -> new Observable[] {e.nameProperty()} );
items.addAll(...);
choiceBox = new ChoiceBox<>(items);
// tell the choice how to represent the item
StringConverter<Test> converter = new StringConverter<Test>() {
#Override
public String toString(Test album) {
return album != null ? album.getName() : null;
}
#Override
public Test fromString(String string) {
return null;
}
};
choiceBox.setConverter(converter);
I had the same issue in JavaFX 8 (with ComboBox too). I was able to get the same functionality by removing the item then adding a new one at the same location.
Example:
This gets selected item, creates a new item, then calls the replace method:
Channel selected = channelChoiceBox.getSelectionModel().getSelectedItem();
Channel newChan = new Channel("Example", "Channel");
replaceChannel(newChan, selected);
This replaces the selected channel with the new one, effectively editing it:
private void replaceChannel(Channel newChan, Channel oldChan) {
int i = channelChoiceBox.getItems().indexOf(oldChan);
channelChoiceBox.getItems().remove(oldChan);
channelChoiceBox.getItems().add(i, newChan);
channelChoiceBox.setValue(newChan);
}
It's not ideal, but does the job.
Disclaimer: I'm new to Java and programming in general.
Yes. This seems to be issue with JavaFx. I too had faced that. Use ComboBox instead of ChoiceBox that will work.