Swing Objekt zu Position (Point) bewegen

evindar

Mitglied
Hallo liebe Freunde,

ich komme wieder mal an einer Stelle nicht mehr weiter und bräuchte darum eure Hilfe.
Das Problem:
Nachdem ich es nun geschafft habe einen JPanel zu animieren (zu bewegen), will ich jetzt nun, dass er sich direkt zu einer Position bewegt. D.h., wenn ich irgend eine Position angebe und die Methode aufrufe soll er sich zu der Position bewegen (auch diagonal). Ich habe die ganze Zeit versucht, dass irgendwie alleine hinzukriegen, bin aber leider nicht weitergekommen. So sieht mein Code aus:

Die Klasse ist in einem JPanel und jedes Mal, wenn ich die Methode panelAnimation() aufrufe wird ein neuer Thread gestartet.

Java:
private class JPanelThread extends Thread {
	private double x;
	private double y;
	private double v;
	JPanel panel;
	Point point;
	
	public JPanelThread(JPanel panel, Point point) {
		this.panel = panel;
		this.point = point;
		x = panel.getLocation().x - point.x;
		y = panel.getLocation().y - point.y;
		v = Math.sqrt(x*x+y*y);
	
		x/=v;
		y/=v;
	}

	public void run() {
		boolean status = false;
		int yjetzt = panel.getLocation().y;
		int xjetzt = panel.getLocation().x;
		
		while (!status) {
			try {

				sleep(20);
				panel.setLocation(xjetzt, yjetzt);
				repaint();
				if (xjetzt < point.x) {
					xjetzt += x;
				} else if (xjetzt > point.x){
					xjetzt -= x;
				}
				if (yjetzt < point.y) {
					xjetzt += y;
				} else if (yjetzt > point.y){
					xjetzt -= y;
				}
				
				if (xjetzt == point.x && yjetzt == point.y) {
						status = true;
				}
			} catch (InterruptedException e) {
					
			  }
		}

	}

}

public void panelAnimation(JPanel panel, Point point) {
	thread = new JPanelThread(panel, point);
	thread.start();
}
 
Ist ein bißchen "gefährlich": Wenn man dort für x/y Werte < 1 rausbekommt, tut sich da gar nichts (Nachkommateile werden abgeschnitten, d.h. xjetzt usw. ändern sich nicht). Und die Abfrage mit der Richtung und der Vergleich mit == um den "status" zu setzen sehe auch ein bißchen :autsch: aus... (Von solchen Kleinigkeiten, wie dass setLocation nur im EDT aufgerufen werden sollte, mal abgesehen).

Wollte gerade mal ein Beispiel machen, aber solche hoch-spezifischen Sachen nerven mich immer ab: NUR die Position verändern ist ja langweilig ... Etwas allgemeiner hatte ich sowas schonmal in http://www.java-forum.org/codeschnipsel-u-projekte/132007-animated-layout-manager.html gebastelt, bestimmte Teile davon hätte man einfach übernehmen können, aber... hier ein Mittelding:

Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

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

public class AnimatedPanel
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
    
    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().setLayout(new BorderLayout());
        
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(null);
        
        final JPanel animatedPanel = new JPanel();
        animatedPanel.setBackground(Color.RED);
        mainPanel.add(animatedPanel);
        animatedPanel.setBounds(100,100,100,100);
        
        f.getContentPane().add(mainPanel, BorderLayout.CENTER);

        final ComponentAnimator c = new ComponentAnimator(animatedPanel);
        final Random random = new Random(0);
        
        JButton button = new JButton("Animate");
        button.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                int x = random.nextInt(800);
                int y = random.nextInt(800);
                int w = random.nextInt(300)+50;
                int h = random.nextInt(300)+50;
                c.animate(new Rectangle(x,y,w,h));
            }
        });
        f.getContentPane().add(button, BorderLayout.SOUTH);
        
        f.setSize(1000,1000);
        f.setVisible(true);
    }

    
}


class ComponentAnimator
{
    private final JComponent component;
    
    public ComponentAnimator(JComponent component)
    {
        this.component = component;
    }
    
    public void animate(Rectangle target)
    {
        final double x0 = component.getX();
        final double y0 = component.getY();
        final double w0 = component.getWidth();
        final double h0 = component.getHeight();
        
        final double x1 = target.getX();
        final double y1 = target.getY();
        final double w1 = target.getWidth();
        final double h1 = target.getHeight();
        
        final int steps = 30;
        final long delayMS = 30;
        
        final double dx = (x1-x0) / steps;
        final double dy = (y1-y0) / steps;
        final double dw = (w1-w0) / steps;
        final double dh = (h1-h0) / steps;
        
        Thread thread = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                for (int i=0; i<=steps; i++)
                {
                    final double x = x0 + i * dx;
                    final double y = y0 + i * dy;
                    final double w = w0 + i * dw;
                    final double h = h0 + i * dh;
                    
                    SwingUtilities.invokeLater(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            component.setBounds((int)x, (int)y, (int)w, (int)h);
                            component.repaint();
                        }
                    });
                    
                    try
                    {
                        Thread.sleep(delayMS);
                    }
                    catch (InterruptedException e)
                    {
                        Thread.currentThread().interrupt();
                        return;
                    }
                }
            }
        });
        thread.setDaemon(true);
        thread.start();
        
    }
}
 
Hallo,

vielen Dank Marco!

Als ich erst probiert hatte, hatte ich die Werte steps und delayMS so gelassen wie sie es waren, aber es lieferte mir dann nicht die gewünschte Optik, also wollte ich nach was anderem suchen. Als du mich aber in der Nachricht nochmal darauf hingewiesen hast, habe ich mal etwas daran rumprobiert und mit den Werten steps = 60 und delayMS = 10 doch zum erwünschten Resultat gekommen!

Vielen Dank nochmal!
 

Zurück
Oben