I'm creating my first JavaFX application, and I'm doing OK so far. I'm just encountering one problem.
For displaying and loading FXML files I'm using a VistaNavigator class found on StackOverflow:
public static void loadVista(String fxml) {
try {
mainController.setVista(
FXMLLoader.load(
VistaNavigator.class.getResource(
fxml
)
)
);
} catch (IOException e) {
e.printStackTrace();
}
}
I have a ScanController, which receives input from the keyboard and checks a ticket ID based on this input. When the ticket is OK, it loads "scan-success.fxml", otherwise it loads "scan-failure.xml", each of these FXML-files have an own controller. I'm loading the success FXML like this:
VistaNavigator.loadVista(VistaNavigator.VISTA_SCAN_SUCCESS);
This is working great. The Success-FXML page is showing and the ScanSuccessController is loading. In the initialize() method of ScanSuccessController.java I have the following code snippet:
try {
Thread.sleep(2000); //1000 milliseconds is one second.
VistaNavigator.loadVista(VistaNavigator.VISTA_SCAN_HOME);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
So I would like to show the success-page for about 2 seconds, and then head back to the home screen (scan-home.fxml with controller ScanHomeController.java) to scan some more tickets. However, when executing this code, just 'nothing' happens, no exception and no change of FXML-file.
When I try to load a new vista after clicking a button (in an EventHandler) it works great.
I can imagine that JavaFX is not able to load a new FXML-file before the controller has been fully initialised, but cannot figure out where to put this line of code..
I hope someone can help me out with this.
What about this:
#Override
public void initialize(URL url, ResourceBundle rb) {
Timeline timeline=new Timeline();
timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(2),
e->VistaNavigator.loadVista(VistaNavigator.VISTA_SCAN_HOME)));
timeline.play();
}
Note that by using a Timeline everything runs in the JavaFX thread.
Related
I am working on my first JavaFX app with FXML file.
My program consists of few elements:
addDeviceButton (addMyoButton)
few TextArea, that will have printed data collected from device.
Short description of working:
Pressing addDecideButton should start collecting data from
DataController (DeviceListener),
Collected data and system
communicates should be printed to TextAreas.
I have two problems:
printing in TextArea doesn't work,
app freezes (doesn't respond after pressing addMyoButton)
In 1) I have no idea what's wrong. With 2) I think I shouldn't put running dataCollector in method responsible for button event. However, I'm not sure how to make this properly.
Do you have any suggestions, ideas how I should write these fragments??
Is the problem in FXML or methods?
Responsible of this part of FXML file looks like:
<TextArea fx:id="communicateTextField"
prefHeight="300.0" prefWidth="300.0" >
<Button fx:id="addMyoButton"
onAction="#addMyo" >
Method addMyo(), that runs after pressing button.
public void addMyo(ActionEvent event) {
try {
Hub hub = new Hub("com.example.hello-myo");
communicateTextField.setText("Attempting to find a Myo...");
Myo myo = hub.waitForMyo(10000);
if (myo == null) {
throw new RuntimeException("Unable to find a Myo!");
communicateTextField.setText(""Unable to find a Myo!");
}
communicateTextField.setText("Connected to a Myo armband!");
DeviceListener dataCollector = new DataCollector();
hub.addListener(dataCollector);
while (true) {
hub.run(1000 / 20);
communicateTextField.setText(dataCollector);
}
} catch (Exception e) {
System.err.println("Error: ");
e.printStackTrace();
System.exit(1);
}
}
Method for printing communicates to TextArea
public void printCommunicate(String communicate) {
communicateTextField.setText(communicate);
}
When Launching the app , directly an intro video kicks in,
I have 2 scenarios :
Watch Full intro , then automatically redirect to another page
Click Skip button to get instantly redirected to another page
both of these 2 scenarios are working flawlessly when I run the app from the IDE,
but when a package the app to jar format the first scenario never work ( see the code for more details )
the Class :
public class SplashScreenController implements Initializable {
#FXML
private HBox introView;
#FXML
private Label btSkipIntro;
MediaPlayer player;
#Override
public void initialize(URL location, ResourceBundle resources) {
// INTRO VIDEO PROCESS ------------------------
player = new MediaPlayer(new Media(getClass().getResource("/Images/SeffirIntro.mp4").toExternalForm()));
MediaView mediaView = new MediaView(player);
mediaView.setPreserveRatio(true);
mediaView.setSmooth(true);
introView.getChildren().add(mediaView);
System.out.println("Started");
player.play();
player.setOnEndOfMedia(() -> {
System.out.println("Ended");
try {
// Code to automatically redirect to another page
Entry.viewNavigator.openView("/Views/LanguageView.fxml");
} catch (IOException e) {
e.printStackTrace();
}
});
#FXML // When the skip button clicked
public void skipClicked() throws IOException{
System.out.println("Skipped");
player.stop();
Entry.viewNavigator.openView("/Views/LanguageView.fxml");
}
in my IDE testing the ( player.setOnEndOfMedia lambda function executes beautifly) but when the jar executes that function is never accessed.
The JAR creation was tested with both maven and the artifact build , both same result the function after when the video ends , doesn't fire
any explanation on why is this issue is happening will be of great help
thanx in advance
I'm fixing a JavaFX application on JDK 8. The app shows multiple images using something like "jLabel.setIcon(new Image(...))". I know their is a component to show images in JavaFX but it is not the issue (because I'm not allowed to modify neither that part from the source nor the FXML files).
My problem is when minimize or change the window ((using ALT+TAB)) and wait some time (even up 1 hour approx) to come back to the window, this doesn't show the images anymore. However, if I move the window, the images come back.
In an attempt to fix the problem (independently of use the minimize button or ALT+TAB), I added in the final of the init() method this piece of code:
public void init() {
...
stage.focusedProperty().addListener((observable, oldvalue, newvalue) -> {
if (newvalue) repaintImages();
});
}
private void repaintImages() {
Object obj = new Object();
synchronized (obj) {
jLabel.repaint();
jLabel.revalidate();
obj.notify();
}
try {
obj.wait();
} catch (Exception e) {
}
}
The code before runs repaintImages() after the windows is focused. I used synchronized with the idea to be ensured the code is executed in thread-safe (independently of lag), Anyway that doesn't fix the problem (images are missing yet). After that, I change this the code to use runLater():
public void init() {
...
stage.focusedProperty().addListener((observable, oldvalue, newvalue) -> {
if (newvalue) Platform.runLater(()->{repaintImages();});
});
}
private void repaintImages() {
Platform.runLater(() -> {
jLabel.repaint();
jLabel.revalidate();
});
}
And it doesn't work either. Please, any suggestion is welcome.
I know, I wrote a long question, but maybe a suggestion could be to move the window when it is focused. In that case, please give the correct way to do this because I tried and not worked too (using synchronized and runLater()). This is the piece of code I used to move the window (placing this into a synchronized block or in the lambda function in runLater()):
Translate elements = null;
if (positive_flag) {
elements = new Translate(1, 0, 0);
positive_flag = false;
} else {
elements = new Translate(-1, 0, 0);
positive_flag = true;
}
anchorPane.getTransforms().addAll(elements);
Finally, consider that to prove if any solution works, I need to wait even up 1h.
I have this code (part of a quite big application):
The following function is located in the controller class of the project.
public void callSearch(){
Stage supplyStage = new Stage();
Parent root = null;
try {
root = FXMLLoader.load(getClass().getResource("supplyResult.fxml"));
supplyStage.setTitle("Supply Result Set");
supplyStage.setScene(new Scene(root, 1400, 900));
supplyStage.show();
} catch (IOException e) {
e.printStackTrace();
}
try {
typeColumn.setCellValueFactory(new PropertyValueFactory<Supply, String>("type"));
nameColumn.setCellValueFactory(new PropertyValueFactory<Supply, String>("name"));
dateColumn.setCellValueFactory(new PropertyValueFactory<Supply, String>("order_date"));
pricePerUnitColumn.setCellValueFactory(new PropertyValueFactory<>("pricePerUnit"));
quantityColumn.setCellValueFactory(new PropertyValueFactory<>("quantity"));
}
catch (NullPointerException npe){
System.out.println("Null...");
}
searchSupplyStartDate = java.sql.Date.valueOf(startDateDatePicker.getValue());
searchSupplyEndDate = java.sql.Date.valueOf(endDateDatePicker.getValue());
tableOutput.setItems(myMain.getSupplies(searchSupplyStartDate,searchSupplyEndDate,null,null));
}
My problem is that I get a NullPointerException in the line typeColumn.setCellValueFactory(new PropertyValueFactory<Supply, String>("type"));
In previous version of the application I had the columns in the same window as the rest of the scene. Now I try to add a second window when displaying the same stuff, to make the first scene a bit more beautiful. (the code was working when I had one scene).
In fact, to make things clear, i want with the press of a button, the function callSearch() to be called. Then a window appears, with a table of 5 columns attached: typeColumn, nameColumn, dateColumn, pricePerUnitColumn, quantityColumn. Those 5 columns are declared in the (only) controller of the project, so i thought that they are visible in any fxml file in the project, but that's not the case.
Does anybody know what am I missing? the typeColumn is visible from the SupplyResult.fxml in scene builder, but does not seem to execute the code it has to...
(note, what i newbie in java)
I a little bit stuck in solving the problem of pass object between javafx scenes and classes.
For example, i have class, which waits for data by server; main class and 2 javafx windows.
Let it looks like this:
Listener.java.
Let it work at another thread. When we got "nelo" from server, then it'll means, what user not logged it, and then, we should open Login Window
// some package
// some imports
public class Listener extends Thread {
public void run() {
System.out.println("[INF] Wait for server...");
while(true) {
handle();
}
}
public void handle()
{
try {
byte[] token = new byte[6];
DataInputStream src = new DataInputStream(in);
src.read(token);
String token_val = new String(token);
switch (token_val) {
case "_nelo_":
System.out.println("[INF] Auth required");
break;
}
} catch (IOException e) {
}
}
}
Okay, there nothing weird. Just simple class for listening.
But here my troubles started. I try to explain it. (previosly, Sorry for bad english, i still learn this language)
Lets create login window (imagine that fxml file and controller created :) ):
// some package
// some imports
public class WindowLogin extends Application{
private Stage stage;
#Override
public void start(Stage primaryStage) throws Exception {
stage = new Stage();
try {
URL location = getClass().getResource("../views/WindowLogin.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
Parent root = (Parent) fxmlLoader.load(location.openStream());
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void show(){
launch();
}
}
So, when user open application, client will try connect to server.
If connection success, then server ask client for auth (Show login window). Next - user enter login and pass and click "Login" button. (Login Window show some indication of proccess). If auth success - Hide login, else - show some info in window.
As a result, i need access from Listener to Login window Controller. i.e. as i wrote before - different answer from server - different elements displayed.
How i can realize access to LoginWindowController ?
Thanks in advance
I will give you basic guidance for each task:
Connection
If connection with the server is successful then:
Platform.runLater(new Runnable() {
public void run() {
try {
WindowLogin login = new WindowLogin();
login.start(new Stage());
} catch (Exception e) {
e.printStackTrace();
}
}
});
Login
Error
You set a blank label on the WindowController and if the user cound't autheticate, than you fill this label.
Succesful login
You could use the same Platform.runLater as I used it before, or you could do something using stackpane and changing it's order ( I strongly recommend to use the Platform.runLater).