JavaFX UI freezes after rotating label - java
After using setRotate() on a label in a function outside of start(Stage primaryStage), the rotation works, but the UI freezes after applying the rotation on the label.
try {
Platform.runLater(() ->
textLabel.setRotate((new Random().nextInt(30 - (-30) + 1) + (-30)))
);
} catch (Exception e1) {
e1.printStackTrace();
}
What do I need to change so the UI won't freeze?
Edit: As requested, here is a more detailed part of my code. What basically happens is that the user can click a button, and then the text should rotate. It does rotate, but then the JavaFX UI freezes completely.
public class Main extends Application {
#FXML
private TextArea TextArea1;
#FXML
private Button Button1;
#FXML
private ImageView BackgroundImgView;
#FXML
public void doSomethingAfterPressingButton1() {
try {
String userText = TextArea1.getText();
if (userText == null || userText.isEmpty())
TextArea1.setText("Please enter a text into this field");
else {
TextArea1.setText(userText);
doRotate(userText);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void doRotate(String text) {
try {
if (Button1.getText().equals("Rotate")) {
Button1.setText("New");
textLabel.setText(text);
String[] colorArray = { "#ffa500", "#ffd106", "#ffffc0", "#ffffa8", "#ffff00", "#ffffc4", "#ffffdd",
"#fddc68", "#fee911", "#f9ed37", "#fcfa85", "#fcf852", "#d7fdec", "#d7edec", "#d7ddec",
"#d7cdec", "#d7bdec", "#00ffec", "#ff0000", "#89ff00", "#fff400", "#e300ff", "#fc59a3",
"#87c830", "#ffd400", "#fe7e0f", "#8e3ccb", "#00f9ff", "#5ff4da", "#ffe441", "#f2f411",
"#b8ff75", "#ffc100", "#c356ea", "#8ff243", "#71aef2", "#ea5645", "#ff0000", "#1dff00",
"#ff8a00", "#fcff00", "#ffca31", "#00fff9", "#ffdb00", "#15ff00", "#ff3300", "#8900ff",
"#1322a6", "#e81111", "#5a36a3", "#106125", "#abd91f", "#f4f1af", "#f7f960", "#fff400",
"#e3ff00", "#a7a10a", "#ff5b5b", "#ffc75d", "#b8ff52", "#91f7ff", "#ff82d4", "#91aaff",
"#ff9e9e", "#ff80c5", "#7afbff", "#8aff9c", "#fff518", "#ffc100", "#55b6ff", "#76ff0c",
"#bd6fff", "#ff7272", "#ffca78", "#fdff58", "#99ff2d", "#31ffdc", "#9600ff", "#bd00ff",
"#ff00e7", "#ff008d", "#ff005a", "#e1e6f5", "#efefef", "#f3ffea", "#ffe9e9", "#ffd8f8",
"#ff0000", "#1dff00", "#ff8a00", "#fcff00", "#ffca31", "#ba1818", "#336927", "#a3ff00",
"#008080", "#9500d8", "#daf0aa", "#b5e37f", "#9fc360", "#ffec7b", "#ecd860",
"#ffffff" };
textLabel.setTextFill(Color.web(colorArray[new Random().nextInt(colorArray.length)]));
textLabel.setVisible(true);
TextArea1.setVisible(false);
addrandomBackgroundImg();
BackgroundImgView.setVisible(true);
Platform.runLater(() -> textLabel.setRotate((new Random().nextInt(30 - (-30) + 1) + (-30))));
} else {
Button1.setText("Rotate");
textLabel.setVisible(false);
TextArea1.setVisible(true);
BackgroundImgView.setVisible(false);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Related
Repaint BorderPane (javaFx)
I have an application that can create a rectangle that decreases in size for example a lapse of time of 10 sec, but here is when I try to shrink the rectangle, the window bug (nothing is displayed in the scene) and wait until the countdown is finished to stop bugging (and then display the rectangle not diminished). I tried to find on the Internet the equivalent of repaint in Swing but not average: / this.requestLayout () -> I found this on the internet but it does not work. Here is my code of my countdown: public class Compteur { DemoBorderPane p ; public DemoBorderPane getPan() { if(p==null) { p = new DemoBorderPane(); } return p; } public Compteur() { } public void lancerCompteur() throws InterruptedException { int leTempsEnMillisecondes=1000; for (int i=5;i>=0;i--) { try { Thread.sleep (leTempsEnMillisecondes); } catch (InterruptedException e) { System.out.print("erreur"); } System.out.println(i); getPan().diminuerRect(35); } } } There is my Borderpane code : public class DemoBorderPane extends BorderPane { private Rectangle r; public Rectangle getRect() { if(r==null) { r = new Rectangle(); r.setWidth(350); r.setHeight(100); r.setArcWidth(30); r.setArcHeight(30); r.setFill( //on remplie notre rectangle avec un dégradé new LinearGradient(0f, 0f, 0f, 1f, true, CycleMethod.NO_CYCLE, new Stop[] { new Stop(0, Color.web("#333333")), new Stop(1, Color.web("#000000")) } ) ); } return r; } public void diminuerRect(int a) { getRect().setWidth(getRect().getWidth()-a); int c= (int) (getRect().getWidth()-a); System.out.println(c); this.requestLayout(); //this.requestFocus(); } public DemoBorderPane() { this.setBottom(getRect()); } } There is my Main code : public class Main extends Application { private DemoBorderPane p; public DemoBorderPane getPan() { if(p==null) { p = new DemoBorderPane(); } return p; } #Override public void start(Stage primaryStage) { Compteur c = new Compteur(); try { //Group root = new Group(); Scene scene = new Scene(getPan(),800,600); //scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm()); //root.getChildren().add(getPan()); primaryStage.setScene(scene); primaryStage.show(); } catch(Exception e) { e.printStackTrace(); } try { c.lancerCompteur(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { launch(args); /*Son s = null; try { s = new Son(); } catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) { // TODO Auto-generated catch block e.printStackTrace(); } s.volume(0.1); s.jouer(); c.lancerCompteur(); s.arreter();*/ } } Thank ;)
As long as you keep the JavaFX application thread busy it cannot perform layout/rendering. For this reason it's important to make sure any methods that run on the application thread, like e.g. Application.start or event handlers on input events return fast. lancerCompteur however blocks the application thread for 5 seconds so the only result you see is the final one after the method completes. In general you can run code like this on a different thread and use Platform.runLater to update the ui. In this case you could take advantage of the Timeline class which allows you to trigger an event handler on the application thread after a given delay: #Override public void start(Stage primaryStage) { Scene scene = new Scene(getPan(), 800, 600); Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), event -> { getPan().diminuerRect(35); })); timeline.setCycleCount(5); timeline.play(); primaryStage.setScene(scene); primaryStage.show(); } You also use different instances of DemoBorderPane in your Main class and the Compteur class; the Rectangle shown in the scene was never subject to an update. there's no need to call requestLayout in diminuerRect. This happens automatically when the Rectangle's size is modified. Lazy initialisation is pointless, if you know for sure the getter will be invoked during the object's creation. DemoBorderPane.getRect is invoked from it's constructor so moving the initialisation to the constructor would allow you to get rid of the if check without affecting functionality.
Communicating with an FXML Controller that's already open
I have searched again and again on this to no avail. I have a JavaFX FXML window which is connected to a Controller; this window is open. Clicking a button on the window triggers the opening of another FXML file, linked to its respective controller. The second window (optionsUI.fxml and optionsController) has a few radio buttons. When one is clicked, I want the location of an image/button to change in the mainUI window. How do I go about doing that? mainController: public void assetPressed(MouseEvent event) { //Get the source of Handler HUDButton button = (HUDButton) event.getSource(); //Check if an asset is already selected //----do a thing //Open stage openStage(currentAsset); } else { //if the current asset selected and the new asset clicked are the same //----do something closeStage(); } //if the current asset selected and the new asset clicked are different else { //----do something else assetIsSelected = true; openStage(currentAsset); } } } //opening optionsUI.fxml public void openStage(Asset asset) { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("optionsUI.fxml")); Parent root = null; try { root = fxmlLoader.load(); } catch (IOException e) { e.printStackTrace(); } optionsController controller = fxmlLoader.getController(); Scene scene = new Scene(root, 300, 450); stage.setScene(scene); if (alreadyExecuted == false) { stage.initStyle(StageStyle.UNDECORATED); stage.initOwner(stageControls); //Making the mainUI the owner of the optionsUI stage.setTitle("HUDEdit Version 3.0.0"); alreadyExecuted = true; } The main issue I am having is adding an event handler on the radio buttons which will change a property of the Button that was pressed (currentButton). I searched on this issue, but what I got was what I have already done: to open a new stage with the new values present in the other FXML file.
You can do something like this in your OptionsController (I am going to rename things to conform to standard naming conventions, btw.) The basic idea here is just to expose a property representing what the user has selected via the radio buttons. public class OptionsController { #FXML private RadioButton radioButton1 ; #FXML private RadioButton radioButton2 ; private SomeType someValue1 = new SomeType(); private SomeType someValue2 = new SomeType(); private final ReadOnlyObjectWrapper<SomeType> selectedThing = new ReadOnlyObjectWrapper<>(); public ReadOnlyObjectProperty<SomeType> selectedThingProperty() { return selectedThing.getReadOnlyProperty() ; } public final SomeType getSelectedThing() { return selectedThingProperty().get(); } public void initialize() { radioButton1.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> { if (isNowSelected) { selectedThing.set(someValue1); } }); radioButton2.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> { if (isNowSelected) { selectedThing.set(someValue2); } }); } // ... } And now when you load Options.fxml you can just observe that property and do whatever you need when it's value changes: public void openStage(Asset asset) { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("optionsUI.fxml")); Parent root = null; try { root = fxmlLoader.load(); } catch (IOException e) { e.printStackTrace(); } OptionsController controller = fxmlLoader.getController(); controller.selectedThingProperty().addListener((obs, oldSelection, newSelection) -> { // do whatever you need with newSelection.... }); // etc... }
JavaFX - Any way to enter the JavaFX-Thread while executing a background task?
I have the following Task, where I import a file. The method starts a Dialog with a ProgressBar, and the progressProperty from the ProgressBar is bound to the progressProperty of the task. Now I want to check if the ProgressBar is already done, but I have to ProgressBar in a special class and I can't access methods from any other classes while executing the Task. Now, my question is, how can I ensure that the program checks if the ProgressBar is done, because my Dialog will only close if the ProgressBar is finished, and at the current moment, the Dialog never closes. Here is my code: public void readFile(File chat) { Task<Void> task = new Task<Void>() { #Override protected Void call() throws Exception { if(chat.getName().contains("KakaoTalk_")) { String s = ""; String gesamt = ""; double laenge = 0; try(BufferedReader brCount = new BufferedReader(new FileReader(chat))) { while((s=brCount.readLine())!=null) { laenge++; } } catch (IOException e) { System.out.println("Fehler beim zählen"); } double momentanErreicht = 0; try(BufferedReader br = new BufferedReader(new FileReader(chat))) { while((s=br.readLine())!=null) { momentanErreicht++; updateProgress(momentanErreicht, laenge); s = s.replace("ß", "ß"); s = s.replace("ö", "ö"); s = s.replace("ü", "ü"); s = s.replace("ä", "ä"); s = s.replace("Ä", "Ä"); s = s.replace("Ãœ", "Ü"); s = s.replace("Ö", "Ö"); gesamt += s+"\n"; } } catch (FileNotFoundException e1) { System.out.println("File not found"); } catch (IOException e2) { System.out.println("IOException"); } mp.isFortschrittDialogCompleted(); mp.eingabeSetText(gesamt); setChat(mp.eingabeGetText()); getChat(); } else mp.mhNichtPassendesFile(); return null; } }; mp.progressP().bind(task.progressProperty()); mp.startFortschrittDialog(); Thread th = new Thread(task); th.setDaemon(true); th.start(); mp.isFortschrittDialogCompleted(); } Here is also my MyRootPane (mp) where the executed methods lead to: public void eingabeSetText(String eingabe) { this.eingabe.setText(eingabe); } public String eingabeGetText() { return eingabe.getText(); } public void startFortschrittDialog() { fd.show(); } public void endFortschrittDialog() { fd.close(); } public void isFortschrittDialogCompleted() { if(fd.isCompleted()) endFortschrittDialog(); } public DoubleProperty progressP() { return fd.getPBProgressProperty(); } And the Dialog with the ProgressBar: public class FortschrittDialog extends Dialog { private ProgressBar pb = new ProgressBar(); public FortschrittDialog() { pb.setPrefWidth(500); pb.setProgress(-1f); getDialogPane().setContent(pb); } public DoubleProperty getPBProgressProperty() { return pb.progressProperty(); } public boolean isCompleted() { if(pb.getProgress()==1.0) return true; else return false; } } I hope anyone understands my problem and can give me a quick and easy solutions, if possible even with explanation. If your missing something of the code, please tell
according to one of this javafx.scene.control.Dialog<R> won't close on pressing "x" question's answer, you can only close the dialog if you have a defined button on your dialog pane, then you can do somethig like this: Window window = dialog.getDialogPane().getScene().getWindow(); window.setOnCloseRequest(event -> dialog.close()); Then as #James_D mentioned in a comment you can use task.setOnSucceeded(event -> window.hide()); this is the relevant part for you from the answer: JavaFX dialogs can only be closed 'abnormally' (as defined above) in two situations: When the dialog only has one button, When the dialog has multiple buttons, as long as one of them meets one of the following requirements: The button has a ButtonType whose ButtonData is of type ButtonData.CANCEL_CLOSE. The button has a ButtonType whose ButtonData returns true when ButtonData.isCancelButton() is called. ... If you are using this solution you don't have to use the doubleProperty and the isCompleted() methods.
Mouse Listener implementation
I am learning Java and trying to implement a MouseListener for the first time. I have read the java doc MouseListener but my code doesnt work, as in nothing happens when i press the button. Here is a jbutton with a pressed and released event. Can someone explain where i have gone wrong? JButton upButton_1 = new JButton("Up"); upButton_1.addMouseListener(new MouseAdapter(){ public void mousePressed(MouseEvent pevt) { upButtonPressPerformed(pevt); } public void mouseReleased(MouseEvent revt) { upButtonReleasePerformed(revt); } public synchronized void upButtonPressPerformed( MouseEvent pevt) { resultsTextArea.setText("Up Button Activated, String: " + downString); try{ //See Above comments for sending ASCII String byte[] bytes = DatatypeConverter.parseHexBinary(upString); TwoWaySerialComm.SerialWriter sw = new TwoWaySerialComm.SerialWriter( twoWaySerCom.serialPort.getOutputStream()); sw.out.write(bytes); } catch (IOException e) { e.printStackTrace(); } } public synchronized void upButtonReleasePerformed( MouseEvent revt) { resultsTextArea.setText("Up Button released, String: " + downString); try{ //See Above comments for sending ASCII String byte[] bytes = DatatypeConverter.parseHexBinary(upString); TwoWaySerialComm.SerialWriter sw = new TwoWaySerialComm.SerialWriter( twoWaySerCom.serialPort.getOutputStream()); sw.out.write(bytes); } catch (IOException e) { e.printStackTrace(); } } });
ActionListener is what you are looking for if you want to work with buttons. JButton button = new JButton("SomeButton"); button.addActionListener(this); void ActionPerformed(ActionEvent e) { if(e.getSource() == button) { // do whatever you want if button is clicked } } Or you can use anonymous inner class: button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //do whatever you want } }); //or the Java8 version button.addActionListener((e) -> { //do whatever you want }); Whit MouseListener you can listen to events like: MouseClicked, MouseEntered, MouseExited, MousePresse, MouseReleased. You could use these, but for button click its more logical to listen to your buttons not your mouse.
How can i show my panels in the other panes?
Hi this is my problem i cant show the panels into the root panel, im doing a similar chat some like skype but the part that i need to show(messages), its not showed, when i send the message to the users. Well this is my code to send my message: btnSend.setOnAction(new EventHandler<ActionEvent>() { #Override public void handle(ActionEvent event) { String empty = ""; String sendMessage = txtMensajes.getText(); String[] talkTo_array = lstDisplayBuddys.getSelectionModel().getSelectedItem().toString().split("-"); String talkTo = talkTo_array[talkTo_array.length - 1]+"#mpns.mcm.net.mx"; try{ // CONDITION IF ARE EMPTY THE MESSAGES if (sendMessage.equals(empty)) { JOptionPane.showMessageDialog(null, "Add some message"); } else{ if (talkTo != sendMessage) { while (true) { try { sendMessage(XMPPChatHelper.encodeBase64(sendMessage), talkTo); System.out.println("send message"); //SHOW MY MESSAGES WHEN I SEND IT Platform.runLater(()->{ pnContArea.getChildren().addAll(drawSendMessage(sendMessage)); txtMensajes.setText(""); }); } catch (XMPPException e) { e.printStackTrace(); } break; } ConnectionDBHistorialHelper ConnectionDBHistorialHelper=new ConnectionDBHistorialHelper(); ConnectionDBHistorialHelper.saveMessageSend(sendMessage); } } }catch(Exception e){ } } }); and this is the method that draw the image and the text into the other panel: public StackPane drawSendMessage(String message){ StackPane paneSend=new StackPane(); Platform.runLater(()->{ Text sendMessageText=new Text(message); ImageView imaSend=new ImageView(HomeController.class.getResource("/image/isend.png").toExternalForm()); paneSend.getChildren().addAll(imaSend,sendMessageText); paneSend.setAlignment(Pos.BASELINE_LEFT); }); return paneSend; } thnks advanced.
He he it's very easy to do that you only need to initilize the whatever variable in this case all panes with #FXML private variablePane variable;