I'm new to Java. I need help figuring out some of the code I'll be displaying below. The point of the code is to simply create an applet which displays a ball moving from left to right using a change in X position. I have began following a tutorial for applets from a website which made this code available to me (http://www.javacooperation.gmxhome.de/BallBewegungEng.html). Basically, I need someone to explain to the following methods and their contents: the start method (what is a thread? I'm aware it's an object, but what purpose does it serve here?). The run method (what exactly am I doing when I set the thread priority to MIN/MAX? Why does this method call the repaint() method even when no such method has been created?). Lastly, the paint method (what exactly is the g.fillOval line doing and how?). I've tried googling these things, but I'm having a hard time understanding understand the jargon that I see with most answers. I need things explained in a more simplistic way so that I may understand the jargon later on.
Thanks for any help in advance. The code:
import java.applet.*;
import java.awt.*;
public class MovingBall extends Applet implements Runnable
{
int x_pos = 10;
int y_pos = 150;
int radius = 20;
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()
{
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while(true)
{
x_pos++;
repaint();
try
{
Thread.sleep (20);
}
catch(InterruptedException ex)
{
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
}
public void paint (Graphics g)
{
g.setColor (Color.red);
g.fillOval (x_pos - radius, y_pos - radius, 2 * radius, 2 * radius);
}
}
A thread is something you use when you want to run multiple pieces of code at the same time, without interrupting the other threads. In this case you use the thread to repaint the screen and pause the loop without affecting the rest of the program.
The run method is overriding from the Runnable object that you pass to the thread to run. When you create a thread, you pass it a runnable object with a run method defined, which will run when the thread starts.
The repaint method is not defined in this class, however it is defined in the parent class(Applet), so you can call it in this class just fine.
The paint method is overriding from Applet as well, so you are defining what the applet will do when it runs the paint method.
Related
There are two java files Animate and Anim1.The Anim1 file has the JFrame and I want to attach the Animate file which has the logic of text scrolling by the screen(supposed to be the JFrame screen).But I cannot find a way.And also the code is throwing the following compile time error-
Exception in thread "Thread-0" java.lang.Error: Unresolved compilation problem:
The method repaint() is undefined for the type Animation
import java.awt.Graphics;
public class Animation implements Runnable {
int x=500;
String s="hello world";
public void run(){
while(true){
repaint();
try{
Thread.sleep(50);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public void paint(Graphics g){
g.drawString("hello world", x,-10 );
x--;
if(x< -100){
x=500;
}
}
}
import java.awt.Component;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Anim1 {
public static void main(String[] args){
Animation a= new Animation();
Thread t= new Thread(a);
t.start();
JFrame frame= new JFrame("animate");
frame.setVisible(true);
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
The repaint method is found in Swing components -- same for the paint and paintComponent. Calling it inside of a class that does not extend a Swing comopnent does not make sense unless you're making the repaint call on another object that is a component. Likewise giving a non-component class a paint method makes no sense since you're not overriding any painting method.
Likely your Animation class should extend JPanel so that it can override paintComponent (not paint) and so that the repaint() call makes sense. Also always pre-pend your painting method (or any other method that you think overrides a parent method) with the #Override annotation. This way the compiler will complain to you when you're not overriding the method correctly (or at all). You'll also want to call the super's painting method inside of your override.
Most important: read the Swing painting tutorials as it's all explained there. Check out: Performing custom painting
Your painting method would look something like so:
#Override
protected void paintComponent(Graphics g) {
// always call the super's method to clean "dirty" pixels
super.paintComponent(g);
// then draw the String. Make y a field too, so it can be controlled
// more easily
g.drawString(s, x, y);
}
Note that I don't change the x value or call any state-changing code within my painting method, and that's by design. The paintComponent method is for painting only. You don't have full control over whether or even if it will be called, and it can be called multiple times.
Instead the x value should be changed within the "game loop", here your Runnable's run() method. Also, as per my comments, while this code can be created using Thread/Runnable, it's safer to instead use a Swing Timer to drive the animation instead, since this saves you from having to worry so much about Swing threading issues.
Perhaps .repaint() needs to be passed something to work. Often animations will take place on a canvas then you would update that. The update method would have to be made separate with all of the things you wish to update.
canvas.update()
public void update(){
what it is you wish to update
canvas.draw()
}
I hope this helps. EDIT so your canvas is your JFrame
I need to generate a new Thread every 2 seconds. So I tried to use the Timer class in the main(String[]) method but my program just exists after the milliseconds I specified in the Timer constructor.
Program.java:
public class Program
{
private static int panelWidth;
private static int panelHeight;
private static MyPanel panel = new MyPanel();
public static void main(String[] args)
{
MyFrame frame = new MyFrame();
frame.add(Program.panel);
Program.panelWidth = frame.getWidth();
Program.panelHeight = frame.getHeight();
Timer generateBallTimer = new Timer(2000, new GenerateBalls());
while (true)
{
generateBallTimer.start();
}
} // End of main method
/**
* Generate a new ball every 2 seconds.
*
*/
public static class GenerateBalls implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
Program.generateBalls();
}
}
public static void generateBalls()
{
// Generate a ball each 2 seconds
while (true)
{
Program.panel.balls.add(new Ball(Program.panel));
}
}
} // End of program class
If in the Timer constructor I will specify 3000ms my program will be closed after 3 seconds and so on.
What am I doing wrong here?
Can you give me example of that "display list"?
You talk about "balls". What does your program need to know about a ball? Probably its position, maybe its speed, maybe its mass. Size? color? other stuff? It's up to you. The simplest implementation of a Ball object would just be a class with public fields to hold all of that information. Then, if Ball is the only kind of moving object in your animation, then your display list could just be a List<Ball>.
In a more complicated program, your Ball class might be an extension of some more general class, maybe VisibleObject, and then your display list would be a List<VisibleObject>.
As far as I know,for all the objects in a game to work concurrently they need to be Threads.
In a sense, you are right because there is only one class in all of Java that can do any work at all, and that class is Thread. No other class actually ever does anything. Other classes merely define methods that can be called by threads.
The trick is, to decouple the threads in the program from the work that they do. That's the motivation for the Runnable interface. Instead of having one object that both is a thread and also, describes the work to be done by the thread, you can have two classes; One takes care of all the thread-y stuff (.start(), .interrupt(), .join(), ...), and the other describes the work to be done (.run()).
Some say, it's hard to write a program that has too many classes/objects, but it's easy to write one that has too few.
As long as your Ball objects or your VisibleObject objects cleanly describe the things that you want to see on the screen and the ways in which you want to see those things move, there's no reason why each one's methods must be called by its own dedicated thread. There's no reason why you can't have just one thread that does the calculations for each one in its turn.
So I'm trying to display an image(ball) which I'll eventually control with user input. For know, the image just gets displayed over intervals using thread's sleep method.
I've made 2 classes, one that extends JPanel and the other extends JFrame.
The JPanel subclass looks like this:
public class BallPanel extends JPanel {
private Image ball;
private int x,y;
public BallPanel(){
try {
ball=ImageIO.read(new File("C:\\Users\\Owner\\Desktop\\ball.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
x=10;
y=10;
Thread thread = new Thread() {
#Override
public void run(){
loop();
}
};
thread.start();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(ball,x,y,null);
}
public void loop(){
while(true){
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
In the loop method I call the sleep method to allow repaint to be called over intervals. Then, loop() is called in the constructor.
The JFrame subclass looks like this:
public class BallFrame extends JFrame {
public BallFrame(){
setVisible(true);
setSize(800,800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setContentPane(new BallPanel());
}
public static void main(String args[]){
//SwingUtilities.invokeLater(new Runnable() {
// #Override
// public void run() {
new BallFrame();
// }
//});
}
}
Now the interesting, or perhaps confusing thing, is that when I run the code as it is shown here, with the anonymous inner class commented out, the ball doesn't always appear. Sometimes I need to re-size the frame (i.e call repaint) before the ball is shown. However, when I call it through the even dispatch thread using the anonymous inner class the ball appears every time I run the code. What is the reason for this?
It has little to do with starting the UI from within the EDT or not (although you should cause that can cause lots of other weird and interesting issues) and more to do with the fact that you've called setVisible before you've established the contents of the UI.
This is possibly an example of a race condition between the system trying to get the EDT up and running and the OS calls responding before it's established.
In either case you SHOULD start the UI from within the EDT and call setVisible last.
Swing can be lazy about updating the UI, this is actually a deliberate design choice as well as a good idea. You don't always want the UI updated after each and every change you make (like adding/removing components), so it hands over some of the control to the developer to decided when it's best to revalidate container hierarchy and request repaints
I would also avoid using a Thread to update the state of the UI as this could cause dirty paints as Swing uses a passive rendering approach (painting when it feels it's required) and consider using a Swing Timer which updated from within the EDT OR use a BufferStrategy and employ a active rendering approach, which you can then control
I've written a program which displays balls in a window which are moving and which absorb each other with a certain probability when getting in contact.
The current version works, the balls's movement is been calculated every time the paintComponent method is (implicitely) invoked:
public class ColliderPanel extends JPanel {
...
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// calculate balls's movement
Random r = new Random();
ListIterator<Ball> it = cp.getColliderPanel().balls.listIterator();
Vector<Ball> ballsToRemove = new Vector<Ball>();
while (it.hasNext()) {
Ball b = it.next();
b.move(1.0 / 60.0);
b.collideFrame(cp.getColliderPanel().getSize());
ListIterator<Ball> it2 = cp.getColliderPanel().balls.listIterator(it.nextIndex());
while (it2.hasNext()) {
Ball b2 = it2.next();
if (b.collide(b2)) {
if (r.nextDouble() < 0.5) {
if (b.m > b2.m) {
b.swallow(b2);
ballsToRemove.add(b2);
} else {
b2.swallow(b);
ballsToRemove.add(b);
}
}
}
}
}
cp.getColliderPanel().balls.removeAll(ballsToRemove);
try {
Thread.sleep((long) (1000.0 / 60.0));
} catch (InterruptedException e) {
e.printStackTrace();
}
for(Ball b : balls) b.draw(g);
repaint();
}
...
}
Now I want to outsource the calculation of the balls's movement to a second thread. I tried to create another class SimulateBallsMovement implements Runnable which does the calculation in the overriden run method and created a new Thread in ColliderPanel, which has SimulateBallsMovement as Runnable-object.
public class ColliderPanel extends JPanel {
private Thread simThread = new Thread(new SimulateBallsMovement());
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// calculate balls's movement
// what to to here? how to synchronize the painting and the calculation?
for(Ball b : balls) b.draw(g);
repaint();
}
...
}
My problem is that I don't know how to synchronize the painting of the balls and the movement calculation? Does ColliderPanel even need the Thread as a member? I just found tutorials on how the synchronize two threads which invoke the same method, but what do I want to do here?
The main thing to remember with Swing is that almost none of the Swing methods should be called from any other thread except the Swing Event Dispatch Thread (EDT).
The EDT is what sits in a loop, waiting for key presses, mouse clicks, and other events, and calling your handlers each time an event happens that interests your program.
Whenever any of your other threads wants to do something that will affect the GUI, it should call the SwingUtilities.invokeLater(r) method where r is some Runnable object. The invokeLater(r) method will post an event containing r to the event queue, and the EDT will handle the event by calling r.run(). The r.run() method can then safely call whatever Swing methods you need it to call.
This looks like classic producer consumer scenario. The thread which calculates ball movements is producer and the thread which paints them is consumer. Check out these tutorial on the topic: http://www.tutorialspoint.com/javaexamples/thread_procon.htm or https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
One suggestion is to move the calculations into a swingworkers background processing method and calling repaint in done method of the worker.
To simplify the use of the AWT thread mechanism, and async component data fetching and component enable/disable while loading data, I wrote the ComponentUpdateThread, a long time ago. It makes it terribly easy to do updates of data and get the right things done in the right thread context.
https://github.com/greggwon/SwingUtil/blob/master/java/main/src1.5/org/wonderly/swing/ComponentUpdateThread.java
new ComponentUpdateThread( button1, button2 ) {
}.start();
is the basic premise of how you use it. All listened components will recursively be traversed and disabled by the actions of start(). There are three methods that you can implement.
The first one, setup(), is invoked by an AWT event thread, and should do anything to components (aside from disabling things that the cons parameters will make happen). This maybe simple things like emptying a list model etc.
The construct() method is invoked by an async, random thread. This method should "go get the data" to be used to populate controls, and put it into an appropriate container structure that it will return.
Finally, finished() is invoked by an AWT Event thread after construct() returns, and it should call getValue() to get the returned value from construct() activities, and then push that data into models/components as appropriate. finished() needs to call super.finished() at the right moment to "enable" the components passed into the cons. You can then disable things conditionally such as last selection in a list, options in checkboxes etc, and then return.
Here's an example of these methods taken from the javadocs. This shows the use of older APIs and doesn't include the fact that with generics, you can now make construct() a generic method with getValue() returning the same type. I have a version of this code that does all kinds of things that have been added more lately into Java.
This code is just to demonstrate the concepts around separation of thread use into separate methods so that you don't have to use SwingWorker directly, all over the place, but can use a more generic mechanism such as this.
My latest version of this code, includes the ability to chain together and next invocations so that more complex data retrieval and population can occur.
Ultimately, it would be really nice to just provide a ModelUpdater class that you could provide the component and any related model details to so that there was a compartmentalized use of data sourcing from remote access mechanisms.
public void setup() {
super.setup();
list.setEnabled(false);
list.clearSelection();
}
public Object construct() {
try {
Vector v = remote.getData();
Collections.sort( v );
return v;
} catch( Exception ex ) {
reportException(ex);
}
return null;
}
public void finished() {
try {
Vector v = (Vector)getValue();
list.setListData(v);
} finally {
super.finished();
list.setEnabled(true);
edit.setEnabled(false);
del.setEnaled(false);
}
}
When my applet starts up the first time from a clean environment, things work the way I expect them to. I spawn two threads, one for generic processing, and one for graphics. I do all GUI manipulation calls from the event dispatching thread. Start/Stop is handled correctly from the appletviewer, but Restart/Reload is not. I have a Canvas called drawCanvas as the only Component in my Applet's content pane, and I use double buffering to draw to it.
I observe the problem here:
public void start() {
/* ... some stuff */
executeOnEDTAndWait(
new Thread() {
#Override
public void run() {
/* ... more stuff ... */
setupDrawCanvas();
if( drawCanvas.isDisplayable() ) {
drawCanvas.createBufferStrategy(2);
/* ... some more stuff */
} else {
/* This is where it runs into difficulties */
}
/* ... */
Where setupDrawCanvas is defined like this:
private void setupDrawCanvas() {
setVisible(false);
setIgnoreRepaint(true);
getContentPane().removeAll();
drawCanvas = new Canvas();
drawCanvas.setName("drawCanvas");
drawCanvas.setSize(
newDrawCanvasDimension.width,
newDrawCanvasDimension.height);
drawCanvas.setIgnoreRepaint(true);
getContentPane().add(drawCanvas);
getContentPane().setVisible(true);
drawCanvas.setVisible(true);
setVisible(true);
}
Also, here's the relevant code in destroy()
public void destroy() {
/* .. some stuff .. */
/* dispose of drawCanvas */
drawCanvas.setVisible(false);
if( drawCanvas.getBufferStrategy() != null ) {
drawCanvas.getBufferStrategy().dispose();
}
/* reset and disable the applet's GUI */
setVisible(false);
getContentPane().removeAll();
removeAll();
/* .. some more stuff */
The first time through, everything works fine. When I do a restart from the appletviewer, first stop() is called which causes all my threads to enter into wait states. Then destroy() is called which wakes all my threads up again and lets them exit, as well as do and invokeAndWait() on the EDT to clean up my widgets and do a setVisible(false). So after destroy completes the appletviewer calls init/start again and the process repeats exactly as before, except it fails in start() at the region I noted above.
Something that I noticed which made very little sense to me was that if I cloned the applet using the appletviewer and then reloaded the clone, everything would work as expected when I attempted to restart or reload the clone the first time, but would crash with an exception the second time.
Something else I noticed while trying to debug this problem is that the appletviewer and a browser act completely differently as hosts to my applet; they don't even call init() and start() under the same conditions. Also, restart and reload seem to be nothing more than a call to stop() -> destroy() -> init() -> start() but with subtle modifications to the execution environment.
So my question is, what is the significance of the restart and reload operations (i.e. when are they used) and is it a problem that my applet fails in the appletviewer when they occur?
Nice Question.
To answer this question we need understand the blocks of java code first.
we have a anonymous, static blocks before construtor that will be executed.
package com.test;
import java.applet.Applet;
import java.awt.*;
public class AppletTest extends Applet {
{
System.out.println("I m Anonymous block");
}
static {
System.out.println("I m static block");
}
public AppletTest()
{
System.out.println("I m constructor");
}
public void init()
{
System.out.println("init");
}
public void start()
{
System.out.println("start");
}
public void stop()
{
System.out.println("stop");
}
public void destroy()
{
System.out.println("destory");
}
public void paint(Graphics g)
{
g.drawString("test Applet",10,10);
}
}
invocation:
<applet code="AppletTest.class" height=300 width=300></applet>
when running this class using appletviewer you can note the difference.
Applet running for the first time you will get
I m static block
I m Anonymous block
I m constructor
init
start
while doing applet restart -
stop
destory
init
start
and on applet reload
stop
destory
I m Anonymous block
I m constructor
init
start
for your second question, applet does not guarantee the same output on different OS, network and hardware components.