Get list of all JavaFX Tasks - javafx

Is there a way to get all running Tasks and Services in JavaFX application?
I would like to display the running Tasks in a List.

brian's answer is the way to go. If you have multiple places you are creating Tasks, this might get a bit tricky to manage. The following shows a way to encapsulate everything into an implementation of Executor. Note that I'm still doing exactly as brian suggests: adding Tasks to a List and removing them when they're complete; I just manage it all in an Executor so that the code to modify the list is all in one place.
MonitoringExecutor.java:
import java.util.concurrent.Executor;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
/**
* Wraps an Executor and exposes an ObservableList of Workers which have been
* executed but have not completed. (Workers are considered completed if they
* exit a RUNNING state; i.e. they are in a SUCCEEDED, FAILED, or CANCELLED state.)
*
*/
public class MonitoringExecutor implements Executor {
private final Executor exec ;
private final ObservableList<Worker<?>> taskList ;
public MonitoringExecutor(Executor exec) {
this.exec = exec;
this.taskList = FXCollections.observableArrayList();
}
#Override
public void execute(Runnable command) {
if (command instanceof Worker) {
final Worker<?> task = (Worker<?>) command ;
task.stateProperty().addListener(new ChangeListener<State>() {
#Override
public void changed(ObservableValue<? extends State> obs,
State oldState, State newState) {
if (oldState == State.RUNNING) {
taskList.remove(task);
}
}
});
taskList.add(task);
}
exec.execute(command);
}
public ObservableList<Worker<?>> getWorkerList() {
return taskList;
}
}
And here's an example of using it:
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TaskMonitor extends Application {
#Override
public void start(Stage primaryStage) {
final IntegerProperty tasksCreated = new SimpleIntegerProperty(0);
final ThreadFactory threadFactory = new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
};
final MonitoringExecutor exec = new MonitoringExecutor(Executors.newFixedThreadPool(5, threadFactory));
final TableView<Worker<?>> taskTable = createTable();
taskTable.setItems(exec.getWorkerList());
final Button newTaskButton = new Button();
newTaskButton.textProperty().bind(Bindings.format("Create task %d", tasksCreated.add(1)));
newTaskButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
tasksCreated.set(tasksCreated.get()+1);
exec.execute(new CountingTask("Task "+tasksCreated.get()));
}
});
final BorderPane root = new BorderPane();
root.setCenter(taskTable);
final HBox controls = new HBox();
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
controls.getChildren().add(newTaskButton);
root.setBottom(controls);
final Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableView<Worker<?>> createTable() {
final TableView<Worker<?>> taskTable = new TableView<>();
final TableColumn<Worker<?>, String> titleCol = new TableColumn<>("Title");
titleCol.setCellValueFactory(new PropertyValueFactory<Worker<?>, String>("title"));
final TableColumn<Worker<?>, Double> progressCol = new TableColumn<>("Progress");
progressCol.setCellValueFactory(new PropertyValueFactory<Worker<?>, Double>("progress"));
progressCol.setCellFactory(new Callback<TableColumn<Worker<?>, Double>, TableCell<Worker<?>, Double>>() {
#Override
public TableCell<Worker<?>, Double> call(TableColumn<Worker<?>, Double> col) {
return new ProgressTabelCell();
}
});
final TableColumn<Worker<?>, State> stateCol = new TableColumn<>("State");
stateCol.setCellValueFactory(new PropertyValueFactory<Worker<?>, State>("state"));
final TableColumn<Worker<?>, String> messageCol = new TableColumn<>("Message");
messageCol.setCellValueFactory(new PropertyValueFactory<Worker<?>, String>("message"));
messageCol.setPrefWidth(200);
taskTable.getColumns().addAll(Arrays.asList(titleCol, progressCol, stateCol, messageCol));
return taskTable;
}
private static class CountingTask extends Task<Void> {
private CountingTask(String title) {
updateTitle(title);
}
#Override
protected Void call() throws Exception {
final int n = new Random().nextInt(100)+100;
for (int i=0; i<n; i++) {
updateProgress(i, n);
updateMessage(String.format("Count is %d (of %d)", i, n));
Thread.sleep(100);
}
return null;
}
}
private static class ProgressTabelCell extends TableCell<Worker<?>, Double> {
final ProgressBar progressBar = new ProgressBar();
#Override
public void updateItem(Double value, boolean empty) {
if (empty || value == null) {
setGraphic(null);
} else {
setGraphic(progressBar);
progressBar.setProgress(value);
}
}
}
public static void main(String[] args) {
launch(args);
}
}

Just add and remove them from a list as needed. Then you can show them in a list. Here's some pieces of code.
ObservableList<String> runningTasks;
runningTasks.add(task.getTitle());
new Thread(task).start();
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
runningTasks.remove(task.getTitle());
}});

Related

JavaFX custom TreeView with ComboBox

I try to create a TreeView that will have on every branch and leaf a ComboBox, an "add child" Button and an "remove child" Button.
Here is my code
package example;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* #author me
*/
public class Example extends Application {
String[] companyNames = new String[10];
#Override
public void start(Stage primaryStage) {
companyNames[0]="FORD";
companyNames[1]="MG";
companyNames[2]="LADA";
companyNames[3]="BMW";
companyNames[4]="KIA";
companyNames[5]="HYUNDAI";
companyNames[6]="AUDI";
companyNames[7]="MERCEDES";
companyNames[8]="DACIA";
companyNames[9]="TOYOTA";
final TreeItem<String> treeRootItem = new TreeItem<>("Root");
final TreeView<String> treeView = new TreeView<>(treeRootItem);
treeRootItem.setExpanded(true);
treeView.setCellFactory(e -> new CustomCell());
VBox mainVBox = new VBox();
mainVBox.getChildren().add(treeView);
Scene scene1 = new Scene(mainVBox,1600,600);
primaryStage.setScene(scene1);
primaryStage.show();
primaryStage.centerOnScreen();
}
//function custom TreeCell CustomCell
class CustomCell extends TreeCell<String> {
#Override
protected void updateItem(String item, boolean empty)
{
ComboBox companiesComboBox = new ComboBox();
Button addChildButton = new Button("Add Child");
Button removeButton = new Button("Remove Child");
super.updateItem(item, empty);
if (isEmpty()) {
setGraphic(null);
setText(null);
}
else {
HBox cellBox = new HBox(10);
if (item.equals("Root"))
{
cellBox.getChildren().addAll(companiesComboBox,addChildButton);
}
else cellBox.getChildren().addAll(companiesComboBox,addChildButton,removeButton);
setGraphic(cellBox);
setText(null);
}
companiesComboBox.getItems().addAll((Object[]) companyNames);
addChildButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
String selection=companiesComboBox.getSelectionModel().getSelectedItem().toString();
TreeItem<String> childNode1 = new TreeItem<>("Child Node");
getTreeItem().getChildren().add(childNode1);
}});
removeButton.setOnAction(value -> {
//somehow i will remove the leaf/branch
});
}
}
public static void main(String[] args) {
launch(args);
}
}
(As Alexandra pointed out, in my prior post, i had many Java Naming Conventions wrong, i hope i fixed it now.
A am sorry that i deleted my prior post but it was off topic with many wrongs so i decided to make a small research how to make a post with better code and more specific without mistakes and come back a few days later.I hope that now is presentable.)
The problem that i have is that when i add a new child , the hole tree loses the ComboBox selection.
Here is a picture of the project running https://ibb.co/8MVDqhX
Any help/suggestion will be appreciated
UPDATE:
After Slaw answer i tried to create a Model Class named SelectedCompanyClass
package example;
import javafx.beans.property.StringProperty;
/**
*
* #author me
*/
public class SelectedCompanyClass {
public String companyNameString;
public SelectedCompanyClass(String companyNameString) {
this.companyNameString = companyNameString;
}
}
And i changed my main class like this
package example;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* #author me
*/
public class Example extends Application {
String[] companyNames = new String[10];
int x=0;
SelectedCompanyClass SelectedCompanyClass1;
#Override
public void start(Stage primaryStage) {
this.SelectedCompanyClass1 = new SelectedCompanyClass("root");
companyNames[0]="FORD";
companyNames[1]="MG";
companyNames[2]="LADA";
companyNames[3]="BMW";
companyNames[4]="KIA";
companyNames[5]="HYUNDAI";
companyNames[6]="AUDI";
companyNames[7]="MERCEDES";
companyNames[8]="DACIA";
companyNames[9]="TOYOTA";
final TreeItem<SelectedCompanyClass> treeRootItem = new TreeItem<>(SelectedCompanyClass1);
final TreeView<SelectedCompanyClass> treeView = new TreeView<>(treeRootItem);
treeRootItem.setExpanded(true);
treeView.setCellFactory(e -> new CustomCell());
VBox mainVBox = new VBox();
mainVBox.getChildren().add(treeView);
Scene scene1 = new Scene(mainVBox,1600,600);
primaryStage.setScene(scene1);
primaryStage.show();
primaryStage.centerOnScreen();
System.out.println("Start runs");
}
class CustomCell extends TreeCell<SelectedCompanyClass> {
protected void updateItem(SelectedCompanyClass SelectedCompanyClass1, boolean empty)
{
ComboBox companiesComboBox = new ComboBox();
Button addChildButton = new Button("Add Child");
Button removeButton = new Button("Remove Child");
super.updateItem(SelectedCompanyClass1,empty);
if (isEmpty()) {
setGraphic(null);
setText(null);
}
else {
HBox cellHBox = new HBox();
if (SelectedCompanyClass1!=null)
{
if (SelectedCompanyClass1.companyNameString.equals("Root"))
{
cellHBox.getChildren().addAll(companiesComboBox,addChildButton);
}
else cellHBox.getChildren().addAll(companiesComboBox,addChildButton,removeButton);
companiesComboBox.getSelectionModel().select(SelectedCompanyClass1.companyNameString);
}
setGraphic(cellHBox);
setText(null);
}
companiesComboBox.getItems().addAll((Object[]) companyNames);
addChildButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
String selection="none";
SelectedCompanyClass SelectedCompanyClass2 = new SelectedCompanyClass(selection);
if (companiesComboBox.getSelectionModel().getSelectedItem().toString()!=null) {
selection=companiesComboBox.getSelectionModel().getSelectedItem().toString();
SelectedCompanyClass2.companyNameString=selection;
}
TreeItem<SelectedCompanyClass> childNode2 = new TreeItem<>(SelectedCompanyClass2);
getTreeItem().getChildren().add(childNode2);
childNode2.setExpanded(true);
}});
removeButton.setOnAction(value -> {
//somehow i will remove the leaf/branch
});
}
}
public static void main(String[] args) {
launch(args);
}
}
Now, thanks to Slaw , i have made progress and i create new objects TreeItem as childs, but parent Node loses its ComboBox selection
UPDATE 2:
After the usefull suggestions, i finally done it, here is the code
The model Class code
package example;
import javafx.beans.property.StringProperty;
public class SelectedCompanyClass {
String companyNameString = new String();
public SelectedCompanyClass() {
companyNameString="Choose";
}
}
and the Main code
package example;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* #author me
*/
public class Example extends Application {
String[] companyNames = new String[10];
int x=0;
#Override
public void start(Stage primaryStage) {
SelectedCompanyClass SelectedCompanyClass1 = new SelectedCompanyClass();
companyNames[0]="FORD";
companyNames[1]="MG";
companyNames[2]="LADA";
companyNames[3]="BMW";
companyNames[4]="KIA";
companyNames[5]="HYUNDAI";
companyNames[6]="AUDI";
companyNames[7]="MERCEDES";
companyNames[8]="DACIA";
companyNames[9]="TOYOTA";
final TreeItem<SelectedCompanyClass> treeRootItem = new TreeItem<>(SelectedCompanyClass1);
final TreeView<SelectedCompanyClass> treeView = new TreeView<>(treeRootItem);
treeRootItem.setExpanded(true);
treeView.setCellFactory(e -> new CustomCell());
VBox mainVBox = new VBox();
mainVBox.getChildren().add(treeView);
Scene scene1 = new Scene(mainVBox,1600,600);
primaryStage.setScene(scene1);
primaryStage.show();
primaryStage.centerOnScreen();
System.out.println("Start runs");
}
class CustomCell extends TreeCell<SelectedCompanyClass> {
protected void updateItem(SelectedCompanyClass SelectedCompanyClass1, boolean empty)
{
ComboBox companiesComboBox = new ComboBox();
Button addChildButton = new Button("Add Child");
Button removeButton = new Button("Remove");
Label objectLabel = new Label();
companiesComboBox.valueProperty().addListener((obs, oldValue, newValue) -> {
SelectedCompanyClass1.companyNameString=newValue.toString();
});
super.updateItem(SelectedCompanyClass1,empty);
if (isEmpty()) {
setGraphic(null);
setText(null);
}
else {
HBox cellHBox = new HBox();
if (SelectedCompanyClass1!=null)
{
cellHBox.getChildren().addAll(companiesComboBox,addChildButton,removeButton,objectLabel);
companiesComboBox.getSelectionModel().select(SelectedCompanyClass1.companyNameString);
}
setGraphic(cellHBox);
setText(null);
}
companiesComboBox.getItems().addAll((Object[]) companyNames);
addChildButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
String selection="none";
SelectedCompanyClass SelectedCompanyClass2 = new SelectedCompanyClass();
TreeItem<SelectedCompanyClass> childNode2 = new TreeItem<>(SelectedCompanyClass2);
getTreeItem().getChildren().add(childNode2);
childNode2.setExpanded(true);
companiesComboBox.valueProperty().addListener((obs, oldValue, newValue) -> {
SelectedCompanyClass2.companyNameString=newValue.toString();
});
}});
removeButton.setOnAction(value -> {
//somehow i will remove the leaf/branch
});
}
}
public static void main(String[] args) {
launch(args);
}
}
Best regards to all

How to add two different attributes to one line of a combobox in javafx? [duplicate]

I have a int value which I want to use for configuration. It can have 2 values - 0 for active and 1 for Blocked. I want to display this into friendly combo box:
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class MainApp extends Application
{
#Override
public void start(Stage stage) throws Exception
{
int state = 0;
ObservableList<String> options = FXCollections.observableArrayList(
"Active",
"Blocked"
);
ComboBox comboBox = new ComboBox(options);
BorderPane bp = new BorderPane(comboBox);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
It's not clear for me how I have to implement this into JavaFX Combobox.
When I have 0 I want to display this as Active and when I have 1 I want to display Blocked and also when I change the ComboBox value to update also int state value.
There are different ways to solve this problem. I have listed three of the solutions below. You can use any one of the below solutions which you feel is apt for your scenario.
Using a custom class
Create a custom class KeyValuePair, for storing the string and its corresponding value. Exposed the getters for the required fields.
Later, I have used the setCellFactory() of the comboxbox to show the required data. Use StringConverter to show the key in place of the object.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception
{
KeyValuePair keyValuePair1 = new KeyValuePair("Active", 0);
KeyValuePair keyValuePair2 = new KeyValuePair("Blocked", 1);
ObservableList<KeyValuePair> options = FXCollections.observableArrayList();
options.addAll(keyValuePair1, keyValuePair2);
ComboBox<KeyValuePair> comboBox = new ComboBox<>(options);
// show the correct text
comboBox.setCellFactory((ListView<KeyValuePair> param) -> {
final ListCell<KeyValuePair> cell = new ListCell<KeyValuePair>(){
#Override
protected void updateItem(KeyValuePair t, boolean bln) {
super.updateItem(t, bln);
if(t != null){
setText(String.valueOf(t.getKey()));
}else{
setText(null);
}
}
};
return cell;
});
comboBox.setConverter(new StringConverter<KeyValuePair>() {
#Override
public String toString(KeyValuePair object) {
return object.getKey();
}
#Override
public KeyValuePair fromString(String string) {
return null; // No conversion fromString needed.
}
});
// print the value
comboBox.valueProperty().addListener((ov, oldVal, newVal) -> {
System.out.println(newVal.getKey() + " - " + newVal.getValue());
});
BorderPane bp = new BorderPane(comboBox);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
class KeyValuePair {
private final String key;
private final int value;
public KeyValuePair(String key, int value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public int getValue() {
return value;
}
}
}
Without using an extra class
As suggested by #kleopatra, you can even do this without using an extra class.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
ObservableList<Integer> options = FXCollections.observableArrayList();
options.addAll(1, 0);
ComboBox<Integer> comboBox = new ComboBox<>(options);
// show the correct text
comboBox.setCellFactory((ListView<Integer> param) -> {
final ListCell<Integer> cell = new ListCell<Integer>(){
#Override
protected void updateItem(Integer t, boolean bln) {
super.updateItem(t, bln);
if(t != null){
setText(t == 1 ? "Active" : "Blocked");
}else{
setText(null);
}
}
};
return cell;
});
comboBox.setConverter(new StringConverter<Integer>() {
#Override
public String toString(Integer object) {
return object == 1 ? "Active" : "Blocked";
}
#Override
public Integer fromString(String string) {
return null;
}
});
// print the value
comboBox.valueProperty().addListener((ov, oldVal, newVal) -> {
System.out.println("Changed from " + oldVal + " to " + newVal);
});
BorderPane bp = new BorderPane(comboBox);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Using Bindings
You can also use Bindings if you don't want to take the pain of creating a new class and you will always have two elements i.e. Active and Blocked.
Just bind the valueProperty() of your combobox to the state, which is supposed to store the value i.e. 0 or 1.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
IntegerProperty state = new SimpleIntegerProperty();
ObservableList options = FXCollections.observableArrayList("Active", "Blocked");
ComboBox<String> comboBox = new ComboBox<>(options);
state.bind(Bindings.when(comboBox.valueProperty().isEqualTo("Active")).then(0).otherwise(1));
BorderPane bp = new BorderPane(comboBox);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Here is another solution:
declare state as BooleanProperty:
private BooleanProperty state = new SimpleBooleanProperty(false);
bind state property to the valueProperty of comboBox:
comboBox.valueProperty().bind(new When(state).then("Active").otherwise("Blocked"));
complete example:
public class ComboboxTest extends Application {
private BooleanProperty state = new SimpleBooleanProperty(false);
private Button button;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
ObservableList<String> options = FXCollections.observableArrayList(
"Active",
"Blocked"
);
ComboBox comboBox = new ComboBox(options);
button = new Button("false");
button.setOnAction(e -> setSate());
button.textProperty().bind(state.asString());
BorderPane bp = new BorderPane(comboBox);
StackPane stackpane = new StackPane(button);
stackpane.setAlignment(Pos.CENTER);
bp.setTop(stackpane);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
comboBox.valueProperty().bind(new When(state).then("Active").otherwise("Blocked"));
}
public void setSate() {
if (state.get()) {
state.set(false);
} else {
state.set(true);
}
}
}

Display Combobox values from numbers

I have a int value which I want to use for configuration. It can have 2 values - 0 for active and 1 for Blocked. I want to display this into friendly combo box:
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class MainApp extends Application
{
#Override
public void start(Stage stage) throws Exception
{
int state = 0;
ObservableList<String> options = FXCollections.observableArrayList(
"Active",
"Blocked"
);
ComboBox comboBox = new ComboBox(options);
BorderPane bp = new BorderPane(comboBox);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
It's not clear for me how I have to implement this into JavaFX Combobox.
When I have 0 I want to display this as Active and when I have 1 I want to display Blocked and also when I change the ComboBox value to update also int state value.
There are different ways to solve this problem. I have listed three of the solutions below. You can use any one of the below solutions which you feel is apt for your scenario.
Using a custom class
Create a custom class KeyValuePair, for storing the string and its corresponding value. Exposed the getters for the required fields.
Later, I have used the setCellFactory() of the comboxbox to show the required data. Use StringConverter to show the key in place of the object.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception
{
KeyValuePair keyValuePair1 = new KeyValuePair("Active", 0);
KeyValuePair keyValuePair2 = new KeyValuePair("Blocked", 1);
ObservableList<KeyValuePair> options = FXCollections.observableArrayList();
options.addAll(keyValuePair1, keyValuePair2);
ComboBox<KeyValuePair> comboBox = new ComboBox<>(options);
// show the correct text
comboBox.setCellFactory((ListView<KeyValuePair> param) -> {
final ListCell<KeyValuePair> cell = new ListCell<KeyValuePair>(){
#Override
protected void updateItem(KeyValuePair t, boolean bln) {
super.updateItem(t, bln);
if(t != null){
setText(String.valueOf(t.getKey()));
}else{
setText(null);
}
}
};
return cell;
});
comboBox.setConverter(new StringConverter<KeyValuePair>() {
#Override
public String toString(KeyValuePair object) {
return object.getKey();
}
#Override
public KeyValuePair fromString(String string) {
return null; // No conversion fromString needed.
}
});
// print the value
comboBox.valueProperty().addListener((ov, oldVal, newVal) -> {
System.out.println(newVal.getKey() + " - " + newVal.getValue());
});
BorderPane bp = new BorderPane(comboBox);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
class KeyValuePair {
private final String key;
private final int value;
public KeyValuePair(String key, int value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public int getValue() {
return value;
}
}
}
Without using an extra class
As suggested by #kleopatra, you can even do this without using an extra class.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
ObservableList<Integer> options = FXCollections.observableArrayList();
options.addAll(1, 0);
ComboBox<Integer> comboBox = new ComboBox<>(options);
// show the correct text
comboBox.setCellFactory((ListView<Integer> param) -> {
final ListCell<Integer> cell = new ListCell<Integer>(){
#Override
protected void updateItem(Integer t, boolean bln) {
super.updateItem(t, bln);
if(t != null){
setText(t == 1 ? "Active" : "Blocked");
}else{
setText(null);
}
}
};
return cell;
});
comboBox.setConverter(new StringConverter<Integer>() {
#Override
public String toString(Integer object) {
return object == 1 ? "Active" : "Blocked";
}
#Override
public Integer fromString(String string) {
return null;
}
});
// print the value
comboBox.valueProperty().addListener((ov, oldVal, newVal) -> {
System.out.println("Changed from " + oldVal + " to " + newVal);
});
BorderPane bp = new BorderPane(comboBox);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Using Bindings
You can also use Bindings if you don't want to take the pain of creating a new class and you will always have two elements i.e. Active and Blocked.
Just bind the valueProperty() of your combobox to the state, which is supposed to store the value i.e. 0 or 1.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
IntegerProperty state = new SimpleIntegerProperty();
ObservableList options = FXCollections.observableArrayList("Active", "Blocked");
ComboBox<String> comboBox = new ComboBox<>(options);
state.bind(Bindings.when(comboBox.valueProperty().isEqualTo("Active")).then(0).otherwise(1));
BorderPane bp = new BorderPane(comboBox);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Here is another solution:
declare state as BooleanProperty:
private BooleanProperty state = new SimpleBooleanProperty(false);
bind state property to the valueProperty of comboBox:
comboBox.valueProperty().bind(new When(state).then("Active").otherwise("Blocked"));
complete example:
public class ComboboxTest extends Application {
private BooleanProperty state = new SimpleBooleanProperty(false);
private Button button;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
ObservableList<String> options = FXCollections.observableArrayList(
"Active",
"Blocked"
);
ComboBox comboBox = new ComboBox(options);
button = new Button("false");
button.setOnAction(e -> setSate());
button.textProperty().bind(state.asString());
BorderPane bp = new BorderPane(comboBox);
StackPane stackpane = new StackPane(button);
stackpane.setAlignment(Pos.CENTER);
bp.setTop(stackpane);
bp.setPrefSize(800, 800);
Scene scene = new Scene(bp);
stage.setScene(scene);
stage.show();
comboBox.valueProperty().bind(new When(state).then("Active").otherwise("Blocked"));
}
public void setSate() {
if (state.get()) {
state.set(false);
} else {
state.set(true);
}
}
}

Scrollpane content moving in pane.Lock the content

This is my sample code, In my project I have used scroll pane, but i am click outside of node and use arrow keys that nodes are move to Center,left,right,bottom.how to lock the node in same position,
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author reegan
*/
public class ComboBoxEditable extends Application {
Node sub;
#Override
public void start(Stage primaryStage) {
ComboBox mainCombo = new ComboBox(listofCombo());
Button save = new Button("Save");
sub = new ComboBox(listofCombo());
HBox root = new HBox(20);
root.getChildren().addAll(mainCombo, sub,save);
ScrollPane pane = new ScrollPane(root);
mainCombo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (newValue == "Others") {
sub = new TextField();
} else {
sub = new ComboBox(listofCombo());
}
root.getChildren().remove(1);
root.getChildren().add(1, sub);
}
});
save.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println(mainCombo.getValue());
if(sub.getClass() == ComboBox.class) {
ComboBox sub1 = (ComboBox)sub;
System.out.println(sub1.getValue());
} else {
TextField field = (TextField)sub;
System.out.println(field.getText());
}
}
});
Scene scene = new Scene(pane, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public ObservableList listofCombo() {
ObservableList<String> list = FXCollections.observableArrayList();
for (int i = 0; i < 10; i++) {
list.add(String.valueOf("Hello" + i));
}
list.add("Others");
return list;
}
}
I am ref this example code :JavaFX: scrolling vs. focus traversal with arrow keys
#James_D told "The default behavior for a scroll pane is that, if it has keyboard focus, the cursor (arrow) keys will cause it to scroll".So consume that event Ref for this solution JavaFX: scrolling vs. focus traversal with arrow keys
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package comboboxeditable;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author reegan
*/
public class ComboBoxEditable extends Application {
Node sub;
#Override
public void start(Stage primaryStage) {
ComboBox mainCombo = new ComboBox(listofCombo());
Button save = new Button("Save");
sub = new ComboBox(listofCombo());
HBox root = new HBox(20);
root.getChildren().addAll(mainCombo, sub, save);
ScrollInterceptor pane = new ScrollInterceptor(root);
mainCombo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (newValue == "Others") {
sub = new TextField();
} else {
sub = new ComboBox(listofCombo());
}
root.getChildren().remove(1);
root.getChildren().add(1, sub);
}
});
save.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println(mainCombo.getValue());
if (sub.getClass() == ComboBox.class) {
ComboBox sub1 = (ComboBox) sub;
System.out.println(sub1.getValue());
} else {
TextField field = (TextField) sub;
System.out.println(field.getText());
}
}
});
Scene scene = new Scene(pane, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public ObservableList listofCombo() {
ObservableList<String> list = FXCollections.observableArrayList();
for (int i = 0; i < 10; i++) {
list.add(String.valueOf("Hello" + i));
}
list.add("Others");
return list;
}
private static class ScrollInterceptor extends ScrollPane {
public ScrollInterceptor() {
remapArrowKeys(this);
}
public ScrollInterceptor(Node content) {
ScrollInterceptor.this.setContent(content);
remapArrowKeys(this);
}
private void remapArrowKeys(ScrollPane scrollPane) {
scrollPane.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case UP:
case DOWN:
case LEFT:
case RIGHT:
event.consume();
}
}
});
}
}
}

JavaFX: How to show an animated ProgressIndicator while adding columns to a TableView?

Adding the TableColumn objects to my TableView is a lengthy operation in my application---it causes everything to freeze for 3-4 seconds. I would like to keep the UI responsive while this is happening, but this is exactly the kind of thing that must be done on the JavaFX application thread. Can anything be done?
package tableviewpausetest;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.WorkerStateEvent;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author drmc
*/
public class TableViewPauseTest extends Application {
public static final int ROW_COUNT = 100;
public static final int COLUMN_COUNT = 80;
public static final ExecutorService executor = Executors.newSingleThreadExecutor();
private TableView<String> tableView = new TableView<>();
private Button button = new Button("Toggle Columns Visibility");
private ProgressIndicator progressIndicator = new ProgressIndicator();
private HBox buttonBox = new HBox(8);
private BorderPane borderPane = new BorderPane();
private Task task = null;
public void start(Stage primaryStage) {
this.tableView.setColumnResizePolicy(
TableView.CONSTRAINED_RESIZE_POLICY);
for (int i = 0; i < ROW_COUNT; ++i) {
this.tableView.getItems().add(":)");
}
this.button.setOnAction(new ToggleHandler(this));
this.buttonBox.getChildren().setAll(this.button);
this.borderPane.setCenter(this.tableView);
this.borderPane.setBottom(this.buttonBox);
Scene scene = new Scene(this.borderPane, 1024, 768);
primaryStage.setTitle("tableviewpausetest");
primaryStage.setScene(scene);
primaryStage.show();
}
private class ToggleHandler implements EventHandler<ActionEvent> {
private TableViewPauseTest app;
public ToggleHandler(TableViewPauseTest app) {
this.app = app;
}
#Override
public void handle(ActionEvent event) {
// Show the progress indicator.
this.app.buttonBox.getChildren().add(this.app.progressIndicator);
this.app.progressIndicator.setPrefHeight(this.app.button.getHeight());
// Ensure the columns exist.
if (this.app.tableView.getColumns().isEmpty()) {
for (int i = 0; i < COLUMN_COUNT; ++i) {
TableColumn<String, String> tableColumn = new TableColumn<>(
String.format("%s", i));
tableColumn.setVisible(false);
this.app.tableView.getColumns().add(tableColumn);
}
}
// Create and submit a concurrent task to toggle column visibility.
this.app.task = new ToggleTask(this.app);
this.app.task.setOnSucceeded(new ToggleSucceededHandler(this.app));
executor.submit(this.app.task);
}
}
private class ToggleSucceededHandler implements EventHandler<WorkerStateEvent> {
private TableViewPauseTest app;
public ToggleSucceededHandler(TableViewPauseTest app) {
this.app = app;
}
#Override
public void handle(WorkerStateEvent event) {
// Hide the progress indicator.
this.app.buttonBox.getChildren().remove(this.app.progressIndicator);
}
}
private class ToggleTask extends Task<String> {
private TableViewPauseTest app;
public ToggleTask(TableViewPauseTest app) {
this.app = app;
}
#Override
public String call() {
boolean newState = false;
String action = "hide";
if (this.app.tableView.getVisibleLeafColumns().isEmpty()) {
newState = true;
action = "show";
}
// This action must be performed on the JavaFX Application Thread,
// and it causes an extremely uncomfortable pause in my application.
Platform.runLater(new ToggleRunnable(this.app.tableView, newState));
return action;
}
}
private class ToggleRunnable implements Runnable {
private TableView<?> tableView;
private boolean newState;
public ToggleRunnable(TableView<?> tableView, boolean newState) {
this.tableView = tableView;
this.newState = newState;
}
#Override
public void run() {
for (TableColumn<?, ?> tableColumn : this.tableView.getColumns()) {
tableColumn.setVisible(this.newState);
}
}
}
public static void main(String[] args) {
Application.launch(args);
}
}
I think this example code useful for you
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package progressbartablecelltest;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
*
* #author reegan
*/
public class ProgressBarTableCellTest extends Application {
public void start(Stage primaryStage) {
TableView<TestTask> table = new TableView<>();
Random rng = new Random();
for (int i = 0; i < 20; i++) {
table.getItems().add(
new TestTask(rng.nextInt(3000) + 2000, rng.nextInt(30) + 20));
}
TableColumn<TestTask, String> statusCol = new TableColumn("Status");
statusCol.setCellValueFactory(new PropertyValueFactory<TestTask, String>(
"message"));
statusCol.setPrefWidth(75);
TableColumn<TestTask, Double> progressCol = new TableColumn("Progress");
progressCol.setCellValueFactory(new PropertyValueFactory<TestTask, Double>(
"progress"));
progressCol
.setCellFactory(ProgressIndicatorTableCell.<TestTask>forTableColumn());
table.getColumns().addAll(statusCol, progressCol);
BorderPane root = new BorderPane();
root.setCenter(table);
primaryStage.setScene(new Scene(root));
primaryStage.show();
ExecutorService executor = Executors.newFixedThreadPool(table.getItems().size(), new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
});
for (TestTask task : table.getItems()) {
executor.execute(task);
}
}
public static void main(String[] args) { launch(args); }
static class TestTask extends Task<Void> {
private final int waitTime; // milliseconds
private final int pauseTime; // milliseconds
public static final int NUM_ITERATIONS = 100;
TestTask(int waitTime, int pauseTime) {
this.waitTime = waitTime;
this.pauseTime = pauseTime;
}
#Override
protected Void call() throws Exception {
this.updateProgress(ProgressIndicator.INDETERMINATE_PROGRESS, 1);
this.updateMessage("Waiting...");
Thread.sleep(waitTime);
this.updateMessage("Running...");
for (int i = 0; i < NUM_ITERATIONS; i++) {
updateProgress((1.0 * i) / NUM_ITERATIONS, 1);
Thread.sleep(pauseTime);
}
this.updateMessage("Done");
this.updateProgress(1, 1);
return null;
}
}
}
class ProgressIndicatorTableCell<S> extends TableCell<S, Double> {
public static <S> Callback<TableColumn<S, Double>, TableCell<S, Double>> forTableColumn() {
return new Callback<TableColumn<S, Double>, TableCell<S, Double>>() {
#Override
public TableCell<S, Double> call(TableColumn<S, Double> param) {
return new ProgressIndicatorTableCell<>();
}
};
}
private final ProgressIndicator progressIndicator;
private ObservableValue observable;
public ProgressIndicatorTableCell() {
this.getStyleClass().add("progress-indicator-table-cell");
this.progressIndicator = new ProgressIndicator();
setGraphic(progressIndicator);
}
#Override public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
progressIndicator.progressProperty().unbind();
observable = getTableColumn().getCellObservableValue(getIndex());
if (observable != null) {
progressIndicator.progressProperty().bind(observable);
} else {
progressIndicator.setProgress(item);
}
setGraphic(progressIndicator);
}
}
}
Table Column Add with Progress Indicator

Resources