Of all these methods what's being run and in what order??
I guess the first question to ask is whats being run first?
And why does th.start() start run()?
import java.applet.*;
import java.awt.*;
import javax.swing.JFrame;
public class BallApplet extends Applet implements Runnable {
int x_pos = 10;
int y_pos = 100;
int radius = 20;
private Image dbImage;
private Graphics dbG;
public void init() {
// setBackground(Color.BLUE);
}
public void start() {
Thread th = new Thread (this);
th.start();
}
public void stop() {}
public void destroy() {}
public void run() {
// 20 second delay per frame refresh (animation doesn't
// need to be perfectly continuous)
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (true) {
x_pos++;
repaint();
try {
Thread.sleep(20);
}
catch (InterruptedException ex) {
System.out.println("Caught!");
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
}
public void update(Graphics g) {
// implements double buffering
// drawing on doublebufferImage, note the dbG=dbImage.getGraphics(), so everything dbG.whatever() is
// drawing on the Image's graphics which is later drawn with g.drawImage()
// initialize buffer
if (dbImage == null) {
dbImage = createImage (this.getSize().width, this.getSize().height);
dbG = dbImage.getGraphics();
}
// clear screen in background
dbG.setColor(getBackground()); // gets background color
dbG.fillRect(0, 0, this.getSize().width, this.getSize().height);
// draw elements in background
dbG.setColor(getForeground());
paint(dbG);
// draw image on the screen
g.drawImage(dbImage, 0, 0, this);
}
public void paint(Graphics g) {
g.setColor(Color.RED);
g.fillOval(x_pos-radius, y_pos-radius, 2*radius, 2*radius);
}
}
The init() and start() methods are invoked first.
That in turn creates a Thread and starts that thread, which causes this class's run() method to be invoked.
The paint() method is invoked by Swing independently in the GUI event handling thread, if Swing detects that the applet needs to be redrawn.
I note that the class's main run() method also repeatedly calls repaint(). That explicitly tells the GUI thread to invoke update().
The browser or Applet viewer first calls
init() method to inform this applet that it has been loaded into the system.
then after init start() method gets called. For more see the Applet class docs.
Inside start() method there is a call to th.start(). That means start() the thread execution
That will cause the run() to get invoked
From the Life Cycle of an Applet section of The Java Tutorials, the Applet's following methods are called in order:
init()
start()
stop()
destroy()
In addition, the code implements the Runnable interface, so the BallApplet's run() method is also executed after a new Thread (here, called th) is run by calling the th.start() method. (Calling the Thread.start() method starts a new thread and calls its run() method.)
The Defining and Starting a Thread section from The Java Tutorials has more information on Runnable and Thread and how threads are started in Java.
The run() method contains a call to repaint(), and this is an app-triggered update, it will call the BallApplet's update(Graphics g) method. In addition, the system-triggered repaint will trigger the paint(Graphics g) method.
For more information about repainting in AWT, refer to Painting in AWT and Swing. For information on system- and app-triggered painting, see the section on System-Triggered vs. App-Triggered Painting.
See Thread.start().
public void start()
Causes this thread to begin execution;
the Java Virtual Machine calls the run
method of this thread.
The result is that two threads are
running concurrently: the current
thread (which returns from the call to
the start method) and the other thread
(which executes its run method).
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
Related
I just started creating games for Android and decided to begin by following Retro Chicken's tutorial.
What I just don't get is where the game actually starts to listen for commands?
Usually they'd have a function like public void run () that is called.
The main is like :
game = new GamePanel(this);
setContentView(game);
And the constructor called of the main is :
public GamePanel(Context context){
super(context);
this.getHolder().addCallback(this);
thread = new MainThread(getHolder(), this); // Inherits [Thread] class. Code posted
player = new RectPlayer(new Rect(100,100,200,200), Color.rgb(255,0,0)); Class made by me. Has nothing special.
playerPoint = new Point(150,150);
// We ensure that THIS canvas will get the focus.
setFocusable(true);
}
I surfed through some super calls, but still nothing
MainThread.java
GamePanel.java
EDIT: I am interested in what calls the run function, where and how ?
This is the block that actually starts the controller thread,
#Override
public void surfaceCreated(SurfaceHolder holder){
thread = new MainThread(getHolder(), this);
thread.setRunning(true);
thread.start();
}
Since class MainThread extends Thread, calling the start method of the Thread object will call the run method on a new Thread.
Now how does this method run?
#Override
public void surfaceCreated
This is an override of the implements SurfaceHolder.Callback definition.
Your game object knows about the interface, because the constructor passes a reference of itself to the holder, itself, containing the interface to be called.
this.getHolder().addCallback(this);
The holder now has a reference to this class, and can call
callback.surfaceCreated();
Where surfaceCreated is interface method you implemented.
Now how did the surface get created?
The surfaceCreated method is called when:
This is called immediately after the surface is first created. Implementations of this should start up whatever rendering code they desire. Note that only one thread can ever draw into a Surface, so you should not draw into the Surface here if your normal rendering will be in another thread.
You started that process by calling finally calling setContentView(game); which inflated the surface.
GamePanel class is SurfaceView, that provide drawing surface. You are adding a layer by setContentView(game);.
Now you need to start drawing. In drawing you need to erase and draw again if you need to change something on Paint Board(Surface View).
Now you need to call draw (Canvas canvas) again and again for the previous purpose. So you're using MainThread.
Look at your run() method of your MainThread, there is a infinite while(true) loop. By that loop your your GamePanel's draw (Canvas canvas) runs call at particular time duration.
Here is where the main thread gets startet, if its that what you want to know.
#Override
public void surfaceCreated(SurfaceHolder holder){
thread = new MainThread(getHolder(), this);
thread.setRunning(true);
thread.start();
}
I think you should specify your question a little bit.
Here is the callback method, that handles touches on the gamepanel.
#Override
public boolean onTouchEvent(MotionEvent event){
/* [event.getAction()] : returneaza un [int] care are o valoeare
in functie de ce fel de touch e
*/
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
playerPoint.set((int)event.getX(), (int)event.getY());
}
return true;
}
I am trying to have a background image draw then have a character draw over it. My code was working until I added sleep do I didn't get 1500 fps.
package sylvyrfysh.screen;
import javax.swing.*;
import java.awt.*;
import game.infos.Information;
public class ImageLoadDraw extends JFrame{
/**
*
*/
private static final long serialVersionUID = 1L;
public static void main(){
DisplayMode dm=new DisplayMode(Information.sX,Information.sY,16,DisplayMode.REFRESH_RATE_UNKNOWN);
ImageLoadDraw i = new ImageLoadDraw();
i.run(dm);
}
public void run(DisplayMode dm){
setBackground(Color.PINK);
setForeground(Color.WHITE);
setFont(new Font("Arial",Font.PLAIN,24));
s=new Screen();
try{
loadpics();
s.setFullScreen(dm,this);
try{
Thread.sleep(10000);
}finally{
doRun=false;
s.restoreScreen();
}
}catch(Exception e){
e.printStackTrace();
}
}
private void loadpics() {
bg=new ImageIcon("src/sylvyrfysh/screen/maze_icon.png").getImage();
chara=new ImageIcon("src/sylvyrfysh/screen/char.png").getImage();
repaint();
}
public void paint(Graphics g){
if(g instanceof Graphics2D){
Graphics2D g2=(Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
while(true&&doRun){
g.drawImage(bg,0,0,null);
g.drawImage(bg,0,480,null);
g.drawImage(bg,360,0,null);
g.drawImage(bg,360,480,null);
g.drawImage(bg,720,0,null);
g.drawImage(bg,720,480,null);
g.drawImage(chara,imgX,imgY,null);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Screen s;
public static int imgX=0;
private int imgY=525;
private Image bg,chara;
private Boolean doRun=true;
}
Any ideas on what is causing it and how to fix it? Like I said, with no sleep it works fine.
Swing is an single threaded framework. That is all UI interactions and modifications are expected to be executed within the content of the Event Dispatching Thread, including repaint requests.
Anything that stops, blocks or otherwise prevents this thread from running will prevent the EDT from processing new events, including repaint requests. This will, essentially, make it appear that you program has hung (or stopped responding), because it has.
In your run method you are calling Thread.sleep. This is likely stopping the EDT from processing new events, but because you've actually called the method from the "main" thread, it might actually work, however...
In you paint method, you have an infinite loop AND a Thread.sleep call. These WILL stop the EDT from running, as paint is called from within the context of the EDT.
Painting won't always occur immediately, on some systems, until the paint method returns, it may not be pushed to the device for output, so, even the idea of looping within the paint, regardless of the fact that it will cause problems for the EDT, is a bad idea any way.
Unlike some other UI frameworks, you do not need to implement a "main-loop", Swing takes care of this for you.
Instead, in your paint method, you should simply paint what you need to paint for that cycle and exit.
Instead, you should do something like...
public void paint(Graphics g){
// Painting is a complex series of chained methods, failing to call super.paint
// to cause significant issues
super.paint(g);
// Graphics is guaranteed to be an instance of Graphics2D since I think 1.4
// You should create a copy, so any changes you make are not carried onto the
// next component, Graphics is shared between all the components being painted
// in this paint cycle.
Graphics2D g2=(Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(bg,0,0,null);
g2.drawImage(bg,0,480,null);
g2.drawImage(bg,360,0,null);
g2.drawImage(bg,360,480,null);
g2.drawImage(bg,720,0,null);
g2.drawImage(bg,720,480,null);
g2.drawImage(chara,imgX,imgY,null);
// If you create, you should dispose of it...
g2.dispose();
}
...instead
Instead of Thread.sleep you should be making use of something like javax.swing.Timer, for example...
s=new Screen();
try{
loadpics();
s.setFullScreen(dm,this);
Timer timer = new Timer(10000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
s.restoreScreen();
}
});
timer.setRepeats(false);
timer.start();
}catch(Exception e){
e.printStackTrace();
}
Take a look at Concurrency in Swing for more details.
You should also avoid overriding top level containers and especially overriding paint. Painting a complex series of chained method calls, each one performing a particular job, building up on top of each other to produce a final result.
Instead, you should start with a custom component of some kind, extending from JPanel for example, and override it's paintComponent method, making sure you call super.paintComponent before you do any of you own painting.
Take a look at Performing Custom Painting for more details
Well this one Thread.sleep(10000); turn off EVERYTHING for 10 seconds. This is NOT what you want. Even doing it for 30 milisec (which is ~30frames/sec) is not what you want, because it stops even input etc.
You should use Timer. It runs timing in another thread and it sleeps and wake up only that thread automatically for given number of milisec, so it does not affect your program and it can call it only after 30milisec for example.
Still to have good application, this timer should have low value and you should count how long passed through System.nanoTime() and for example repaint once each 30milisec, however read input each 5milisec etc.
I THINK->This is because you need to call the loadpics() parallel, try this
public void run(DisplayMode dm){
setBackground(Color.PINK);
setForeground(Color.WHITE);
setFont(new Font("Arial",Font.PLAIN,24));
s=new Screen();
loadpics();
s.setFullScreen(dm,this);
try{
new Thread(new Runnable() {
#Override
public void run() {try {Thread.sleep(1000);doRun=false;s.restoreScreen();} catch (Exception e) {}
}
}).start();
}
also setting the doRun as volatile.
private Boolean doRun=true;
I am a beginner when it comes to making Java applets, and for my first applet, I drew a smiley face using paint(). Now, I want to make the smiley face blink. I have managed to get my timers and everything set up, but I need to use the start() method to get the timers going, and it seems that by including other methods, the paint method does not invoke itself. Because of this, I am assuming that I need to invoke paint() from start(), but the problem is I do not know what I am supposed to initialize the Graphics variable to in order to get paint() to actually work.
SSCCE
import java.awt.*;
import javax.swing.*;
import java.applet.Applet;
import java.awt.event.*;
public class Project2_15 extends Applet
{
public void paint(Graphics g)
{
setBackground(Color.lightGray);
}
// This handles the starting of timer execution.
public void start()
{
Graphics g; // What do I initialize this to?
paint(g);
}
// Timer Stuff
ActionListener blinkShut;
public Project2_15(final Graphics g) {
this.blinkShut = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
g.setColor(Color.black);
}
};
}
}
Here is the code with some corrections:
import java.awt.*;
import javax.swing.*;
import java.applet.Applet;
import java.awt.event.*;
public class Project2_15 extends Applet
{
public boolean wink = false;
Timer timer;
public void paint(Graphics g)
{
super.paint(g);
// Graphics g; // What do I initialize this to? ALREADY INITIALIZED
//paint(g);
if (wink) {
g.drawLine(1,1,100,100);
} else {
g.drawOval(1,1,100,100);
}
}
// This handles the starting of timer execution. NO IT DOES NOT!
// public void start()
#Override
public void init()
{
setBackground(Color.lightGray);
timer = new Timer(250,blinkShut);
}
#Override
public void start() {
timer.start();
}
#Override
public void stop() {
timer.stop();
}
// Timer Stuff
ActionListener blinkShut = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
wink = !wink;
repaint();
}
};
}
See Performing Custom Painting. It would be the same basic process with applet or frame.
Add a container (Panel/JPanel) to the top-level container.
Override the paint(..) AWT or paintComponent(..) Swing method.
Call super.. as the first statement.
Do the custom painting to the supplied Graphics instance.
Animation can be achieve using a Swing based Timer.
Of course I would tend to replace steps 1) to 4) with painting to a BufferedImage displayed in a JLabel/ImageIcon.
You need your timer to change the state of the applet, suggest that it be repainted, and then have your applet's paint method to react to the state. Some suggestions:
Use a Swing Timer for your timer
Give your applet a non-static boolean field called blink.
In the Timer's actionPerformed method, change the boolean field of the applet, blink, to its opposite state: blink = !blink;
Then call repaint(). This will tell the JVM to possibly repaint the applet.
In your paint(...) method use the state of the blink variable in an if block, and if true paint an eye, if false paint a closed eye.
You're better off using a Swing applet or JApplet.
If you're using a JApplet, then you'll do your painting in a JPanel's paintComponent(...) method, not in the paint method.
Either way, be sure to call the super method as the first method call in your painting method, either super.paint(g) if in the Applet's paint method or super.paintComponent(g) if in a JPanel's paintComponent method. This allows your GUI to erase previous painting.
Edit
Regarding your code:
public void start()
{
Graphics g; // What do I initialize this to?
paint(g);
}
and:
public Project2_15(final Graphics g) {
this.blinkShut = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
g.setColor(Color.black);
}
};
}
Please throw this code out as you almost never paint this way or call paint directly. Please read or re-read my recommendations above.
Edit 2
Regarding your comments:
So I can't just create a separate timer and put the code in their?
I never said this. Feel free to use a separate timer, and put in decent code inside of it. You of course will have to discard your current code since you do not want to manipulate the Graphics object directly as you're trying to do.
In addition to his eyes blinking, I was also hoping to have his tongue go in and out using a separate timer.
Then go for it!
I was wondering how I would thread the following code, or just a method in general:
public void run (){
public void paint(Graphics g) {
g.fillRect(20, 20, 20, 20);
for (int i = 20; i < 1000; i++) {
g.fillRect(20, i, 20, 20);
Thread.sleep(10);
}
}
}
I find that I am unable to make a thread of this code because I get an illegal start of expression error, which is fair but I do not see a way around it.
Its hard to tell what you are doing,
but seems like you are trying to override paint() of a Runnable from within its run() method.
This can surely not be done.
The logic is
Take a component
Override its paint method to draw what we need
Call method to update co-ordinates of rectangle (or in this case timer will do that)
Than call repaint() on the component so paint method may be called again and redraw the rectangle with its new co-ordinates (Timer would also take care of repainting after changing co-ordinates of Rectangle)
repeat last 2 steps as many times as needed/wanted
(when I say component I actually mean JPanel, paint method refers to overridden paintComponent(..) of JPanel as this is best practice.)
Some suggestions:
1) Dont override paint rather use JPanel and override paintComponent.
2) Dont forget to honor the paint chain and call super.XXX implementation of overridden paintComponent(Graphics g) (or any overridden method for that fact) unless purposefully leaving it out. i.e
class MyPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//do drawings here
}
}
3) If drawing in paintComponent it is usually needed to override getPreferredSize() and return Dimensions which fit the contents/drawings of JPanel, i.e:
class MyPanel extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(300,300);
}
}
3) Look at Swing Timer instead of Thread.sleep(..) as sleep will block GUI thread and make it seem to be frozen. i.e
Timer t = new Timer(10, new AbstractAction() {
int count = 20;
#Override
public void actionPerformed(ActionEvent ae) {
if (count < 1000) {
//increment rectangles y position
//now repaint container so we can see changes in co-ordinates (unless you have a timer which repaints for you too)
count++;
} else {//counter is at 1000 stop the timer
((Timer) ae.getSource()).stop();
}
}
});
t.start();
4) An alternative (because I see for now you are only moving a Rectangle which is not a Swing component) to Swing timer is TimerTask, and this can be used as long as no Swing components will be created/manipulated from within its run() method (as TimerTask does not run on EDT like Swing Timer). Note revalidate() and repaint() are Thread-safe so it can be used within TimerTask.
The advantage of the above is unnecessary code is kept of EDT (i.e moving AWT rectangle by changing co-ords) i.e
final TimerTask tt = new TimerTask() {
#Override
public void run() {
if (count < 1000) {
//increment rectangles y position
//now repaint container so we can see changes in co-ordinates (unless you have a timer which repaints for you too)
count++;
} else {//counter is at 1000 stop the timer
cancel();
}
}
};
new Timer().scheduleAtFixedRate(tt, 0, 10);//start in 0milis and call run every 10 milis
I have a class that is supposed to simulate a firework animation using paintComponent and repaint() the problem that I have detected is that a "Firework" is newly initialized
each time the method is invoked so the projectileTime field of the firework is reset to zero (as specified in the constructor) each time. Where is the appropriate place to instantiate a firework object so that the projectileTime field is incremented appropriately? (In this class or in another class)
see code:
public class FireworkComponent extends JComponent {
private static final long serialVersionUID = 6733926341300224321L;
private double time;
public FireworkComponent(){
time=0;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.translate(0, this.getHeight());
Firework f= new Firework(this.getWidth()/2,0,73,90,Color.red,5);
f.addFirework(75,35,Color.BLUE,6);
f.addFirework(75, 155, Color.green, 6);
time+=.1;
Point point=f.addTime(.1);
g.fillOval(point.x, (-point.y),15,15);
try{
Thread.sleep(500);
System.out.println("sleep");
}
catch (InterruptedException e){
e.printStackTrace();
}
this.repaint();
}
}
First of all get rid of the Thread.sleep() from the paintComponent() method.
Then you need to define properties of the Firework component that change over time.
Finally, you would use a Swing Timer to schedule the animation of the fireworks. Every time the Timer fires you would update the component properties and then invoke repaint() on the component.
Store the Firework as a class level attribute and instantiate it in the FireworkComponent constructor.
please
don't add Firework f= new Firework(this.getWidth()/2,0,73,90,Color.red,5); inside Paint Graphics2D, you have to prepare this before
don't delay you paint by using Thread.sleep(int);, for Graphics2D is there javax.swing.Timer, but you have to initialize paintComponent() by using Timer, not stop to painting inside the Paint body
not sure if somehow working Point point=f.addTime(.1);
EDIT
for animations is there example