I've created a visualizer in JavaFX for a problem I'm solving, and currently I can get it to show up after the calculations in my application are done, but I would like the window to first be opened and then run the calculations, so I can animate the visualization during the computations.
This is the code for creating an instance of the problem, showing the visualizer and performing the calculations:
public static void run(Visualizer v) {
readInput();
if (v != null) {
v.resizeCanvas(rectangles);
v.drawAllRectangles(rectangles);
v.show();
}
calculateArea();
System.out.println(totalArea);
}
The Visualizer class extends javafx.application.Application and utilizes a JavaFX Canvas. calculateArea() simply runs a static method which performs some calculations.
What currently happens when I run my program is:
It waits for input on stdin
The computations are run
The visualization is displayed
What I want:
It waits for input on stdin
The visualization is displayed
The computations are run
So for some reason the displaying of the visualization is delayed even though I call v.show() before calculateArea().
My first hunch would be to run the calculations in a new thread, but according to
the documentation "The JavaFX scene graph, which represents the graphical user interface of a JavaFX application, is not thread-safe and can only be accessed and modified from the UI thread also known as the JavaFX Application thread."
I tried putting a Thread.sleep(3000) right after v.show(), and what happened was that my program just waited 3 seconds before running calculateArea() followed by the window being displayed.
Thanks for any input!
You should call your calculation method in a separate thread (as suggested by #Selim) launched in the applications start() method.
If your calculation method directly changes graphical content on screen (which it should not do BTW...) you need to pass this graphics code (not the calculation itself) to Platform.runLater().
Related
I'm making a Minecraft 1.8 client, and I'm trying to create a loading screen animation.
I know that updating the screen every time Minecraft loads something would make the animation choppy, so I tried making it run asynchronously, updating the screen every 10 milliseconds. The following code runs in Minecraft.java when the game starts:
CompletableFuture.runAsync(() -> {
int xPosition = // calculation of the value
// draw the rectangle
try {
TimeUnit.MILLISECONDS.sleep(10L);
}
catch (InterruptexException ignored) {
}
this.updateDisplay(); // render the rectangle
});
However, due to CompletableFuture running the code in a different thread, LWJGL can't find the rendering context (it can be found in the Minecraft thread), and can't update the screen (an IllegalStateException is thrown).
Is it possible to call the updateDisplay (or any) method on a different thread instead of the current thread?
Okay, so this problem has been plaguing me for the past few days. And before anyone comments about it, yes I have made the jframe visible and I have added all the components that I need to it. Also, all components are added well before the GUI is set to visible and activate() is called.
So I am trying to run a couple simeple lines of code.:
g.setVisible(true);
g.activate();
Simple enough. g is an object made from a class I made GUI which extends JFrame. and activate() is a method that runs an infinite loop that just does a bunch of things until the user tells it to exit. However, when the program gets to the g.setVisible() line it opens a JFrame that is the size I specified however is completely devoid of anything. Then it moves onto the g.activate(); which at the moment runs for a specific amount of iterations and stops. At which point it finally decides that it can go back and display my GUI. The issue with that is that the GUI is meant to be updated by the loop from active() and keep the user in the know of what is going on.
Any help is appreciated let me know if you need more detials and thank you in advance.
In many different UI frameworks, it's common for the methods you call to queue some work rather than perform it immediately. From your description, it seems like setVisible() may be creating a native window but then queuing the rendering of the components. Since this code is (presumably) running in the UI thread, it won't perform the work it queued until after running activate().
Long-running tasks should never be run on the UI thread. In Swing, you can use SwingWorker or explicitly create a background thread.
I'm trying to close my main application user interface, but leave code running in my main() function that launched the application. Right now the problem I have is on a Mac the program name remains in Mac's menu bar even though there are no windows shown.
So basically in the code that would exit the application I have:
private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
//System.exit(0);
this.setVisible( false );
// Do something here to finish closing application.
}
The main function that starts the application looks like:
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
// NewApplication is a javax.swing.JFrame
new NewApplication().setVisible(true);
}
});
while (true) {
// Watch for user to relaunch UI and do lots of other tasks.
}
}
If I used System.exit(0) it would stop the entire JVM completely and stop running the stuff in the while loop. I cannot figure out how to exit the main application UI, stop from showing in the menu bar, but still run the while loop stuff.
The reason I'm trying to do this is I need something that will run continuously and sometimes the user will need to run a user interface that interacts with the stuff that is running. The stuff inside the while loop checks to see if they are trying to launch the user interface again (among other functions) and would reload it. One option is to make one program that runs continuously and use inter-process communication to talk between the user interface and a non-UI program, but I would need to pass lots of data back and forth so I don't like that option.
It appears there is not an easy way of doing this. For those that have the same problem here are a few options:
1) It looks like other programs I have do this by using Mac’s task bar (in the upper right corner of the screen). The only way you access the program is through a menu on the task bar. Even when you have UI’s shown you get to the UI through the task bar. The downside of doing this is that when the UI is shown you can’t use Cmd+Tab to get over to the window. This is non-intuitive for Mac users. If you want to use this option you can start the java jar file with the command line option “-Dapple.awt.UIElement="true”” and that will prevent the program from showing a menu ALWAYS, and then you'll want to create a task bar icon so the user can get to your program.
See How to hide the Java SWT program icon in the Dock when the application is in the tray
2) Have 2 programs that run, one with a UI and another without. They can communicate using interprocess communication (IPC) using files, sockets, etc. If you don’t have much data to pass between the processes, this is a good solution.
3) You could probably use JNI to remove the menu on the application after all the UI’s close. But you’ll need to dig into Mac’s Objective C language. I can't confirm you can actually do this though.
jf is a JFrame I'm trying to move a pixel in every 200 milliseconds. I created this method so I ciould pause the software for 200 milliseconds before cntinuing. millis and millisn are static longs.
public static void waitsec() {
millis =System.currentTimeMillis();
millisn =System.currentTimeMillis();
while (millisn<(millis+200)){
millisn=System.currentTimeMillis();
}
}
the following part is the part where I'm trying to make my JPanel (jp) to move slowly 50 pixels when a button is being pressed:
public void actionPerformed(ActionEvent h){
if (h.getSource() == button){
for (int i = 0; i <50; ++i){
waitsec();
out.println ("" + i);//I'm checkinf if the waitsec() is working OK
x +=1;
jp.setLocation(x, 0);
totalGUI.repaint();
jp.setVisible(true);//setting visible so I could focus on it
jp.requestFocusInWindow (); //suspicious part
jp.requestFocus ();
}}
}
The results of running this program are:
The numbers appear in the console one after another with 200 mmillis between them as expected.
The JPanel is not moving all the way once the numbers stop appearing (the program is done running). and if I try to minimize and maximize the window it doesn't show up till the program is done running as if the program has no focus at all...
why doesn't it focus although I had set it visible and focused it?
A number of things...
Firstly, you are blocking the Event Dispatching Thread, preventing it from processing any new events, including repaint events. This will make your application appear as it has hung, because essentially, it has.
Secondly, instead of rolling your waitSec method, you should be taking advantage of the available API functionality, for example, instead of trying to loop until a time period has passed, which while consume CPU cycles, you should use Thread.sleep instead.
Having said that though, you should NEVER sleep within the context of the EDT.
Instead, you should use something like a javax.swing.Timer which can be configured to raise an event on a regular bases. The benefit of this is it raises the event within the context of the EDT, making it safe to update the UI from within (unlike making your own Thread for example)
Take a look at Concurrency in Swing and How to use Swing Timers for more details
Thirdly, JPanel is not focusable by default, so calling requestFocusInWindow is not likely to have any effect
Fourthly, by default, Swing makes use of layout managers, so you may actually be struggling against this as well
I have coded a game proto-type in Java during my spare-time. This game was merely for my educational purposes only. I have it working fine via a JNLP launch file on the web, as well as on my main machine, via a JFrame.
My main intention is to make this proto-type playable in web-browsers via the use of a JApplet. I have coded a class, called AppletPlayer.java. The intention of this class is to essentially serve as a launcher for my Game's main class. The AppletPlayer.java file is pretty much as follows:
public class AppletPlayer extends JApplet {
private Game myGame_; // This is my game's main class
private boolean started_ = false;
public void init() {}
public void start() {
if (!started_) {
started_ = true;
myGame_ = new Game();
this.setContentPane(myGame_);
myGame_.start() // I set focusable, and enabled to 'true' in the Game's start method
// My Game class has no init method. Just a start method that spawns a new thread, that the game runs in
}
}
Now, the Game class itself extends JComponent, and implements Runnable, KeyListener, and FocusListener. If I launch AppletPlayer via Eclipse it works like a charm in its Applet Viewer. However, when I deploy to the web I see two things:
On a Windows XP machine the Applet loads, stays stuck on the main title screen, never receiving focus, hence never registering any type of user input.
On a Windows 7 Machine the Applet loads, I hear my game's music, but the Applet screen itself renders a plain white box and nothing else.
These issues occur in both IE and Firefox.
I have been perusing Google and StackOverFlow for awhile now, trying to dig up a solution but haven't had any luck. I am a bit unfamiliar with Applets, and was hoping for a nudge in the right direction.
One thing that may be the reason: Swing is not thread-safe, so all changes on the GUI (with includes your setContentPane) should occur in the AWT event dispatch thread. The start() method of an applet is not called on this thread.
Wrap all your GUI-related method calls in an EventQueue.invokeLater(...) call (or invokeAndWait, if you need some results, and SwingUtilities also has these methods, if you prefer) and look if you see some changes.