I have a problem when a JButton on my interface, when pressed the button triggers this event listener:
if (event.getSource() == goButton)
{
MainLauncher.doProgram(assetsField.getText(), FileFinder.completePath(String.format("%s\\%s", modDirectoryPath, modList.getSelectedValue())), databaseField.getText());
}
which runs the following code:
public static void doProgram(final String baseGamePath, final String modPath, final String databasePath)
{
new Thread()
{
public void run()
{
System.out.println("Running: " + modPath + "\n");
reader = new MetaDataReader(databasePath);
reader.formConnection();
long start = System.currentTimeMillis();
long temp;
File cache = new File("RegisterCache.SC");
if (!cache.exists())
{
temp = System.currentTimeMillis();
start += System.currentTimeMillis() - temp;
System.out.println("Calculating number of files");
FileFinder baseGame = new FileFinder();
baseGame.calculateNumFiles(baseGamePath);
System.out.println(String.format("Loading %s base game files", baseGame.getNumFiles()));
gui.doProgressBar();
baseGame.findFiles(baseGamePath, true);
gui.killProgressBar();
System.out.println();
//load the base game assets, we want to move this to metadata later
System.out.println("Checking for base game reference errors");
new ReferenceDetector(Table.getRegister()).findReferences(true);
Table.serializeTable(cache); //write the database to cache, we can use it next time
}
else
{
System.out.println("Loading cache");
Table.unserializeTable(cache);
}
gui.doCommands(); //calls reset()!!! be careful with the temporary excludes!
System.out.println("Eliminating base game requires errors");
RequiresWhere.executeRequires(true);
temp = System.currentTimeMillis();
start += System.currentTimeMillis() - temp;
System.out.println("Calculating number of files");
FileFinder mod = new FileFinder();
mod.calculateNumFiles(modPath);
System.out.println(String.format("Loading %s mod files", mod.getNumFiles()));
gui.doProgressBar();
mod.findFiles(modPath, false);
gui.killProgressBar();
System.out.println();
System.out.println("Finding reference errors");
new ReferenceDetector(Table.getRegister()).findReferences(false);
System.out.println("Finding requires errors");
RequiresWhere.executeRequires(false);
System.out.println("Checks complete");
reader.killConnection();
System.out.println(String.format("Execution Time: %dms", System.currentTimeMillis() - start));
Table.reset();
}
}.run();
}
The odd thing is this:
When testing I didn't have my button added to the interface, and so on main() I was calling goButton.doClick(); which triggered the doProgram(), and gives me the results I expected which is this:
a couple of things are printed out (to a JTextArea on the interface that receives from System.out.println()), a progress bar pops up above the console, and goes from 0% to 100% in around 10 seconds, disappears, a few more things are printed etc etc.
However when I added the button to the interface I clicked it and the behavior was not the same at all:
Nothing is printed. The progress Bar comes up, and stays at 0% for 10 seconds, then disappears, a few seconds later the doProgram finishes executing and all the information that should have been printed during runtime is suddenly printed all at once.
Can anybody tell me what is causing this strange behavior and how it can be fixed?
I would post a SSCCE, but it is a little difficult to do for this program as there are so many tasks and subprocesses. Note that, the progress bar I use it run on the GUI thread, the main code is done in it's own thread (as you can see)
EDIT: I added setEnabled(false); and true inside the listener surrounding the call to doProgram, and when the button is programatically pressed, the button is greyed out and this renabled as I expect, however if I click the button by hand it does not disable, and I can press it again
The code looks a bit confusing.
However, first of all: You are calling the run() method of the new Thread that you are creating there. This will cause the code from the run() method to be executed by the thread that calls doProgram, and not by the new Thread that you are creating there. In order to execute the code really in this new Thread, you have to call start() instead of run().
This explains probably most of the differences that you described. However, keep in mind that modifications to Swing components always have to be done on the Event Dispatch Thread. So whatever you are doing, for example, with gui.doCommands(), make sure that you don't violate this Single Thread Rule.
Related
I'm using Java within a Processing project. I'm trying to make a delay that doesn't stop the program, but stops only a given block of code. That "processing" block of code could for example add 1 to a variable, then wait one second and then add 1 again. The problem is that delay() (see reference) stops the whole program and Thread.sleep() doesn't work in a Processing project.
You should not use delay() or Thread.sleep() in Processing unless you're already using your own threads. Don't use it on the default Processing thread (so don't use it in any of the Processing functions).
Instead, use the frameCount variable or the millis() function to get the time that your event starts, and then check that against the current time to determine when to stop the event.
Here's an example that shows a circle for 5 seconds whenever the user clicks:
int clickTime = 0;
boolean showCircle = false;
void draw(){
background(64);
if(showCircle){
ellipse(width/2, height/2, width, height);
if(clickTime + 5*1000 < millis()){
showCircle = false;
}
}
}
void mousePressed(){
clickTime = millis();
showCircle = true;
}
Side note: please try to use proper punctuation when you type. Right now your question is just one long run-on sentence, which makes it very hard to read.
I'm trying to visualize various graph-algorithms. I want to make it so, that after every 2 seconds the graph get updated and gets repainted. I have tried using the Thread.sleep() method but it just freezes the GUI and then after a while is done with the complete algorithm.
(I am fairly new to Java so don't be to harsh with the code)
The Code in question:
else if(ae.getSource() == fordFulkersonButton){
dinicButton.setEnabled(false);
edmondsKarpButton.setEnabled(false);
gtButton.setEnabled(false);
if(checkbox.isEnabled()){
fordFulkersonButton.setEnabled(false);
while(!fordFulkerson.getIsDone()){
flowNetwork = fordFulkerson.algoFF(flowNetwork);
popupText.setVisible(true);
Integer i = new Integer(flowNetwork.getCurrentFlow());
String s = i.toString();
popupText.setText("Aktueller Fluß: "+s);
graphDrawer.setFlowNetwork(flowNetwork);
this.showFrame();
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Integer in = new Integer(flowNetwork.getCurrentFlow());
String st = in.toString();
popupText.setText("Algorithmus is beendet mit Fluss: "+st);
}
flowNetwork = fordFulkerson.algoFF(flowNetwork);
popupText.setVisible(true);
Integer i = new Integer(flowNetwork.getCurrentFlow());
String s = i.toString();
if(fordFulkerson.getIsDone()){
popupText.setText("Algorithmuss beednet mit maximalen Fluß: "+s);
}else{
popupText.setText("Aktueller Fluß: "+s);
}
graphDrawer.setFlowNetwork(flowNetwork);
this.showFrame();
}
Doing huge amounts of work in a UI thread freezes the UI. If you want to do animations or complex work, use a worker thread or a Swing timer.
You must not call Thread.sleep() in Swing UI code. Instead, you need to think like an animator: Show one frame of the animation at a time. Some external source will call your code to show the next frame. The external source is the Swing timer. Your code draws the next frame and returns. That way, you never block the UI thread for long.
Google for "swing animation". Interesting results are:
http://www.java2s.com/Tutorial/Java/0240__Swing/Timerbasedanimation.htm
http://zetcode.com/tutorials/javagamestutorial/animation/
I am working on a school project that involves generating two separate Swing Canvas objects which animate Breadth/Depth-First Search Algorithms on cloned copies of a Matrix/Grid Data Structure I have designed.
I have created a few classes that help translate the Matrix/Grid into graphics, which are combined in a SearchAnimation class that acts a ViewController for managing the animations. In the image below, they appear on the right (not in the yellow background area). Each SearchAnimation object includes a JLabel, Canvas, and White Background.
Below is a screenshot of the layout:
The JFrame contains two instances of the SearchAnimation Class in the Application Controller Class (ICL.java). These animations must run concurrently. I have created separate Threads for each animation, passing it separate SearchAnimation objects:
public void setupDepthFirstPanel() {
// Create a new GridGraphic Panel
//canvasDepthFirst = new GridPanel(null, DEPTH_FIRST_LABEL);
mDepthAnimation = new SearchAnimation(null, SearchAnimationType.DEPTH_FIRST_ANIMATION);
mDepthThread = new Thread(mDepthAnimation, "Depth Thread");
}
public void setupBreadthFirstPanel() {
// Create a new GridGraphic Panel
//canvasBreadthFirst = new GridPanel(null, BREADTH_FIRST_LABEL);
mBreadthAnimation = new SearchAnimation(null, SearchAnimationType.BREADTH_FIRST_ANIMATION);
mBreadthThread = new Thread(mBreadthAnimation, "Breadth Thread");
}
I start the Threads in the ActionListener class that responds to the Click Event of the button that labeled "Label Components":
if ( source == labelComponents ) {
if (DEBUG && DEBUG_CLICK_LISTENER) System.out.println("\"Label Components\" Button Clicked!");
/*This is where the call for the labelBreadth and labelDepth of the
ICLLogic class is going to occur*/
// Run Animation
// Set Up Threads
System.out.println("ICL.ActionPerformed - Current Thread: " + Thread.currentThread());
//mBreadthThread = new Thread(mBreadthAnimation, "Breadth Animation");
//mDepthThread = new Thread(mDepthAnimation, "Depth Animation");
// Start Threads
mBreadthThread.start();
mDepthThread.start();
}
When the program runs and the "Label Components" button is clicked, only one of the graphics starts animating, but it seems as though both SearchAnimation Threads are running within a single JPanel/Canvas since the animation does not follow the logic of either algorithm.
Here is the implementation of the Runnable Interface within SearchAnimation:
// THREAD METHODS
/** Implementation of the Runnable interface for Multithreading of the
* SearchAnimation Class, which allows multiple SearchAnimations to run Concurrently.
* In this case, the Breadth & Depth-First SearchAnimations
*
*/
public void run() {
System.out.println("Thread Started - " + mAnimationType.toString());
// Run the Animation
step();
}
Which eventually calls determineSearchType() that switches on an Enum to pick the appropriate Algorithm:
public void determineSearchType(Pixel p) {
// Animate a single pixel movement, step depends on AnimationType
if (DEBUG && DEBUG_STEP_NEXT_PIXEL) { System.out.println("Determining Animation Type..."); }
switch (mAnimationType) {
case BREADTH_FIRST_ANIMATION:
if (DEBUG && DEBUG_STEP_NEXT_PIXEL) { System.out.println("Animation Type: Breadth-First"); }
// Begin Breadth-First Search
stepBreadthSearch(p);
break;
case DEPTH_FIRST_ANIMATION:
if (DEBUG && DEBUG_STEP_NEXT_PIXEL) { System.out.println("Animation Type: Depth-First"); }
// Begin Depth-First Search
stepDepthSearch(p);
//simpleDepthSearch(mCurrentPixel);
break;
}
}
When I alternate commenting them out, each Thread/Animation executes in its own JPanel/Canvas graphic and produces the expected results. I am pretty new to threading and I'm sure someone has an easy solution. Any ideas at how I can fix the issue that the animations won't animate simultaneously?
option1 :
to give another Thread chance to be executed. at the end of thread code, try yield() and see if you have some luck
Thread.currentThread().yield();
option2 :
add flag in your thread, to pause and continue the thread. the idea is
after thread 1 finish the step
- pause thread 1 - then start thread 2 - after thread 2 finish the step
- pause thread 2 - and continue thread 1 again.
I have written a program which uses the progressbar class from the default java runtime. It works perfectly except for the fact that it only works once. I use it to display the loading of various images into my GUI and it works fine on startup. However, once I call it again it just displays a JFrame with no content. I can drag the JFrame around and everything, it's just that it won't display anything. This is peculiar considering it works when it runs the first time, but not there after. Here is my code:
public void prefetch (){
try{
pageURLs = mangaEngine.getPageList();
monitor = new ProgressMonitor(parent, "Loading Chapter..,", null, 0, mangaEngine.getPageList().length);
pages = new StretchIconHQ[pageURLs.length];
//Resets page counter to first page by fetching pages in reverse order
monitor.setMaximum(pageURLs.length-1);
for(int i = pageURLs.length-1; i>=0; i--){
pages[i] = mangaEngine.loadImg(pageURLs[i]);
monitor.setProgress(pageURLs.length-1-i);
monitor.setNote("Loading Image:" + (pageURLs.length-1-i) + " of " + (pageURLs.length-1));
}
}
catch(Exception ex){
ex.printStackTrace();
}
}
Any ideas on how to fix it?
You need to run the long-running code in a background thread such as that created by a SwingWorker.
In fact, the Progress Monitor Tutorial describes how to do this exactly:
Create a SwingWorker
Add a PropertyChangeListener to it
Listen to the "progress" property
Update your monitor's progress with that of the SwingWorker's.
I am using freeTTS to speak out some text, in the background i want a animated gif to keep playing
When i try this: as soon as the voice starts speaking, the image in background gets hanged even if i keep it in some other JFrame... and after the speech is completed it starts moving. I want it to run properly without pauses.
I am placing a animated gif in a label by importing it to my application and changing the icon to that image in label' properties.
Edit
Here is my code:
private void RandomjBActionPerformed(java.awt.event.ActionEvent evt) {
Voice voice;
voice = voiceManager.getVoice(VOICENAME);
voice.allocate();
voice.speak("Daksh");
}
I am actually using a lot of setVisible, setText, declaration of integers, calculating on them but i have removed them to simplify the code for you to understand. Still it gives the same problem if executed.
The button 'RandomjB' is clicked from another button by the following code:
final Timer timer = new Timer(zad, new ActionListener() {
int tick = 0;
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Success" + ++tick);
RandomjB.doClick();
final int col = Integer.parseInt(t3.getText());;
if (tick >= col) {
((Timer) e.getSource()).stop();
for(int g=0; g<col; g++){
jButton2.setVisible(true); // Check Button -> Visible
}
}
}
});
timer.setInitialDelay(0);
System.out.format("About to schedule task.%n");
timer.start();
System.out.format("Task scheduled.%n");
It is hard to tell without the code, I however assume that you loop the speech synthesis within the one and only Swing-Thread and therefore block all kind of window updates as long as the speech loop is in progress.
As stated by Shaun Wild: you need to use a second Thread for the speech loop.
You may want to do some research on Threads and Concurrency
These allow two things to operate simultaneously, this is just my assumption.
Assuming that you instantiate some kind of class for the FreeTTS you may want to do something like this
FreeTTSClass tts;
new Thread(new Runnable(){
public void run(){
tts = new FreeTTSClass();
}
}).start();