I am trying to move an object randomly. I have my GUI class which uses another class (lets say Obj) to create a new image and then start the thread to make the object move randomly. But my repaint() does not work in this context. The code below can give you an idea about how I am using the repaint method.
thanks,
Gui class
public class GUI extends JFrame implements ActionListener {
public void addNewObj(){
Obj f = new Obj();
x = panel.getGraphics();
f.paint(x);
Thread thr=new Thread(f);
thr.start();
}
}
Create object class
public class Obj extends JPanel implements Runnable
{
public Obj()
{
try {
myImage = ImageIO.read(new File("b:\\imgs\\bottle.jpg"));
}
catch (IOException e) {}
}
public void run()
{
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (true)
{
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;
try
{
moveRandom();
repaint();
Thread.sleep(1000);
}
catch (InterruptedException e)
{
System.out.println("interrupted");
}
beforeTime = System.currentTimeMillis();
}
}
The problem is very basic: Never paint an object in the way you do. You should add it to the frame or an container. This is also the reason, why repaint() doesn't work. Your object never makes it into the componenthierachy, and therefore repaint will only repaint this single object, but nothing else (including the frame, which should be repainted). Simply add the object directly to the frame, validate and repaint the frame.
the new addNewObj:
public void addNewObj(){
Obj f = new Obj();
Thread t = new Thread(f);
t.start();
panel.add(f);//add it to the panel
panel.validate();//validate the hierachy
panel.repaint();//repaint the whole thing to make the new obj visible
}
And override your Obj class to paint the objects:
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(myImage , 0 , 0 , Color.white , null);
}
Related
So I have been looking to update one of my panels in a my client code with data that comes from a server in Indonesia. The delay is rather long (2-8) sec and Im noticing that my UI is freezing during the time it takes for the response to return from the server.
The response will be used to draw some points on a map (not yet implemented).
I have been looking all over the net to find out how to do it and I have come across:
InvokeLater.
SwingWroker.
ScheduledThreadPoolExecutor.
Making the JPanel a runnable to run in its own thread(seems like best option).
http://www.java2s.com/Tutorial/Java/0160__Thread/CreateathreadtoupdateSwing.htm
But tbh most of the data i find is out dated (more than 5 years old).
Here is the JPanel class i want to update based on a server query:
public class MapPanel extends JPanel implements Pointable, Runnable {
private static final long serialVersionUID = 1L;
private List<Shape> shapes = new LinkedList<>();
private State mapPanelState;
public Shape selected;
private BufferedImage image;
public MapPanel() {
Commander.getInstance().addShapeContainer(this);
mapPanelState = NoState.getInstance();
MouseHandler mouseHandler = new MouseHandler(this);
KeyListener keyListener = new KeyListener();
readImage();
this.addMouseListener(mouseHandler);
this.addMouseMotionListener(mouseHandler);
this.addKeyListener(keyListener);
this.setBackground(Color.white);
this.setFocusable(true);
this.requestFocusInWindow();
}
private void readImage(){
try {
image = ImageIO.read(new File("/MapCoordProject/earthmap1.jpg"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void setState(State state) {
mapPanelState = state;
}
public List<Shape> getShapes() { return shapes; }
public void setShapes(List<Shape> shapes) {
this.shapes = shapes;
}
public Shape getLastShape(){ return shapes.get(shapes.size()-1); }
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
for (Shape shape : shapes)
shape.draw((Graphics2D) g);
}
public void select(Point point) {
for (Shape shape : shapes) {
if (shape.intersects(point)) {
selected = shape;
}
}
}
#Override
public Dimension getPreferredSize() {
if (image == null) {
return super.getPreferredSize();
} else {
int w = image.getWidth();
int h = image.getHeight();
return new Dimension(w, h);
}
}
public void pointerDown(Point point) {
mapPanelState.pointerDown(point, this);
}
public void pointerUp(Point point) {
mapPanelState.pointerUp(point, this);
selected = null;
}
public void pointerMoved(Point point, boolean pointerDown) {
mapPanelState.pointerMoved(point, pointerDown, this);
}
#Override
public void run() {
}
}
I want a method that updates the "Shapes" array in a separate thread to stop everything from freezing.
Any suggestions?
Making your JPanel implement Runnable is not the best solution. There is no reason to expose a run() method to other classes.
Instead, create a private void method that takes no arguments. A method reference that refers to that method can act as a Runnable, since it will have the same arguments and return type. You can then pass it to a Thread constructor.
public MapPanel() {
// ...
readImage();
new Thread(this::readShapes, "Reading shapes").start();
// ...
}
private void readShapes() {
try {
List<Shape> newShapes = new ArrayList<>();
URL server = new URL("https://example.com/indonesia/data");
try (InputStream dataSource = server.openStream()) {
while ( /* ... */ ) {
Shape shape = /* ... */;
newShapes.add(shape);
}
}
EventQueue.invokeLater(() -> setShapes(newShapes));
} catch (IOException e) {
e.printStackTrace();
EventQueue.invokeLater(() -> {
JOptionPane.showMessageDialog(getTopLevelContainer(),
"Unable to retrieve data:\n" + e, "Load Error",
JOptionPane.ERROR_MESSAGE);
});
}
}
Notice that calls to methods involving Swing objects are always wrapped in a call to EventQueue.invokeLater, to make sure they run on the correct thread.
It is possible to improve this by creating a progress dialog that shows while the data is being loaded, but that would make this answer much longer and would require more knowledge about the Indonesian API you’re calling.
What I am trying to do is an Appled which throws 2 threads, each running a counter which increases itself via an infinite loop
I then use a while(true) in the Applet's paint() method, which continuously paints the counters, the problem is that I have also 2 buttons, each intended to stop each thread, but the infinite loop in the paint() method doesn't let me neither click none of them nor close the Applet's window nor anything
Here a screenshot followed by the code
btw I'm certain the problem is the paint() loop as if I disable the loop I can interact with the buttons, but the counters are obviously not updated, and weird thing is that I put the mouse cursor over the buttons to show it took the form like when you want to resize a windows but the imprpant didn't capture it :/
http://i.imgur.com/PJnDI4u.png
public class MainApplet extends Applet implements ActionListener {
private static final long serialVersionUID = -2500043816999861110L;
private Font fuente;
private Button bUno, bDos;
private HiloContador hUno, hDos;
public void init() {
setBackground(Color.LIGHT_GRAY);
fuente = new Font("Verdana",Font.BOLD,26);
bUno = new Button("Parar");
bUno.addActionListener(this);
bDos = new Button("Parar");
bDos.addActionListener(this);
bUno.setSize(40,20);
add(bUno);
bDos.setSize(40,20);
add(bDos);
hUno = new HiloContador(20);
hUno.start();
hDos = new HiloContador(40);
hDos.start();
}
#SuppressWarnings({ "deprecation", "static-access" })
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(bUno)){
hUno.parar();
bUno.setLabel("1 parado");
}else if (e.getSource().equals(bDos)){
hDos.parar();
bDos.setLabel("2 parado");
}
}
public void paint(Graphics g) {
while (true){
g.clearRect(1,1,getSize().width,getSize().height); //dibuja la ventana
g.setFont(fuente);
g.drawString(hUno.getContador()+"",40,60);
g.drawString(hDos.getContador()+"",100,60);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
in case it helps anyone, solved deleting the infinite loop and adding this method
Timer timer = new Timer();
timer.schedule( new TimerTask() {
public void run() {
repaint();}
}, 0, 1000);
Hi im writting a very simple game. Player can use mouse to move spaceship and every 200ms new beam is shoot. This beam is moved in while(true) loop and when its y is 0 or 400 (bounds of frame) i use break to end the loop (and thread). Every beam has its own thread. There are also stars which move in background. Every of them moves like beams and has its own thread. So as you can see there are often add and removes from arrayLists. Everything works but from time to time I get such errors:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at spacecommander.MainPanel.paintComponent(MainPanel.java:50)
They doesnt make any problems in game but how can I eliminate them? Maybe I should use synchronization or something?
EDIT: HERE IS THE CODE
public class MainPanel extends JPanel {
private Player player = new Player(100, 100, 3, 3);
private Point2D targetPoint = new Point2D.Float(130, 350); //Poczatkowa pozycja statku
private ArrayList<Beam> beams = new ArrayList<Beam>();
private InputMap imap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
private ActionMap amap = getActionMap();
private Random rand = new Random();
public MainPanel() {
setPreferredSize(new Dimension(300, 400));
addMouseMotionListener(new MouseMotionHandler());
//Rozpoczynanie watkow
Thread t = new Thread(new PlayerMoveRunnable());
t.start();
Thread t2 = new Thread(new PlayerShootRunnable());
t2.start();
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, 300, 400);
//Rysowanie gracza
g2.drawImage(player.getImage(), (int)player.getX(), (int)player.getY(), null);
//Rysowanie pociskow
for (Beam beam : beams) {
g2.drawImage(beam.getImage(), (int)beam.getX(), (int)beam.getY(), null);
}
}
public void makeShortcut(String name, String keys, AbstractAction action) {
imap.put(KeyStroke.getKeyStroke(keys), name);
amap.put(name, action);
}
//Watek dziala caly czas bo gracz i tak caly czas sie rusza
private class PlayerMoveRunnable implements Runnable {
public void run() {
try {
while (true) {
player.moveToPoint(targetPoint);
repaint();
Thread.sleep(15);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//Takze dziala caly czas. Dodaje nowy pocisk co 200ms
private class PlayerShootRunnable implements Runnable {
public void run() {
try {
while (true) {
//Wybranie pocisku do wystrzelenia w zaleznosci od mode gracza
Thread t;
switch (player.getBeamMode()) {
case 1:
t = new Thread(new BeamMoveRunnable(new Beam1(100, 100, 10, 10, 10)));
break;
}
t.start();
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private class BeamMoveRunnable implements Runnable {
private Beam beam;
public BeamMoveRunnable(Beam beam) {
this.beam = beam;
}
public void run() {
Beam beam = this.beam;
beams.add(beam);
try {
while (true) {
if (beam.getY() <= 0) {
beams.remove(beam);
break;
}
beam.move();
repaint();
Thread.sleep(20);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private class MouseMotionHandler extends MouseAdapter {
public void mouseMoved(MouseEvent event) {
targetPoint = event.getPoint();
}
}
}
This seems to be a synchronization issue, as you suspected. Probably while your drawing code is iterating the beams-list, a BeamMoveRunnable modifies the list at the same time (either adding or removing a beam), and causes the ConcurrentModificationException. Personally I wouldn't use separate threads to move the beams, but a simple loop which first updates the game (moving all the beams one at a time etc.) and then redraws the screen. However, you can also just synchronize the access to the list so only a single thread can access it at a time.
Since you are using multiple threads different threads are trying to modify your beams arraylist. You can use synchronized block to avoid concurent modification exception as below
Looping the list
synchronized (beams) {
for (Iterator it = beams.iterator(); it.hashNext(); ) {
Beam beam = (Beam) it.next();
g2.drawImage(beam.getImage(), (int)beam.getX(), (int)beam.getY(), null);
}
}
Adding item to the list
syncronized (beams) {
beams.add(beam);
}
removing item from the list
syncronized (beam) {
list.remove(beam);
}
This typically happens when you try to add or remove an item from a list while iterating:
for (String s : list) {
list.add("abc"); //ConcurrentModificationException
}
It is difficult to be more specific without seeing the code that is around line 50 of your MainPanel class (cf. stacktrace: at spacecommander.MainPanel.paintComponent(MainPanel.java:50)).
EDIT
Following your edit, a simple change would be to use a CopyOnWriteArrayList which is thread safe, instead of an ArrayList, to hold your Beam objects.
First code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class cos {
public static int a;
private static JLabel labeler;
// public static Runnable r1;
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
a = 0;
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
cos window = new cos();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public cos() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
public void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 205, 194);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel lblTime = new JLabel("Time:");
frame.getContentPane().add(lblTime, BorderLayout.WEST);
final JLabel labeler = new JLabel("");
frame.getContentPane().add(labeler, BorderLayout.CENTER);
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
Runnable r1 = new Runnable() {
public void run() {
while (a <= 10) {
a = a + 1;
labeler.setText(Integer.toString(a));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
public void actionPerformed(ActionEvent arg0) {
Thread threder = new Thread(r1);
threder.start();
// liczniczek bla = new liczniczek();
}
});
frame.getContentPane().add(btnNewButton, BorderLayout.SOUTH);
}
public void licznik() {
while (a < 60) {
a = a + 1;
labeler.setText(Integer.toString(a));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
And now my question. I wanna use code like this:
Runnable r1 = new Runnable(){
public void run(){
licznik();
}
};
But that doesen't work. What i must do to separate this code ? Sorry for my bad english
Sierran.
never use Thread#sleep(int) during EDT, sure if is there only this thread then works correctly (with blockng EDT),
Runnable r1 = new Runnable(){
public void run(){
licznik();
}
};
is wrong than same as you call plain licznik();, you have to wrap that this way
Runnable r1 = new Runnable(){
public void run(){
labeler.setText(Integer.toString(a));
}
};
but again without Thread#sleep(int), you have three choises
1) change Thread to the javax.swing.Timer
2) change Thread to the Runnable#Thread, there you can delaying with Thread#sleep(int), but output to the GUI must be
Runnable r1 = new Runnable(){
public void run(){
labeler.setText(Integer.toString(a));
}
};
3) use SwingWorker, where output is in the EDT and you can use Thread#sleep(int) too
example Thread#sleep(int) during EDT
put all together
EDIT
don't use reserved words as class, method, variable, whatever Name in the Programing languages (meaning cos)
your code works by implements all three options that I post here,
What do you mean "it doesn't work"? It works for me. How are you trying to use this code, and what errors or problems are you having when you run it? Myself, I'd use a SwingWorker though and I'd set the JLabel's text via the SwingWorker's publish/process method pair. To learn more on how to use this, please see this tutorial: Concurrency in Swing
Edit
Actually, an easier way to accomplish what you want is to not use threads or Runnables directly at all but to use a Swing Timer as they're built for just this case. For more on this, please check out the Swing Timer Tutorial
I gather that you want the function licznik() to run in a separate thread. You create a Runnable, but you have to do something more to make its run() method execute. There are a couple of ways to do this:
Runnable r1 = new Runnable(){
public void run(){
licznik();
}
};
new Thread(r1).start();
or you can just subclass Thread directly:
Thread r1 = new Thread(){
public void run(){
licznik();
}
};
r1.start();
Runnable interface has no method licznik(). You can create class that implements Runnable with licznik() method.
Or if you do not need to reuse this method and use it just once, then the fastest way is to move its implementation inside new Runnable() block
Runnable r1 = new Runnable(){
public void run(){
this.licznik();
}
public void licznik(){
while (a < 60){
a = a + 1 ;
labeler.setText(Integer.toString(a));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
Look on GitHub under at https://github.com/greggwon/Ham. Look at the source code in https://github.com/greggwon/Ham/blob/master/SwingUtil/src/org/wonderly/swing/ComponentUpdateThread.java to see how I've packaged this whole detail into a single class which uses anonymous inner classes to do the work. It would be possible to change this to lambdas now, but I have not used Java in several years and thus haven't made that change.
new ComponentUpdateThread( new Action[] { add, del, edit } ) {
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();
if( v != null ) list.setListData(v);
} finally {
super.finished();
list.setEnabled(true);
edit.setEnabled(false);
del.setEnaled(false);
}
}
}.start();
With this style of work, you can use final values from surrounding blocks or other class visible data to control various aspects of what happens before, during and after background thread execution.
I've change this code around over the years in various ways and there are other variations of this that exist.
The arguments to the ComponentUpdateThread constructor are controls/actions to be "disabled" while the background thread is running. Other enable/disable activities can be more literally embedded into the activities in setup() and finished() (which are run in the AWT event thread) before "construct" is run in the background thread.
I have a school project and i want to dedicate this for New Year, the project that i came up is a Text-Firework, i am using characters and symbols as the Explosion particles, and just constantly changing their X and Y position inside Paint().
I am confused on how to use Paint and Thread together. The problem is it's not painting on the screen or maybe the thread is not starting. (i cant really tell, im sorry). the problem is i dont get any error, it just doesn't work :(
the code is a little bit long i think, thank you for reading it.
How it should Works: When a user click, a Firework Thread will be started on the mouse position,
this Firework class has a paint loop for recreating the incremental explosion. so basically, i want the user to create multiple explosions thats why i made it a Thread.
here is the main applet:
public class TBFireworks extends Applet implements MouseListener
{
public void init()
{
setBackground( Color.black );
addMouseListener( this );
}
public void mouseEntered( MouseEvent e ) { }
public void mouseExited( MouseEvent e ) { }
public void mousePressed( MouseEvent e ) { }
public void mouseReleased( MouseEvent e ) { }
public void mouseClicked( MouseEvent e )
{
new Firework( e.getX(),e.getY(), this);
}
}
and the Firework Thread class:
class Firework extends Thread
{
Point center = new Point(0,0);
int blastRadius = 10;
Point posIncrement = new Point(0,0);
Applet applet;
public Firework(int positionX, int positionY, Applet apple)
{
center.x = positionX;
center.y = positionY;
applet = apple;
new Thread(this).start();
}
public void run()
{
while(blastRadius > 0)
{
applet.paint(applet.getGraphics());
try {
this.sleep(1000/20);
} catch (InterruptedException e) { ; }
}
}
public void paint(Graphics g)
{
if(blastRadius > 0)
{
Point[] fakeFire = {new Point(20,20),new Point(20,30),new Point(30,20)};
ApplyNextPos(fakeFire,posIncrement);
g.setColor(Color.red);
for(int xaa=1; xaa<5; xaa++) // draw the formation
{
for(int zaa=0;zaa<fakeFire.length;zaa++)
{
fakeFire[zaa] = GetQuadrant(xaa,center,fakeFire[zaa]);
}
for(int yaa=0;yaa<fakeFire.length;yaa++)
{
g.drawString("*",fakeFire[yaa].x,fakeFire[yaa].y);
}
}
posIncrement.incrementPos(5);
blastRadius--;
}
}
}
First, you seem not to be using your paint-method in the FireWork thread, you call the applet's paint method instead.
I'm a bit rosty in the applet and AWT stuff, but if it were Swing (I guess it not that different), I would suggest another approach. Painting should (can?) only be done in the EDT (Event Dispatch Thread). When the user clicks, you create a similar object to FireWork, and add that to a list. Then you start ONE thread (if not already started, that continously calls repaint on some panel. Then in the paint-method of your panel you loop the list of all fireworks and draw them.
This will also be more memory efficient, since you only use one thread.
The paint method should (normaly) only be called by the GUI when the corresponding component or part of it needs to be (re-)painted. It should not be called by the application (if not from inside another paint method).
The paint method is called to draw the actual state of the component. The state should be changed by another method/thread. The repainting of the component is forced by calling repaint.
An incomplete, untested example:
public class Animation extends Canvas {
private final List<Firework> fireworks = new ArrayList<Firework>();
public void start() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
step();
Thread.sleep(STEP_TIME); // InterruptedException ?
}
}
});
t.start();
}
#Override
public void paint(Graphics g) {
super.paint(g);
for (Firework fw : fireworks)
fw.draw(g); // draw the Firework
}
private void step() {
for (Firework fw : fireworks)
fw.step(); // update/move the Firework
repaint();
}
// methods for adding/deleting Fireworks, synchronization?
}