JavaFX creating a new scene from KeyCombination correctly - model-view-controller

I dont like menu bars so I am limiting my application to KeyCombinations to spawn events. I have the key combination working however I have a feeling I am not using controllers correctly. I need to edit the new scene within my controller but instead I find myself doing so within the try/catch of the KeyCombination event.
I would like to make all changes to the scene in class SettingsController.java
where I create a new scene/view
final KeyCombination settingsCMD = new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN);
scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>()
{
#Override
public void handle(KeyEvent event)
{
if (settingsCMD.match(event))
{
System.out.println("CTRL + S was pressed on " + name + " display\n" +
"Opening Settings Scene");
/*
* This is where we need to launch a scene for settings
*/
try
{
Parent root = FXMLLoader.load(getClass().getResource("/sample/view/settingsscreen.fxml"));
Stage settingsStage = new Stage();
settingsStage.setTitle("Settings");
settingsStage.setScene(new Scene(root, 500 , 400));
settingsStage.show();
// This really needs to be done in the controller. How do I do this?
JSON jsonTools = new JSON();
jsonTools.readJSONSettings();
jsonTools.writeJSONSettings();
} catch (Exception e)
{
e.printStackTrace();
}
}
}
});
SettingsController.java
public class SettingsController
{
#FXML private TextField hostname;
public String getText()
{
String textProp = textProperty().get();
System.out.println("testProperty is " + textProp + "\n");
return textProp;
}
public void setText(String value)
{
textProperty().set(value);
}
private StringProperty textProperty()
{
return hostname.textProperty();
}
}

You can get a reference to the view controller class from the FXMLLoader:
FXMLLoader loader = new FXMLLoader(getClass().getResource(resource));
Scene scene = new Scene(loader.load());
parentStage.setScene(scene);
Controller controller = loader.getController();
On this reference you can call the appropriate method
final KeyCombination settingsCMD = new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN);
scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>()
{
#Override
public void handle(KeyEvent event)
{
if (settingsCMD.match(event))
{
System.out.println("CTRL + S was pressed on " + name + " display\n" +
"Opening Settings Scene");
/*
* This is where we need to launch a scene for settings
*/
try
{
FXMLLoader loader = new FXMLLoader.load(getClass().getResource("/sample/view/settingsscreen.fxml"));
Parent root = loader.load();
SettingsController controller = loader.getController();
Stage settingsStage = new Stage();
settingsStage.setTitle("Settings");
settingsStage.setScene(new Scene(root, 500 , 400));
settingsStage.show();
controller.yourMethod();
} catch (Exception e)
{
e.printStackTrace();
}
}
}
});

Related

Vaadin auto refresh grid data's based on API call in every 30 seconds

I need to call an API every 30 seconds and need to refresh the grid with updated data. I using Server push, but I can't find the optimal solution in my case. Below is my UI code
#Route(value = UserNavigation.ROUTE)
#PreserveOnRefresh
#org.springframework.stereotype.Component
public class UserNavigation extends AppLayout {
CCUIConfig config;
#Autowired
public UserNavigation( CCUIConfig config) {
this.config = config;
addToDrawer(createAccordianMenu());
}
private Component createAccordianMenu() {
VerticalLayout scrollableLayout = new VerticalLayout();
Div kioskMonitor_div = new Div(kiosksMonitorLabel);
kioskMonitor_div.addClickListener(event -> {
try {
setContent(new Monitor(config).getDashboard());
} catch (Exception e) {
e.printStackTrace();
}
});
scrollableLayout.add(kioskMonitor_div);
return scrollableLayout;
}
}
#Push
#Route
public class Monitor extends VerticalLayout{
CCUIConfig config;
Grid<Model> grid = new Grid<>();
private FeederThread thread;
public Monitor(CCUIConfig config) {
this.config = config;
}
#Override
protected void onAttach(AttachEvent attachEvent) {
// Start the data feed thread
super.onAttach(attachEvent);
thread = new FeederThread(attachEvent.getUI(),grid);
thread.start();
}
#Override
protected void onDetach(DetachEvent detachEvent) {
thread.interrupt();
thread = null;
}
public Component getDashboard() throws IOException{
String updateddate =null;
VerticalLayout dashboardview = new VerticalLayout();
Grid.Column<Model> idColumn = grid.addColumn(Model::getid)
.setHeader(ID);
Grid.Column<Model> nameColumn = grid.addColumn(Model::getName)
.setHeader(Name);
Grid.Column<Model> memoryColumn = grid.addColumn(Model::getRefreshTime)
.setHeader(Refresh time"));
dashboardview.add(grid);
return dashboardview;
}
}
class FeederThread extends Thread {
private final com.vaadin.flow.component.UI ui;
private final Grid<Model> grid;
private final CCUIConfig config;
private int count = 30;
public FeederThread(com.vaadin.flow.component.UI ui,Grid<Model> grid) {
this.config = new CCUIConfig();
this.ui = ui;
this.grid= grid;
}
#Override
public void run() {
while (count>0){
try {
Thread.sleep(1000);
ui.access(()-> {
System.out.println("Thread Entry ");
try {
StringBuilder jsongrid = HttpClientGetRequestClient.executeUrlGet(config.getRefreshAPI());
ObjectMapper mapper = new ObjectMapper();
List<Model> userlist = new ArrayList<Model>();
String date="";
if(jsongrid!=null)
{
ModelWrapper eh = mapper.readValue(jsongrid.toString(), ModelWrapper.class);
userlist = eh.getMetricsData();
}
if(userlist != null)
{
grid.setItems(userlist);
grid.getDataProvider().refreshAll();
}
}catch(JSONException |JsonProcessingException e) {
e.printStackTrace();
}
});
count--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
UserNavigation is the page that loads after user login, it contains a sidebar with multiple options(or functionalities). One of the functionality is the Monitor screen.
Monitor is the page with a grid where we need to refresh it in 30 seconds.
FeederThread is the thread class that calls an API and update the data in the grid asynchronously.
As from the above code, what happens is like
onAttach(AttachEvent attachEvent)
is not getting executed so the grid is not getting displayed on the page, we use vaadin 14, any help will be appreciated.

javafx User interface not updating?

I'm new to JavaFX.
I'm building a GUI for a project of mine, and I have a problem with it -
it seems that once I show my UI it stops updating.
In my case, it supposed to update a fill colour for a circle but it does not.
I tried to move the line:
someCircleId.setFill(color));
to be above the line:
Main.stage.show();
in the initialize function in my code and it did change the color of
the certain circle.
public class UIController implements Initializable {
public UIController() {
fillMap();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
Main.stage.show();
}
#FXML
public void pressExitButton() {
Main.dropDBSchema();
System.exit(0);
}
public void changeCircleColor(String circleKey, Color color) {
Platform.runLater(
() -> {
Circle circle = this.circles.get(circleKey);
PauseTransition delay = new PauseTransition(Duration.seconds(10));
delay.setOnFinished(event -> circle.setFill(color));
delay.play();
}
);
}
}
And this is the class that uses these functions:
public class MonitoringLogicImpl implements MonitoringLogic {
public void updateUI(UUID flowUUID, String sender, String receiver, DATA_STATUS status){
String key = flowUUID.toString()+"_"+sender+"_"+receiver;
Color color = this.uiController.getColorAccordingToStatus(status);
this.uiController.changeCircleColor(key, color);
}
}
This is the FXML initialization :
public void start(Stage stage){
this.stage = stage;
FXMLLoader loader = new FXMLLoader();
try {
loader.setLocation(getClass().getResource("/UserInterface.fxml"));
this.root = loader.load();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
stage.setTitle("Troubleshooting project");
stage.setScene(new Scene(root, 900, 700));
stage.show();
}
I created my UI using Scene-Builder tool.

JavaFX more Scenes

Hi Guys i build a GUI and on this GUI is a Button and when I press the Button a second GUI appears, on the second GUI is also a Button and when i press the Button it goes back
GU1
btn.setOnAction(new EventHandler <ActionEvent>(){
public void handle(ActionEvent arg0) {
try {
new GUI2().start(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
});
My Questions!
Is GUI1 still running when i press the Button?
GUI2
btn.setOnAction(new EventHandler <ActionEvent>(){
public void handle(ActionEvent arg0) {
try {
//back to the main menu
new GUI1().start(primaryStage);
} catch (Exception e) {
e.printStackTrace();
}
}
});
When i press the Button, does it go back to the same instance when beginning the program? Or make it a new Instance witch has the same look, and use it more RAM;
How should it works, when i want to open the second GUI in a external Window
When i press the Button, does it go back to the same instance when beginning the program?
No, a new instance is created based on your code new GUI2().start(primaryStage);. Always remember that thenew keyword ALWAYS creates a new object.
How should it works, when i want to open the second GUI in a external Window?
There are lots of ways to do this.
Method 1
If it happen that you created two applications, both extending the Application class, this method should work.
public class MultiWindowFX {
private static final Logger logger = Logger.getGlobal();
public static class GUI1 extends Application {
private final Button buttonShowGUI2;
private final GUI2 gui2;
public GUI1() {
buttonShowGUI2 = new Button("Show GUI 2");
gui2 = new GUI2();
}
public Button getButtonShowGUI2() {
return buttonShowGUI2;
}
#Override
public void start(Stage primaryStage) throws Exception {
//add an action event on GUI2's buttonShowGUI1 to send front GUI1
gui2.getButtonShowGUI1().setOnAction(gui2ButtonEvent -> {
if (primaryStage.isShowing()) primaryStage.toFront();
else primaryStage.show();
});
//button with action to show GUI 2
buttonShowGUI2.setOnAction(actionEvent -> {
try {
if (gui2.getPrimaryStage() == null) gui2.start(new Stage());
else gui2.getPrimaryStage().toFront();
} catch (Exception ex) {
logger.log(Level.SEVERE, null, ex);
}
});
//set scene and its root
Pane root = new StackPane(buttonShowGUI2);
Scene stageScene = new Scene(root, 400, 250);
//set stage
primaryStage.setScene(stageScene);
primaryStage.centerOnScreen();
primaryStage.setTitle("GUI 1");
primaryStage.show();
}
public static void launchApp(String... args) {
GUI1.launch(args);
}
}
public static class GUI2 extends Application {
private Stage primaryStage;
private final Button buttonShowGUI1;
public GUI2() {
buttonShowGUI1 = new Button("Show GUI 1");
}
public Button getButtonShowGUI1() {
return buttonShowGUI1;
}
public Stage getPrimaryStage() {
return primaryStage;
}
#Override
public void start(Stage primaryStage) throws Exception {
//get stage reference
this.primaryStage = primaryStage;
//set scene and its root
Pane root = new StackPane(buttonShowGUI1);
Scene stageScene = new Scene(root, 400, 250);
//set stage
primaryStage.setScene(stageScene);
primaryStage.centerOnScreen();
primaryStage.setTitle("GUI 2");
primaryStage.show();
}
public static void launchApp(String... args) {
GUI2.launch(args);
}
}
public static void main(String... args) {
GUI1.launchApp(args);
}
}
Method 2
For me, this is the best approach especially if you want window ownership and modality works.
public class GUI1 extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Show GUI2");
btn.setOnAction(actionEvent -> {
//prepare gui2
Stage gui2Stage = createGUI2();
//set window modality and ownership
gui2Stage.initModality(Modality.APPLICATION_MODAL);
gui2Stage.initOwner(primaryStage);
//show
gui2Stage.show();
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 400, 250);
primaryStage.setTitle("GUI 1");
primaryStage.setScene(scene);
primaryStage.show();
}
private Stage createGUI2() {
Button btn = new Button();
btn.setText("Show GUI1");
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 150);
Stage gui2Stage = new Stage();
gui2Stage.setTitle("GUI 2");
gui2Stage.setScene(scene);
//add an action event to GUI2's button, which hides GUI2 and refocuses to GUI1
btn.setOnAction(actionEvent -> gui2Stage.hide());
return gui2Stage;
}
public static void main(String[] args) {
launch(args);
}
}
...and among other methods. Choose the approach that fits to your requirements.

How to create a new Image() with an image file located in a directory outside the current working directory

I'm trying to list iamges in a TilePane. I get an error when I try to create an Image, new ImageView("address"); with a address like so:
"file:D:/Chrysanthemum.jpeg/"
The above is in a directory outside the current working directory. The other images are inside the class path.
Here's the rest of the code in an scec:
public class TilePaneExample extends Application {
#Override
public void start(Stage primaryStage) {
VBox root = new VBox(30);
String[] imageResources = new String[]{
//loading images
"file:D:/Chrysanthemum.jpeg/",
"ImageResources/faviicon.png",
"ImageResources/jquery-logo.png",
"ImageResources/linkedin_32.png",
"ImageResources/loading1.png",
"ImageResources/twitter.png",
"ImageResources/twitter_32.png",
"ImageResources/wp.png",};
// Pane
TilePane tilePane = new TilePane();
tilePane.setHgap(5);
tilePane.setVgap(5);
for (final String imageResource : imageResources) {
Image image = new Image(getClass().getResourceAsStream(imageResource));
ImageView imageView = new ImageView(image);
imageView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
File f = new File(imageResource);
String absolutePath = f.getAbsolutePath();
String folderPath = absolutePath.
substring(0, absolutePath.lastIndexOf(File.separator));
System.out.println(folderPath);
try {
// Desktop.getDesktop().open(new File("D:\\WAKILI\\WAKILIdb"));
Desktop.getDesktop().open(new File(folderPath));
} catch (IllegalArgumentException iae) {
System.out.println("File Not Found");
} catch (IOException ex) {
Logger.getLogger(TilePaneExample.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
tilePane.getChildren().add(imageView);
}
root.getChildren().addAll(tilePane);
primaryStage.setTitle("TilePane Example");
Scene scene = new Scene(root, 300, 150);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The error:
Caused by: java.lang.NullPointerException: Input stream must not be null
Please help. Thank you all.
You are using getClass().getResourceAsStream(imageResource) even for your none classpath images, pass the URL-String directly for cases you are not loading from the classpath:
Image image;
if(imageResource.startsWith("file:")) {
image = new Image(imageResource);
} else {
image = new Image(getClass().getResourceAsStream(imageResource));
}

transition animation for switching JAVA FX FXML

How to add transition animation in javafx when switching between fxml files.
I am working javafx project. I having trouble to changing fxml with using animation add to it.
Here is the code for switching fxml.
public void start(Stage primaryStage) {
try {
stage = primaryStage;
gotohome();
primaryStage.show();
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void gotohome() {
try {
FXMLController home = (FXMLController) replaceSceneContent("Homepage.fxml");
home.setApp(this);
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void gotoproductwise() {
try {
SampleController product_wise = (SampleController) replaceSceneContent("/product_wise/product_wise.fxml");
product_wise.setApp(this);
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
private Initializable replaceSceneContent(String fxml) throws Exception {
FXMLLoader loader = new FXMLLoader();
InputStream in = Main.class.getResourceAsStream(fxml);
loader.setBuilderFactory(new JavaFXBuilderFactory());
loader.setLocation(Main.class.getResource(fxml));
AnchorPane page;
try {
page = (AnchorPane) loader.load(in);
} finally {
in.close();
}
// Store the stage width and height in case the user has resized the window
double stageWidth = stage.getWidth();
if (!Double.isNaN(stageWidth)) {
stageWidth -= (stage.getWidth() - stage.getScene().getWidth());
}
double stageHeight = stage.getHeight();
if (!Double.isNaN(stageHeight)) {
stageHeight -= (stage.getHeight() - stage.getScene().getHeight());
}
Scene scene = new Scene(page);
if (!Double.isNaN(stageWidth)) {
page.setPrefWidth(stageWidth);
}
if (!Double.isNaN(stageHeight)) {
page.setPrefHeight(stageHeight);
}
// stage.setOpacity(1);
stage.setScene(scene);
stage.sizeToScene();
return (Initializable) loader.getController();
}

Resources