When tableview has to show data which is in one class (Servicios for example), it is done properly. The problem comes when I has to access another class from one class. In this case TableView shows data from the first class, but does not show data from the second class. I don't know why. Here is my code.
package mrpuppy.entity;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="tarifa")
public class Tarifa
{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy = "tarifa")
private List<Servicio> servicios = new ArrayList<Servicio>();
#Column(name="precio")
private float precio;
#Column(name="descuento")
private float descuento;
#Column(name="fecha_inicio")
private Date fechaInicio;
#Column(name="fecha_fin")
private Date fechaFin;
public Long getId()
{
return id;
}
public List<Servicio> getServicios()
{
return servicios;
}
public void setServicios(List<Servicio> servicios)
{
this.servicios = servicios;
}
public float getPrecio()
{
return precio;
}
public void setPrecio(float precio)
{
this.precio = precio;
}
public float getDescuento()
{
return descuento;
}
public void setDescuento(float descuento)
{
this.descuento = descuento;
}
public Date getFechaInicio()
{
return fechaInicio;
}
public void setFechaInicio(Date fechaInicio)
{
this.fechaInicio = fechaInicio;
}
public Date getFechaFin()
{
return fechaFin;
}
public void setFechaFin(Date fechaFin)
{
this.fechaFin = fechaFin;
}
}
package mrpuppy.entity;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name="servicio")
public class Servicio
{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#ManyToOne(cascade = {CascadeType.ALL})
#JoinColumn(name="id_tarifa")
private Tarifa tarifa;
#Column(name="nombre")
private String nombre;
#Column(name="raza")
private String raza;
#OneToOne(mappedBy="servicio", cascade = {CascadeType.ALL})
private CitaServicio citaServicio;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public Tarifa getTarifa()
{
return tarifa;
}
public void setTarifa(Tarifa tarifa)
{
this.tarifa = tarifa;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public String getRaza()
{
return raza;
}
public void setRaza(String raza)
{
this.raza = raza;
}
public CitaServicio getCitaServicio()
{
return citaServicio;
}
public void setCitaServicio(CitaServicio citaServicio)
{
this.citaServicio = citaServicio;
}
}
package mrpuppy.controller.tarifas;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import mrpuppy.entity.Servicio;
import mrpuppy.entity.Tarifa;
import mrpuppy.service.TarifaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
#Controller
public class TarifasControllerImpl implements TarifasController
{
private Stage primaryStage;
private Scene scene;
private final String css = this.getClass().getResource("/css/tarifas.css").toExternalForm();
#Autowired
private AnadirTarifaController anadirTarifaController;
#Autowired
private TarifaService tarifaService;
#FXML
private TableView<Servicio> tablaServicios;
#FXML
private TableColumn<Servicio, String> columnServicio;
#FXML
private TableColumn<Tarifa, Float> columnTarifa;
#FXML
private TableColumn<Tarifa, Float> columnDescuento;
#FXML
private ComboBox<String> comboRaza;
#FXML
private Button buttonAnadir;
#FXML
private Button buttonMostrar;
#Override
public void openWindow()
{
try
{
primaryStage = new Stage();
primaryStage.setResizable(false);
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/tarifas.fxml"));
loader.setController(this); //Establecemos esta clase como "controller"
scene = loader.load();
scene.getStylesheets().add(css);
primaryStage.setScene(scene);
primaryStage.show();
ObservableList<String> oListRazas;
oListRazas = tarifaService.obtenerRazas();
comboRaza.setItems(oListRazas);
buttonAnadir.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
anadirTarifaController.openWindow();
}
});
buttonMostrar.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
Collection<Servicio> lista = new ArrayList<Servicio>();
String raza = comboRaza.getValue();
lista = tarifaService.buscarServicios(raza);
mostrarDatos(lista);
}
});
}
catch(IOException ioe)
{
System.out.println(ioe.getMessage());
}
}
private void mostrarDatos(Collection<Servicio> lista)
{
ObservableList<Servicio> servicioData = FXCollections.observableArrayList();
for(Servicio servicio : lista)
{
servicioData.add(servicio);
}
columnServicio.setCellValueFactory(new PropertyValueFactory<Servicio, String>("nombre"));
columnTarifa.setCellValueFactory(new PropertyValueFactory<Tarifa, Float>("precio"));
columnDescuento.setCellValueFactory(new PropertyValueFactory<Tarifa, Float>("descuento"));
tablaServicios.setItems(servicioData);
}
}
By the
private TableView<Servicio> tablaServicios;
your tableview is going to render Servicio objects, so logically the tablecolumns should render some fields/parts of Servicio object. For example
private TableColumn<Servicio, String> columnNombre;
private TableColumn<Servicio, String> columnRaza;
etc. However you are trying to render a Tarifa object in that table. That's not possible. Instead of
private TableColumn<Tarifa, Float> columnDescuento;
...
columnDescuento.setCellValueFactory(new PropertyValueFactory<Tarifa, Float>("descuento"));
define it as
private TableColumn<Servicio, Float> columnDescuento;
...
columnDescuento.setCellValueFactory(c ->
new ReadOnlyStringWrapper( String.valueOf( c.getValue().getTarifa().getDescuento() ) ) );
Do the same for others.
Related
In this code, I'm trying to read data from the bin file and set it in the table view column. But I can't set the loop properly in loadTableFromFileButtonOnClick.It is only showing the latest value from the bin file. But I want to load all the binding data from the bin file Here is my controller class code.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.time.LocalDate;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
public class FXMLMainSceneController implements Initializable {
#FXML private TextField idTxt;
#FXML private TextField nameTxt;
#FXML private TextField deptTxt;
#FXML private TextField cgpaTxt;
#FXML private DatePicker birthdayDatePicker;
#FXML private TableView<Student> tableView;
#FXML private TableColumn<Student, String> idColumn;
#FXML private TableColumn<Student, String> nameColumn;
#FXML private TableColumn<Student, LocalDate> birthdayColumn;
#FXML private TableColumn<Student, String> deptColumn;
#FXML private TableColumn<Student, String> cgpaColumn;
#Override
public void initialize(URL url, ResourceBundle rb) {
idColumn.setCellValueFactory(new PropertyValueFactory<Student,String>("id"));
nameColumn.setCellValueFactory(new PropertyValueFactory<Student,String>("name"));
birthdayColumn.setCellValueFactory(new PropertyValueFactory<Student,LocalDate>("birthday"));
deptColumn.setCellValueFactory(new PropertyValueFactory<Student,String>("dept"));
cgpaColumn.setCellValueFactory(new PropertyValueFactory<Student,String>("cgpa"));
}
#FXML
private void saveToFileButtonOnClick(ActionEvent event) {
Student stud = new Student(
Integer.parseInt(idTxt.getText()),
nameTxt.getText(),
birthdayDatePicker.getValue(),
deptTxt.getText(),
Float.parseFloat(cgpaTxt.getText())
);
idTxt.setText(null); nameTxt.setText(null); cgpaTxt.setText(null); deptTxt.setText(null);
stud.display();
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Stud.bin"));
oos.writeObject(stud);
oos.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
#FXML
private void loadTableFromFileButtonOnClick(ActionEvent event) {
ObjectInputStream ois=null;
try {
Student s;
//There will be a loop for set up all the data ,i tried bt can't apply it properly
ois = new ObjectInputStream(new FileInputStream("Stud.bin"));
s = (Student) ois.readObject();
s.display();
tableView.getItems().add(s);
} catch (Exception ex) {
try {
if(ois!=null)
ois.close();
}
catch (IOException e) {
e.printStackTrace();
}
ex.printStackTrace();
}
}
#FXML
private void idTxtOnMouseClick(MouseEvent event) {
idTxt.setText(null);
}
#FXML
private void nameTxtOnMouseClick(MouseEvent event) {
nameTxt.setText(null);
}
#FXML
private void cgpaTxtOnMouseClick(MouseEvent event) {
cgpaTxt.setText(null);
}
#FXML
private void deptTxtOnMouseClick(MouseEvent event) {
deptTxt.setText(null);
}
}
Here is my subclass
import java.io.Serializable;
import java.time.LocalDate;
public class Student extends Person implements Serializable{
int id;
String dept;
float cgpa;
public Student(int id, String name, LocalDate birthday, String dept, float cgpa) {
super(name, birthday);
this.id = id;
this.dept = dept;
this.cgpa = cgpa;
}
public void setId(int id) {
this.id = id;
}
public void setDept(String dept) {
this.dept = dept;
}
public void setCgpa(float cgpa) {
this.cgpa = cgpa;
}
public int getId() {
return id;
}
public String getDept() {
return dept;
}
public float getCgpa() {
return cgpa;
}
#Override
public String toString(){
return "Id="+id+", Name="+name+", DoB="+birthday+", Dept="+dept+", Cgpa="+cgpa;
}
public void display(){
System.out.println("Id="+id+", Name="+name+", DoB="+birthday+", Dept="+dept+", Cgpa="+cgpa);
}
}
here is my superclass
import java.io.Serializable;
import java.time.LocalDate;
import javafx.beans.property.SimpleStringProperty;
public class Person implements Serializable{
protected String name;
protected LocalDate birthday;
public Person(String name, LocalDate birthday) {
this.name = name;
this.birthday = birthday;
}
public void setName(String name) {
this.name = name;
}
public void setBirthday(LocalDate birthday) {
this.birthday = birthday;
}
public String getName() {
//return firstName;
return name;
}
public LocalDate getBirthday() {
return birthday;
}
}
I want to check if usernames and passwords in Regisration.java are matched with usernames and passwords in Login.java. For example, if I type in "Ali" as username, and "123" as password in Registration.java and saved it, which I have already done. Then, when I go to Login.java and type in for example "Ross" as username and "1010" as password in Login.java, it will print "Username or Password is wrong"
Users.java:
import java.util.ArrayList;
/**
*
* #author ammar
*/
public class Users {
public static ArrayList<String> usernames = new ArrayList<String>();
public static ArrayList<String> passwords = new ArrayList<String>();
public void addusers(String u, String p){
usernames.add(u);
passwords.add(p);
}
public ArrayList getUserNames()
{
return usernames;
}
public ArrayList getPasswords()
{
return passwords;
}
}
Login.java
package javaapplication6;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
/**
* FXML Controller class
*
* #author ammar
*/
public class LoginController implements Initializable {
#FXML
private Label Titlelbl;
#FXML
private Label UserNamelbl;
#FXML
private Label Passwordlbl;
#FXML
private Button Registerbtn;
#FXML
private Button Loginbtn;
#FXML
private Label Forgetbtn;
private Label Outputlbl;
#FXML
private TextField UserNametxt;
#FXML
private TextField Passwordtxt;
#FXML
private Label Outputlbl1;
#FXML
private Label Outputlbl2;
#FXML
private ImageView Img;
#FXML
private Button Viewbtn;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
Image image = new Image(getClass().getResourceAsStream("/javaapplication6/icons/uqu.png"));
Img.setImage(image);
}
#FXML
private void Login(ActionEvent event) {
var valid = true;
// Validate the username field
if (UserNametxt.getText().isEmpty() ) {
valid = false;
Outputlbl1.setText("Please Enter User Name ");
} else if (UserNametxt.getText().equals("Ali")) {
Outputlbl1.setText("Welcome");
} else {
Outputlbl1.setText("In");
}
if (Passwordtxt.getText().isEmpty()) {
valid = false;
Outputlbl2.setText("Please Enter Password");
} else {
Outputlbl2.setText("");
}
}
#FXML
private void Registerbtn(ActionEvent event) {
try {
((Node)event.getSource()).getScene().getWindow().hide();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("SecondWindow.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root1));
stage.show();
} catch (Exception e) {
System.out.println("Cant load new window");
}
}
#FXML
private void view(ActionEvent event) {
Users u = new Users();
ArrayList<String> uname = new ArrayList<String>();
ArrayList<String> pass = new ArrayList<String>();
uname = u.getUserNames();
pass = u.getPasswords();
System.out.println("The user Names-"+uname);
}
}
Registration.java (I named it SecondWindowController.java):
package javaapplication6;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
/**
* FXML Controller class
*
* #author ammar
*/
public class SecondWindowController implements Initializable {
#FXML
private Button Backbtn;
#FXML
private Button Savebtn;
#FXML
private TextField UserNameReg;
#FXML
private TextField PasswordReg;
/**
* Initializes the controller class.
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void back(ActionEvent event) throws IOException {
((Node)event.getSource()).getScene().getWindow().hide();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Login.fxml"));
Parent root1 = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root1));
stage.show();
}
#FXML
private void save(ActionEvent event) {
Users user = new Users();
user.addusers(UserNameReg.getText(), PasswordReg.getText());
}
}
FXMain:
package javaapplication6;
import java.io.IOException;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
*
* #author ammar
*/
public class FXMain extends Application {
#Override
public void start(Stage stage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/javaapplication6/Login.fxml"));
Scene scene = new Scene(root, 600, 400);
stage.setScene(scene);
stage.setTitle("UQU");
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
I know questions similar to this have been asked, and on different dates, but I'll put an SSCCE in here and try to ask this simply.
I would like to be able to update the data model, and have any views upon it automatically update, such that any caller updating the model is not aware of whatever views there presently are. This is what I learned/tried so far, and without calling TableView.refresh() it does not update. What am I missing?
main.java:
package application;
import javafx.application.Application;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
public class Main extends Application {
#Override
public void start(Stage stage) {
// data
ObservableList<Crew> data = FXCollections.observableArrayList();
data.addAll(new Crew(1, "A"), new Crew(2, "B"));
// table
TableColumn<Crew, Integer> crewIdCol = new TableColumn<Crew, Integer>("Crew ID");
crewIdCol.setCellValueFactory(new PropertyValueFactory<Crew, Integer>("crewId"));
crewIdCol.setMinWidth(120);
TableColumn<Crew, String> crewNameCol = new TableColumn<Crew, String>("Crew Name");
crewNameCol.setCellValueFactory(new PropertyValueFactory<Crew, String>("crewName"));
crewNameCol.setMinWidth(180);
TableView<Crew> table = new TableView<Crew>(data);
table.getColumns().addAll(crewIdCol, crewNameCol);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
// button
Button button = new Button(" test ");
button.setOnAction(ae -> {
// test
StringProperty nameProp = data.get(0).crewName();
if(nameProp.get().equals("A")) {
data.get(0).setCrewName("foo");
// table.refresh();
System.out.println("foo");
} else {
data.get(0).setCrewName("A");
// table.refresh();
System.out.println("A");
}
});
VBox box = new VBox(10);
box.setAlignment(Pos.CENTER);;
box.getChildren().addAll(table, button);
Scene scene = new Scene(box);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Crew.java
package application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Crew {
private final IntegerProperty crewId = new SimpleIntegerProperty();
private final StringProperty crewName = new SimpleStringProperty();
Crew(int id, String name) {
crewId.set(id);
crewName.set(name);
}
public IntegerProperty crewId() { return crewId; }
public final int getCrewId() { return crewId.get(); }
public final void setCrewId(int id) { crewId.set(id); }
public StringProperty crewName() { return crewName; }
public final String getCrewName() { return crewName.get(); }
public final void setCrewName(String name) { crewName.set(name); }
}
Your model class Crew has the "wrong" name for the property accessor methods. Without following the recommended method naming scheme, the (somewhat legacy code) PropertyValueFactory will not be able to find the properties, and thus will not be able to observe them for changes:
package application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Crew {
private final IntegerProperty crewId = new SimpleIntegerProperty();
private final StringProperty crewName = new SimpleStringProperty();
Crew(int id, String name) {
crewId.set(id);
crewName.set(name);
}
public IntegerProperty crewIdProperty() { return crewId; }
public final int getCrewId() { return crewId.get(); }
public final void setCrewId(int id) { crewId.set(id); }
public StringProperty crewNameProperty() { return crewName; }
public final String getCrewName() { return crewName.get(); }
public final void setCrewName(String name) { crewName.set(name); }
}
Alternatively, just implement the callback directly:
crewIdCol.setCellValueFactory(cellData -> cellData.getValue().crewIdProperty());
in which case the compiler will ensure that you use an existing method name for the property.
I am wondering if it is possible to convert a color defined in CSS like
.root {
my-blue: rgb(50,100,200);
}
Into a Color Object in JavaFX.
For example with the CSS definition I could use setStyle on a Node to set its Color:
label1.setStyle("-fx-background-color: my-blue");
But is it possible to do something like:
Color blue = my-blue; // is this possible somehow?
Background background = new Background(new BackgroundFill(blue, null, null));
label1.setBackground(background);
I was able to do it by using StyleableProperties like this:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javafx.beans.property.ObjectProperty;
import javafx.beans.value.WritableValue;
import javafx.css.CssMetaData;
import javafx.css.Styleable;
import javafx.css.StyleableObjectProperty;
import javafx.css.StyleableProperty;
import javafx.scene.Parent;
import javafx.scene.paint.Color;
import com.sun.javafx.css.converters.ColorConverter;
public class CssToColorHelper extends Parent{
public static final Color DEFAULT_NAMED_COLOR = null;
private ObjectProperty<Color> namedColor;
public ObjectProperty<Color> namedColorProperty() {
if(namedColor == null) {
namedColor = new StyleableObjectProperty<Color>(DEFAULT_NAMED_COLOR) {
#Override
protected void invalidated() {
super.invalidated();
}
#Override
public CssMetaData<? extends Styleable, Color> getCssMetaData() {
return StyleableProperties.NAMED_COLOR;
}
#Override
public Object getBean() {
return CssToColorHelper.this;
}
#Override
public String getName() {
return "namedColor";
}
};
}
return namedColor;
}
public Color getNamedColor() {
return namedColorProperty().get();
}
public CssToColorHelper() {
setFocusTraversable(false);
getStyleClass().add("css-to-color-helper");
}
private static class StyleableProperties {
private static final CssMetaData<CssToColorHelper, Color> NAMED_COLOR =
new CssMetaData<CssToColorHelper, Color>("-named-color", ColorConverter.getInstance(),
DEFAULT_NAMED_COLOR) {
#Override
public boolean isSettable(CssToColorHelper n) {
return n.namedColor == null || !n.namedColor.isBound();
}
#Override
public StyleableProperty<Color> getStyleableProperty(CssToColorHelper n) {
return (StyleableProperty<Color>) (WritableValue<Color>) n.namedColorProperty();
}
};
private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
static {
final List<CssMetaData<? extends Styleable, ?>> styleables =
new ArrayList<>(Parent.getClassCssMetaData());
styleables.add(NAMED_COLOR);
STYLEABLES = Collections.unmodifiableList(styleables);
}
}
#Override
public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
return StyleableProperties.STYLEABLES;
}
}
The main class of my SSCCE looks like this:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class TestMain extends Application {
private CssToColorHelper helper = new CssToColorHelper();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group(), 450, 250);
scene.getStylesheets().add("colors.css");
TextField textfield = new TextField();
Group root = (Group) scene.getRoot();
root.getChildren().add(textfield);
root.getChildren().add(helper);
stage.setScene(scene);
Color blue = getNamedColor("my-blue");
Background bgf = new Background(new BackgroundFill(blue, null, null));
textfield.setBackground(bgf);
stage.show();
}
Color getNamedColor(String name) {
helper.setStyle("-named-color: " + name + ";");
helper.applyCss();
return helper.getNamedColor();
}
}
And the CSS-file looks like this:
.root {
my-blue: rgb(50,100,200);
}
.css-to-color-helper {
}
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());
}});