JLayeredPane not updating movement of JLabel - java

I have a for loop that changes the location of a JLabel in a JLayeredPane layout.
c.setVisible(true);
jLayeredPane.moveToFront(c);
for (int i = 0; i < 1000; ++i) {
c.setBounds(i, 500, 94, 136);
System.out.println(c.getLocation());
try {
Thread.sleep(2);
} catch (Exception e) {
}
}
This method is referencing to jLayeredPane, which is accessed from another class. It does indeed update the x value of the JLabel c, yet it does not show it on the screen.
What do I have to do to make it update in real time? I need this to run in order, not simultaneous to the next part of the program, thus I suppose multi-threading is disallowed.

What do I have to do to make it update in real time?
Don't use Thread.sleep(). This will cause the Event Dispatch Thread (EDT) to sleep, which means the GUI can't repaint itself until the entire loop is finished executing.
For animation you need to use a Swing Timer
I need this to run in order, not simultaneous to the next part of the program
When the Timer fires the required number of times you then stop the Timer and invoke a method containing the rest of your code.
Also, you should not be hardcoding "1000" as the loop control. You have no idea what the resolution of the screen will be when code is executed on different screens. You can use the Toolkit class and the getScreenSize() methods to get the appropriate dimension to use based on your actual requirement.

Related

Wait doesn't allow the JFrame to update

In my program, I need to wait for the user to input from a JFrame. When the user is done with the first input they press a JButton. This calls a constructor for a Class I made: HumanTrainer. In the constructor I need the user to have more inputs. I made two functions to wait and notify. But when the code gets to wait, everything freezes, and the JFrame doesn't update to what it should.
This is the action the first button preforms
startingButton.addActionListener((e)->{
Trainer[]t=new Trainer[2];//HumanTrainer extends Trainer
String[]names=new String[2];
for(int a=0;a<2;a++)
names[a]=((JTextField)(startingInputs[2][1+a])).getText();
grid.removeAll();//The JPanel that the Frame has
Frame.repaint();//The JFrame
Frame.validate();
if(isHuman[0])
t[0]=new HumanTrainer(names[0],grid,Frame);//The constructor
if(isHuman[1])
t[1]=new HumanTrainer(names[1],grid,Frame);
});
And the constructor for HumanTrainer
HumanTrainer(String name,JPanel grid,JFrame Frame){
super(name);
GridBagConstraints manager=new GridBagConstraints();
manager.gridx=0;
manager.gridy=0;
manager.gridheight=1;
manager.gridwidth=1;
manager.fill=GridBagConstraints.HORIZONTAL;
Font Format=new Font("Courier New",Font.PLAIN,14);
JButton cont=new JButton("Continue");//This is the button that when clicked should run the function that notifies
grid.add(cont,manager);
grid.repaint();//One of these four things SHOULD change the view of the frame
grid.validate();
Frame.repaint();
Frame.validate();
System.out.print("TEST");//This prints
cont.addActionListener((e)->{
made();//This is a function contained in HumanTrainer that only calls notify();
});
make();//This is a function contained in HumanTrainer that only calls wait(); With the proper try and catch
}
But when starterButton is pressed the screen freezes and doesn't update so that cont can be pressed.
Start by taking a look at Concurrency in Swing. Swing uses a single thread to dispatch it's events from, if you perform any long running or blocking operation from within the EDT (like calling wait), then it freeze your program and the user will have to terminate it.
You have two basic choices. You can either use a modal dialog to gather information from the user, see How to Make Dialogs, which will block the execution of the code at the point they are displayed, without blocking the entire EDT OR use a observer pattern, which can generate notifications that the user has provided what ever information you are expecting.
To be honest, a modal dialog is generally easier and can help prevent unexpected side effects
This...
make();//This is a function contained in HumanTrainer that only calls wait(); With the proper try and catch
would seem to be the core of your problem, but without more information and context of what you are trying to do, it's impossible to really suggest what you should do, however I'd recommend having a look at model-view-controller and seperare your code into more appropriate layers
First of all, you may want to close that for loop with {} so that it doesn't loop the whole code twice. Also you should check if wait() and notify() work correctly by individually testing them without java awt.

Java graphics not updating correctly

In my program, a the graphics on my screen are supposed to move across the screen. I have a loop that calls the draw function(the draw function is display.draw()), but whenever the amount of times the loop runs is greater than one, the display doesn't update after each time like it should. Instead, it waits until the loop finishes to update the display.
below is the refreshing function that only apparently runs at the end.
public void refresh()
{
myPanel.removeAll();
myPanel.add(display.draw());
myPanel.validate();
myPanel.repaint();
}
And here's the loop. I added a 1 second sleep after each iteration to make sure it just wasn't moving faster than I could see.
for(int i = 0; i < 2; i++)
{
myGraphics.rearrange();
this.refresh();
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
}
myGraphics.rearrange() simply changes the values of the variables which the drawing function uses,
changing the x and y variables for the positions of all the objects.
What is happening that it's not updating?
You're calling Thread.sleep(...) in a Swing program on the Swing event thread. What this does is put the entire application to sleep and so is not something that you should be doing. Instead use a Swing Timer to drive your animation.
For example:
Similar question 1
Similar question 2
Similar question 3
For more specific help, consider posting more code, preferably an mcve.

my JPanel refuses to be focused

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

(Java Swing) Calling function in time intervals and displaying time to next call in label

I have function like this in Java Swing app. I need after click on button call many function in intervals and in cycles. Function must be called inside jbutton because I have some global parameters in View that are used in jbutton function. Can you please help me how can I create time delay between calling functions and how to display remaining time in jLabel?
private void jButton1MouseClicked(java.awt.event.MouseEvent evt) {
statusMessageLabel.setText("Proccess started.");
for(int i=0;i< cycles;i++) {
//display remaining time
jLabelTimer.setText("00:09:59");
// after time call many functions and then go again
manyFunctions();
} catch (Exception e) {
System.out.println(e);
}
statusMessageLabel.setText("Proccess ended.");
}
}
I agree with Howard's recommendation that a Swing Timer could work well here (1+), but my other concern with your code is here:
manyFunctions();
What exactly is going on at this spot? Are you calling lots of code that is time/cpu-consuming? If so, you will need to take care not to call this on the main Swing thread, the EDT, but rather call it in a background thread, but at the same time taking are to update Swing components only on the EDT. This can be simplified by using a SwingWorker, and you can read up more on this here: Concurrency in Swing
It sounds like you want to have a look at swing timers. With those you can schedule single calls or do them periodically.
This way you can also add a timer which resets your label text periodically.

Call repaint from another class in Java?

I'm probably doing this wrong, so please be nice.
I'm developing a Java game, and I'm at the stage of testing character movement / animation.
The "person" can move up down left and right on a grid.
The class the grid is drawn in is the gamePanel class.
The buttons are in the gameControlPanel class.
I have a button which spawns a person on the grid.
I then have a button to move the person up down left and right.
When the move up button is pressed, it calls the move up method from the person class.
(At the moment, I'm only testing one "person" at a time.)
In that method is the following code...
int move = 10;
while(move!=0)
{
setTopLeftPoint(new Point((int)getTopLeftPoint().getX(),
(int)getTopLeftPoint().getY() - 3));
try
{
Thread.sleep(300);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
move-=1;
}
The problem is that I can't seem to call the repaint method for the gamePanel class from within the Person class.
To get around this, I created a timer in the gamePanel class which repaints every 20ms.
When I press the up button after the person is spawned, the button remains pressed down until the cycles of the while loop have been completed, and then the circle representation of the person is displayed in the grid square above.
I will try to answer any questions regarding this.
repaint() does not immediately repaint the GUI. Rather, it posts a message to the AWT thread telling it to paint at the next convenient opportunity. When it gets the chance, it will repaint your app. However, if you do this in an event handler, then the AWT thread is already busy and you need to exit the handler to give control back to the AWT handler.
As a general rule of thumb, you don't want to do any long-running calculations on the AWT thread (including in event handlers) since these will stop the app from responding to other events until your calculations are done. This will often appear to the user as stuck buttons like you described. To get around this, use a SwingWorker which can do the calculations on a separate thread.
Finally, something to be aware (but not necessarily to change) is that timers and sleeps do not guarantee when they will awaken. Rather, they guarantee that they will not waken before the amount of time elapses, but can theoretically sleep indefinitely. Also, not all machines have 1 ms timer resolution. In particular, on many windows machines the timers only have 55 ms resolution, so a 20 ms timer may give weird results.
If you want to repaint at a certain interval, javax.swing.Timer is probably the class for you. In the specific case of repaint you can call it from a non-EDT thread, but you may get yourself into difficulty as you are now dealing with multiple threads.
I don't have much experience making games but having a loop to control all animation is a fundamental aspect of game programming. Most simple 2d games only have 1 loop to render most of its animation.
In my experience a good way to render a whole bunch of stuff is to have a collection of all the entities in your game in one place and just loop over this collection passing the Graphics object to each entity.
This will allow each entity to draw itself onto the graphics object. Although this is just one way to do it.
synchronized ( entities ) {
for ( Entity e : entities ) {
e.draw( g );
e.doAction();
}
}
Is the button press handled by the event-dispatch thread of your GUI?
If this is a case, then the repaint method on the GUI will not fire until the event dispatch thread ends (i.e. when the button is released and it breaks out of the loop). I had this problem recently, and the best solution I can suggest is to make the class with the movement algorithm threadable and fire off a thread when the keypress is detected. This allows the event-dispatch thread to finish and therefore allows the gui to repaint.
For more information on threading see Starting a thread.

Categories

Resources