JavaFX 8 - How to bind TextField text property to TableView integer property - java

Let's say I have a situation like this: I have a TableView (tableAuthors) with two TableColumns (Id and Name).
This is the AuthorProps POJO which is used by TableView:
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
public class AuthorProps {
private final SimpleIntegerProperty authorsId;
private final SimpleStringProperty authorsName;
public AuthorProps(int authorsId, String authorsName) {
this.authorsId = new SimpleIntegerProperty(authorsId);
this.authorsName = new SimpleStringProperty( authorsName);
}
public int getAuthorsId() {
return authorsId.get();
}
public SimpleIntegerProperty authorsIdProperty() {
return authorsId;
}
public void setAuthorsId(int authorsId) {
this.authorsId.set(authorsId);
}
public String getAuthorsName() {
return authorsName.get();
}
public SimpleStringProperty authorsNameProperty() {
return authorsName;
}
public void setAuthorsName(String authorsName) {
this.authorsName.set(authorsName);
}
}
And let's say I have two TextFields (txtId and txtName). Now, I would like to bind values from table cells to TextFields.
tableAuthors.getSelectionModel()
.selectedItemProperty()
.addListener((observableValue, authorProps, authorProps2) -> {
//This works:
txtName.textProperty().bindBidirectional(authorProps2.authorsNameProperty());
//This doesn't work:
txtId.textProperty().bindBidirectional(authorProps2.authorsIdProperty());
});
I can bind Name TableColumn to txtName TextField because authorsNameProperty is a SimpleStringProperty, but I can't bind Id TableColumn to txtId TextField because authorsIdProperty is a SimpleIntegerProperty. My question is: How can I bind txtId to Id TableColumn?
P.S. I can provide working example if it's necessary.

Try:
txtId.textProperty().bindBidirectional(authorProps2.authorsIdProperty(), new NumberStringConverter());

Related

Enum based Combobox

cmbSablonSecim = new ComboBox<>();
cmbSablonSecim.setItems(EnumSablonSecim.values());
My combo box --> TUMU,GRAFIK,DAGILIM
I want fill my combobox with Enum->islemAdi
Combobox --> Tümü,Grafik,Dağılım (Enum->islemAdi)
public enum EnumSablonSecim {
TUMU(0, "Tümü"),
GRAFIK(1, "Grafik"),
DAGILIM(2, "Dağılım")
;
private final Integer islemKodu;
private final String islemAdi;
private EnumSablonSecim(Integer islemKodu, String islemAdi) {
this.islemKodu = islemKodu;
this.islemAdi = islemAdi;
}
public Integer getIslemKodu() {
return islemKodu;
}
public String getIslemAdi() {
ResourceBundle messages = I18n.getInstance(this.getClass());
if (messages.containsKey(islemAdi)) {
return messages.getString(islemAdi);
} else {
return islemAdi;
}
}
public static EnumSablonSecim get(Integer islemKodu) {
for (EnumSablonSecim enumSablonSecim : EnumSablonSecim.values()) {
if (enumSablonSecim.islemKodu == islemKodu) {
return enumSablonSecim;
}
}
return null;
}
}
My combobox must return (islemAdi).is it possible or not? Thank you...
ComboBox::setItemLabelGenerator
Are you asking if you can show the islemAdi field as the label in the combo box?
You can specify code to generate a label used for displaying each item in your enum. Call ComboBox::setItemLabelGenerator. Pass a method reference for your getter. Vaadin then calls this method as needed to display each item.
cmbSablonSecim.setItemLabelGenerator(EnumSablonSecim::getIslemAdi);
See Showing a List of Data with Data Providers in the manual.

JavaFX TableView only populating some columns

I'm trying to populate a TableView in JavaFX, but only one of the columns is being populated with Data. I've been following the oracle documentation and think that my name conventions are correct.
Data Model:
import javafx.beans.property.SimpleIntegerProperty;
public class PeakClassification {
private final SimpleIntegerProperty peakStart;
private final SimpleIntegerProperty peakEnd;
private final SimpleIntegerProperty peakMaxima;
private final SimpleIntegerProperty peakHeight;
private final SimpleIntegerProperty peakWidth;
public PeakClassification(int peakStart, int peakEnd, int peakMaxima, int peakHeight) {
this.peakStart = new SimpleIntegerProperty(peakStart);
this.peakEnd = new SimpleIntegerProperty(peakEnd);
this.peakMaxima = new SimpleIntegerProperty(peakMaxima);
this.peakHeight = new SimpleIntegerProperty(peakHeight);
this.peakWidth = new SimpleIntegerProperty(peakEnd - peakStart);
}
public int getPeakWidth() {
return peakWidth.get();
}
public int getPeakHeight() {
return peakHeight.get();
}
public int getPeakStart() {
return peakStart.get();
}
public int getPeakEnd() {
return peakEnd.get();
}
public int getPeakMaxima() {
return peakMaxima.get();
}
}
Code for creating the table:
//instantiate the table
TableView tableView = new TableView();
//start values
TableColumn startValue = new TableColumn("Start pos");
startValue.setMinWidth(100);
startValue.setCellValueFactory(new PropertyValueFactory<PeakClassification, Integer>("peakStart"));
TableColumn maximumValue = new TableColumn("Max pos");
startValue.setCellValueFactory(new PropertyValueFactory<PeakClassification, Integer>("peakMaxima"));
tableView.setItems(peakClassifications);
tableView.getColumns().addAll(startValue, maximumValue);
I've printed out the peakClassifications list to console to verify that the maximumValue isn't null.
The getter for the peakMaxima field is getPeakMaxima() so it should be able to find it. I've looked at other stackoverflow entries and that seems to be the issue in most of the cases.
Here's a snippet of the result:
Its probably an obvious mistake. Any ideas?
Thanks.
Error is here, you mistankenly used startValue variable again instead of maximumValue
TableColumn maximumValue = new TableColumn("Max pos");
startValue.setCellValueFactory(new PropertyValueFactory<PeakClassification, Integer>("peakMaxima"));

JavaFX How to set String values to TableView

To give some background: I now am able to load files onto my mp3 program and play them but all the values in my tableview are null?
My song class
package application;
//imports here
public class Song {
private String title;
private String artist;
private String album;
private SimpleStringProperty pTitle;
private SimpleStringProperty pArtist;
private SimpleStringProperty pAlbum;
private Media music;
private MediaPlayer mp;
private Image coverArt;
public Song(File file) {
music = new Media(file.toURI().toString());
music.getMetadata().addListener((Change<? extends String, ? extends Object> c) -> {
if (c.wasAdded()) {
if ("artist".equals(c.getKey())) {
System.out.println(c.getKey()+":"+c.getValueAdded());
this.pArtist = new SimpleStringProperty(c.getValueAdded().toString());
//pArtist.set(c.getValueAdded().toString());
artist = c.getValueAdded().toString();
} else if ("title".equals(c.getKey())) {
title = c.getValueAdded().toString();
System.out.println(c.getKey()+":"+c.getValueAdded());
} else if ("album".equals(c.getKey())) {
album = c.getValueAdded().toString();
System.out.println(c.getKey()+":"+c.getValueAdded());
} else if ("image".equals(c.getKey())) {
coverArt = (Image) c.getValueAdded();
}
}
});
mp = new MediaPlayer(music);
System.out.println(pArtist);
System.out.println(artist);
//artist = (String) mp.getMedia().getMetadata().get("artist");
//title = (String) music.getMetadata().get("title");
//album = (String) music.getMetadata().get("album");
//artist = "test";
//album = "test";
//title = "test";
}
public void play() {
mp.play();
}
public void pause() {
mp.pause();
}
public void stop() {
mp.stop();
}
public String getTitle(){
return title;
}
public void setTitle(String title){
this.title = title;
}
public String getArtist(){
return artist;
}
public void setArtist(String artist){
this.artist = artist;
}
public String getAlbum(){
return album;
}
public void setAlbum(String album){
this.album = album;
}
public Image getCover(){
return coverArt;
}
public MediaPlayer getMP(){
return mp;
}
}
Weirdly enough at first I thought it was because my String variables were not setting correctly and were set to null since it shows as null in the console when I put these print lines to test it when the Song object is being constructed. Here is a sample of the console when I test this.
null
null
artist:Foo Fighters
album:Saint Cecilia EP
title:Saint Cecilia
Here is my controller class
public class SceneController implements Initializable{
#FXML
private Button stopBtn;
#FXML
private Slider volume;
#FXML
private Button loadBtn;
#FXML
private Button playBtn;
#FXML
private TableView<Song> table;
#FXML
private Label label;
#FXML
private ProgressBar proBar;
private TableColumn songCol,artistCol,albumCol;
ObservableList<Song> songList = FXCollections.observableArrayList();
List<File> list;
FileChooser fileChooser = new FileChooser();
Desktop desktop;
Song mySong;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
TableColumn songCol = new TableColumn("Song");
TableColumn artistCol = new TableColumn("Artist");
TableColumn albumCol = new TableColumn("Album");
songCol.setCellValueFactory(
new PropertyValueFactory<Song,String>("title"));
//songCol.setCellFactory(new Callback);
artistCol.setCellValueFactory(
new PropertyValueFactory<Song,String>("artist"));
albumCol.setCellValueFactory(
new PropertyValueFactory<Song,String>("album"));
volume.setMin(0);
volume.setMax(100);
volume.setValue(100);
volume.valueProperty().addListener(new InvalidationListener() {
#Override
public void invalidated(Observable observable) {
mySong.getMP().setVolume(volume.getValue()/100.0);
}
});
}
// Event Listener on Button[#loadBtn].onAction
#FXML
public void loadFile(ActionEvent event) {
Node source = (Node) event.getSource();
Window theStage = source.getScene().getWindow();
//set fileChooser filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("MP3 files", "*.mp3");
fileChooser.getExtensionFilters().add(extFilter);
fileChooser.setTitle("Select MP3 files");
//File file = fileChooser.showOpenDialog(theStage);
//mySong = new Song(file);
list = fileChooser.showOpenMultipleDialog(theStage);
if(list!=null){
for(File x: list) {
mySong = new Song(x);
System.out.println(mySong.getTitle());
songList.add(mySong);
}
}
table.setItems(songList);
}
#FXML
public void playSong(ActionEvent event) {
mySong.play();
}
#FXML
public void stopSong(ActionEvent event) {
//mySong.pause();
System.out.println("song title: "+mySong.getArtist()+mySong.getTitle());
ImageView img = new ImageView(mySong.getCover());
//img.fitWidthProperty().bind(label.widthProperty());
//img.fitHeightProperty().bind(label.heightProperty());
img.setFitHeight(120);
img.setFitWidth(200);
label.setGraphic(img);
//label.setGraphic(new ImageView(mySong.getCover()));
}
But I made another test print line for my "Stop" button in the controller class and after everything is loaded and I press it, it prints out the artist and title fine. I have saw this other thread and checked my getter methods and they seem to be correct? I am really lost on this and if anyone could provide some insight and a solution as to whether it is because my variables are null or my PropertyValueFactory is not done correctly
Also I notice that the nulls come first even though should they not be the last thing printed since when I create a new song object in my controller class the first print lines that run are in the if statements?
There are several things wrong with the way you have your current code, that are evident from the limited example you posted in the question:
Your Song class does not properly follow the JavaFX properties pattern. In particular, you store each "property" twice, once in a "traditional" JavaBean-style field, for example private String title, and once in a JavaFX property: private StringProperty pTitle;. Each property should be stored once. If you want the table to be aware when the value changes, you should use JavaFX properties, and have the "standard" getXXX() and setXXX() retrieve and set the underlying values stored in those properties.
The listener you attach to the media's metadata is called asynchronously at some indeterminate point in the future. When you add the song to the table's list, the cell value factories attached to the columns will, at some point, be executed, and retrieve the assigned property from the Song instance. With the code the way you currently have it, those property instances are only actually created once the listener on the metadata is invoked. So it is possible (perhaps likely) that the cell value factory will inspect the Song instance for its property before the JavaFX property is instantiated, making it impossible for the table to properly observe the property and respond to changes in it. You should instantiate the JavaFX properties when the Song instance is created, and set their value in the listener on the metadata.
At no point do you add the columns you create in the controller to the table. If you are creating them in the FXML file (which you didn't post in the question), you should inject those columns into the controller and initialize those columns with the cell value factories. (Since the screenshot shows there are columns in the table, I am going to assume they are defined in the FXML file, and have appropriate fx:ids.)
So your Song class should look something like this:
public class Song {
private final StringProperty title = new SimpleStringProperty();
private final StringProperty artist = new SimpleStringProperty();
private final StringProperty album = new SimpleStringProperty();
private Media music;
private MediaPlayer mp;
private Image coverArt;
public Song(File file) {
music = new Media(file.toURI().toString());
music.getMetadata().addListener((Change<? extends String, ? extends Object> c) -> {
if (c.wasAdded()) {
if ("artist".equals(c.getKey())) {
setArtist(c.getValueAdded().toString());
} else if ("title".equals(c.getKey())) {
setTitle(c.getValueAdded().toString());
} else if ("album".equals(c.getKey())) {
setAlbum(c.getValueAdded().toString());
} else if ("image".equals(c.getKey())) {
// maybe this needs to be a JavaFX property too: it is not clear from your question:
coverArt = (Image) c.getValueAdded();
}
}
});
mp = new MediaPlayer(music);
}
public void play() {
mp.play();
}
public void pause() {
mp.pause();
}
public void stop() {
mp.stop();
}
public StringProperty titleProperty() {
return title ;
}
public final String getTitle(){
return titleProperty().get();
}
public final void setTitle(String title){
titleProperty().set(title);
}
public StringProperty artistProperty() {
return artist ;
}
public final String getArtist(){
return artistProperty().get();
}
public final void setArtist(String artist){
artistProperty.set(artist);
}
public StringProperty albumProperty() {
return album ;
}
public final String getAlbum(){
return albumProperty().get();
}
public final void setAlbum(String album){
albumProperty().set(album);
}
public Image getCover(){
return coverArt;
}
public MediaPlayer getMP(){
return mp;
}
}
For your controller, I am going to assume your FXML file has defined table columns with fx:ids of "songCol", "artistCol", and "albumCol", respectively. You need to inject these into the controller as you do with the other columns. I also strongly recommend not using the PropertyValueFactory class, which uses reflection and lacks much in the way of compile-time checking, and implementing the callback yourself. Using lambda expressions makes this pretty easy.
So your controller should look like:
public class SceneController implements Initializable{
// non-table code omitted...
#FXML
private TableView<Song> table;
#FXML
private Label label;
#FXML
private ProgressBar proBar;
#FXML
private TableColumn<Song, String> songCol ;
#FXML
private TableColumn<Song, String> artistCol ;
#FXML
private TableColumn<Song, String> albumCol;
ObservableList<Song> songList = FXCollections.observableArrayList();
List<File> list;
FileChooser fileChooser = new FileChooser();
Desktop desktop;
Song mySong;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
songCol.setCellValueFactory(cellData -> cellData.getValue().titleProperty());
artistCol.setCellValueFactory(cellData -> cellData.getValue().artistProperty());
albumCol.setCellValueFactory(cellData -> cellData.getValue().albumProperty());
// ...
}
// other non-table code omitted...
}
You didn't post an minimal, complete, verifiable example, so there may well be other errors in your code which prevent the table from displaying correctly. This should get you started, however.
Normally the TableColumns would be defined in FXML and injected via #FXML.
See the Oracle TableView FXML example.
If you don't want to do it that way, you need to do:
table.getColumns().add(songCol);
And similarly for your other columns.
Also, as HypnicJerk pointed out in comments you also need to follow appropriate naming conventions when using the PropertyValueFactory.
songCol.setCellValueFactory(
new PropertyValueFactory<Song,String>("title")
);
For more details see:
Javafx tableview not showing data in all columns

Refreshing an FXML Table on button Press

How do you refresh the data in your tableView on button Press using FXML?
I have the following file structure and I want to refresh the data in this table when a button is pressed. Would anyone know a solution?
public class MyTable {
private final SimpleStringProperty ID = new SimpleStringProperty("");
private final SimpleStringProperty ParticipantID = new SimpleStringProperty("");
public Positions() {
this("", "")
}
public Positions(String ID, String ParticipantID) {
setMemberID(ID);
setParticipantID(ParticipantID);
}
public String getParticipantID() {
return ParticipantID.get();
}
public void setParticipantID(String pID) {
ParticipantID.set(ParticipantID);
}
public String getID() {
return ID.get();
}
public void ID(String cID) {
ID.set(ID);
}
}
I initialise this table on the tablecontroller file for this. Now on button press I would like the tableview which is an FXML file update itself. How do I do this?
Thanks but the solution to this was to have one global ObservableList<> data which you then modify on a button press action event. What I was trying to do was create another observable list which does not work.
If you want to update only on button press and not as data is modified that is the default way ?
The simplest way to do would be to create a bean to which all data is updated and the make the button synchronize it with the bean that represents a row in your table.
public class TableBean
{
MyTable child;
String Id;
String ParticipantId;
public void Sync()
{
child.Id(Id);
child.setParticipantID(ParticipantId);
}
}
It is important to note that your methods
violate JavaFX convetion , this probably brakes things. An example of 3 methods used for every propery in JavaFX.
private final IntegerProperty ratio = new SimpleIntegerProperty();
public int getRatio() {
return ratio.get();
}
public void setRatio(int value) {
ratio.set(value);
}
public IntegerProperty ratioProperty() {
return ratio;
}

Add table column with BeanItemContainer

I should add a column to a table that has a BeanItemContainer datasource.
This is my situation:
I hava an entity bean
#Entity
public class MyBean implements {
#Id
private Long id;
//other properties
}
Then in my vaadin panel i have this method
private Table makeTable(){
Table table = new Table();
tableContainer = new BeanItemContainer<MyBean>(MyBean.class);
table.setContainerDataSource(tableContainer);
table.setHeight("100px");
table.setSelectable(true);
return table;
}
Now, I want to add a column that should give me the ability to delete an item in this container.
How can i do?
You could create a ColumnGenerator which creates the button for you.
Have a look here.
Example:
Let's say we have a MyBean class:
public class MyBean {
private String sDesignation;
private int iValue;
public MyBean() {
}
public MyBean(String sDesignation, int iValue) {
this.sDesignation = sDesignation;
this.iValue = iValue;
}
public String getDesignation() {
return sDesignation;
}
public int getValue() {
return iValue;
}
}
We then can create a table with a generated column giving a button to delete the current item.
Table table = new Table();
BeanItemContainer<MyBean> itemContainer = new BeanItemContainer<MyBean>(MyBean.class);
table.setContainerDataSource(itemContainer);
table.addItem(new MyBean("A", 1));
table.addItem(new MyBean("B", 2));
table.addGeneratedColumn("Action", new ColumnGenerator() { // or instead of "Action" you can add ""
#Override
public Object generateCell(final Table source, final Object itemId, Object columnId) {
Button btn = new Button("Delete");
btn.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
source.removeItem(itemId);
}
});
return btn;
}
});
table.setVisibleColumns(new Object[]{"designation", "value", "Action"}); // if you added "" instead of "Action" replace it by ""
I would recommend using shourtcut instead:
table.addShortcutListener(new ShortcutListener("Delete", KeyCode.DELETE, null) {
#Override
public void handleAction(final Object sender,
final Object target) {
if (table.getValue() != null) {
// here send event to your presenter to remove it physically in database
// and then refresh the table
// or just call tableContainer.removeItem(itemId)
}
}
});
if you don't want shourtcuts you would need add the column, eg:
table.addContainerProperty("Delete", Button.class, null);
and then put there the button that would do the same action.

Categories