ToggleButtons in JavaFX with generic listeners - java

I have 10 toggle buttons say tb1, tb2,.. and so on. Each one has one user data attached to it. I need to attach a listener for a action (sequence of instructions) to be performed when button are clicked and unclicked. I would prefer the listener to be generic (usable for all the buttons).
The problem I am facing is that, how can I access the user data of clicked button in the listener.Please help through this.
#FXML
private ToggleButton tb1;
#FXML
private ToggleButton tb2;
String cpuLoad1 ="D:/myWorkspace/TestAttacks/input_folder/app_debug.apk";
String cpuLoad2 = "D:/myWorkspace/TestAttacks/input_folder/cpuLoad1.apk";
public void initialize(){
tb1.setUserData(cpuLoad1);
tb2.setUserData(cpuLoad2);
ChangeListener clt1 = new ChangeListener() {
public void changed(ObservableValue ov,
Object toggle, Object new_toggle){
if(new_toggle.equals(true)){
/*how can I acces togglebutton userdata here.
*I would like to pass it as argument to this class object*/
App load = new App(buttonClicked.getUserData()); //button clicked could tb1 or tb2
load.installApp();
load.launchApp();
}else{
System.out.println("OFF");
/*how can I acces togglebutton userdata here.
*I would like to pass it as argument to this class object.*/
App load = new App(buttonClicked.getUserData());
load.unInstallApp();
}
}
};
tb1.selectedProperty().addListener(clt1);
tb2.selectedProperty().addListener(clt1);
}

You have several options.
Option1: Collect the ToggleButtons into a collection and use the reference directly in the listener:
List<ToggleButton> toggles = new ArrayList<>(Arrays.asList(tb1, tb2));
for(ToggleButton toggle:toggles)
toggle.selectedProperty().addListener((observable, oldValue, newValue) ->
System.out.println(toggle.getText() + " - Selected: " + toggle.isSelected() + "; UserData: " + toggle.getUserData()));
Option2: You can use the onActionProperty:
tb1.setOnAction(e -> {
ToggleButton toggle = (ToggleButton) e.getSource();
System.out.println(toggle.getText() + " - Selected: " + toggle.isSelected()
+ "; UserData: " + toggle.getUserData());
});
Option3: If you need to store the listeners, you can implement you own ChangeListener.
public class Toggles extends Application {
public static void main(String[] args) { launch(args); }
#Override
public void start(Stage primaryStage) throws Exception {
VBox vBox = new VBox();
for (int i = 0; i < 20; i++) {
ToggleButton tb = new ToggleButton("ToggleButton" + i);
tb.setUserData("UserData" + i);
tb.selectedProperty().addListener(new ToggleButtonSourcedChangeListener(tb));
vBox.getChildren().add(tb);
}
Scene scene = new Scene(new BorderPane(vBox), 320, 240);
primaryStage.setScene(scene);
primaryStage.show();
}
private abstract static class SourcedChangeListener<T extends Node> implements ChangeListener<Boolean> {
T source;
SourcedChangeListener(T source) {
this.source = source;
}
}
private static class ToggleButtonSourcedChangeListener extends SourcedChangeListener<ToggleButton> {
ToggleButtonSourcedChangeListener(ToggleButton source) {
super(source);
}
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
System.out.println(source.getText() + " - Selected: " + source.isSelected()
+ "; UserData: " + source.getUserData());
}
}
}
In this SSCE I created an abstract SourceChangeListener that can be extended by concrete implementations. The intention behind the generic parameter <T extends Node> is to avoid casts.
When you execute this code, and click on the toggles, the output will be like:
ToggleButton4 - Selected: true; UserData: UserData4
ToggleButton5 - Selected: true; UserData: UserData5
ToggleButton4 - Selected: false; UserData: UserData4
ToggleButton8 - Selected: true; UserData: UserData8
ToggleButton5 - Selected: false; UserData: UserData5
ToggleButton2 - Selected: true; UserData: UserData2
I would propose one of the options that use the selectedProperty as the onActionProperty will change only if the button was pressed (by mouse, touch or key) or if you programatically call the fire() method. The other two options will work always, even if you change the selected state programatically.

Related

JavaFX: Initialize RadioButton selection status

I need to save the selection status of multiple RadioButtons, so I can see which RadioButton is selected, when I go back to the scene later on. It's not about the userData, it's about to see whether it's selected. Right now I know how to make it work but with a lot of messy copy & paste. Something like this for every ToggleGroup:
#FXML private RadioButton rb1;
#FXML private RadioButton rb2;
public static int[] status = new int[600];
// to save it
if (rb1.getSelect(true)){
status[0] = 1;
} else {
status[0] = 0;
}
// to load it
if (status[0] == 1){
rb1.setSelected(true);
} else {
rb2.setSelected(true);
}
The problem is that I program a survey with more than 300 questions with binary answers. So I have more than 600 different RadioButtons. It'd take hours to implement it this way.
Is there any smart way to do it? I'm grateful for any advice. Thanks in advance!
Here is a SCVExample, that contains the simplest implementation based on my comment: It defines a model (Survey and Question) then binds the GUI to this model.
public class Radios extends Application {
class Survey {
private ObservableList<Question> questions = FXCollections.observableArrayList();
public ObservableList<Question> getQuestions() {
return questions;
}
}
class Question {
private StringProperty text = new SimpleStringProperty("");
private BooleanProperty answer = new SimpleBooleanProperty(false);
public Question(String text) {
setText(text);
}
public boolean isAnswer() {
return answer.get();
}
public BooleanProperty answerProperty() {
return answer;
}
public void setAnswer(boolean answer) {
this.answer.set(answer);
}
public String getText() {
return text.get();
}
public StringProperty textProperty() {
return text;
}
public void setText(String text) {
this.text.set(text);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
// Model
Survey survey = new Survey();
for (int i = 0; i<300; i++) {
Question question = new Question("Do you like number " + i + "?");
question.answerProperty().addListener((obs, oldval,newval) -> {
System.out.println("Question: " + question.getText() + " answer changed from " + oldval + " to " + newval);
});
survey.getQuestions().add(question);
}
// View
VBox root = new VBox();
root.setSpacing(10);
for (Question question : survey.getQuestions()) {
VBox vBox = new VBox();
vBox.setSpacing(5);
HBox answerHBox = new HBox();
answerHBox.setSpacing(20);
vBox.getChildren().addAll(new Label(question.getText()), answerHBox);
RadioButton yes = new RadioButton("Yes");
RadioButton no = new RadioButton("No");
ToggleGroup toggleGroup = new ToggleGroup();
yes.setToggleGroup(toggleGroup);
no.setToggleGroup(toggleGroup);
answerHBox.getChildren().addAll(yes, no);
yes.setSelected(question.isAnswer());
no.setSelected(!question.isAnswer());
toggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
question.setAnswer(newValue.equals(yes));
});
root.getChildren().add(vBox);
}
Scene scene = new Scene(new ScrollPane(root), 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This will generate a survey like:
Console output:
Question: Do you like number 1? answer changed from false to true
Question: Do you like number 3? answer changed from false to true
Question: Do you like number 6? answer changed from false to true
Question: Do you like number 8? answer changed from false to true
Question: Do you like number 8? answer changed from true to false
Question: Do you like number 8? answer changed from false to true

How to add two buttons in a TableColumn of TableView JavaFX

I want to add two button in action TableColumn, i already read this How to add button in JavaFX table view and this Add a button to a cells in a TableView (JAVAFX) but both of them use one button in setGraphic, so when i try to use :
actionFld.setCellFactory(param -> new TableCell<Patient, Patient>() {
private final JFXButton editButton = new JFXButton("edit");
private final JFXButton deleteButton = new JFXButton("delete");
#Override
protected void updateItem(Patient patient, boolean empty) {
super.updateItem(patient, empty);
if (patient == null) {
setGraphic(null);
return;
}
deleteButton.setOnAction(event -> {
Patient getPatient = getTableView().getItems().get(getIndex());
System.out.println(getPatient.getNom() + " " + getPatient.getPrenom());
});
editButton.setOnAction(event -> {
Patient getPatient = getTableView().getItems().get(getIndex());
System.out.println(getPatient.getNom() + " " + getPatient.getPrenom());
});
setGraphic(deleteButton);//<<<---------------add button 1
setGraphic(editButton);//<<------------------add button 2
}
});
it show me just one button :
How can i solve this problem?
You can use HBox to add your component one beside the other for example :
HBox pane = new HBox(deleteButton, editButton);
setGraphic(pane);
result:
If you have another way, i will be happy for it!

My method is not abstract and cannot override another method

I've been trying to create a music player and part of that requires listening to a time slider. So I've added to the time slide and this is the error I get:
I've been trying to get my head around how you fix this error and the whole business of overriding.
Can anyone point me in the right direction on how to fix this error?
My Code:
public class graphicalController implements Initializable
{
//GUI Decleration
#FXML
public Button centreButton;
#FXML
public Button backButton;
#FXML
public Button forwardButton;
#FXML
public ToggleButton muteToggle;
#FXML
public MenuItem loadFolder;
#FXML
public Text nameText;
#FXML
public Text albumText;
#FXML
public Text timeText;
#FXML
public Text artistText;
#FXML
public Slider timeSlider;
#FXML
public Slider volumeSlider;
//Controller Decleration
String absolutePath;
SongQueue q = new SongQueue();
MediaPlayer player;
Status status;
boolean isPlaying = false;
boolean isMuted = false;
boolean isPaused = false;
private Duration duration;
/**
* The constructor. The constructor is called before the initialize()
* method.
*
* Anything in regards to CSS styling with FXML MUST be done within the initialize method.
*/
public graphicalController() {
}
/**
* Initializes the controller class. This method is automatically called
* after the fxml file has been loaded.
*/
#FXML
public void initialize(URL location, ResourceBundle resources)
{
centreButton.setStyle("-fx-background-image: url('/Resources/Play_Button.png')");
centreButton.setText("");
backButton.setStyle("-fx-background-image: url('/Resources/Back_Button.png')");
backButton.setText("");
forwardButton.setStyle("-fx-background-image: url('/Resources/Forward_Button.png')");
forwardButton.setText("");
muteToggle.setStyle("-fx-background-image: url('/Resources/ToggleSound_Button.png')");
muteToggle.setText("");
nameText.setText("");
albumText.setText("");
artistText.setText("");
volumeSlider.valueProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue) {
double sliderValue = newValue.intValue();
handleVolumeSlider(sliderValue);
}
});
timeSlider.valueProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue) {
//outputTextArea.appendText("Slider Value Changed (newValue: " + newValue.intValue() + ")\n");
}
});
timeSlider.valueProperty().addListener(new InvalidationListener() {
public void invalidated(Observable ov) {
if (timeSlider.isValueChanging()) {
// multiply duration by percentage calculated by slider position
if(duration!=null) {
player.seek(duration.multiply(timeSlider.getValue() / 100.0));
}
updateValues();
}
}
});
}
public void setSongText() {
String file = q.peek().fileName;
String songName = q.peek().songName;
String albumName = q.peek().albumName;
String artistName = q.peek().artistName;
if (songName == "") {
songName = "Song name not specified in metadata.";
}
else if (albumName == "")
{
albumName = " Album name not specified in metadata.";
}
else if (artistName == "")
{
artistName = "Artist name not specified in metadata.";
}
nameText.setText(songName);
albumText.setText(albumName);
artistText.setText(artistName);
}
}
You will find my problem in the initialize method.
Are you using the correct Observable type? It should be of type javafx.beans.Observable.

How to implement the MouseListener from Swing in JavaFX

I have a simple login panel that I wrote using Swing and now I have to redo everything with JavaFX, but I don't know how to convert the ActionListeners/MouseListeners.
Whenever the "Neu-Anmeldung" checkbox is checked/unchecked, the values true/false should be seen in the Eclipse console.
My Swing code for this purpose:
// ...
this.jBoxNeuAnmeldung.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (LoginFrame.this.jBoxNeuAnmeldung.isSelected())
neuAnmeldung = true;
else
neuAnmeldung = false;
System.out
.println("Neu-Anmeldung Checkbox angekreutzt? " + neuAnmeldung);
}
});
// ...
How do I do the same thing with JavaFX?
...
checkBox.setOnAction((event) -> {
neuAnmeldung = checkBox.isSelected();
System.out.println("Neu-Anmeldung Checkbox angekreutzt? "
+ neuAnmeldung);
});
replace checkBox by check box name, e.g.
final CheckBox jBoxNeuAnmeldung = new CheckBox();
...
jBoxNeuAnmeldung.setOnAction((event) -> {
neuAnmeldung = jBoxNeuAnmeldung.isSelected();
System.out.println("Neu-Anmeldung Checkbox angekreutzt? "
+ neuAnmeldung);
});
(in standard Java 8 you can also omit final in CheckBox when used in labmda expression).
By adding a ChangeListener to the selected property
checkBox.selectedProperty().addListener((observable, oldValue, newValue) -> System.out.println("Neu-Anmeldung Checkbox angekreutzt? " + newValue));
#FXML
public CheckBox checkBoxNeuAnmeldung;
#FXML
public void handleCheckBoxNeuAnmeldungAction(ActionEvent event) {
if (checkBoxNeuAnmeldung.isSelected()) {
neuAnmeldung = true;
} else
neuAnmeldung = false;
System.out.println("Neu-Anmeldung Checkbox angekreutzt? " + neuAnmeldung);
}
I managed to implement a simpler method using ActionEvent and connected it tp my FXML file.

distinguish between radio buttons in vaadin

I'm building an application which has a few radio buttons and based on the selection the user makes I have to do one thing or another. Now I've used an OptionGroup to create the radio buttons but I don't seem to be able to understand how I can differentiate between radio buttons. In pure java it's pretty straightforward as I would create each radio button and then group them together with a ButtonGroup object but in vaadin I really don't know. The documentation is as usual abysmal, so I'm a bit stuck. Here is some code for you:
public class ConverterComponent extends CustomComponent{
private TextField name2 = new TextField();
private OptionGroup single;
private TextField userInput;
private TextField result;
private Button submit;
private Button reset;
private static final String conversion1 = "Km to miles";
private static final String conversion2 = "Miles to Km";
private static final long serialVersionUID = 1L;
public ConverterComponent(){
submit = new Button("Submit");
reset = new Button("Reset");
result = new TextField();
userInput = new TextField();
result.setEnabled(false);
result.setVisible(false);
userInput.setVisible(false);
reset.setVisible(false);
submit.setVisible(false);
single = new OptionGroup("Select the conversion");
single.addItems(conversion1, conversion2);
reset.addClickListener(new Button.ClickListener(){
#Override
public void buttonClick(ClickEvent event){
clearFields();
getResult().setVisible(false);
}
});
submit.addClickListener(new Button.ClickListener(){
#Override
public void buttonClick(ClickEvent event) {
getResult().setVisible(true);
//NEED TO KNOW WHICH RADIO BUTTON HAS BEEM CLICKED SO THAT i CAN DECIDE WHICH CONVERSION TO USE
}
});
single.addValueChangeListener(new Property.ValueChangeListener(){
#Override
public void valueChange(ValueChangeEvent event) {
clearFields();
/*System.out.println("You chose: " + event.getProperty().getValue().toString() + "\n");
System.out.println("other line " + event.getProperty() + "\n" + " id is " + single.getId() + " size " + single.size());*/
//System.out.println("event is " + event.getProperty().getValue());
switch(event.getProperty().getValue().toString()){
case conversion1:
System.out.println(conversion1);
break;
case conversion2:
System.out.println(conversion2);
break;
}
displayFields();
}
});
}
public OptionGroup getRadioButtons(){
return single;
}
public TextField getResult(){
return result;
}
public TextField getUserInput(){
return userInput;
}
public void displayFields(){
//getResult().setVisible(true);
getUserInput().setVisible(true);
getResetButton().setVisible(true);
getSubmitButton().setVisible(true);
}
public Button getResetButton(){
return reset;
}
public Button getSubmitButton(){
return submit;
}
public void clearFields(){
getResult().setValue("");
getUserInput().setValue("");
}
public void validateInputs(){
}
}
Bear in mind that I have to add more options in the future, but what I'm trying to get to is, when the the user selects a radio button, no matter which, he will get two input boxes one for his input and the other one - read only - displaying the conversion. The point is that when the selection is made and the input boxes are displayed I have to know already what selection the user has made because I have to be able to grab the input and convert it correctly. In the code above I'm displaying the user's choice but I don't have anything to check it or compare it to. Ideally what I would like to do is:
-click the first radio button
-determine which radio button has been selected so I know which conversion to use.
You can use any objects as item ids in Vaadin. For example you could do something like this:
If you for example have an enum presenting different conversions
public enum Conversion {
KM_TO_MILES,
MILES_TO_KM
}
then you could do something like this:
OptionGroup optionGroup = new OptionGroup();
optionGroup.addItem(Conversion.KM_TO_MILES);
optionGroup.setItemCaption(Conversion.KM_TO_MILES, "Km to miles");
optionGroup.addItem(Conversion.MILES_TO_KM);
optionGroup.setItemCaption(Conversion.MILES_TO_KM, "Miles to Km");
optionGroup.addValueChangeListener(e -> {
if (e.getProperty().getValue() == Conversion.KM_TO_MILES) {
// km to miles selected
}
});

Categories