I've just starting delving into the wonders of Java ME but have become frustrated when trying to create a thread...
Below is the code which compiles absolutely fine. However, as soon as I install it on my G600 and run it, 'Java Game Error' pops up.
My method of putting it in a jar file and installing it works, as I have created a game with no threads and that works fine.
import java.util.Random;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import javax.microedition.midlet.*;
public class CanvasTest extends MIDlet {
Display display;
public CanvasTest() {
}
public void startApp() {
TestCanvas thecanvas = new TestCanvas();
display = Display.getDisplay(this);
display.setCurrent(thecanvas);
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
}
class TestCanvas extends GameCanvas implements Runnable {
Font font;
int width;
int height;
boolean running = true;
public TestCanvas() {
super(false);
setFullScreenMode(true);
width = getWidth();
height = getHeight();
Thread thisThread = new Thread(this);
thisThread.start();
}
public void paint(Graphics g) {
Random rand = new Random();
g.setColor(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255));
g.fillRect(0, 0, width, height);
}
public void run() {
while(running) {
paint(getGraphics());
flushGraphics();
try {
Thread.sleep(50);
}
catch(InterruptedException ex) {}
}
}
};
Note: yes, this is not the game, it merely demonstrates the problem I am facing.
Thanks in advance!
Just a wild guess, but a general rule in Java is that you can't "touch" the UI out of the main thread. Well, this a little bit roughly explained, but there are many articles about the topic.
I suggest you to avoid calling UI methods like paint() or flushGraphics() from a separate Thread.
I hope it helps.
did you test it at emulator prior to phone? if not - why? if yes - how did it go?
regarding the code it looks OK to me except for the slippery two lines where you create and start thread from constructor. I'd rather move these two lines at the end of startApp
public void startApp() {
TestCanvas theCanvas= new TestCanvas();
display = Display.getDisplay(this);
display.setCurrent(theCanvas);
new Thread(theCanvas).start(); // add here and...
}
//...
public TestCanvas() {
super(false);
setFullScreenMode(true);
width = getWidth();
height = getHeight();
// ...and remove here
// Thread thisThread = new Thread(this);
// thisThread.start();
}
Related
I'm trying to make my own version of Snake for learning purposes. Everything seems to work fine except that if I want my frame to be repainted, I have to resize my window manually. Here is my code:
package snake;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PlayGame extends JPanel implements Runnable{
public boolean animate = false;
public final int FRAME_DELAY = 750;
PickupBall b = new PickupBall();
Snake bob = new Snake();
public synchronized void start() {
animate = true;
}
public synchronized void stop() {
animate = false;
}
private synchronized boolean animationEnabled() {
return animate;
}
#Override
public void run(){
while(true){
if (animationEnabled()){
repaint();
}
try {
Thread.sleep(FRAME_DELAY);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
b.draw(g);
bob.draw(g);
}
public static void main(String[] args) {
JFrame jfr = new JFrame("Snake");
jfr.setSize(640,640);
jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfr.setResizable(true);
PlayGame p = new PlayGame();
jfr.setContentPane(p);
p.setBackground(Color.WHITE);
p.start();
new Thread(p).start();
jfr.setVisible(true);
}
}
Why isn't repaint() triggered without altering the frame size? I get the correlation but it makes no sense to me why it needs such a trigger when it's in a while(true) loop anyway.
What am I missing here?
Edit 1:
Removed thread object
Replaced t.start() with p.start()
Edit 2:
Added new Thread(p).start(); and now it works! Thanks.
Edit 3:
Removed revalidate();
You are executing repaint() in the worker thread and not in the event dispatch tread (EDT) which is the only one actually drawing onto the screen.
You have to en queue the call to repaint() in the EDT using SwingUtilities static methods invokeLater() or invokeAndWait().
Added new Thread(p).start();
Still have no idea how or why this is different to
Thread t = new Thread(p);
t.start();
But it worked.
This small applet is supposed to move a String from the bottom to the top of applet frame, when it reaches top it should start from the bottom again. Problem is it's only moving when I resize the applet window. It doesn't move itself, why does it works that way?
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
public class Zad1 extends Applet implements Runnable {
Thread runner;
int yPos = 500;
public void start() {
if (runner == null) {
runner = new Thread(this);
}
}
public void stop() {
if (runner != null) {
runner = null;
}
}
public void run() {
while (true) {
repaint();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void paint(Graphics g) {
g.drawString("Hello java", 50, yPos);
yPos--;
if (yPos < -30)
yPos = 500;
}
}
The thread is not started
runner = new Thread(this);
runner.start(); // <----------- Insert this!
But note that the style of this applet is bad in many ways (e.g. there should be no logic in "paint", you should probably not overwrite "paint" of an Applet at all, you should consider a JApplet, etc...). You should probably read http://docs.oracle.com/javase/tutorial/uiswing/components/applet.html and other examples.
I'm very new to java (and to object oriented programming for that matter). As a first java project I've been instructed to get a tag cloud engine applet up and running. So I found WordCram and a small example bit of code for using PApplets and thought I'd have an easy time...
But while my code doesn't generate any errors per-se, it throws the following upon running:
Exception in thread "Animation Thread" java.lang.NullPointerException
at processing.core.PApplet.handleDraw(PApplet.java:2336)
at processing.core.PGraphicsJava2D.requestDraw(PGraphicsJava2D.java:243)
at processing.core.PApplet.run(PApplet.java:2176)
at java.lang.Thread.run(Thread.java:722)
I have a TON of code, and I'm hesitant to post it all here... But over the course of trying to get to the bottom of my code I'm always frustrated at how little of the code the inquirer gives: so I'll tentatively paste it here and I'll look out for people telling me to reformat or edit out some or most of it.
First of two classes:
package tagengine;
import java.awt.*;
public class TagFrame extends Frame {
public TagFrame()
{
super("Embedded PApplet");
Engine embed = new Engine();
setLayout(new BorderLayout());
add(embed, BorderLayout.CENTER);
embed.init();
}
public static void main(String[] args)
{
TagFrame tagFrame = new TagFrame();
}
}
And the second:
package tagengine;
import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PVector;
import wordcram.*;
public class Engine extends PApplet {
#Override public void setup() {
this.size(900, 500);
this.colorMode(HSB);
this.noLoop();
this.setVisible(true);
}
#Override public void draw() {
this.background(68);
new WordCram(this)
.fromWebPage("http://en.wikipedia.org/wiki/Barcamp")
.withColors(color(0, 0, 0),
color(0, 0, 255),
color(30, 255, 255)) // mustard, red)
.withFonts(PFont.list())
.withAngler(moreRandomByWeight())
.withPlacer(crazyPlacer())
.sizedByWeight(8, 100)
.maxNumberOfWordsToDraw(300)
.drawAll();
}
WordAngler moreRandomByWeight() {
return new WordAngler() {
#Override public float angleFor(Word w) {
float range = (1 - w.weight) * PI;
return random(-range, range);
}
};
}
WordPlacer crazyPlacer() {
return new WordPlacer() {
#Override public PVector place(Word w, int rank, int words,
int ww, int wh, int fw, int fh) {
float x = (fw - ww) * (1 - w.weight);
float y = random(fh - wh);
return new PVector(x, y);
}
};
}
#Override public void mousePressed() {
redraw();
}
}
You're adding your Engine to the BorderLayout before calling init(), and it looks like an immediate paint operation is trying to execute before the Engine is ready to be painted.
Please have a look at the following code
First, Please note I am a 100% newbie to Java Mobile.
In here, I am making the light on and vibrate on when user click the button. However, I really wanted to create a SOS application which turn the whole screen into white, and go to black, like that, in the thread. I guess I didn't achieve that by this app because even the lights are on, the buttons are still there. I tried to turn the "Form" color to "white" but it seems like JME has no "Color" class.
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class Midlet extends MIDlet{
private Form f;
private Display d;
private Command start,stop;
private Thread t;
public Midlet()
{
t = new Thread(new TurnLightOn());
}
public void startApp()
{
f = new Form("Back Light On");
d = Display.getDisplay(this);
d.setCurrent(f);
start = new Command("Turn On",Command.OK,0);
stop = new Command("Turn Off",Command.OK,1);
f.addCommand(start);
f.setCommandListener(new Action());
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional)
{
this.notifyDestroyed();
}
private class Action implements CommandListener
{
public void commandAction(Command c, Displayable dis)
{
f.append("Light is Turnning On");
t.start();
}
}
private class ActionOff implements CommandListener
{
public void commandAction(Command c, Displayable dis)
{
}
}
private class TurnLightOn implements Runnable
{
public void run()
{
f.append("Working");
for(int i=0;i<100;i++)
{
try
{
d.flashBacklight(200);
d.vibrate(200);
Thread.sleep(1000);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
}
}
Use the javax.microedition.lcdui.Canvas instead of Form. This example can get you started
public void startApp()
{
f = new Form("Back Light On");
d = Display.getDisplay(this);
start = new Command("Turn On",Command.OK,0);
stop = new Command("Turn Off",Command.OK,1);
f.addCommand(start);
f.setCommandListener(new Action());
myCanvas = new MyCanvas();
d.setCurrent(myCanvas);
myCanvas.repaint();
}
Now create a canvas and implement paint method like this:
class MyCanvas extends Canvas {
public void paint(Graphics g) {
// create a 20x20 black square in the center
// clear the screen first
g.setColor(0xffffff);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(0xffffff); // make sure it is white color
// draw the square, <b>changed to rely on instance variables</b>
<b>g.fillRect(x, y, getWidth(), getHeight());</b>
}
}
First of all here are some code snippets:
public void startThread() {
this.animationThread = new Thread(this);
this.animationThread.start();
try {
this.animationThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void run() {
pirateMainAnimation.animate();
}
public void animate() {
for (int j = 0; j < 9; j++) {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
break;
}
PirateAnimationPanel.getInstance().setCurrent(j);
PirateAnimationPanel.getInstance().repaint();
}
}
I'm trying to animate some images. The thing is that I want the main thread to wait for the animation thread to finish and then to continue. I searched around, read a little bit and decided to use the join() method. It perfectly waits for the thread to finish but I doesn't animate correctly. The repaint() method gets called 2 times instead of nine. I think maybe the problem is because I used singletons. Here is the singleton implementation.
import java.awt.Graphics;
import java.awt.MediaTracker;
import javax.swing.JPanel;
import uk.ac.aber.dcs.piratehangman.animation.PirateMainAnimation;
import uk.ac.aber.dcs.piratehangman.utilityclasses.AnimationThread;
#SuppressWarnings("serial")
public class PirateAnimationPanel extends JPanel {
private int current;
private MediaTracker mTracker;
private PirateMainAnimation pirateMainAnimation;
private AnimationThread animationThread;
private PirateAnimationPanel() {
this.current = 0;
this.pirateMainAnimation = new PirateMainAnimation();
mTracker = new MediaTracker(this);
this.animationThread = new AnimationThread();
setMediaTracker();
repaint();
}
private void setMediaTracker() {
for (int i = 0; i < 9; i++) {
mTracker.addImage(
this.pirateMainAnimation.getImagesForAnimation()[i],
this.pirateMainAnimation.getImagesForAnimationID()[i]);
try {
mTracker.waitForID(this.pirateMainAnimation
.getImagesForAnimationID()[i]);
} catch (InterruptedException e) {
System.out.println("Error loading image: " + i);
}
}
}
public void playAnimation() {
this.animationThread.startThread();
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
System.out.println("called");
g.drawImage(this.pirateMainAnimation.getImagesForAnimation()[current],
0, 0, this);
}
private static class PirateAnimationPanelHolder {
private static final PirateAnimationPanel pirateAnimationPanel =
new PirateAnimationPanel();
};
public static PirateAnimationPanel getInstance() {
return PirateAnimationPanelHolder.pirateAnimationPanel;
}
public void setCurrent(int current) {
this.current = current;
}
public int getCurrent() {
return current;
}
}
I think you mean that the paintComponent() methods only gets called twice. Also I think you should be able to remove the call to super.paintComponents() if you fill the component to the background color.
The repaint() method only marks the component as dirty and requests a re-render on the next paint.
I would have expected the Swing thread to be able to repaint within the 250ms but I'm not sure what other work is being done/rendered. You might want to put a call to MediaTracker.waitForAll() before the animation.
While the static singleton is not adding much I don't think it is causing a problem (in this case).
Update:
So the problem is that the join() is on the Swing event Thread which is blocking the repainting of the component. I suggested a call like the following to show the "new game dialog after the last animation:
SwingUtilities.invokeLater(new Runnable() {
public void run() { showDialog(); }
})
"Note that events being posted to the EventQueue can be coalesced," which may explain the disparity. Also, be certain to build your GUI on event dispatch thread. See A More Complex Image Icon Example for a more detailed discussion.
Addendum: Improving Perceived Performance When Loading Image Icons has a nice SwingWorker example that may simplify the off-loading.