Java Application : repaint isn't executed in While Loop? - java

I've got this Thread that is supposed to Update the game's elements, i.e. repaint, wait for a bit of time then do it again, the problem is that it doesn't repaint. I've tested every other component, they all works, but the paint method is only called once ( Because the components are painted ), even if I call repaint() in the loop. Here's my Code of the Loop:
Thread t = new Thread(){
public void run()
{
mouse.init();
while(true)
{
mouse.Refresh();//Adds Dirty Regions in the RepaintManager
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//What here?
}
});
}
}
};
No need to see the thread or anything, it loops.
Here's the Paint Method :
#Override
public void paint(Graphics g)
{
EndTime = System.currentTimeMillis();//For the FPS Counter
Time = EndTime - StartTime;
FPS = (byte) (1000/Time);
TotalFPS += FPS;
TotalFrame++;
JPT.AverageFPs.setText( "" + TotalFPS/TotalFrame);
JPT.CurrentFPS.setText( "" + FPS);
StartTime = System.currentTimeMillis();
g.clearRect(0,0,dim.width,dim.width);
for(int x = 0; x < Variables.Width; x++)
{
for(int y = 0; y < Variables.Height; y++)
{
if(Variables.Map[x][y] == 0)
{
g.setColor(new Color(0x613F37));
g.drawLine(x, y, x, y);
}
else if(Variables.Map[x][y] == 1)
{
g.setColor(Color.black);
g.drawLine(x, y, x, y);
}
else if(Variables.Map[x][y] == 2)
{
g.setColor(new Color(0xDEDEDE));
g.drawLine(x, y, x, y);
}
}
}
g.setColor( new Color(0.5f, 0.5f, 0.5f, 0.5f));
g.fillRect(Variables.CurrentX, Variables.CurrentY, Variables.Zoom, Variables.Zoom);
}
Thanks alot in advance.
Also I want to point out that I made this Game as an Applet before and it was working like a charm, but now I need it as Application.

Try paintImmediately(0, 0, getWidth(), getHeight());

This is because the RepaintManager collapses multiple requests into a single repaint for members of a component tree.

I think your data is not synchronized between threads (there is not enough code to determine if this the case tough).
repaint is called on the Swing EDT and update.UpdateGravity() is called in your main thread. I guess your update changes Variable, but do you ever synchronize this data structure such that the Swing EDT sees the updated value?
EDIT:
here is what you should do:
variables = update.updateGravity(); // runs in your main thread
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
yourCustomSwingComponent.update(variables); // will run on the Swing EDT
}
}
and yourCustomSwingComponent contains the paint() method you have. There is a rule in Swing that the state of any Swing component can only be modified (or read) from the Swing EDT.
You should read about Swing and multi-threading. Actually, you must read about multi-threading to use Swing.

Not answering the question directly, but it might be very useful to have a look at some of the existing Java2D animation libraries. For example, Trident originally developed by Kirill Grouchnikov. If there is a reason not to use it, at least it could be useful to inspect the source and borrow some ideas.
Also, Swing Timer could be of some interest for implementing time based Swing related actions.

Related

Why is this oval moving so fast?

I am learning Java and I've tried to build an app that drops a ball when I click on the panel. The problem is that when the oval is painted its moving so fast that even setting Thread.sleep to max value just makes it barely noticable. How can I slow it down?
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.red);
g2.drawOval(x,y,20,20);
Thread thread = new Thread() {
public void run() {
while (true) {
y = y + 1;
repaint();
try {
Thread.sleep(2147483647);
}
catch (InterruptedException ex) {
}
}
}
};
thread.start();
}
I have not tried your program in my own environment, but from what I know, it seems like what is moving your ball is the:
y = y + 1;
line, therefore you could probably consider changing that to a smaller number, most likely a double. Also, as was already mentioned, maybe you can try not using the:
while (true)
statement, as that will just always and forever evaluate to true and it's not the biggest issue, but maybe you can think of using something else like using something that has to do with the y variable like: while (y < 768 ) or even something like a for loop depending on what it is you're doing.
Hopefully this helps, and I would also advise you take a look at this answer here:
Java Graphics Updating Too Fast
Wishing you the best!
Get rid of creating the thread in the paintComponent method.
You need to use the java Swing Timer with an actonListener to
increment the x and y coordinates and then call repaint(). Check the Java API for details.
When you start the program, use SwingUtilities.invokeLater(()->new className()) to invoke the class. This schedules the app in queue for processing in the Event Dispatch Thread (EDT). All events and repainting need to be handled in the EDT.
In your paintComponent method, set anti-aliasing using Graphics2D via setRenderingHints. It is also explained in the Java API. It will make your graphics appear smoother by averaging the edges.

Graphical Bug with Java Swing - Drawing from a list makes elements jump around

So I was messing with Swing for the first time in a while and I came across a strange issue. So I am adding "shapes" to a list every so often, and then in the paintComponent method of a JPanel I am looping through the list and drawing the shapes. I also draw a shape outside of the for loop for testing purposes.
What happens is the shapes in the for loop will jump around the screen randomly. This only happens when the shapes are drawn in this loop.
What I have tried already:
Updating graphics drivers for both the integrated GPU and discrete GPU
Using java.util.Timer instead of Swing Timer
Using Thread/Runnable
Using things other than ArrayList, such as LinkedList, Vector, and a normal Array.
Trimmed literally everything out of my code except the basics, which is what we're left with here. I was drawing more complex things before when I noticed it.
Changed the timing (PERIOD variable, in millis). It will get worse if I increase or decrease it.
Changed from using System time in milliseconds to the System time in nanoseconds, converted to milliseconds. I know this should be the same but I was running out of ideas.
Here is a gif of the problem (15 seconds long):
image
You'll notice that the small squares will jump around at random intervals. This should not occur. I'm just trying to "spawn" a square at random coords.
Here is the code in a pastebin:
code
I have included all 3 classes in this order: the JPanel class, the Main class (extends JFrame), and the shape class
If any of the links don't work, inform me and I will promptly post other links.
Thanks.
This setup ...
#Override
public final void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (this.startTime == -1L) {
this.startTime = Main.timeMillis();
}
final long timeDiff = Main.timeMillis() - this.startTime;
if (this.circlesIndex <= 19 && timeDiff > 2000) {
final int randX = this.rand.nextInt(this.WIDTH);
final int randY = this.rand.nextInt(this.HEIGHT);
this.testShapes.add(new TestShape(randX, randY));
this.startTime = Main.timeMillis();
}
for (TestShape ts : this.testShapes) {
ts.draw(g);
}
g2.setColor(Color.gray);
g2.fill3DRect(350, 400, 100, 60, true);
}
#Override
public final void actionPerformed(final ActionEvent event) {
x++;
if (x > WIDTH) {
x = -50;
}
repaint();
}
is wrong.
Paint is for painting - you should not modify the state of the UI from inside any paint method, do this within your ActionListener. The problem is, your component can be painted for any number of reasons, many of which you don't control or know about

Make an object render half way through a reapint

I am currently working on an animation to compare two stock exchange algorithms. I am running the algorithms within the paint component extending JComponent. (not the best, but I don't care) I need to have the screen refresh half way through the paint component. I do not want it to have to get all the way through before it up dates the screen. The reason being is I have one algorithm with a nested while loop and the other without. How would I go about doing this?
public void paintComponent(Graphics g) {
//calls in the super class and calls the calibrate the graphics method
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
calibrateFrame( getHeight(), getWidth() );
//Clears the rectangle to avoid overlaying, makes it black
g2D.clearRect(0, 0, getWidth(), getHeight());
g2D.setColor(Color.BLACK);
g2D.fillRect(0, 0, getWidth(), getHeight());
//Draws the rectangles without the algorithm started
redraw(g2D, -1);
/**
*algorithms
*/
fastSpans[0] = 1;
slowSpans[0] = 1;
//Makes a new stack pushes 0 on the stack
Stack myStack = new Stack();
myStack.push(0);
//If it has not been sorted or paused, continue the algorithm
if (!(pause) && !(sorted)){
//The slower algorithm needs to start out at zero (j)
int j = indexValue-1;
g2D.setColor(Color.BLUE);
//Calculates the values for the X and Y coordinates for the
//new rectangle, along with the height
int slowY = calSlowY(j);
int slowX = calSlowX(j);
int curHeightSlow = (int) ((stocks[j]/maxStockValue)*maxHeight);
//Here is the actual algorithm
int k = 1;
boolean span_end = false;
//Nested While Loop
while (((j-k)>0) && !span_end){
if (stocks[j-k] <= stocks[j]){
k = k + 1;
// Draw the current component
// **********************
// DO REFRESH MID PAINT COMPONENT
}
else{ span_end = true; }
}
slowSpans[j] = k;
g2D.setColor(Color.WHITE);
for(int i = 0; i < numberOfStock ; i++){
}
if (!(indexValue >= numberOfStock)){
while (!( myStack.empty()) && (stocks[(int)myStack.peek()]) <= stocks[indexValue]){
myStack.pop();
}
if (myStack.empty()){
fastSpans[indexValue] = indexValue + 1;
}
else {
fastSpans[indexValue]= indexValue - (int) myStack.peek();
//System.out.println("Im in the else");
}
myStack.push(indexValue);
}
}
drawStrings(g2D);
}
I am running the algorithms within the paint component extending JComponent. (not the best, but I don't care)
But you should care, since this impacts on your problem and possible solution.
I need to have the screen refresh half way through the paint component. I do not want it to have to get all the way through before it up dates the screen. The reason being is I have one algorithm with a nested while loop and the other without. How would I go about doing this?
Then don't run the algorithm through paintComponent. Instead use a SwingWorker<Void, Image>, update a BufferedImage and pass that image to the GUI through the worker's publish/process method pair, calling repaint() at the same time. For more on how to use a SwingWorker, please have a look at: Lesson: Concurrency in Swing
Don't understand what half way means.
If it means half of the component, then the simple way is to using two JComponent.
If u means in same component one line updated but another line not updated.
What I understand the repaint is calling when it packs(), updateUI(), or caused by invalidate().
So in my view, the repaint() should only care about paint these lines/2D, and in another thread to execute these loops/generate these data. Once the data collection is finished just call updateUI()/paintImmediately.
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
repaint();
}
});

java getGraphics() returns null, how to access paintComponent?

I have a class with a JPanel, and paintComponent(). I also have a class that implements Runnable, and which I plan to draw images onto the paintComponent once the thread is started. My Constructor takes in the JPanel, and from there I call getGraphics(). However through testing, and searching this always seems to return null.
System.err.println("Thread Started");
isRunning = true;
System.err.println(pap.getGraphics());
Graphics g = pap.getGraphics(); //pap is the name of the JPanel
while (isRunning)
{
while(xPos <= pap.getWidth() + 1)
{
xPos+=horizontalDirection;
System.err.println(xPos);
drawImage(upImgs[1], xPos, yPos, g);
pap.repaint();
pause();
//g.drawOval(xPos, 10, 10, 10);
if(xPos >= pap.getWidth())
horizontalDirection = -horizontalDirection;
if(xPos < 1)
horizontalDirection = 1;
}
//pap.repaint();
//pause(); // let this thread sleep a bit
}
System.err.println("Thread Ended");
returns
Thread Started
2
null
Exception in thread "Thread-1" java.lang.nullPointerException
How can I properly get the paintComponent to draw on it from this separate class?
You can't do that. Awt/Swing are not thread safe, so drawing can only be done from the gui thread.

Multithreading multiball game

I am working on a school project about multiple balls bouncing. So far, I managed to create the app and everything works ok. But, I also need to implement multi-threading in the app, and this is where I am stuck. I was thinking of one ball one thread, but I am not sure of how to implement it. Here is my code so far (part):
public void paintComponent(Graphics g)
{
super.paintComponent(g);
//The balls are painted only after the timer is started
if(bTimer)
{
for(Ball ball:ballList.ballsArrayList)
{
Thread ballThread = new Thread(ball);
ballThread.start();
ball.draw(g);
/*other code for moving the ball*/
}
}
}
In the class Ball:
public void draw(Graphics g) {
Color color = new Color(this.getColorR(),this.getColorG(),this.getColorB());
g.setColor(color);
int radius = this.getsize();
g.fillOval((int)(this.getX() - radius), (int)(this.getY() - radius), (int)(2 *
radius), (int)(2 * radius));
}
public void run() {
String name = Thread.currentThread().getName();
for (int i = 0; i < 200; i++) {
//ball.draw(g); ??
try {
Thread.sleep(50);
System.out.println("Sleeping");
} catch (Exception ex) {}
}
}
I was thinking that I could put the ball.draw() function in the run() function for the thread. But I don't know how I can do that or if it's a good idea. Multi-threading is still difficult for me to understand and implement =((
Not a real answer, but too long to put in a comment.
You should note that Swing is not thread-safe. All Swing components should be accessed on the Event Dispatch Thread, and on that thread only. See the Concurrency in Swing guide for more information.
This means that you can have one thread per ball which updates the position of the ball. However, if you access the position of the ball during the painting, this access happens on the EDT. Meaning that you cannot update the position of the ball in your background thread at any moment. You will have to implement some locking or simply update the position on the EDT.
I am not sure what you try to achieve, but if you simply want to update the position of a ball at certain time intervals I would opt for a javax.swing.Timer. This timer is triggered on the EDT, allowing you to update the position in a thread-safe manner. The Swing wiki tag contains some more links for implementing animation in Swing.
All swing code has to run on the event dispatching thread. Therefore what you're doing in the code snippets is bad.
However, if calculating ball positions is cpu intensive and requires time, you do want to move the logic in a separate thread, otherwise your UI will become unresponsive.
This would become a typical producer/consumer problem: one thread produces cooridnates and the event dispatch thread consumes them by drawing the balls.

Categories

Resources