This question already has answers here:
JFrame not updating before thread.sleep()
(2 answers)
Closed 6 years ago.
I'm trying to change the text in JTextArea whenever the following PRINT() method is run. The entire program is long so I can only post a bit but basically a [50][50] char array contains is being turned into 50 lines of 50-character strings. The JFrame holding this JTextArea is initiated when a button is pushed and immediately prints the char array into the JTextArea (when I've made it so that the char array is never updated). The program is meant to update this text every few seconds.
Instead of updating every second, though, The JFrame appears as basically a blank box until the last time PRINT() has been run. Currently, it is meant to print 1...10 in separate lines through 10 calls to PRINT(), each after output.outputLines has been updated with the added number. Instead, it only shows a blank frame until the last number has been loaded, then prints the whole thing.
PRINT() method:
public boolean PRINT(){
String result = ""; //Used to hold the characters to be printed to the screen
for(int x = 0; x<50; x++){
for(int y = 0; y<50; y++) {
result = result + String.valueOf(output.outputLines[x][y]);
}//End of inner FOR statement
result = result + "\n";
output.jTextArea1.setText(result);
}//End of outer FOR statement
return true;
}
code used to pause between PRINT() calls:
try {
java.lang.Thread.sleep(1000);
catch (Exception ex) {
System.out.println("Exception in Thread.sleep()");
Can anybody help me to figure out what is going wrong?
You're calling Thread.sleep(...) on the Swing event thread, essentially putting it and your GUI to sleep. The solution (as always) is don't do this. If you want to pause use a Swing Timer. If you need to run long-running code, use a background thread such as a SwingWorker.
Related
This question already has answers here:
Catching Ctrl+C in Java
(3 answers)
Closed 2 years ago.
Say I have a java program (actually I wrote a CLI) which goes into an endless loop and within that loop it's incrementing a counter. When I hit Ctrl + C from my command line to exit from the program, can I print the value of the counter and then exit? Say I have a function like:
public void count(){
int count = 1;
while (count>0) {
count++;
}
}
Now, I invoke this bit of code and the execution begins. After a while, I hit Ctrl + C on the terminal and the program is forced to exit. While it exits, can I somehow print the value of count and then exit?
Note: I'm not doing this exactly in my program. I'm just trying to figure out if there's a way I can force exit a program and upon force exit print something to the console.
Slight copy pasta from another site (StackOverflow prefers answers here though)
public class Main {
public static var message; //can be String, int, whatever.
static class ForceClosedMessage extends Thread {
public void run() {
System.out.println(message);
}
}
public static void main(String... args) {
Runtime.getRuntime().addShutdownHook(newForceClosedMessage());
//Go about your business
}
}
You can use break() method in your while.
For example:
int count = 1;
while (count>0)
{
count++;
if(count==10){
break();
}
}
System.out.println(String.valueof(count));
This code finishes when count equals 10
I am newish to Java and trying to building a small rocket program.
I have 3 distinct methods that change the size and colour of the rockets exhaust jet on the graphical display when invoked which work great individually.
public void pulse1()
{
jet.setDiameter(6);
jet.setColour(OUColour.RED);
jet.setXPos(58);
}
public void pulse2()
{
jet.setDiameter(12);
jet.setColour(OUColour.ORANGE);
jet.setXPos(55);
}
public void pulse3()
{
jet.setDiameter(24);
jet.setColour(OUColour.RED);
jet.setXPos(48);
}
However, what I am trying to do is code another method ignition() that uses some sort of loop to invoke each of the three pulse methods in that chronological order a maximum of 5 times with a 500 millisecond delay between each call. (the idea being to simulate on the graphical display the firing up of the rockets engines)
Thus far I have tried the following without success.
public void ignition()
{
pulse1();
delay(500); // uses the inbuilt delay method
pulse2();
delay(500);
pulse3();
}
In Java, a loop will execute the contents of a code block. A code block is anything between two curly braces.
{
statement1;
statement2;
} // statement2 and statement2 are both inside the code block
So, when you declare a loop (perhaps with for or while), the loop will act on the very next code block. You can simply call the delay function once each time within the loop block, and it will wait once per loop.
A way to achieve what you are talking about using a for loop might be like so
public void ignition() {
for(int i = 0; i < 5; i++) {
pulse1();
delay(500); // uses the inbuilt delay method
pulse2();
delay(500);
pulse3();
delay(500);
}
EDIT: Misinterpreted what OP wanted to loop through
As you are not definite on how many number of times you should traverse in a loop but have a maximum limit of 5, use a random no. generator.
int i = rand.nextInt(5) + 1; //1 is minimum and 5 is maximum
int a=0;
while(a<i){
pulse1();
delay(500); // uses the inbuilt delay method
pulse2();
delay(500);
pulse3();
a++;
}
You could also use Thread.sleep(500) if your delay method is giving you issues.
I am developing a small game, (Java, LibGdx) where the player fills cloze-style functions with predefined lines of code. The game would then compile the code and run a small test suite to verify that the function does the stuff it is supposed to.
Compiling and running the code already works, but I am faced with the problem of detecting infinite loops. Consider the following function:
// should compute the sum of [1 .. n]
public int foo(int n) {
int i = 0;
while (n > 0) {
i += n;
// this is the place where the player inserts one of many predefined lines of code
// the right one would be: n--;
// but the player could also insert something silly like: i++;
}
return i;
}
Please note that the functions actually used may be more complex and in general it is not possible to make sure that there cannot be any infinite loops.
Currently I am running the small test suite (provided for every function) in a Thread using an ExecutorService, setting a timeout to abort waiting in case the thread is stuck. The problem with this is, that the threads stuck in an endless loop will run forever in the background, which of course will at some point have a considerable impact on game performance.
// TestClass is the compiled class containing the function above and the corresponding test suite
Callable<Boolean> task = new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
// call the test suite
return new TestClass().test();
}
};
Future<Boolean> future = executorService.submit(task);
try {
Boolean result = future.get(100, TimeUnit.MILLISECONDS);
System.out.println("result: " + (result == null ? "null" : result.toString()));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
future.cancel(true);
}
My question is now: How can I gracefully end the threads that accidentally spin inside an endless loop?
*EDIT To clarify why in this case, preventing infinite loops is not possible/feasable: The functions, their test suite and the lines to fill the gaps are loaded from disk. There will be hundrets of functions with at least two lines of code that could be inserted. The player can drag any line into any gap. The effort needed to make sure no combination of function gap/code line produces something that loops infinitely or even runs longer than the timeout grows exponentially with the number of functions. This quickly gets to the point where nobody has the time to check all of these combinations manually. Also, in general, determining, whether a function will finish in time is pretty much impossible because of the halting problem.
There is no such thing as "graceful termination" of a thread inside the same process. The terminated thread can leave inconsistent shared-memory state behind it.
You can either organize things so that each task is started in its own JVM, or make do with forceful termination using the deprecated Thread.stop() method.
Another option is inserting a check into the generated code, but this would require much more effort to implement properly.
The right way is to change the design and avoids never ending loops.
For the time being, inside your loop you could check if the thread is interrupted some way by: isInterrupted() or even isAlive().
And if it is you just exit.
It is not normal to have a never ending loop if it not wanted.
To solve the problem You can add a counter in the loop and if you reach a limit you can exit.
int counter = 0;
while (n > 0) {
counter++;
if (counter > THRESHOLD) {
break;
}
i += n;
// this is the place where the player inserts one of many predefined lines of code
// the right one would be: n--;
// but the player could also insert something silly like: i++;
}
I don't know if this is possible. I'm making a lottery application, and I'm trying to use as few GUI components as possible. So I have a JTextArea that is supposed to show the following message (for example):
"Calculating...55.4%"
When I print it to console, it shows just fine, but it won't print it to the JTextArea. I tried to use SwingUtilities.invokeLater but that's not working either.
for (int x = 0; x < daysBetween; x++)
{
completion = "Calculating..." + df.format((100 * (x + 1)) / daysBetween) + "%";
if (!textArea.getText().equals(completion))
{
textArea.setText(completion);
}
/*
Here I have a lot of irrelevant code that compares your tickets to the winning tickets and counts your winnings and other statistics...
*/
}
ticketReport += "Computation time: " + getElapsedTime(start, System.nanoTime());
ticketReport += "\nEnd date: " + (cal.get(Calendar.MONTH) + 1) + "/" + cal.get(Calendar.DAY_OF_MONTH) + "/" + cal.get(Calendar.YEAR);
ticketReport += "\nTotal # of tickets purchased: " + numOfTicketsPurchased;
/*
etc. with filling out the ticket report
*/
textArea.setText(ticketReport);
As you can guess, I want the JTextArea to update as I set the text of the textArea in the for loop above. It does not update the JTextArea until the end of the method, which is the very bottom when I set the text area to show the ticket report.
MY END GOAL: I want to eventually turn this into an Android phone application, so that's why I don't want to use any pop-ups or anything.
My original SwingWorker approach made it where it showed the completion percentage status in the JTextArea. I added an option to cancel the operation, and when I attempted to cancel, the "thread" (SwingWorker) would not cancel. When I cancel and restart, it would stack constantly. Each successive starting while the other was going would cause the calculations to go slower and slower, and then give incorrect information.
The way I did it this second time solved the original problem and this new problem. I created a new private class that extends Thread, overran its run() method, and inserted the code to be executed in the thread in that method. I noticed any method to stop the thread was deprecated because of potential issues, so I created a boolean to be set when the user requests to stop the thread, and inside the thread it periodically reads the value of the boolean, then exits when it equals to true.
The way I start the thread is by re-initializing the object BackgroundCalc and calling its start() method.
private class BackgroundCalc extends Thread
{
public void run()
{
/*
initializing stuff here
*/
for (int x = 0; x < daysBetween; x++)
{
progress = (100 * (x + 1)) / daysBetween;
if (destroyCalcThread) return;
/*
background calculations here
*/
}
/*
finish up thread here
*/
}
}
I'm a little inexperienced with threads, so hopefully my struggle here and the way I explained it will help someone else who's inexperienced with the concept.
/*
EDIT: This temporarily solved the problem, but I ran into another problem. Now when I attempted to cancel the SwingWorker by calling its cancel method with parameter true, it would not cancel. Please see my other answer for the way I solved this.
*/
I figured it out. The method above I put inside a SwingWorker, as follows:
SwingWorker<Void, Void> sw = new SwingWorker<Void, Void>()
{
#Override
protected Void doInBackground() throws Exception
{
//method here
}
}
Inside that method, I called setProgress method with parameter "(100 * (x + 1)) / daysBetween" to show the correct % completion. Then after that, I added this:
sw.execute();
sw.addPropertyChangeListener(new PropertyChangeListener()
{
#Override
public void propertyChange(PropertyChangeEvent arg0)
{
textArea.setText("Calculating..." + sw.getProgress() + "%");
if (sw.getProgress() == 100)
textArea.setText(ticketReport);
}
});
It shows percentages as whole numbers rather than the #.## I originally wanted, but I can change very easily if I wanted to.
I am using NetNeans
I have a JPanel that is supposed to show some already input data along with a progress bar while the remainder of the program carries out some lengthy processing (about 1 minute long). Once the processing is done, this same JPanel is supposed to be updated with a few JTextFields containing the processed data.
The issue:
The JPanel shows up completely blank throughout the time period the processing is going on. Once the processing is done, then all the data shows up. Its baffling me. Here is how i've programmed it:
/*The parent class which calls the output JPanel
*Lister is the output JPanel. The constructor calls initComponents(), and fills
*text fields that contain the data that has already been input.
*fillresult then triggers the processing function that takes a while. Once the
*processing function is done, fillresult fills the processed data into the
*respective Text Fields
*/
ListWords = new Lister();
System.out.println("l");
ListWords.setVisible(true);
ListWords.fillResult();
//Lister constructor:
Lister(){
initComponents();
MatchWords = new Matcher();//Matcher() only contains the initialization of a List
jTextField1.setText(Scrabbulous.scrab.EntryWind.getCombo().substring(0, 1));
jTextField2.setText(Scrabbulous.scrab.EntryWind.getCombo().substring(1, 2));
jTextField3.setText(Scrabbulous.scrab.EntryWind.getCombo().substring(2, 3));
jTextField4.setText(Scrabbulous.scrab.EntryWind.getCombo().substring(3, 4));
jTextField5.setText(Scrabbulous.scrab.EntryWind.getCombo().substring(4, 5));
jTextField6.setText(Scrabbulous.scrab.EntryWind.getCombo().substring(5, 6));
jTextField7.setText(Scrabbulous.scrab.EntryWind.getCombo().substring(6));
}
//fillresult():
public void fillResult(){
int rIndex = 0;
MatchWords.makeWords(rIndex);
while(MatchWords.realWords.Head == null && rIndex < 2){
rIndex++;
updateStatusBar();
MatchWords.makeWords(rIndex);
}
Wordpoints = new String[MatchWords.realWords.getSize()];
for(int i=0; i<Wordpoints.length; i++){
Wordpoints[i] = "";
}
for(int i=0; i<MatchWords.realWords.getSize(); i++){
int total = 0;
for(int j=0; j<MatchWords.realWords.getNode(i).getWord().length(); j++){
for(int k=0; k<Scrabbulous.scrab.scralphabet.length; k++){
if(MatchWords.realWords.getNode(i).getWord().charAt(j) == Scrabbulous.scrab.scralphabet[k].getLetter()){
total += Scrabbulous.scrab.scralphabet[k].getValue();
Wordpoints[i] = ""+total;
}
}
}
}
try{
jTextField8.setText(MatchWords.realWords.Head.getWord());
jTextField13.setText(Wordpoints[0]);
}catch(NullPointerException e){
jTextField8.setText("No Match Found");
jTextField13.setText("-");
}
try{
jTextField9.setText(MatchWords.realWords.getNode(1).getWord());
jTextField14.setText(Wordpoints[1]);
}catch(NullPointerException e){
jTextField9.setText("No Match Found");
jTextField14.setText("-");
}
try{
jTextField10.setText(MatchWords.realWords.getNode(2).getWord());
jTextField15.setText(Wordpoints[2]);
}catch(NullPointerException e){
jTextField10.setText("No Match Found");
jTextField15.setText("-");
}
try{
jTextField11.setText(MatchWords.realWords.getNode(3).getWord());
jTextField16.setText(Wordpoints[3]);
}catch(NullPointerException e){
jTextField11.setText("No Match Found");
jTextField16.setText("-");
}
try{
jTextField12.setText(MatchWords.realWords.getNode(4).getWord());
jTextField17.setText(Wordpoints[4]);
}catch(NullPointerException e){
jTextField12.setText("No Match Found");
jTextField17.setText("-");
}
Could someone please be of assistance? Oh yes, and I read about adding a .refactor() and/or repaint(), but atleast the jForms initialized in the constructor should show up? :/
Also, it might be worth mentioning that all the code that is currently in the fillresult() function was initially in the constructor, and the output was displaying. However, since I want the progressbar here, I've shifted it to a new function. help please?
"The issue: The JPanel shows up completely blank throughout the time period the processing is going on. Once the processing is done, then all the data shows up."
What's happening is that everything is occurring on one thread, the Event Dispatch Thread (EDT). In order for an event to occur, like your JPanel updating, the process before it needs to complete.
As stated about the EDT:
" Tasks on the event dispatch thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive."
To work around this, you'll want to run your long process in a background thread. You should have look at Concurrency in Swing - the section on Worker Threads and SwingWorker in particular.