When I try to call Desktop.getDesktop().open(), my program crashes.
I'm on Ubuntu GNOME 16.10, running Gnome 3.20.4. I haven't had a chance to test this code on another platform, but on this platform it is definitely crashing the program.
browseMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.runLater( new Runnable() {
public void run() {
try {
System.out.println ( Desktop.isDesktopSupported() );
Desktop.getDesktop().open( albumTable.getSelectionModel().getSelectedItem().getPath().toFile() );
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
});
Any thoughts on how to fix or troubleshoot this?
You're mixing JavaFX and AWT, which is likely causing the problem. Instead of
Desktop.getDesktop().open(file);
try using the JavaFX API:
getHostServices().showDocument(file.toURI().toString());
getHostServices() is defined in Application (so you may need to retrieve it in your start method and pass it to whichever object - perhaps a controller - is registering the listener with the menu item).
It looks like #James_D's answer is the better way to do things, but currently (as of 2017/05/03) it doesn't work on the OpenJDK / OpenJFK.
Thankfully, his comment about mixing JFX and Swing helped me find a solution which will work on OpenJDK / OpenJFX:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Desktop.getDesktop().open( albumTable.getSelectionModel().getSelectedItem().getPath().toFile() );
} catch (IOException e) {
e.printStackTrace();
}
}
});
The trick was using SwingUtilities.invokeLater() rather than Platform.runLater(), since the code inside is swing.
Related
I've been trying to figure it out for some time,
I'm trying to write a chat - server app, just for learning.
I have an obstacle that I cannot understand,
The while loop inside of the GUI class freeze, but just when it trying to read:
public void run(){
Platform.runLater(() -> {
do {
try {
msg = getFromServer.readUTF(); // <--- freeze GUI
chatWindow.appendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
} while (true);
});
}
You can see that it's running in a thread, but i did try to run it in other ways...
Only the DataInputStream make it stuck,
msg = getFromServer.readUTF();
And this it the methud that it's coming from:
public void connectToServer(){
try {
serverConectionState = new Socket("127.0.0.1", 6789);
getFromServer = new DataInputStream(serverConectionState.getInputStream());
sendToServer = new DataOutputStream(serverConectionState.getOutputStream());
onlineOffline.setText("Online");
onlineOffline.setTextFill(javafx.scene.paint.Color.web("#0076a3"));
} catch (IOException ex){
chatWindow.appendText("server connection fail\n");
}
}
This class, is the Controller.class - if it's make any diffrent.
My first question in stackoverflow, after a lot of help from the community.
Thanks in advance
I'm assuming the run method you showed is part of a Runnable that is executed in a background thread.
You are running the entire loop on the FX Application Thread (by using Platform.runLater()). So you block that thread and prevent it from repainting. You should run only the UI updates on the FX Application Thread:
public void run(){
do {
try {
String msg = getFromServer.readUTF(); // <--- freeze GUI
Platform.runLater(() -> chatWindow.appendText(msg));
} catch (IOException e) {
e.printStackTrace();
}
} while (true);
}
instead of using platform.runlater you should use java task, so that you can run the code in different thread, without freezing the UI thread
This seems like it is a very basic issue and that the answer is right in front of me, but I still can't figure out what's wrong. I have a button, and when handling the click event I change the style and text of a Label. After that, I call a method which changes the style once again when finished.
My problem is that the style changes in the handle() method does not affect my label, and instead it goes straight from its default style to the style set by connect().
Mind you that it's not because it changes too fast, the connect() method usually takes a full second or so to complete as it connects to a remote server.
I tried sleeping the thread for a second (in case my were too slow) inbetween setStyle() and connect(), but to no avail. I would greatly appreciate any help, and hopefully learn something along the way.
This is my code:
Button loginButton = new Button();
loginButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
loginStatus.setText("Loggin in...");
//The line below should change the color until connect does it's thing, but it doesn't
loginStatus.setStyle("-fx-text-fill:#ffcc00");
connect(username.getText(), password.getText(), serverField.getText());
}
});
And connect() looks like this:
private void connect(String username, String password, String server) {
try {
api = new DiscordBuilder(username, password).build();
api.login();
api.joinInviteId(server);
api.getEventManager().registerListener(new ChatListener(api));
//Instead, it goes straight from the old style to the style set below.
loginStatus.setStyle("-fx-text-fill:#009933");
loginStatus.setText("Online");
} catch (NoLoginDetailsException e) {
loginStatus.setText("No login details!");
loginStatus.setStyle("-fx-text-fill:#cc3300");
e.printStackTrace();
} catch (BadUsernamePasswordException e) {
loginStatus.setText("Bad username or password!");
loginStatus.setStyle("-fx-text-fill:#cc3300");
e.printStackTrace();
} catch (DiscordFailedToConnectException e) {
loginStatus.setText("Failed to connect!");
loginStatus.setStyle("-fx-text-fill:#cc3300");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
what you need is Task.
also as stated here
Implementing long-running tasks on the JavaFX Application thread
inevitably makes an application UI unresponsive. A best practice is to
do these tasks on one or more background threads and let the JavaFX
Application thread process user events.
so your code should look like this
Button loginButton = new Button();
loginButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
loginStatus.setText("Loggin in...");
//The line below should change the color until connect does it's thing, but it doesn't
loginStatus.setStyle("-fx-text-fill:#ffcc00");
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
connect(username.getText(), password.getText(), serverField.getText());
return null;
}
};
new Thread(task).start();
}
});
and in your connect method surround your ui updating methods with Platform.runLater
Platform.runLater(() -> {
loginStatus.setStyle("-fx-text-fill:#009933");
loginStatus.setText("Online");
}) ;
I have an application which on exit should close all windows and write some configuration files.
Without the things I did below, the following was never triggered and so the closeEXES which writes all the configs out was never run.
mainframe.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(WindowEvent winEvt) {
closeEXES();
}
});
I used the following to catch the Cmd-Q on Mac OS:
import com.apple.eawt.QuitStrategy;
import com.apple.eawt.Application;
And in main:
if (System.getProperty("os.name").equals("Mac OS X")) {
Application.getApplication().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
The version before that I did:
public class MacQuitAdapter extends ApplicationAdapter {
#Override
public void handleQuit(ApplicationEvent e) {
System.out.println("Using deprecated AplicationAdapter for handling Quit.");
}
}
How would I accomplish the same thing with JDK 8? The "same thing" is to make sure that when Command-Q is hit, the closing of the windows will be passed to AWT so that the windowClosing method will do what I want.
Alternatively, is there some other listener I need to sense the Command-Q? I'll keep looking but thought it was worth asking here.
Thanks.
I'm sorry to answer my own question. Please let me know if this is a faux pas. I used this plus still kept the close-window part of the code. For JDK 8 this does most of what I want.
So now the code looks like this:
mainframe.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(WindowEvent winEvt) {
closeEXES();
}
});
if (System.getProperty("os.name").equals("Mac OS X"))
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
#Override
public void run()
{
System.out.println("in : run () : shutdownHook");
doCloses();
System.out.println("Shutdown hook completed...");
}
});
}
one method, closeEXES, prompts the user to make SURE they really meant to quit the application. The other checks a condition (have the files been closed before?) and closes them if they have not been closed.
For completeness:
public void closeEXES() {
int n = JOptionPane.showConfirmDialog(mainframe,
"Close EXES GUI?", "Closing EXES GUI",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if (n == 0) {
System.out.println("Exiting...start");
doCloses();
System.exit(0);
}
}
public void doCloses() {
if ( beenClosed )
{
System.out.println("Already closed all files.");
}
else
{
// ... a bunch of stuff here writing GUI screen positions to a file and
// things like that ...
beenClosed = true;
}
}
I don't have any code to show in particular to link because this is quite a general question...you see, I made a small game applet with 8 AudioClip variables, and these were supposed to play every time a certain action was taken by the user. Ex: Player clicks = Shooting sound plays. The thing is, the moment I added these AudioClip files my program just freezes terribly and becomes borderline unplayable if the freezing is particularly bad.
The simple way I did it is here (From the book, actually)
AudioClip playerShooting;
playerShooting=getAudioClip(getDocumentBase(),"PlayerShooting.wav");
Then I would just use the following whenever the user clicked:
playerShooting.play():
My program worked smoothly before I added these wav files. They aren't even that long. Where did I go wrong here, and, how can I remove the random freezing?
EDIT:
This is the code I am running:
public void mouseClicked(MouseEvent e)
{
if(playerAlive)
{
timeShotsAfter=System.currentTimeMillis();
if((timeShotsAfter-timeShotsBefore)>=100)
{
if(shotIndex<10)
{
playerShooting(); //Here is where I call the function
shotFiredX[shotIndex]=currentX;
shotFiredY[shotIndex]=currentY;
shotSize[shotIndex]=20;
}
if(shotIndex<10)
shotIndex++;
else
shotIndex=0;
timeShotsBefore=System.currentTimeMillis();
}
else{}
toggleShooting=false;
}
}
This is the function:
public void playerShooting()
{
new Thread(
new Runnable() {
public void run() {
try {
playerShooting.play();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
I was having the same problem a while back. What I did to solve my problem was update to JDK 8. In previous JDK versions, audio files appear to have been an afterthought and can be buggy. If you are still having problems, JDK 8 has the ability to play mp3 files which are significantly smaller than wav (you may want to try this). Make sure you use sound.stop() when your clips are done as this might free up some memory.
Play the audio clip in another thread?
EDIT:
new Thread(
new Runnable() {
public void run() {
try {
playerShooting.play():
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
Edit:
I'm not quite sure if this part is correct:
getAudioClip(getDocumentBase(),"PlayerShooting.wav");
Try adding System.out.println(getDocumentBase()); to see whether the location is correct.
I want to use the Substance L&F library in my Java application, so I downloaded the .jar files and added them to the project classpath. Then I want to set the L&F in the application's main() function like this:
SwingUtilities.invokeAndWait(new Runnable()
{
#Override
public void run()
{
try
{
// Substance
String skin = "org.pushingpixels.substance.api.skin.SubstanceGraphiteAquaLookAndFeel";
SubstanceLookAndFeel.setSkin(skin);
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
}
catch(Exception e)
{
System.err.println("Can't initialize specified look&feel");
e.printStackTrace();
}
}
});
That is done before the JFrame is being created. However, even though no exception is thrown, nothing happens, the GUI is rendered in default Swing L&F.
Any ideas what I am missing here?
EDIT
Instead of the SubstanceLookAndFeel.setSkin(skin); call I tried it with UIManager.setLookAndFeel(skin); instead. This still doesn't work, but at least I get an exception now:
org.pushingpixels.substance.api.UiThreadingViolationException:
State tracking must be done on Event Dispatch Thread
Isn't that solved by calling this via invokeAndWait()?
EDIT-2
Ok, so the problem was something different. The exception was thrown while creating a JTable, not when setting the L&F. I was able to solve the issue - the L&F is now correctly rendered - by calling the JFrame constructor (which then basically runs the whole application) via EventQueue.invokeLater(). But I never did that before, is it "save" (valid in Java terms) to do it that way?
There is a small trick when setting Substance LaF. You have to call UIManager.setLookAndFeel(new SubstanceGraphiteAquaLookAndFeel()); before you call UIManager.setLookAndFeel("org.pushingpixels.substance.api.skin.SubstanceGraphiteAquaLookAndFeel");. So, set it like this:
public class App {
public static void main(String [] args) {
try {
UIManager.setLookAndFeel(new SubstanceGraphiteAquaLookAndFeel());
UIManager.setLookAndFeel("org.pushingpixels.substance.api.skin.SubstanceGraphiteAquaLookAndFeel");
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable(){
public void run() {
//Your GUI code goes here..
}
});
}
}