I'm using Eclipse to write javafx code for my university courses. When I run the code either in Eclipse, or after exporting it as a jar file, The program sometimes freezes.
For Example:
Normal box for data entry:
I have this window, where values for a rectangle can be entered.
If you press "submit" without adding both values, a NumberFormatException occurs, which I catch like so:
catch (NumberFormatException ex) {
System.err.println("NumberFormatException: " + ex.getMessage());
Alert alert = new Alert(AlertType.ERROR, "Bitte alle Felder ausfüllen", ButtonType.OK);
alert.showAndWait();
The alert window sometimes appears and works fine. Sometimes (rarely) it does 10 times in a row. Other times I get this:
Error State:
The program is now frozen and nothing is clickable. There is a thin, black line through one of the textfields. The program never recovers and has to be manually terminated through Eclipse or the task manager.
This sometimes happens on the first click on submit. Sometimes on the 5th, or later. But it always eventually happens. The program works fine in all other instances, so long as this alert is not triggered too often.
I have also had it happen in another project, where the trigger was a new window for data entry opening, much like the one I have here, but this time, only the alert freezes the program. The data entry window can be opened as many times as I like.
I'm using (course mandated) JavaFX11 and JavaSE-11 in Eclipse, on Manjaro.
Minimal reproducible example:
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.GridPane;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
GridPane root = new GridPane();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
Button submit = new Button("submit");
Alert alert = new Alert(AlertType.ERROR, "Bitte alle Felder ausfüllen", ButtonType.OK);
submit.setOnAction(e -> alert.show());
root.add(submit,0,0);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Opens a simple GridPane with just the submit button. If I click it, it sometimes shows the alert, but it often freezes as described above. I can see no pattern in the freezes. It's not always the first time, or always the second. Sometimes it's immediate, sometimes it works 3 or 4 times, then freezes on the next submit.
There is no error message in the console.
Edit: Further experimentation has shown, that the window does not freeze. If you hit return, it hits the button in the alert, which closes it and lets me use the rest of the program.
So it seems the error is in the window not being displayed correctly and only showing up as a thin black line. Which is still a problem, because it also happens with windows where I can't just hit enter to close them, which leaves me stuck.
Turns out it was the issue described here: https://github.com/javafxports/openjdk-jfx/issues/222
Plasma-KDE has a bug that prevents these kinds of windows from opening. There's a workaround posted if it's a one time thing.
I fixed it by switching to xfce.
Related
I am on a Windows 10 machine with Oracle JDK 14 and OpenJFX 14 installed. When keyboard focus is in a TextField control and that control's orientation is right-to-left, pressing the left and right arrow keys on the keyboard does not move the cursor within the TextField. Here is a simple program that demonstrates the problem.
import javafx.application.Application;
import javafx.geometry.NodeOrientation;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class FxTxtFld extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
TextField txtFld = new TextField("sampler");
txtFld.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT);
Group root = new Group(txtFld);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Run the above code and then simply try to move the cursor by pressing the arrow keys on the keyboard. When I do it, the cursor does not move. I can move the cursor by clicking the mouse within the text contents of the TextField. Also the up-arrow key moves the cursor to before the letter s, i.e. the start of the text and the down-arrow key moves the cursor to after the letter r but pressing the left- and right-arrow keys does not move the cursor at all. Note that if the orientation is left-to-right the arrow keys do move the cursor.
When I print out the Java [System] properties, I see the following.
user.language en
user.country US
I Googled for the terms javafx textfield cursor does not move but I only saw results that talk about manipulating the cursor via code and not via user actions.
EDIT
Perhaps someone can verify whether this problem also exists in earlier JavaFX versions?
UPDATE
For anyone interested, the issue appears to be resolved in JavaFX 15 Windows x64 SDK
I can't find anything on this and i am not sure if this is even possible but i will try. I have a JavaFX application showing a stage when you start typing text (it listen to os inputs). Everything is working fine except when the application is set to full screen on macOS. The stage will not show over the application, even if alwaysontop is true.
Only way i got this to work was using a JDialog in Type.POPUP but this is causing other issues in my code. I tried playing with the window level but it doesn't work.
Here is a test i ran to test the issue. This will go over any application except when it is in full screen.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class ontopTest extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage stage){
Scene scene = new Scene(new Pane(new Label("test application")));
stage.setTitle("test");
stage.initStyle(StageStyle.UNDECORATED);
stage.setWidth(300);
stage.setHeight(300);
stage.setScene(scene);
// stage.setAlwaysOnTop unneeded as com.sun.glass.ui sets window to top
stage.setY(0); // Set Y Axis to 0
// Need to show window first
stage.show();
com.sun.glass.ui.Window.getWindows().get(0).setLevel(3);
// Set window level to 3 (Maximum)
}
}
I want to know if this is possible with JavaFX or any other workaround. I want my view to be over any application, even full screen.
I am trying to create a simple menu for a small project using a JSpinner and JOptionPane. I created my desired output, but when I interact with the window or even hover over the buttons in the box, it creates visual artifacts over and over again (see images below):
JOptionPane before mouse hover
JOptionPane after mouse hover
I did some researching and thought it might be due to JOptionPane not being thread safe, but could not get anything to work.
Overall, my specific question is how do I prevent Java from repainting these visual artifacts over my JOptionPane window?
For reference, please see the method I am using to show this menu:
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.JSpinner;
public class Battleship
{
public static void main(String[] args)
{
SpinnerNumberModel battleshipRange = new SpinnerNumberModel(1, 1, 5, 1);
JSpinner rangeSpinner = new JSpinner(battleshipRange);
JOptionPane.showMessageDialog(null, rangeSpinner, "Battleship Number", JOptionPane.QUESTION_MESSAGE);
}
}
I am running this code on BlueJ and am using Windows 10 Pro.
Thank you in advance and apologies if this is a beginner question. I am still fairly new to programming.
EDIT: Updated code to give complete source of problem, but it disappeared. I will keep an eye on it to see where the source of the error first occurred.
After completing my project, I finally found why visual artifacts would pop up in all buttons/radio buttons/etc. in my game.
In the GridWorld source code, under the "GridPanel.java" script, the original programmers created a method called "setToolTipsEnabled(boolean flag)". Its function is to pop up a message box next to the cursor when it is hovering over the grid when the game stops running.
When extending GridWorld to create my project, the method reaches past the grid structure and attempts to create a tool tip underneath anything the cursor hovers over. Thus, creating visual artifacts on buttons/radio buttons/etc.
To fix this, I made sure this method was always set to false as I did not need tool tips for my game anyway. This method was implemented in the "GridPanel.java" and "GUIController.java" scripts (in the GridWorld code). I changed following methods to fix this problem:
GridPanel.java
/**
* Construct a new GridPanel object with no grid. The view will be
* empty.
*/
public GridPanel(DisplayMap map, ResourceBundle res)
{
displayMap = map;
resources = res;
// Phillip Sturtevant: Commented out to prevent visual artifacts
//setToolTipsEnabled(true);
}
GUIController.java
/**
* Stops any existing timer currently carrying out steps.
* Phillip Sturtevant Note: keep tool tips hidden to prevent visual artifacts
*/
public void stop()
{
display.setToolTipsEnabled(false); // hide tool tips while stopped
timer.stop();
running = false;
}
Alternatively, the method calls could be omitted entirely, but I commented them out in case I needed them in the future.
For reference, the method below sets the tool tips visibility in GridWorld (located in "GridPanel.java"):
/**
* Enables/disables showing of tooltip giving information about the
* occupant beneath the mouse.
* #param flag true/false to enable/disable tool tips
*/
public void setToolTipsEnabled(boolean flag)
{
if ("hide".equals(System.getProperty("gridworld.gui.tooltips")))
flag = false;
if (flag)
ToolTipManager.sharedInstance().registerComponent(this);
else
ToolTipManager.sharedInstance().unregisterComponent(this);
toolTipsEnabled = flag;
}
Below is the code sample, with other features left out. The code below encompasses the media player only. It's used on a menu screen for a project I'm working on. My issue is getting the musicButton (which is a toggle button- On/Off) to work properly. Using the following code, when I interact with the music toggle button, the playing music stops. When I click it again to resume playing, it does not resume. It stops once and stops altogether.
You can see I've tried simply using the boolean values of the toggle button in two if statements... If it's off and pressed, pause the music. If its on and pressed, resume the music. The problem is, as stated earlier, pausing the music works but it cannot be resumed. I've tried some combinations with loops, but nothing worked either.
I think if statements are too simple for this. I've scoured the JavaDocs and various online articles but I cannot find anything definitive. I've read a little about listeners, but they seem overly-complex for an on/off switch.
My question:
How do I get the musicButton to pause/play the music, whenver the user clicks it?
Any help is appreciated, thanks.
-Bagger
/* A simple game, the mechanics not yet implemented.
This is simply working on the title screen. */
import java.io.File;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
public class MenuFX extends Application {
#Override
public void start (Stage primaryStage) {
// Make the window a set size...
primaryStage.setResizable(false);
// Create media player
// Rather than inputting the entire absolute URI, which would confine the program
// to the creator's device, we create a new file, grab the URI on whatever machine
// the program is running on and convert it to a string... portability.
Media menuMusic = new Media(new File("music/menu.mp3").toURI().toString());
MediaPlayer menuPlayer = new MediaPlayer(menuMusic);
// Want to see the absolute URI? Uncomment the next line
//System.out.println(new File("music/menu.mp3").toURI().toString());
// Adjust the cycles and volume then start playing menu music
// Lazy, but it will suffice
menuPlayer.setCycleCount(999999999);
menuPlayer.setVolume(0.1);
menuPlayer.setAutoPlay(true);
/*
Need assistance here
*/
// Create music toggle button
ToggleButton musicButton = new ToggleButton("Music On/Off");
if (musicButton.isSelected() == false) {
musicButton.setOnAction(e -> menuPlayer.pause());
}
if (musicButton.isSelected() == true) {
musicButton.setOnAction(e -> menuPlayer.play());
}
// Add all nodes to the vbox pane and center it all
// Must be in order from top to bottom
menuVBox.getChildren().add(musicButton);
menuVBox.setAlignment(Pos.CENTER);
// New scene, place pane in it
Scene scene = new Scene(menuVBox, 630, 730);
// Place scene in stage
primaryStage.setTitle("-tiles-");
primaryStage.setScene(scene);
primaryStage.show();
}
// Needed to run JavaFX w/o the use of the command line
public static void main(String[] args) {
launch(args);
}
}
I think you are over thinking it. You should have an EventListener on your ToggleButton to Pause and Play the music.
musicButton.setOnAction(event -> {
if (musicButton.isSelected()) {
menuPlayer.pause();
}else {
menuPlayer.play();
}
});
This should give you the desired effect.
The reason your code was not working is because the ToggleButton is not selected by default, so the only EventListener that gets associated with it is the menuPlayer.pause();. So when you click on it, it only ever pauses. I have moved your code into one EventListener, and used the approriate if-else.
I am developing a application. I want when I exit it, a message box appears having message, for example, "Thanks for using Soft Attendance". Then disappear automatically say after few seconds.
I have write code for this as following:
public void windowClosing(WindowEvent e){
int whichOption;
whichOption=JOptionPane.showConfirmDialog(f1,"Are you Serious?","Soft Attendence",JOptionPane.YES_NO_OPTION);
if(whichOption==JOptionPane.YES_OPTION){
f1.dispose();
JOptionPane.showMessageDialog(null,"Thanks for using Soft Attendence");
}
}
When i click on exit button a confirmation dialog box appear and after clicking yes button
application is exited and a another message box appears.
Now I have two questions in my mind :
First question is I have dispose application already and then message box is shown. Is it fine to show message box after its parent is killed?
When second message box appears I don't want to click on "OK" button. I want it should automatically disappear. So my second question is How to shown message box that disappear automatically after some time?
Is it fine to show message box after its parent is killed?
I think this would not be a ideal case. But you can open dialog if the parentComponent has no Frame JOptionPane.showConfirmDialog(null,"...");
How to shown message box that disappear automatically after some time?
Auto disposable you can get it by a trick, you can create a SwingWorker which normally performs GUI-interaction tasks in a background thread. Set a timer and which will execute after time period and close your dialog explicitly.
class AutoDisposer extends SwingWorker<Boolean, Object> {
#Override
public String doInBackground() {
try{
JOptionPane.getRootFrame().dispose();
return Boolean.True;
}catch(Exception ex){...}
return Boolean.False;
}
}
...
new Timer(seconds * 1000, autoDisposer).start();