Looking to update GUI first thing upon click of a button however Platform.runLater executes at a later stage and am looking for the piece of code which updates the GUI to happen first thing upon click of a button.
Platform.runLater(new Runnable() {
#Override
public void run() {
//Update GUI here
}
});
Would highly appreciate if anyone can provide any inputs or recommendations.
Although the API specifies that Platform.runLater "runs the specified Runnable on the JavaFX Application Thread at some unspecified time in the future", it usually takes little to no time for the specified thread to be executed. Instead, you can just add an EventHandler to the button to listen for mouse clicks.
Assuming the controller implements Initializable
#FXML Button button;
#Override
public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
button.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
updateGUI();
}
});
}
private void updateGUI() {
// code
}
Related
I want to be able to see updates on my graphical interface while the program is executing and not to wait till the click event on button ends
public class MainController implements Initializable {
#FXML
private label label;
#Override
public void initialize(URL url, ResourceBundle rb) {
}
private void Event(ActionEvent event) {
// start is a button
if (event.getSource() == Start) {
// calculations
// updating label
label.setText(" update me ");
// other calculations
// updating label for the second time
label.setText(" update me ");
}
}
}
This is a simple example of my code (javaFXML), please note that the calculations and updates are more complicated than the demonstrative example and takes too much time to execute that's why I want to preview updates while executing.
You should Know and use the threads concept
Your code will be like this:
if (event.getSource() == Start) {
new Thread(new Runnable() {
#Override
public void run() {
//do the calculations
System.out.println("calculations is finished");
}
}).start();
// updating label
label.setText(" update me ");
new Thread(new Runnable() {
#Override
public void run() {
//do the other calculations
System.out.println("calculations is finished");
}
}).start();
// updating label for the second time
label.setText(" update me ");
}
But you must be aware the synchronization problems that may occur between the calculations.
I recommend you follow this course :
https://www.youtube.com/playlist?list=PLBB24CFB073F1048E
I have a method that takes a while to complete, when the jar application is started. To have some feedback, i created the form frmWaiting, that displays a simple indeterminate progress bar. I also have a controller for the form,
PrincipalController.
Entry point for the application
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Stage stagePrincipal = new Stage();
Parent parentPrincipal = FXMLLoader.load(getClass().getClassLoader().getResource("frmPrincipal.fxml"));
Scene scenePrincipal = new Scene(parentPrincipal, 300, 275);
stagePrincipal.setScene(scenePrincipal);
stagePrincipal.setHeight(400);
stagePrincipal.setWidth(500);
stagePrincipal.setResizable(false);
stagePrincipal.setTitle("Instalador");
stagePrincipal.show();
} catch (Exception e) {
e.printStackTrace();
}
}
PrincipalController - frmPrincipal.fxml:
#Override
public void initialize(URL location, ResourceBundle resources) {
try {
Stage stageWaiting = new Stage();
Parent parentWaiting;
parentWaiting = FXMLLoader.load(getClass().getClassLoader().getResource("frmWaiting.fxml"));
Scene sceneWaiting = new Scene(parentWaiting, 300, 275);
stageWaiting.setScene(sceneWaiting);
stageWaiting.setHeight(300);
stageWaiting.setWidth(400);
stageWaiting.setResizable(false);
stageWaiting.setTitle("Instalador");
stageWaiting.show();
} catch (IOException e) {
}
}
WaitingController - frmWaiting.xml:
public class WaitingController implements Initializable {
#FXML private ImageView img;
#FXML private ProgressBar progressBar;
#FXML private ProgressIndicator pgIndicator;
private Task copyTask;
#Override
public void initialize(URL location, ResourceBundle resources) {
img.setImage(new Image(getClass().getClassLoader().getResourceAsStream("image.png")));
progressBar.setProgress(ProgressBar.INDETERMINATE_PROGRESS);
ArquivoController.getInstance().copiaArquivosPadrao(); //This is the method that takes a while.
}
public ProgressBar getProgressBar() {
return progressBar;
}
I want to initialize my main form, frmPrincipal, when my method that takes a while finishes. I also want to get the progress bar working. I have tried to do it on another Thread, but i could not get the response from it when the method finishes.
All the .fxml files are correct, ommited them to make things easier if possible.
The way it is, the application waits for the method to finish, then opens the other form. But, the progressBar does not update.
Inside ArquivoController.getInstance().copiaArquivosPadrao(); you have to update the progressBar's progress.
You could do it the nice way, using a Task to run copiaArquivosPadrao(), update the tasks progress accordingly and binding to the tasks progress property.
Or you could do it the ugly way, passing progressBar to copiaArquivosPadrao(), something like this:
public void initialize(URL location, ResourceBundle resources) {
img.setImage(new Image(getClass().getClassLoader().getResourceAsStream("image.png")));
progressBar.setProgress(ProgressBar.INDETERMINATE_PROGRESS);
ArquivoController.getInstance().copiaArquivosPadrao(progressBar); //This is the method that takes a while.
}
and
public void copiaArquivosPadrao(ProgressBar progressBar) {
// call progressBar.setProgress() in here to update the progress bar
// eg.
progressBar.setProgress(0.0F);
doSomething();
progressBar.setProgress(0.20F);
doSomething();
progressBar.setProgress(0.40F);
doSomething();
progressBar.setProgress(0.60F);
doSomething();
progressBar.setProgress(0.80F);
doSomething();
progressBar.setProgress(1.00F);
}
For sure, you can do this more fine-grained in a loop or similar.
public void handle(){
submit.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
LoginConnection login = new LoginConnection();
boolean pass = login.login(usernameField.getText(), passwordField.getText());
if(pass)
flip(SceneNames.Main);
else
invalLoginMessage.setOpacity(1.00);
}
});
register.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
flip(SceneNames.Register);
}
});
}
When i click on submit or register, it takes two click for it to do anything. How do i fix this?
What happens is that on first click it adds the handlers specified in the method and on second and consecutive clicks, it uses the handlers. To fix it just create separate methods to add through fxml or scene builder.
I need to keep focus on JTextField. Application uses Swing library. I need set focus on that field from time to time in order to avoid user mistakes that would change focus to other comonents. I suppose I need to use SwingWorker. Set focus is an operation on Swing
component so it should be invoked in EDT. My question is how to write SwingWorker to do that?
I know that method done() pass tasks to be invoked in EDT but I need this task to be invoked every let's sey 2 seconds. Method done() is called one time.
So maybe sth like this will be ok?
public class myWorker extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//here set focus on JTextField
return null;
}
});
}}
Edit:
I noticed that method process() that is a part of SwingWorker may be appropriate beacuse it is invoked in EDT. I'm not sure but this method is probably invoked always when I call publish() metod. So could you tell me if this code is valid to do this task?
private class KeepFocusWorker extends SwingWorker<Void, Void>
{
#Override
protected Void doInBackground() throws Exception
{
while(true)
{
publish();
}
}
#Override
protected void process(List<Void> chunks)
{
codeBar.requestFocusInWindow();
}
}
Use javax.swing.Timer instead of SwingWorker. In this case actionPerformed will be executed in EDT. Also to set focus in a component, you need to call requestFocus. As the name suggests, it is a request only and not guaranteed. So you may change you approach.
Timer timer = new Timer(2000, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
codeBar.requestFocus();
}
});
timer.setRepeats(true);
timer.start();
Surely it's better to limit the user's ability to take focus away from the textfield in the first place? Personally I don't see why it's an issue but I suppose it's better to keep focus in the one component rather than letting the user shift focus only for it to be shifted back every few seconds.
Therefore you could add a FocusListener to the component, override the focusLost method and basically requestFocus() again.
codeBar.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
codeBar.requestFocus();
}
});
NB I've not actually tried this myself but can't see why it wouldn't work.
Alternatively you can use an InputVerifier which always returns false to prevent focus being taken away.
i have an application in java, and this have a one popup with javafx application (embed videos from Youtube). I see this correctly but when i close this popup, the javafx thread not close and javafx application running in background. This is my javafx class:
public class JavaFXClass extends Application {
#Override
public void start(final Stage stage) throws Exception {
final WebView webview = new WebView();
/*...*/
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Platform.runLater( new Runnable() {
#Override
public void run() {
//I need stop javafx when this class close.
}
});
}
});
stage.show();
}
public static void LoadClass(String Data) { //I use this function to load class
/*...*/
launch(); //return error when i re-call this function (already launch).
}
If i put webview.getEngine().load(null); Platform.exit(); code in the "OnCloseRequest" works fine but an exception is created ("Attempt to call defer when toolkit not running")
i need use webview.getEngine().load(null); or similar because if i not use this, the video in webview remain playing in background. And if i not use Platform.exit() the main frame crashes (lock).
Sorry for my bad english, tried to write the best I could
use this:
[...]
stage.setOnCloseRequest(this.getCloseSystemEvent());
}
public EventHandler<WindowEvent> getCloseSystemEvent() {
return new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
Platform.exit();
}
};
}
Also, you should check the concurrency API. Your code prevents the runtime from closing the thread properly.