Hello I am Trying to pass Variable data from database from one Controller to another, but I Have one problem, when I am passing the data to the controller A to Controller B, appear a Null value, the jerarchy between Scenes is this:
LoginController->AdminController->UserController
in the LoginController to Access AdminController and Pass the Value i do this:
public String getRoladmin() {
return roladmin;
}
public void setRoladmin(String roladmin) {
this.roladmin = roladmin;
}
public String roladmin="";
I Capture the Variable roladmin in this portion of my code like this:
while(rs.next()) {
comparauser=rs.getString("NOMBREUSUARIO");
comparapass=rs.getString("PASS");
miadmin=rs.getString("NOMBRE_ADMIN");
roladmin=rs.getString("ROL_ADMIN");
}
to access the Stage I validate if the user and pass are correct like this:
----rest of code--- if(comparauser.equals(fusuario.getText().toString())&&comparapass.equals(fcontrasena.getText().toString().trim())) {
try {
Stage administrador=new Stage();
FXMLLoader carga = new FXMLLoader(getClass().getResource("Admin.fxml"));
Parent StackPane = (Parent)carga.load();
Scene scene = new Scene(StackPane);
AdminScreenController loadl = carga.<AdminScreenController>getController();
/*loadl.UserScreen.setText("Bienvenido"+" "+fusuario.getText().toString());*/
loadl.UserScreen.setText("Bienvenido"+" "+miadmin);
/* String r=loadl.UserScreen.getText().toString();*/
-----in this part I call the LoginController and pass the variable Roladmin------
----begin of call--
String h=LoginController.this.roladmin;
LoginController.this.setRoladmin(h);
String r=LoginController.this.getRoladmin();
loadl.setCapdata(r);
-----end of call-----
if(!r.equals("ADMINISTRADOR")) {
loadl.btnimg5.setDisable(true);
loadl.btnimg5.setStyle("-fx-opacity:0.65;");
}
else {
loadl.btnimg5.setDisable(false);
}
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
administrador.setScene(scene);
administrador.setTitle("AdminScreen");
Stage login=(Stage)fusuario.getScene().getWindow();
login.hide();
administrador.show();
}catch(Exception e) {
Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, e);
}
}
---rest of code---
now i Pass that variable to the AdminController like this
in AdminController i have this:
public String capdata;
public String h;
public String getCapdata() {
return capdata;
}
public String setCapdata(String data) {
return this.capdata = data;
}
this is the code i have to load UserController Stage:
public void UserView() throws IOException {
Stage userstage = new Stage();
FXMLLoader cargauser =new FXMLLoader(getClass().getResource("UsuarioScreen.fxml"));
Parent StackPane = (Parent)cargauser.load();
UserController cargatodouser = cargauser.<UserController>getController();
String pasadato=UserScreen.getText().toString();
cargatodouser.iduser.setText(pasadato);
---begin of call to pass the variable---
h=AdminScreenController.this.getCapdata();
---end of call---
/*String r=cargatodouser.iduser.getText().toString();*/
Scene scene = new Scene(StackPane);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
userstage.setScene(scene);
userstage.setTitle("QuoraApp");
Stage AdminScreen=(Stage)btnimg1.getScene().getWindow();
AdminScreen.hide();
userstage.show();
}
now when i am passing the variable to the UserController Class i have a null value I am doing this:
In UserController class i have this to go back AdminController:
public String capturau;
public String getCapturau() {
return capturau;
}
public String setCapturau(String capturau) {
return this.capturau = capturau;
}
public void inicio() throws IOException {
Stage administrador=new Stage();
FXMLLoader carga = new FXMLLoader(getClass().getResource("Admin.fxml"));
Parent StackPane =(Parent) carga.load();
AdminScreenController loadl = carga.<AdminScreenController>getController();
String pasadato=iduser.getText().toString();
loadl.UserScreen.setText(pasadato);
/*Captura.setText(loadl.getCapdata());
String captura=Captura.getText().toString();
System.out.println(captura);*/
UserController.this.setCapturau(loadl.getCapdata());
String gg=UserController.this.getCapturau();
System.out.println(gg);
}
what i am doing wrong? a little help here please.
You need to look into the concept of static variables
Here is a static variable I declare on one Controller and use and another Controller
A BIG word of caution about using static variables or Global Variables
What ever you put in a static variable it holds that value till you clear it or change it
static Integer strID;
Here is the use of the static variable strID in the other Controller Class
Notice it needs to be imported to the new Controller
import static diary.ChildTableViewController.strID;
private void ReadDetailView() throws SQLException{
stmnt = conn.createStatement();
///String sql = "SELECT * FROM Child WHERE CID = "+strID;
///ResultSet rs = stmnt.executeQuery(sql);
ResultSet rs = stmnt.executeQuery("SELECT * FROM Child WHERE CID = "+strID);
Welcome to SO
Related
I have an object Bean containing a List<String>. I would like to "bind" this list to an ObservableList so when an item is added to or removed from the original list, the ObservableList is updated (which then triggers the listeners that monitor the ObservableList).
I found this question whose answer shows how to wrap a simple String into a JavaFX StringProperty using JavaBeanStringPropertyBuilder.
I tried to do the same thing but replacing the String with a List<String> as shown below:
public class Bean {
private final List<String> nameList;
private final PropertyChangeSupport propertySupport ;
public Bean() {
this.nameList = new ArrayList<>();
this.propertySupport = new PropertyChangeSupport(this);
}
public List<String> getNameList() {
return nameList;
}
public void setNameList(List<String> nameList)
{
List<String> oldList = new ArrayList<>(this.nameList);
this.nameList.clear();
this.nameList.addAll(nameList);
propertySupport.firePropertyChange("nameList", oldList, this.nameList);
}
public void addName(String name) {
List<String> oldList = new ArrayList<>(this.nameList);
this.nameList.add(name);
propertySupport.firePropertyChange("nameList", oldList, this.nameList);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertySupport.addPropertyChangeListener(listener);
}
}
Bean bean = new Bean();
JavaBeanObjectProperty<List<String>> listProperty = null;
try
{
listProperty = JavaBeanObjectPropertyBuilder.create().bean(bean).name("nameList").build();
} catch (NoSuchMethodException e)
{
throw new RuntimeException(e);
}
listProperty.addListener((ObservableValue<? extends List<String>> obs, List<String> oldName, List<String> newName) ->
{
System.out.println("List changed");
});
bean.setNameList(Arrays.asList("George", "James"));
But the listener is not triggered after calling setNameList() and I don't know what I'm missing.
Could you help me please?
A change listener registered with a Property<T> will only be notified if the value of the property actually changes. That is, the set(T newValue) method is implemented something like this:
public void set(T newValue) {
T oldValue = this.get();
if (! oldValue.equals(newValue)) {
// notify change listeners...
}
}
The JavaBeanObjectPropertyBuilder is going to create a JavaBeanObjectProperty<List<String>> (an implementation of Property<List<String>>) and set its value to the result of calling bean.getNameList(). I.e. the value held internally by listProperty is a reference to bean.nameList.
The JavaBeanObjectProperty also registers a listener via the call to bean.addPropertyChangeListener(...). When
propertySupport.firePropertyChange("nameList", oldList, this.nameList);
is invoked, the internal listener in JavaBeanObjectProperty will set its own value to the new value fired by the property change support; i.e. it will call
set(bean.nameList);
However, since this is just a reference to the current value of the property, no change listener registered with listProperty will be notified (basically, no change has occurred).
To clarify, if it helps: the content of the List<String> returned by listProperty.get() will change when you call
this.nameList.clear();
and
this.nameList.addAll(nameList);
in the bean (because the listProperty references bean.nameList), but the actual list reference itself has not changed.
You can test this with, e.g.
Bean bean = new Bean();
JavaBeanObjectProperty<List<String>> listProperty = null;
try
{
listProperty = JavaBeanObjectPropertyBuilder.create().bean(bean).name("nameList").build();
} catch (NoSuchMethodException e)
{
throw new RuntimeException(e);
}
listProperty.addListener((ObservableValue<? extends List<String>> obs, List<String> oldName, List<String> newName) ->
{
System.out.println("List changed");
});
List<String> oldList = listProperty.get();
bean.setNameList(Arrays.asList("George", "James"));
List<String> newList = listProperty.get();
System.out.println(oldList);
System.out.println(newList);
System.out.println(oldList == newList);
The best fix is simply to use an ObservableList in your Bean class:
public class Bean {
private final ObservableList<String> nameList;
public Bean() {
this.nameList = FXCollections.observableArrayList<>();
}
public ObservableList<String> getNameList() {
return nameList;
}
public void addName(String name) {
this.nameList.add(name);
}
}
Note you don't lose the functionality provided by setNameList(...); you can do
bean.getNameList().setAll(...);
if you want to set the entire content of the list. If you want the same API, you can use a ListProperty instead of the ObservableList.
The test code you have then becomes
Bean bean = new Bean();
bean.getNameList().addListener((ListChangeListener.Change<? extends String> change) ->
{
System.out.println("List changed");
});
bean.getNameList().setAll("George", "James");
As stated in the comments in the question, I don't really understand having any restriction preventing the use of ObservableList in the model; indeed this is exactly the use case for which ObservableList (along with the properties and bindings API) was designed.
There is no adapter designed for use with observable lists in the same way as there are Java Bean adapters for simple properties. Thus if you really wanted to avoid use of ObservableList in your model class (which, again, doesn't really make sense to me), you would have to implement your own listener notification for the Bean:
public class Bean {
private final List<String> nameList ;
private final List<Consumer<String>> nameAddedListeners ;
private final List<Consumer<List<String>>> nameListReplacedListeners ;
public Bean() {
this.nameList = new ArrayList<>();
this.nameAddedListeners = new ArrayList<>();
this.nameListReplacedListeners = new ArrayList<>();
}
public List<String> getNameList() {
return nameList ;
}
public void setNameList(List<String> newNames) {
this.nameList.setAll(newNames);
nameListReplacedListeners.forEach(listener -> listener.accept(newNames));
}
public void addName(String name) {
this.nameList.add(name);
nameAddedListeners.forEach(listener -> listener.accept(name));
}
public void addNameListReplacedListener(Consumer<List<String>> listener) {
nameListReplacedListeners.add(listener);
}
public void addNameAddedListener(Consumer<String> listener) {
nameAddedListeners.add(listener);
}
}
Now you could do
Bean bean = new Bean();
bean.addNameListReplacedListener(list -> System.out.println("Names changed"));
bean.setNameList(List.of("George", "James"));
or you could effectively create an adapter:
Bean bean = new Bean();
ObservableList<String> names = FXCollections.observableArrayList(bean.getNameList());
bean.addNameAddedListener(names::add);
bean.addNameListReplacedListener(names::setAll);
etc.
I need to add to my TreeTableView the content for two columns("Id" and "Workplace").
I don't know how to do it, because I can't get nested value from Manager -> ArrayList.
What should I pass in TreeItemPropertyValueFactory if the type of the content can be only String???
The rest of code works OK.
I will be grateful for any help.
public void showStaffInTreeTable(){
Employee emp_1 = new Employee("1", "secretary");
Employee emp_2 = new Employee("2", "cleaner");
Employee emp_3 = new Employee("3", "driver");
Employee emp_4 = new Employee("4", "mechanic");
ArrayList<Employee> johnStaff = new ArrayList<>(Arrays.asList(emp_1, emp_2));
ArrayList<Employee> amandaStaff = new ArrayList<>(Arrays.asList(emp_3, emp_4));
Manager john = new Manager("John", johnStaff);
Manager amanda = new Manager("Amanda", amandaStaff);
TreeTableColumn<Manager, String> columnManager = new TreeTableColumn<>("Manager");
TreeTableColumn<Manager, String> columnStaffId = new TreeTableColumn<>("Id");
TreeTableColumn<Manager, String> columnStaffWorkplace = new TreeTableColumn<>("Workplace");
columnManager.setCellValueFactory(new TreeItemPropertyValueFactory<>("managersName"));
columnStaffId.setCellValueFactory(new TreeItemPropertyValueFactory<>
("how to pass here: Manager-> ArrayList<Employess> -> getEmployee -> getId???"));
columnStaffWorkplace.setCellValueFactory(new TreeItemPropertyValueFactory<>
("how to pass here: Manager-> ArrayList<Employess> -> getEmployee -> getWorkplace???"));
TreeTableView<Manager> managers = new TreeTableView<>();
managers.getColumns().addAll(columnManager, columnStaffId, columnStaffWorkplace);
TreeItem managerItem_1 = new TreeItem(john);
managerItem_1.getChildren().addAll(new TreeItem<>(emp_1), new TreeItem<>(emp_2));
TreeItem managerItem_2 = new TreeItem(amanda);
managerItem_2.getChildren().addAll(new TreeItem<>(emp_3), new TreeItem<>(emp_4));
TreeItem root = new TreeItem(new Manager("", new ArrayList<>()));
root.getChildren().addAll(managerItem_1, managerItem_2);
root.setExpanded(true);
managers.setRoot(root);
}
public class Employee {
private String id;
private String workplace;
public Employee(String id, String workplace) {
this.id = id;
this.workplace = workplace;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getWorkplace() {
return workplace;
}
public void setWorkplace(String workplace) {
this.workplace = workplace;
}
}
public class Manager {
private String managersName;
private List<Employee> managersStaff = new ArrayList<>();
public Manager(String managersName, List<Employee> managersStaff) {
this.managersName = managersName;
this.managersStaff = managersStaff;
}
public String getManagersName() {
return managersName;
}
public void setManagersName(String managersName) {
this.managersName = managersName;
}
public List<Employee> getManagersStaff() {
return managersStaff;
}
public void setManagersStaff(List<Employee> managersStaff) {
this.managersStaff = managersStaff;
}
}
You can do
columnStaffId.setCellValueFactory(cellData -> {
TreeItem<?> item = cellData.getValue();
Object data = item.getValue();
if (data instanceof Employee) {
Employee employee = (Employee)data ;
return new SimpleStringProperty(employee.getId());
} else {
return new SimpleStringProperty("");
}
});
Note in Java 14 you can simplify this to
columnStaffId.setCellValueFactory(cellData -> {
if (cellData.getValue().getValue() instanceof Employee employee) {
return new SimpleStringProperty(employee.getId());
} else {
return new SimpleStringProperty("");
}
});
Your setup is a little weird, as you declare a TreeTableView<Manager> but some of the items don't contain Managers, but Employees. So there's no real guarantee you don't get ClassCastExceptions thrown in places here, or other errors caused by the TreeItemPropertyValueFactory trying to call getManagersName() on an object that isn't a Manager.
You might want to refactor so you use a TreeTableView<Object>, or maybe refactor the model so that Manager and Employee are both subclasses of some other class (which you then use as the type for your TreeTableView).
Im making a mediaplayer using JavaFX Media classes. I made a SongModel class, that incapsulates all metadata from a file and creates Media and MediaPlayer instances.
It looks something like this:
private final StringProperty album =
new SimpleStringProperty(this, "album");
public String getAlbum(){ return album.get(); }
public void setAlbum(String value){ album.set(value); }
public StringProperty albumProperty() { return album; }
There are also artist, year, title, and albumCover fields that look just like that. Also, MediaPlayer property is exposed as a read-only:
public MediaPlayer getMediaPlayer(){ return mediaPlayer.get(); }
public ReadOnlyObjectProperty<MediaPlayer> mediaPlayerProperty(){
return mediaPlayer.getReadOnlyProperty();
}
I use a MapChangelistener to check if the field is available and then pass it to the handleMetadata method:
private void initializeMedia(String url){
try {
final Media media = new Media(url);
media.getMetadata().addListener(new MapChangeListener<String, Object>(){
#Override
public void onChanged(MapChangeListener.Change<? extends String, ? extends Object> ch) {
if(ch.wasAdded()){
handleMetadata(ch.getKey(), ch.getValueAdded());
}
}
});
mediaPlayer.setValue(new MediaPlayer(media));
mediaPlayer.get().setOnError(new Runnable() {
#Override
public void run() {
String errorMessage = mediaPlayer.get().getError().getMessage();
System.out.println("MediaPlayer error: "+errorMessage);
}
});
}catch(RuntimeException e){
System.out.println("Construction error: "+e);
}
}
private void handleMetadata(String key, Object value){
if(key.equals("album")){
setAlbum(value.toString());
} else if (key.equals("artist")){
setArtist(value.toString());
} if (key.equals("title")){
setTitle(value.toString());
} if (key.equals("year")){
setYear(value.toString());
} if (key.equals("image")){
setAlbumCover((Image)value);
}
}
Then I made an AbstractView class that provides access to SongModel:
public abstract class AbstractView {
protected final SongModel songModel;
protected final Node viewNode;
public AbstractView(SongModel songModel){
this.songModel = songModel;
this.viewNode = initView();
}
public Node getViewNode() {
return viewNode;
}
protected abstract Node initView();
}
But when I try to make a MetadataView class, I run into some problems.
Heres how it looks:
public class MetadataView extends AbstractView{
public Label artist;
public Label album;
public Label title;
public Label year;
public ImageView albumCover;
public MetadataView(SongModel songModel) {
super(songModel);
}
#Override
protected Node initView() {
artist = new Label();
artist.setId("artist");
album = new Label();
album.setId("album");
title = new Label();
title.setId("title");
year = new Label();
year.setId("year");
final Reflection reflection = new Reflection();
reflection.setFraction(0.2);
final URL url = getClass().getResource("resources/defaultAlbum.png");
Image image = new Image(url.toString());
albumCover = new ImageView(image);
albumCover.setFitWidth(240);
albumCover.setPreserveRatio(true);
albumCover.setSmooth(true);
albumCover.setEffect(reflection);
final GridPane gp = new GridPane();
gp.setPadding(new Insets(10));
gp.setHgap(20);
gp.add(albumCover, 0,0,1, GridPane.REMAINING);
gp.add(title, 1,0);
gp.add(artist, 1,1);
gp.add(album, 1,2);
gp.add(year, 1,3);
final ColumnConstraints c0 = new ColumnConstraints();
final ColumnConstraints c1 = new ColumnConstraints();
c1.setHgrow(Priority.ALWAYS);
gp.getColumnConstraints().addAll(c0,c1);
final RowConstraints r0 = new RowConstraints();
r0.setValignment(VPos.TOP);
gp.getRowConstraints().addAll(r0,r0,r0,r0);
return gp;
}
}
And heres how I call it in the start method:
metaDataView = new MetadataView(songModel);
The problem is that it displays only default metadata without taking it from the songmodel class. I tried running metadata view code together with data handling in one class and everything worked, but when i try to put them in separate classes - it doesnt. Music runs just fine, its just the data thats not displaying. Could anybody tell me what am I missing? How do i make it display metadata from a SongModel class? Ive spent a lot of time on that and dont want it to go to waste.
After a day of searching I have found an answer: binds. All I had to do was to bind label property of SongModel class to label property of MetadataView class:
title.textProperty().bind(songModel.titleProperty());
artist.textProperty().bind(songModel.artistProperty());
album.textProperty().bind(songModel.albumProperty());
year.textProperty().bind(songModel.yearProperty());
albumCover.imageProperty().bind(songModel.albumCoverProperty());
I have an object Contract and it contains Summary and Observable List of another object ContractDetails inside it.
Now, I am using ContractDetails to populate in tableview from Contract object.
I have a save button, which on clicking needs to save Contract along with ContractDetails. I am able to access ContractDetails since they are in tableview.
How do I access Contract properties in eventlistener of save button.
The related code is given below
public class Contract {
private String tradeDate;
private String contractNote;
.....
.....
private String brokerId;
private ObservableList<ContractDetails> contractdetails = FXCollections.observableArrayList();
public Contract() {
}
public Contract(String tradeDate, String contractNote, ....., String brokerId,ObservableList<ContractDetails> contractdetails) {
this.tradeDate = tradeDate;
this.contractNote = contractNote;
....
....
this.contractdetails=contractdetails;
}
public String getTradeDate() {
return tradeDate;
}
public void setTradeDate(String tradeDate) {
this.tradeDate = tradeDate;
}
public String getContractNote() {
return contractNote;
}
public void setContractNote(String contractNote) {
this.contractNote = contractNote;
}
....
....
public ObservableList<ContractDetails> getContractdetails() {
return contractdetails;
}
public void setContractdetails(ObservableList<ContractDetails> contractdetails) {
this.contractdetails = contractdetails;
}
}
public class ContractDetails {
private String orderNo;
private String contractType;
private String symbol;
private String buysell;
private Integer quantity;
private Double buysellprice;
private Double netcontractValue;
public ContractDetails() {
}
public ContractDetails(String orderNo, String contractType, String symbol, String buysell, Integer quantity, Double buysellprice, Double netcontractValue) {
this.orderNo = orderNo;
this.symbol = symbol;
this.buysell = buysell;
this.quantity = quantity;
this.buysellprice = buysellprice;
this.netcontractValue = netcontractValue;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
....
....
public Double getNetcontractValue() {
return netcontractValue;
}
public void setNetcontractValue(Double netcontractValue) {
this.netcontractValue = netcontractValue;
}
}
In the controller
==================
public class ContractViewController implements Initializable {
#FXML
private TableView<ContractDetails> tblcontractfx;
#FXML
private TableColumn<ContractDetails, String> contractTypefx;
#FXML
private TableColumn<ContractDetails, String> symbolfx;
....
....
#FXML
private Button savefx;
#FXML
private TextField txtclientcodefx;
#FXML
private TextField txttradedtfx;
private void fetchContracts(TableView tableView, Contract contract)
{ txttradedtfx.setText(contract.getTradeDate());
txtclientcodefx.setText(contract.getClientCode());
symbolfx.setCellValueFactory(new PropertyValueFactory<ContractDetails, String>("symbol"));
contractTypefx.setCellValueFactory(new PropertyValueFactory<ContractDetails, String>("contractType"));
tableView.setItems((ObservableList) contract.getContractdetails());
#FXML
private void saveClicked(ActionEvent event) { DBConnection DBcon = new DBConnection();
//Now I am getting the contract details from tableview tblcontractfx
ObservableList<ContractDetails> contractdetails = tblcontractfx.getItems();
//How do I get the summary values from contract. I am able to get those which are in text fields like txttradedtfx and txtclientcodefx.However contractNote which I am not using, I still need to retrieve it to populate into database.
String clientCode=txtclientcodefx.getText();
Thanks
Just store the contract in a local variable.
Contract contract;
private void fetchContracts(TableView tableView, Contract contract)
{
this.contract = contract;
...
}
private void saveClicked(ActionEvent event) {
// here you have full access to the contract variable
String contractNote = contract.getContractNote();
}
As an alternative, if you insist on combining it all in a single table, you could put the Contract into the table via setUserData and retrieve it via getUserData.
By the way, I still don't get your code. Why is there a tableView parameter when you have full access to TableView<ContractDetails> tblcontractfx
Every time I try to open a file at the #Timeout, Java returns Null Pointer Exception
#Singleton
public class EngineTrans {
#Resource
private TimerService timerService;
public void createProgrammaticalTimer() {
ScheduleExpression everyTenSeconds = new ScheduleExpression().second("*/15").minute("*").hour("4-20");
timerService.createCalendarTimer(everyTenSeconds, new TimerConfig(
"passed message " + new Date(), false));
}
#Timeout
public void handleTimer() {
System.out.println("timer received - contained message is: " + new Date());
File xmlFile = new File(FacesContext.getCurrentInstance().getExternalContext().getRealPath(""));
}
}
Any ideas?
There is no JSF context within an #Timeout method. Perform the getRealPath call in the createProgrammaticalTimer method, and then pass it to the #Timeout method via the first parameter of the TimerConfig constructor (the "info" parameter). If necessary, create an inner class to hold all the data you need to pass to the #Timeout method:
#Singleton
public class EngineTrans {
#Resource
private TimerService timerService;
private static class TimeoutData {
private final Date date = new Date();
private final String resourcePath;
...
}
public void createProgrammaticalTimer() {
...
String resourcePath = FacesContext.getCurrentInstance().getExternalContext().getRealPath("...");
TimeoutData timeoutData = new TimeoutData(resourcePath);
timerService.createCalendarTimer(everyTenSeconds, new TimerConfig(timeoutData, false));
}
#Timeout
public void handleTimer(Timer timer) {
TimeoutData timeoutData = (TimeoutData)timer.getInfo();
...
}
}