JProgressbar not showing and code executing in wrong order? - java

I've been having some issues with making a GUI for a program. Back-end program works fine but sometimes it takes a while to complete.
In the GUI I want to show the user that work is being done and thought an indeterminate JProgressBar (progress) would suffice - it's indeterminate as I only want an indicator that something is happening and not actually follow the real progress. The bar has already been added to a frame so it's always there, and it's just unhidden when the button is clicked and the process starts.
It should then be re-hidden once the process has finished. I've also put in some text that also should show that the process is running, which is then changed to a completed bit after it's run.
However, it's not working as intended. What seems to be happening is that the code appears to be executing in the wrong order. The c.run() instruction seems to run before the setVisible(true) one does as the progress bar only appears once the run command has finished, and I can't see why. The run() command is quite a large operation so takes a while (it's only a single threaded application), but I don't know why it would be doing this as the code definitely runs in the right order when you use print debugging to see which instructions run in which order.
but.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
runCSVReader(e);
}
});
private void runCSVReader(ActionEvent evt) {
progress.setVisible(true);
label8.setForeground(Color.YELLOW);
label8.setText("Processing...");
correctInput();
String accTypes = tf5.getText() + "\\" + tf6.getText() + ".csv";
String inputFile = tf.getText() + "\\" + tf4.getText() + ".csv";
String outputFile = tf7.getText() + "\\" + tf2.getText();
System.out.println("acctypes " + accTypes+"\ninput " + inputFile + "\noutput " + outputFile);
try {
csvreader c = new csvreader();
c.setAccTypesFile(accTypes);
c.setInputFile(inputFile);
c.setOutputFile(outputFile);
c.run();
// progress.setVisible(false);
label8.setForeground(Color.GREEN);
label8.setText("Complete");
//pb.end();
}
It's just weird as it almost seems like the code runs in the order
c.run();
progress.setVisible(true);
label8.setForeground(Color.YELLOW);
label8.setText("Processing...");
// progress.setVisible(false);
label8.setForeground(Color.GREEN);
label8.setText("Complete");
as the text changes straight to the green completion message (with only the yellow message showing for a very short time) and (when uncommented) the setvisible go straight to false.
Any idea on why this might be happening? As far as I can tell there aren't any conflicting calls within the called methods that should affect this.
Is it the case that because it's a single-threaded program the progress bar won't show until the main thread is free from the run() command, and if so, why is it that the text also appears to not run when first called?

Related

How to make multiple buttons on a GUI work

Im creating a GUI program with multiple buttons. I'm only able to use one of the buttons at the moment. Here is my Button Listener class. I want to be able to use the "Test" button and then use the "Yes" or "No" button after. Let me know if you need to see any more of my code.
public class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==TestButton)
{
TestWord = (Text_Input.getText());
StringBuilder RevTestWord = new StringBuilder();
RevTestWord.append(TestWord);
RevTestWord = RevTestWord.reverse();
DisplayText = "Is " + RevTestWord + " a real word?";
Test_Anadrome.setText(DisplayText);
if(e.getSource()==YesButton)
{
DisplayText = "Word added to Anadrome list.";
Test_Anadrome.setText(DisplayText);
}
if(e.getSource()==NoButton)
{
DisplayText = "Type a different word and press the 'Test Word' Button.";
Test_Anadrome.setText(DisplayText);
}
}
}
}
Sorry I'm pretty new to Java.
It looks like your if/else statements for your YesButton and NoButton are inside of your if statement for TestButton, so as a result those statements are only being checked if source==TestButton. Try moving this code outside of the if statement:
if(e.getSource()==YesButton)
{
DisplayText = "Word added to Anadrome list.";
Test_Anadrome.setText(DisplayText);
}
if(e.getSource()==NoButton)
{
DisplayText = "Type a different word and press the 'Test Word' Button.";
Test_Anadrome.setText(DisplayText);
}
You need to have all your testing at the same level. The nested ifs are causing problems. And remember to use if/else. No sense in continuing to do other checks if the previous one succeeds.
You can also set the ActionCommand which is a String. For components that use the actionListener, you can do for example button.setActionCommand("mycommand").
Then in the actionPerformed(ActionEvent e) you can do
String cmd = e.getActionCommand();
That allows you do discern between buttons or other components without having direct access to their instance.
If you don't set the ActionCommand it defaults to the button's text.

Libgdx actor position resets after adding another action

I'm making some simple animation using Actors (Labels, to be precize) and Actions.
My initial plan was to move one of them far to the left instantly, then make it smoothly appear through the edge of screen, replacing another. But every time a new Action is executed, Label's position resets, so I can't get the effect I planned. How do I avoid it?
Here's code, if you need it:
newAttack.addAction(Actions.moveBy(-1 * game.W, 0));
newAttack.setText(game.local.get(_attack));
newAttackType.background = game.skin.getDrawable("attack_" + getAttackType(_attack));
lastAttack.addAction(Actions.sequence(Actions.moveBy(game.W, 0, 1.5f),
Actions.run(new Runnable() {
public void run() {
System.out.println(lastAttack.getX() + " " + lastAttack.getY());
newAttack.addAction(Actions.sequence(Actions.moveBy(game.W, 0, 1.5f), Actions.run(new Runnable() {
public void run() {
lastAttack.addAction(Actions.moveBy(-1 * game.W, 0));
newAttack.addAction(Actions.moveBy(-1 * game.W, 0));
System.out.println(lastAttack.getX() + " " + lastAttack.getY() + "\n" + "--");
lastAttack.setText(game.local.get(_attack));
lastAttackType.background = game.skin.getDrawable("attack_" + getAttackType(_attack));
}
})));
}
})));
This may not work, but looking into the source code of Label.setText() reveals that the method calls Actor.invalidateHierarchy. This means that whatever is containing the lastAttack actor will reset the lastAttack's position.
So since you are adding the actions before you are calling Label.setText(), the position will be reset and then the actions won't work properly.
You should try setting the text, then setting the position of the actor to off screen, and then adding the slide in Action.

Trying to start my thread

First, I know that the way I'm trying to read the input is really bad, but I've tried to use Keylistener, and it doesn't work no matter what I try. I don't know what I'm doing wrong, so this is what I'm trying at the moment. I'm trying to call a thread in Controller.java from PreControls.java. If you could help me implement a working keylistener, it would me much appreciated, but I think fixing this thread problem will work too. I have tried debugging it, and the thread doesn't seem to start.
Code in PreControls.java:
Controller C = new Controller();
C.start();
System.out.print("Thread Should be started ");
Code in Controller.java:
package Game;
public class Controller extends Thread {
public void MyShipController(){
System.out.print("Thread Is started ");
String CharIn = "";
while(SpaceInvaders.GameOn = true){
CharIn = PreControls.ReadKeyPressed.getText();
if(CharIn.equalsIgnoreCase("a")){
SpaceInvaders.MyPos[0]--;
System.out.print("Move Left ");
}else if(CharIn.equalsIgnoreCase("d")){
SpaceInvaders.MyPos[0]++;
System.out.print("Move Right");
}else if(CharIn.equalsIgnoreCase(" ")){
//Fire Bullet
}
PreControls.ReadKeyPressed.setText("");
SpaceInvaders.MyShip.setLocation(SpaceInvaders.MyPos[0], SpaceInvaders.MyPos[1]);
jp1.repaint();
}
}
}
Sorry for not providing an SSCCEE. I'd need to send my whole project, and that defeats the point of doing a project.
ReadKeyPressed is the JTextArea that I'm having the letters inputted into.
jp1 is the JFrame
I'm working in the Eclipse IDE.
EDIT: forgot to add: After I start the applet, the Console reads "Thread Should be started" only, so it is a problem with the how I made the thread, or how I'm trying to create it.
Edit 2: My End goal is to detect when a (or left arrow) is pressed and move MyShip (a JLabel) to the left by 1 position and more it to the right by 1 position if d (or right arrow) is pressed.
Alright, I've accepted Williams answer as it made my thread run. And as suggested, I'm going to look into key bindings to detect when the keys are pressed. Thanks for all the help.
This = is an assinment operator.
while(SpaceInvaders.GameOn = true)
I think you wanted this ==
while(SpaceInvaders.GameOn == true)
Or better yet, and much cleaner, just
while(SpaceInvaders.GameOn)
Also, you should use key bindings instead of KeyListener, which my give you focus problems. See this answer for an example of using key bindings. Also see the tutorial
The code you've written in method MyShipController should be placed inside the run method of your thread. The run method is what the thread actually executes within.
As you've written it now, calling start on your Controller class will start your thread, and that thread will end immediately as its run method is empty.
public class Controller extends Thread {
#Override
public void run()
//public void MyShipController(){
System.out.print("Thread Is started ");
String CharIn = "";
while(SpaceInvaders.GameOn = true){
CharIn = PreControls.ReadKeyPressed.getText();
if(CharIn.equalsIgnoreCase("a")){
SpaceInvaders.MyPos[0]--;
System.out.print("Move Left ");
}else if(CharIn.equalsIgnoreCase("d")){
SpaceInvaders.MyPos[0]++;
System.out.print("Move Right");
}else if(CharIn.equalsIgnoreCase(" ")){
//Fire Bullet
}
PreControls.ReadKeyPressed.setText("");
SpaceInvaders.MyShip.setLocation(SpaceInvaders.MyPos[0], SpaceInvaders.MyPos[1]);
jp1.repaint();
}
}
}
However, I suggest your controller class extend Runnable rather than Thread.

Making moving motion with labels using threads in java

I'm having a problem I'm making a pool game and I need the ballos to react when I simulate a hit, the program works like this, you click the direction and power to hit the ball and the click go, the go button is in the GUI class where my labels are created, the button calls a method from my main class that recieves the parameter and then with a while in it, changes the X and Y of the ball till the power is reduced to 0 and then stops, the code is working, but the ball moves until the while stops. So the while works and when the power int is 0 the while goes out and then the new X,Y are painted.
This is the funcion that the button calls, the button sends all the parameters
public void golpe(int pbola, int pvelocidad, String pdireccion, JLabel[] listalabels) throws InterruptedException{
listabolas[pbola].setVelocidad(pvelocidad);
listabolas[pbola].setDireccion(pdireccion);
while (listabolas[pbola].getVelocidad() > 0) {
moverBola(pbola, listalabels);
//System.out.println(listabolas[pbola].getPosX());
//System.out.println(listabolas[pbola].getPosY());
Thread.sleep(500);
//This line is supposed to change the X and Y of the object over and over
//but only does it till the end
listalabels[pbola].setLocation(listabolas[pbola].getPosX(), listabolas[pbola].getPosY());
}
}
Here is the function moverbola(), only copied one "if" so that the code doesn't look to big
private void moverBola(int pbola, JLabel[] listalabels) {
if (listabolas[pbola].getDireccion().equals("SE")) {
int pposX = listabolas[pbola].getPosX();
listabolas[pbola].setPosX(pposX + 1);
int pposY = listabolas[pbola].getPosY();
listabolas[pbola].setPosY(pposY + 1);
}
Swing is a single threaded framework. That is, all interactions with UI are expected to occur from within a single thread, known as the Event Dispatching Thread.
Any action that blocks this thread, will prevent the EDT from updating the screen or processing any new events.
Your while-loop is blocking the EDT, preventing it from painting any updates until after the while-loop is completed.
Take a look at Concurrency in Swing for more details.
There are a number of approaches you could take...
You could use a Thread, but this causes problems as you need to ensure that any changes you make to the UI are re-synced back to the EDT and this can become messy...
For example
You could use a javax.swing.Timer that ticks at a regular interval and you would update any internal parameters from within it's assigned ActionListener. Because the tick events occur within the EDT, it is save to update the screen from within it.
For example
You could use a SwingWorker to run the task in the background. It has methods for re-syncing updates back to the EDT, but might be a little over kill for your purposes...
Updated with a possible Timer example
Caveat- It is very hard to produce a reasonable example with only a code snippet, but, something like this might work
public void golpe(final int pbola, int pvelocidad, String pdireccion, final JLabel[] listalabels) throws InterruptedException{
listabolas[pbola].setVelocidad(pvelocidad);
listabolas[pbola].setDireccion(pdireccion);
Timer timer = new Timer(40, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (listabolas[pbola].getVelocidad() == 0) {
((Timer)evt.getSource()).stop();
} else {
moverBola(pbola, listalabels);
}
}
});
timer.setRepeats(true);
timer.start();
}

JAVA Swing Gui Window Hangs

I am having an issue with SWING GUI or at least I think it is the swing gui.
Here is my main code file:
/**
*
*/
package com.tda.t2.ctas.slasher;
import javax.swing.SwingUtilities;
import com.tda.t2.ctas.slasher.gui.mainFrame;
import com.tda.t2.ctas.slasher.utils.MyCloseListener;
public class SLASHer {
public SLASHer () {
}
/**
* #param args
*/
public static void main(String[] args) {
//EventQueue.invokeLater(new Runnable() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ConfigData myconfig = new ConfigData();
try {
//TdaUrlHelper window = new TdaUrlHelper();
//window.tdaFrame.setVisible(true);
mainFrame tdaFrame = new mainFrame();
tdaFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Simple call to create the frame and open it. There are other files that I did not put here for space. But the problem that I have (and I have tried on several machines and operation systems) is that the buttons on the window seem to hang. I can select the window and click on the buttons and they highlight like they were hit but nothing happens. I have a tabbed plane and clicking on the other tabs also does nothing. Some times this last for about 15 seconds and other times it lasts several minutes. But it always eventually comes back and will respond to new input (ie it does not remember all the click around I did before it came back). The application overall is simple in that it sits waiting until a user does something before it does something so I am confused on why it seems to hang.
Any help would be appreciated.
Thanks
What is the offending code attach to the button that hangs? Check your console for exceptions, and put some System.out.println() statements at the top and bottom of that code. See if you see those print statements print out. Watch how long it takes for the one at the top to print and bottom one to print. If you see both statements then you know that whole block is executing, but if it takes a while to show the last statement you know you are hanging up the Swing thread (also known as EDT - event dispatch thread). Rule number one in Swing the UI can't repaint while it's executing your ActionListener.
In order to make a responsive UI you have to see the first and last statement appear on the console in under 10-100ms (visually almost instantaneous). If you really want to get fancy you can use System.currentTimeMillis() at the stop and bottom. Subtract the two values and println() it. That'll tell you exactly how long that listener ran for. If it's greater than 100ms you need to restructure your code by either improving your algorithm or off loading the long calculation on a thread (see this SwingWorker tutorial).
public void actionPerformed(ActionEvent event) {
System.out.println("Starting SomeProcess");
long start = System.currentTimeMillis();
// all your code belongs here
long duration = System.currentTimeMillis() - start;
System.out.printf("SomeProcess took %,d ms%n", duration );
}

Categories