Avatar billede Druesukker Nybegynder
16. januar 2011 - 01:43 Der er 5 kommentarer og
1 løsning

Synkronisering af hoppende bolde

Hej.
Jeg er i gang med at lære java og i den forbindelse har jeg et par spørgsmål.
Hvorfor virker følgende kode ikke som synchronized? boldene bliver ikke malet over hver gang...

// klasse der laver en bold
import java.awt.*;

public class Bold implements Runnable
{
  double x, y, fartx, farty;
  Graphics g;

  public Bold(Graphics g1, int x1, int y1)
  {
    g = g1;
    x = x1;
    y = y1;

    fartx = Math.random();
    farty = Math.random();
    Thread t = new Thread(this);
    t.start();
  }

  public void run()
  {
    for (int tid=0; tid<5000; tid++)
    {
        synchronized (this)
        {
          // Tegn bolden over med hvid på den gamle position
          g.setColor(Color.WHITE);
          g.drawOval((int) x, (int) y, 50, 50);
       
       
          // Opdater positionen med farten
          x = x + fartx;
          y = y + farty;

          // Tegn bolden med sort på den nye position
          g.setColor(Color.BLACK);
          g.drawOval((int) x, (int) y, 50, 50);

          // ændr boldens hastighed lidt nedad
          farty = farty + 0.1;

          // Hvis bolden er uden for det tilladte område skal den
          // rettes hen mod området
          if (x < 0) fartx = Math.abs(fartx);
          if (x > 400) fartx = -Math.abs(fartx);
          if (y < 0) farty = Math.abs(farty);
          if (y > 100) farty = -Math.abs(farty);

          // Vent lidt
          try { Thread.sleep(10);} catch (Exception e) {};
      }
    }
  }
}

Andet spørgsmål. Jeg blev desuden nødt til at lave en helt anden klasse der extends JPanel for at kunne male baggrunden på min JFrame hvid hvordan kan det være? De efterfølgende klasser kommer også lige med for en sikkerheds skyld:

import javax.swing.*;
import java.awt.*;

public class PanelIndeholdBolde extends JPanel
{
  public void paint(Graphics g){
  }
}

og

import java.awt.*;
import javax.swing.*;

public class FlertraadetGrafik
{
  public static void main(String[] arg)
  {
    SwingUtilities.invokeLater(new Runnable(){
      public void run(){
        FlertraadetGrafik start = new FlertraadetGrafik();
        start.åbnPanelOgVin();
    }
      });
  }
 
  public void åbnPanelOgVin(){
    JFrame f = new JFrame();
    f.setSize(400,150);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setBackground(Color.WHITE);
    f.setVisible(true);
    f.add(new PanelIndeholdBolde());
    Graphics g = f.getGraphics();
       
    new Bold(g,  0, 0);
    new Bold(g, 50,10);
    new Bold(g,100,50);
    new Bold(g,150,90);     
  }
}

Håber der er en der har tid til at hjælpe mig lidt .. :)
Avatar billede arne_v Ekspert
16. januar 2011 - 03:00 #1
Den var svær.

Jeg mener grundliggende at programmet er struktueret helt forkert og at problemer du har skyldes den strukturering.

Her er et noget tilsvarende eksempel på hvordan jeg ville gribe noget tilsvarende an:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class MovingBalls extends JFrame {
    public MovingBalls() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Moving balls");
        getContentPane().setLayout(new BorderLayout());
        Ball red = new Ball(200,200,50,Color.RED);
        Ball green = new Ball(400,200,50,Color.GREEN);
        Ball blue = new Ball(400,400,50,Color.BLUE);
        Ball yellow = new Ball(200,400,50,Color.YELLOW);
        MultiBalls mb = new MultiBalls(600, 600);
        mb.addBall(red);
        mb.addBall(green);
        mb.addBall(blue);
        mb.addBall(yellow);
        getContentPane().add(mb);
        (new BallMover(red, mb)).start();
        (new BallMover(green, mb)).start();
        (new BallMover(blue, mb)).start();
        (new BallMover(yellow, mb)).start();
        pack();
       
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame f = new MovingBalls();
                f.setVisible(true);
            }
        });
    }
}

class MultiBalls extends JPanel {
    private List<Ball> balls;
    public MultiBalls(int w, int h) {
        setPreferredSize(new Dimension(w, h));
        balls = new ArrayList<Ball>();
    }
    public void addBall(Ball b) {
        balls.add(b);
    }
    @Override
    public void paint(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0,getWidth(), getHeight());
        for(Ball b : balls) {
            g.setColor(b.getC());
            g.fillOval(b.getX() - b.getR(), b.getY() - b.getR(), 2*b.getR(), 2*b.getR());
        }
    }
}

class Ball {
    private volatile int x;
    private volatile int y;
    private int r;
    private Color c;
    public Ball(int x, int y, int r, Color c) {
        this.x = x;
        this.y = y;
        this.r = r;
        this.c = c;
    }
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    public int getR() {
        return r;
    }
    public void setR(int r) {
        this.r = r;
    }
    public Color getC() {
        return c;
    }
    public void setC(Color c) {
        this.c = c;
    }
}

class BallMover extends Thread {
    private Random rng = new Random(getId() + System.currentTimeMillis());
    private Ball b;
    private JPanel p;
    public BallMover(Ball b, JPanel p) {
        this.b = b;
        this.p = p;
    }
    @Override
    public void run() {
        for(;;) {
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int x = b.getX() + rng.nextInt(21) - 10;
            int y = b.getY() + rng.nextInt(21) - 10;
            x = Math.max(x, b.getR());
            x = Math.min(x, p.getWidth() - b.getR());
            y = Math.max(y, b.getR());
            y = Math.min(y, p.getHeight() - b.getR());
            b.setX(x);
            b.setY(y);
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    p.repaint();
                }
            });
        }
    }
}
Avatar billede Druesukker Nybegynder
16. januar 2011 - 03:53 #2
Tak, det er smart at gentegne hele panelet i stedet for  en enkelt bolt af gangen.

Hvorfor kalder du getContentPane()? Jeg har aldrig brugt den før hehe.

Du fortjener flere point end dem jeg har udlovet for det store arbejde.. Men kom med et svar så får du :)
Avatar billede arne_v Ekspert
16. januar 2011 - 15:46 #3
Jeg kalder getContentPane() af gammel vane, fordi man ikke kunne sætte de ting direkte på JFrame i gamle dage. Det blev tilføjet i Java 1.5 i 2004 og jeg er et vane dyr.
Avatar billede arne_v Ekspert
16. januar 2011 - 15:46 #4
svar
Avatar billede arne_v Ekspert
16. januar 2011 - 15:46 #5
Jeg mener at ideen med at gentegne panel og lade bolde ikke være grafisk er den rigtige løsning.
Avatar billede Druesukker Nybegynder
16. januar 2011 - 19:41 #6
Ja og super flot kode i øvrigt :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester