I have 2 scenes :
The first one has a "Balance" Label, which displays the balance from a variable.
The second scene is the deposit scene where the user adds to the balance.
(Each scene has its controller class)
I want the balance to be updated when the user goes back to the first scene.
what's the best way to do so? I couldn't find an event for the scene shown, I found online only a stage example which triggers an event when the window is closed, but here I am just changing scenes by changing the mainstage scene.
I have tried making an object of the first scene class inside the second scene's class and calling a method to change the label text when I click the back button but that didn't work.
Here's the code for the first scene where lbBalance is the label I want to update, and updateBal is the method I am using in the second scene class.
public class accountController extends Controller implements Initializable {
#FXML private Label gilbert;
#FXML private Label lbBalance;
#FXML private Button deposit;
#FXML private Button btn_showBalance;
private application.depositController depositController;
#Override
public void initialize(URL location, ResourceBundle resources) {
lbBalance.setText(String.valueOf(BAL));
}
#FXML
public void handleDeposit(ActionEvent event) throws IOException {
Parent depositParent = FXMLLoader.load(getClass().getResource("deposit.fxml"));
depositScene = new Scene(depositParent);
mainStage.setScene(depositScene);
mainStage.show();
}
public void updateBal() {
lbBalance.setText(String.valueOf(BAL));
}
}
Here's the second scene's class
accountController backtoscene= new accountController();
#FXML private Label info;
#FXML private Button btn_depositfinal;
#FXML private TextField depositamount;
#FXML private Button btn_back;
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
#FXML
public void handleDepositFinal(ActionEvent event) {
deposit(Integer.parseInt(depositamount.getText()));
info.setVisible(true);
}
#FXML
public void handleBackButton(ActionEvent event) throws IOException {
backtoscene.updateBal();
mainStage.setScene(newscene);
}
TL;DR calling the method is giving me a nullPointerException, is there any other way to update the balance label when getting back to previous scene?
NOTE: I haven't tested the code, I just wrote it freehand, but it gives you a general idea.
Your main issue is that you are creating a new AccountController in the DepositController. Meaning it's a different one than the one you originally instantiated.
public class AccountController extends Controller implements Initializable {
#FXML private Label gilbert;
#FXML private Label lbBalance;
#FXML private Button deposit;
#FXML private Button btn_showBalance;
private application.DepositController depositController;
#Override
public void initialize(URL location, ResourceBundle resources) {
lbBalance.setText(String.valueOf(BAL));
}
#FXML
public void handleDeposit(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("deposit.fxml"));
Parent depositParent = loader.load();
depositScene = new Scene(depositParent);
depositController = loader.getController();
depositController .setAccountController(this);
mainStage.setScene(depositScene);
mainStage.show();
}
public void updateBal() {
lbBalance.setText(String.valueOf(BAL));
}
}
Here's the second class where you need to set the AccountController to be the one you originally initialized :
public class DepositController extends Controller implements Initializable {
AccountController backtoscene;
#FXML private Label info;
#FXML private Button btn_depositfinal;
#FXML private TextField depositamount;
#FXML private Button btn_back;
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
public void setAccountController(AccountController controller){
backtoscene = controller;
}
#FXML
public void handleDepositFinal(ActionEvent event) {
deposit(Integer.parseInt(depositamount.getText()));
info.setVisible(true);
}
#FXML
public void handleBackButton(ActionEvent event) throws IOException {
backtoscene.updateBal();
mainStage.setScene(newscene);
}
}
Now you have access to the AccountController you originally initialized at the start, and the AccountController has access to the correct DepositController.
Related
I have two Controller class(Controller and Dailog Controller). COntroller class has tableView. On Double click on Tableview row the Dialog popup. The dialogController class has two button i.e update and delete.
The Update button updating and deleting data in database. After updating or deleting i want to refresh tableview. The problem is tablview refresh method is in Controller class. So how can i refresh it?
public class Controller implements Initializable{
#FXML
private TabPane tabPane;
#FXML
private Tab createTaskTab;
#FXML
private TextArea textArea;
#FXML
private Button saveBtn;
#FXML
private Tab viewTasksTab;
#FXML
private TableView<Task> tableView;
#FXML
private TableColumn<Task, Integer> idColumn;
#FXML
private TableColumn<Task, String> dateColumn;
#FXML
private TableColumn<Task, String> timeColumn;
#FXML
private TableColumn<Task, String> taskColumn;
#FXML
private TableColumn<Task, String> statusColumn;
#FXML
void saveTask(ActionEvent event) {
String getTask = textArea.getText();
if(getTask.length() > 0)
{
MysqlConnection mysqlConnection = new MysqlConnection();
int count = mysqlConnection.insertTask(getTask);
if(count > 0)
{
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle("Saved");
alert.setContentText("Task Saved");
alert.show();
textArea.clear();
}
}
else
{
Alert alert = new Alert(AlertType.WARNING);
alert.setTitle("Empty TextArea");
alert.setContentText("Please write the task");
alert.show();
}
}
#FXML
public void viewTasks(Event e)
{
try{
tabPane.getSelectionModel().selectedItemProperty().addListener(
new ChangeListener<Tab>() {
#Override
public void changed(ObservableValue<? extends Tab> observable, Tab oldValue, Tab newValue) {
if(newValue == viewTasksTab)
{
refreshTable();
}
}
});
}catch(Exception exception)
{
System.out.println("Exception in viewTasks");
}
}
protected void refreshTable() {
MysqlConnection myconn = new MysqlConnection();
idColumn.setCellValueFactory(new PropertyValueFactory<>("id"));
dateColumn.setCellValueFactory(new PropertyValueFactory<>("date"));
timeColumn.setCellValueFactory(new PropertyValueFactory<>("time"));
taskColumn.setCellValueFactory(new PropertyValueFactory<>("task"));
statusColumn.setCellValueFactory(new PropertyValueFactory<>("status"));
tableView.setItems(myconn.fetchTasks());
}
#FXML
public void onEdit(MouseEvent event)
{
if(event.getClickCount() == 2){
Task selectedTask = tableView.getSelectionModel().getSelectedItem();
Scene scene;
Stage stage;
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("DialogBox.fxml"));
Parent root = (Parent) loader.load();
DialogBoxController dialog = loader.getController();
dialog.editTask(selectedTask);
scene = new Scene(root);
stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setScene(scene);
stage.showAndWait();
} catch (IOException e) {
System.out.println("Exception in onEdit"+e.getMessage());
}
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
}
DialogController class:
[public class DialogBoxController implements Initializable{
#FXML
private Label idLabel;
#FXML
private Label dateLabel;
#FXML
private Label timeLabel;
#FXML
private ComboBox<String> statusComboBox;
#FXML
private TextArea textAreaDialog;
#FXML
private Button updateBtn;
#FXML
private Button deleteBtn;
private void closeStage(ActionEvent event) {
Node source = (Node) event.getSource();
Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
public void editTask(Task task)
{
idLabel.setText(""+task.getId());
dateLabel.setText(task.getDate());
timeLabel.setText(task.getTime());
textAreaDialog.setText(task.getTask());
statusComboBox.setValue(task.getStatus());
textAreaDialog.setEditable(false);
}
#FXML
public void update(ActionEvent event){
int taskID = Integer.parseInt(idLabel.getText());
String status = statusComboBox.getSelectionModel().getSelectedItem().toString();
MysqlConnection myconn = new MysqlConnection();
myconn.updateTask(taskID, status);
closeStage(event);
}
#FXML
public void delete(ActionEvent event){
int taskID = Integer.parseInt(idLabel.getText());
MysqlConnection myconn = new MysqlConnection();
myconn.deleteTask(taskID);
closeStage(event);
}
#Override
public void initialize(URL location, ResourceBundle resources) {
statusComboBox.getItems().addAll("Pending","Done","Aborted");
}
Snapcshot of Application
You can add this to the DialogBoxController class:
public class DialogBoxController {
private Controller controller;
public void setController(Controller controller){
this.controller = controller;
}
#FXML
public void delete(ActionEvent event){
// Your code
controller.refreshTable();
closeStage(event);
}}
And in the Controller:
DialogBoxController dialog = loader.getController();
dialog.editTask(selectedTask);
dialog.setController(this);
I am trying to fill data into my new scene when I switch to it. The user logs in (which is working because if I toString() him I get everything I need). When I call setText() on the JFXTextField for example, it does not work.
This is my controller. Updatehome is called when I switch to this scene
public class DashboardController {
#FXML JFXTextField txtGastDashboardSuchfeld;
#FXML Label lblGastDashboardNachnameVorname;
#FXML JFXTextField txtGastHomeVorname;
#FXML JFXTextField txtGastHomeNachname;
#FXML JFXTextField txtGastHomeSteuernummer;
#FXML JFXTextField txtGastHomeAusweisnummer;
#FXML JFXTextField txtGastHomeEmail;
#FXML JFXPasswordField pwfGastHomePasswort;
public void updateHome() {
if(Main.user == null) {
Controller.errorMessage("Fataler Fehler", "User konnte nicht aufgelöst werden!");
return;
}
System.out.println(Main.user.toString());
lblGastDashboardNachnameVorname.setText(Main.user.getVollername());
txtGastHomeVorname.setText(Main.user.getVorname());
txtGastHomeNachname.setText(Main.user.getNachname());
txtGastHomeSteuernummer.setText(Main.user.getSteuernummer());
txtGastHomeAusweisnummer.setText(Main.user.getAusweisnummer());
txtGastHomeEmail.setText(Main.user.getEmailAdresse());
pwfGastHomePasswort.setText(Main.user.getPasswort().toString());
}
}
In my Main class I have this (Scenes are being loaded)
public static Controller controller;
public static DashboardController dashboardController;
public static Person user = null;
public static Stage window;
public static TreeMap<String, Scene> scenes = new TreeMap<>();
public static ArrayList<Scene> history = new ArrayList<>();
#Override
public void start(Stage primaryStage) {
window = primaryStage;
controller = new Controller();
dashboardController = new DashboardController();
loadScenes();
}
This is a snippet from the method that loads the scenes into my treemap
FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlPath));
try {
if(sceneName.contains("dashboard")) {
loader.setController(dashboardController);
} else
loader.setController(controller);
Parent parent = (Parent)loader.load();
scenes.put(sceneName, new Scene(parent));
I am a newbie in Javafx and I am trying to fix a cropping over an image. I found an interesting solution for cropping with rubber band and now I try to modified this in my scenario.
I have two controllers. One controller has the crop button (CropController) and another controller which contain an image as ImageController.
CropController:
public class CropController {
#FXML
private void initialize() {}
#FXML
private void handleCrop(){
}
}
ImageController:
public class ImageController {
#FXML
private ImageView MainImage;
#FXML
private void initialize() {
modelSharedOne.imageProperty()
.addListener((obs, oldImage,newImage)-> MainImage.setImage(newImage));
}
#FXML
private void handleMousePresses(){}
#FXML
private void handleMouseDragged(){}
#FXML
private void handleMouseReleased(){}
}
Based on the rubber band solution I need to group those three mouse handlers. I do not know what could be the best solution for this. I have tried many solutions like creating a model between these two controllers but I have not managed to solve this solution.
Anyone knows how can I solve this?
My current solution
CropController:
public class ToolboxController {
#FXML
private void initialize() {
}
#FXML
private void handleCrop(){
SharedModelTwo.callHandlerInWorkstation();
}
}
SharedModelTwo:
public class CropImageModel {
ImageController imageController;
public void callHandlerInImage(){
imageController = new ImageController();
imageController.handleCrop();
}
}
ImageController:
public class ImageController {
#FXML
private ImageView MainImage;
#FXML
private void initialize() {
modelSharedOne.imageProperty()
.addListener((obs, oldImage,newImage)-> MainImage.setImage(newImage));
}
public void handleCrop() {
Image image = getImage();
ImageView imageView = new ImageView(image);
rect = new Rectangle( 0,0,0,0);
rect.setStroke(Color.BLUE);
rect.setStrokeWidth(1);
rect.setStrokeLineCap(StrokeLineCap.ROUND);
rect.setFill(Color.LIGHTBLUE.deriveColor(0, 1.2, 1, 0.6));
Group imageLayer = new Group();
imageLayer.getChildren().add(imageView);
rubberBandSelection = new RubberBandSelection(imageLayer);
}
}
And rubberBandSelection is a class as it was in the linked. when I run that it does not hit when mouse pressed on image.
I a have tabPane with multiple tabs and inside one of the tabPane i have scrollPane. Inside the scrollPane i have a number of UI controls As shown on this image that i want to be dynamically added when i click a button.
This image here shows the UI setup of what i have. The UI controls are in an Hbox which is inside a Vbox.
When a user clicks the add button i would like to add another row with all the controls as shown in this image.
I have looked at post such as these and still cannt get to achieve the same effect on my code.
JavaFX continuous form dynamically add new row with content in gridpane,
Dynamically add elements to a fixed-size GridPane in JavaFX,
How to maintain GridPane's fixed-size after adding elemnts dynamically
When i followed the approach suggested by another stack-overflow member on the first question cited above, to use a listView the code worked. However his suggestion programmatically codes UI controls and when i try to change and use UI controls i created within scene builder it doesn't work. Also when i put the controls inside a tabPane my code doesn't work. Meaning when i click the add button it doesn't add the UI controls as expected.
My question is how can i dynamically add UI controls within a tab inside a tabPane when a button which is also in that tab is clicked.
Here is my code :
public class DynamicalyAddControlsController {
#FXML
private VBox vbox;
#FXML
private HBox hbox;
#FXML
private StackPane stack1;
#FXML
private Label taskid;
#FXML
private TextField taskname;
#FXML
private ComboBox<String> combobox;
#FXML
private TextArea textarea;
#FXML
private Button save;
private ObservableList<Car> cars = FXCollections.observableArrayList();
public void initialize(URL url, ResourceBundle rb) {
cars.addAll(new Car(CAR_TYPE.CAR1), new Car(CAR_TYPE.CAR2), new Car(CAR_TYPE.CAR3));
ListView<Car> carsListView = new ListView<>();
carsListView.setCellFactory(c -> new CarListCell());
carsListView.setItems(cars);
stack1.getChildren().add(carsListView);
}
private class CarListCell extends ListCell<Car> {
private ChoiceBox<CAR_TYPE> choiceBox = new ChoiceBox<>();
public CarListCell(){
choiceBox.setItems(FXCollections.observableArrayList
(CAR_TYPE.values()));
hbox.getChildren().addAll(taskid,taskname,combobox,choiceBox);
vbox.getChildren().addAll(hbox,textarea);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setGraphic(vbox);
}
#Override
protected void updateItem(Car item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
} else {
setGraphic(vbox);
choiceBox.setValue(item.getType());
save.setOnAction(e -> {
Car newCar = new Car(choiceBox.getValue());
cars.add(newCar);
});
}
}
}
private enum CAR_TYPE {
CAR1, CAR2, CAR3;
}
private class Car {
private CAR_TYPE type;
public Car(CAR_TYPE type) {
this.type = type;
}
public CAR_TYPE getType() {
return type;
}
public void setType(CAR_TYPE type) {
this.type = type;
}
}
public void initialize(URL url, ResourceBundle rb) {
}
}
JavaApplication main class
#Override
public void start(Stage primaryStage) throws Exception{
Parent viewB = FXMLLoader.load(getClass().getResource("DynamicalyAddControls.fxml"));
Stage stageB = new Stage();
stageB.setScene(new Scene(viewB));
stageB.show();
}
public static void main(String[] args) {
launch(args);
}
Having gone through about all the answers related to my posted question, i was able to get the desired result but my first fxml was missing some details. After rectifying it, the second fxml page has refused to load. My first fxml page has got a button while the second fxml is a simple login page. I would appreciate any detailed assistance because I've been battling with it for like a week trying various codes.
TestPatch.java
public class TestPatch extends Application {
#Override
public void start(Stage stage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("WinSecHome.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
First controller
public class WinSecAdminLoginController implements Initializable {
#FXML
TextField usernameInput;
#FXML
PasswordField passwordInput;
#FXML
Button loginButtton;
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void loginAction(ActionEvent event) {
}
}
Second Controller
public class WinSecHomeController implements Initializable {
#FXML
Button button;
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
#FXML
private void buttonAction(ActionEvent event) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("WinSecAdminLogin.fxml"));/* Exception */
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();
}
}