# meine paint-methode macht faxen?



## hdi (15. Feb 2008)

hallo,

ich mach's kurz:


```
public static void main(string[] arg){
     View v = new View();
     while (true) v.repaint();
}
```

in meiner view liegt ein Jpanel, und dort hab ich die methode:


```
protected void paintComponent(Graphics g){
		super.paintComponent(g);
		
		p.draw(g);   // p ist hier ein Point, dessen draw-methode einfach g.drawRect() aufruft

	}
```

und noch nen mouselistener

```
public void mouseClicked(MouseEvent e){
		
		while(!(p.getPos().equals(e.getPoint()))){
			p.move(e.getPoint());
		}
	}
```

die methode "p.move(e.getPoint)" bewegt bei jedem aufruf den Punkt "p" in richtung des Punktes, auf den man geklickt hat. (nähert den Punkt jeweils um 1 pixel auf der x und y achse an)


so, und das problem:
wenn ich irgendwohin klicke, dann passiert für kurze zeit nix auf dem bildschirm, und dann plötzlich ist der Punkt an der neuen Stelle.

Ich will aber, dass man die Bewegung sieht. MEine main-methode macht doch die ganze zeit repaint(), wieso paintet er erst wieder wenn der Punkt angekommen ist, und nicht die ganze zeit? man sieht halt die bewegung gar nicht...

Ich könnte wetten, ich hab das genau so schon mal gemacht, und da hats funktioniert...


----------



## Gast (16. Feb 2008)

Ganz spontan würde ich sagen:

```
public static void main(String[] args){

SwingUtilities.invokeLater(new Runnable(){
public void run(){
new View();
}
});
}
```

und


```
public void mouseClicked(MouseEvent e){
(new SwingWorker(){
doInBackground(){
while(!p.getPos().equals(e.getPoint())){
p.move
publish(...);
}
process(){
//hier jetzt das neu Zeichnen
}
}
}).start();
}
```

Das scheint mir ein Threadingproblem zu sein.

Warum 
while (true) v.repaint(); ?

wenn sich an v nichts ändert, warum neuzeichnen. Erzeugt nur unnötig Last auf dem System.

Nur EventDischpatschingThread zeichnen lassen und EventDischpatschingThread nur zeichnen lassen.
Dafür eventuell die Hilfe eines SwingWorkers in anspruch nehmen bzw. ab Java 6 den SwingWorker.


----------



## Gast (16. Feb 2008)

achja und das neuzeichnen kann statt repaint() auch parametrisiert erfolgen. Kleinstmögliches Quadrat in dem sich der alte und neue Punkt befinden.


----------



## André Uhres (16. Feb 2008)

```
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class View extends JFrame {
    public View() {
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(400, 300);
        setLocationRelativeTo(null);
        add(new DrawingPanel());
    }
    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new View().setVisible(true);
            }
        });
    }
}
class DrawingPanel extends JPanel {
    private Punkt p;
    private SwingWorker pointMover;
    public DrawingPanel() {
        p = new Punkt(100, 100);
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(final MouseEvent e) {
                if (pointMover == null || pointMover.isDone()) {
                    startPointMover(e);
                }
            }
            private void startPointMover(final MouseEvent e) {
                pointMover = new SwingWorker() {
                    @Override
                    protected Object doInBackground() throws Exception {
                        while (!(p.getPos().equals(e.getPoint()))) {
                            p.move(e.getPoint());
                            //"repaint" fügt den angegebenen Bereich zu der 
                            //"dirty region list" hinzu. Die Komponente wird 
                            //neugezeichnet, nachdem alle anstehenden Events 
                            //auf dem "Event Dispatch Thread" abgefertigt wurden:
                            repaint(p.getBounds());
                        }
                        return p;
                    }
                };
                pointMover.execute();
            }
        });
    }
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        p.draw(g);
    }
}
class Punkt extends Point {
    private Rectangle bounds;
    private int size = 5;
    public Punkt(int x, int y) {
        super(x, y);
        bounds = new Rectangle(x - 2, y - 2, size + 4, size + 4);
    }
    public void draw(Graphics g) {
        g.drawRect(x, y, size, size);
    }
    public Punkt getPos() {
        return this;
    }
    public void move(Point point) {
        if (point.x > x) {
            x++;
        } else {
            x--;
        }
        try {
            Thread.sleep(5);
        } catch (InterruptedException ex) {
        }
    }
    public boolean equals(Point point) {
        return x == point.x;
    }
    public Rectangle getBounds() {
        bounds.x = x - 2;
        bounds.y = y - 2;
        return bounds;
    }
}
```
MovingPoint.jar


----------



## Gast (16. Feb 2008)

Sehr schön!


----------



## Guest (16. Feb 2008)

krass, vielen dank !!

wobei ich es nicht wirklich verstehe:

was ist der vorteil von diesem invokeLater() ? Und was ist der Vorteil eines SwingWorkers, anders gefragt:
Was ist der unterschied zwischen run() und doInBackground(), bzw. start() und execute() ?

Da ich das nicht weiss, erscheint mir dein code einfach sehr kompliziert.
Ich würde das niemals so machen. Ich kenn bisher nur Threads mit einem start-aufruf und halt die paintComponent methode.
Andwenden kann ich sowas natürlich nur richtig, wenn ich auch verstehe was der Sinn von den Sachen sind.

Wäre sehr nett, wenn du mir das noch zu deinem tollen code erklärst 

danke


----------



## Tobias (16. Feb 2008)

http://www.javalobby.org/eps/galbraith-swing-2/

Der erklärt das ganz gut  ...

mpG
Tobias


----------



## André Uhres (16. Feb 2008)

Tobias hat gesagt.:
			
		

> http://www.javalobby.org/eps/galbraith-swing-2/
> Der erklärt das ganz gut  ...


Dort wird zwar die alte Version von "SwingWorker" erklärt, aber die Erklärungen
sind vorzüglich. In unserem speziellen Fall bringt die Klasse eigentlich keinen Vorteil,
da wir lediglich die "doInBackground" Methode benutzen (="construct" in der alten Version). 
Wir könnten auch einen einfachen "Thread" nehmen :wink:
"invokeLater" wird benutzt, um den Code auf den "Event Dispatch Thread" (EDT) zu schicken.
Eine GUI sollte immer auf dem EDT gestartet werden.
Siehe auch: http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html


----------



## Guest (17. Feb 2008)

tobias vielen dank für den geilen link! jetz kann ich mir endlich vorstellen wie das alles passiert und kann nun auch ganz gut einschätzen, wo die probleme sein könnten.

trotzdem erfordert swing mit threads und vielen listenern find ich sehr viel übung, es ist wirklich ein ziemlich schweres thema.

ich hab auf der seite gekuckt ob es noch mehr von solchen tuts gibt, aber unter "podcast" und "presentations" find ich irgendwie nx.

habt ihr noch andere solche links, wo man das so presäntiert bekommt? das is nämlich echt unglaublich nützlich!


----------



## André Uhres (17. Feb 2008)

Anonymous hat gesagt.:
			
		

> tobias vielen dank für den geilen link!..


Mein Link ist aber auch nicht Ohne  
Den ersten Teil von Galbraith's presentation findest du hier:
http://www.javalobby.org/eps/galbraith-swing-1/


----------



## Guest (17. Feb 2008)

> Mein Link ist aber auch nicht Ohne



nee.. dein link is der schlechteste link, den ich jemals angeklickt hab. du stinkst.  :bae: 

okay aber danke für den zweiten


----------



## André Uhres (17. Feb 2008)

Anonymous hat gesagt.:
			
		

> . dein link is der schlechteste link, den ich jemals angeklickt hab..


Ach  komm, du willst nur nicht zugeben, dass der so toll ist


----------



## Guest (17. Feb 2008)

hmm.. also unter allen links, die ich bisher auf der welt geklickt habe, da ist dieser, deiner, link, der mit sehr großem abstand (sehr sehr groß) der schlechteste, sinnloseste, am meisten meine zeit vergeudete, link, den ich bisher unter allen links, die ich bisher auf der welt geklickt hab, geklickt hab. tut mir leid, das musst du einfach akzeptieren, dass dein link der schlechteste link ist, den je jemand verlinkt hat. 

mfg  :gaen:


----------



## André Uhres (17. Feb 2008)

Na denn, also ich find ihn echt super, einer meiner allerbesten


----------



## Guest (17. Feb 2008)

hm also ich hab mir nun das foxtrot runtergeladen, aber weiss nicht wie ich es nutzen kann??

in der readme steht, man muss "lib/foxtrot.jar" in den class path einfügen.

irgendwie wollt ich das importieren aber es geht nie.

wisst ihr, wo ich das hinhauen muss (ordner) und wie ich das dann genau benutze (import...)

(benutze netbeans, falls das wichtig ist)


----------



## André Uhres (17. Feb 2008)

"File" menu
"project name" Properties
Categories: Libraries
Compile -> Add JAR/Folder -> foxtrot.jar

import foxtrot.*;


----------



## Guest (17. Feb 2008)

oh mensch leute ich check das noch immer null 

jetzt klappt gar nix mehr, jetzt zeichnet er überhaupt nix mehr.
ich check die zusammenhänge anscheinend doch noch überhaupt nicht.

und das, obwohl ich jetzt schon 2 wochen mit swing rummach. das is so deprimierend  :cry: 

schaut euch mal *bitte* folgenden code an, das wär super, und sagt mir, was ich da jetzt noch, und wo, reinschreiben muss, dass er mir alles zeichnet, auch die bewegungen und alles.

ich hab eigentlich das genauso gemacht wie im tutorial mit dem SwingWorker, aber es haut nix hin..
egal wo ich versuche eine repaint() methode reinzuhauen, er zeichnet nix. ich hab sie jetzt rausgenommen,
sagt mir bitte wo sie rein muss :bahnhof: 


```
public class Main extends JFrame {
    
    public Main(){
        setSize(800,800);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setLayout(new BorderLayout());
        
        Player p = new Player();
        
        add(new GamePanel(p),BorderLayout.NORTH);
         
        pack();
        setVisible(true);
    }

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {

            public void run() {
                new Main();
            } 
                
        }
       );
    }

}
```


```
class GamePanel extends JPanel implements MouseListener{

    private Player p;
    
    public GamePanel(Player p) {
        setPreferredSize(new Dimension(800,600));
        this.p = p;
        addMouseListener(this);
    }

    public void mouseClicked(final MouseEvent e) {
        System.out.println("geklickt");  // <--------------- KOMISCH: die meldung erscheint erst gute 1-2 sekunden
                                                     // nach dem klick!!! was soll denn das??

        SwingWorker swingw = new SwingWorker() {

            @Override
            protected Object doInBackground() throws Exception {
                while (p.getPosition().x != (e.getPoint().x)) {
                    p.move(e.getPoint());   // bewegt einen Punkt, der den Spieler repräsentiert, in richtung vom Klick
                }
                return p;
            }
        };
        swingw.execute();
    }

    @Override
    protected void paintComponent(Graphics g) {
        p.paint(g);
    }

}
```

Dank euch!!


----------



## André Uhres (17. Feb 2008)

```
package demo;
/*
 * GamePanel.java
 */
import foxtrot.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class GamePanel extends JPanel implements MouseListener {

    private Player p;

    public GamePanel(Player p) {
        setPreferredSize(new Dimension(800, 600));
        this.p = p;
        addMouseListener(this);
    }

    public void mouseClicked(final MouseEvent e) {
        System.out.println("geklickt");  // <--------------- KOMISCH: die meldung erscheint erst gute 1-2 sekunden
        // nach dem klick!!! was soll denn das??
        final Point mousePoint = e.getPoint();
//        SwingWorker swingw = new SwingWorker() {
//
//            @Override
//            protected Object doInBackground() throws Exception {
//                while (p.getPosition().x != (mousePoint.x)) {
//                    p.move(mousePoint);   // bewegt einen Punkt, der den Spieler repräsentiert, in richtung vom Klick
//                    repaint();
//                }
//                return p;
//            }
//        };
//        swingw.execute();
        try {
            Worker.post(new Task() {

                public Object run() throws InterruptedException {
                    synchronized (GamePanel.this) {
                        while (p.getPosition().x != (mousePoint.x)) {
                            p.move(mousePoint);   // bewegt einen Punkt, der den Spieler repräsentiert, in richtung vom Klick
                            repaint();
                        }

                    }
                    return p;
                }
            });
        } catch (InterruptedException x) {
            x.printStackTrace();
        } catch (Exception x) {
        // Never thrown
        }

    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        p.paint(g);
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }
}

class Player {

    int x = 100;
    int y;

    Point getPosition() {
        return new Point(x, y);
    }

    void move(Point point) {
        if (point.x > x) {
            x++;
        } else {
            x--;
        }
        try {
            Thread.sleep(5);
        } catch (InterruptedException ex) {
        }
    }

    void paint(Graphics g) {
        g.drawRect(x, 100, 10, 10);
    }
}
```


----------



## Guest (18. Feb 2008)

das gibts doch nich, genauso hab ichs mitm swingworker gemacht, und da ging gar nix... danke auf jeden fall   

hab aber ne frage dazu: ich würde gerne bei einem neuen klick die schleife abbrechen, und mit dem neuen punkt anfangen. wenn man jetzt nach rechts klickt und gleich danach nach links, läuft er erst den ganzen weg nach recht,s und dann erst nach links.

ist dann überhaupt foxtrot das richtige dafür? wie kann ich so einen abbruch einleiten?

und noch 2 dinge:

1. wieso reagiert er so krass langsam auf einen klick? das is nich wirklich akzeptabel 
2. bei dem ersten klick bewegt sich der spieler die ersten paar pixel gaaaanz langsam, es sieht so aus als müsste das programm erstmal "warmlaufen" oder so.. allerdings hat das nix mit dem programmstart zu tun, sondern mit dem ersten klick. auch wenn ich 1 minute warte bis zum ersten klick ist das so.

woran liegt das denn, bzw. kann ich den worker beim laden vom programm schon mal vorladen oder so?

dankeschön


----------



## André Uhres (18. Feb 2008)

Zur Performance kann ich nicht viel sagen. Bei mir ist es OK.

```
package demo;
/*
 * GamePanel.java
 */

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

class GamePanel extends JPanel implements MouseListener {

    private Player p;
    private Point mousePoint;

    public GamePanel(Player p) {
        setPreferredSize(new Dimension(800, 600));
        this.p = p;
        addMouseListener(this);
    }

    public void mouseClicked(final MouseEvent e) {
        mousePoint = e.getPoint();
        System.out.println("geklickt"); 
        try {
            Worker.post(new Task() {

                public Object run() throws InterruptedException {
                    synchronized (GamePanel.this) {
                        while (p.getPosition().x != (getMousePoint().x)) {
                            p.move(mousePoint);   // bewegt einen Punkt, der den Spieler repräsentiert, in richtung vom Klick
                            repaint();
                        }

                    }
                    return p;
                }
            });
        } catch (InterruptedException x) {
            x.printStackTrace();
        } catch (Exception x) {
        // Never thrown
        } finally {


        }
    }

    private Point getMousePoint() {
        return mousePoint;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        p.paint(g);
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

}

class Player {

    int x = 100;
    int y;

    Point getPosition() {
        return new Point(x, y);
    }

    void move(Point point) {
        if (point.x > x) {
            x++;
        } else {
            x--;
        }
        try {
            Thread.sleep(5);
        } catch (InterruptedException ex) {
        }
    }

    void paint(Graphics g) {
        g.drawRect(x, 100, 10, 10);
    }
}
```


----------



## Guest (18. Feb 2008)

jo mein fehler war dass ich keine Variable für den Punkt gemacht hab, deshalb hat er nicht sofort mit dem neuen Punkt gerechnet..

aber was ist mit den anderen PRoblemen, die ich oben erwähnte? So ist das ja auf keinen Fall gut, die Verzögerung ist recht schlimm (bei dir sicher auch), und vorallem das komische Verhalten dass er am Anfang so langsam rechnet/malt was auch immer..


----------



## André Uhres (18. Feb 2008)

Anonymous hat gesagt.:
			
		

> ..die Verzögerung ist recht schlimm (bei dir sicher auch)..


Hast du wohl übersehen:


			
				André Uhres hat gesagt.:
			
		

> Zur Performance kann ich nicht viel sagen. Bei mir ist es OK.


----------

