# JPanel durch "klicken und ziehen" verschieben



## Reality (11. Mai 2008)

Hi,
ich möchte gerne einen JPanel durch klicken und ziehen verschieben.
Leider klappt das nur teilweise, denn das JPanel wird nicht exakt dort hin verschoben, wo ich das will und springt teilweise ganz woanders hin.

Hier der Quellcode:



```
public class IdentifierBuilder {
	
	public void IdentifierBuilder(){

	}
	
	public static void main(String args[]){
		IdentifierBuilder idBuilder = new IdentifierBuilder();
		Window window = new Window();
	}
}
```


```
import java.awt.event.*;
import javax.swing.*;
import java.awt.color.*;
import java.awt.*;

public class Window extends JFrame{
	
	private JFrame jfNewProject = new JFrame("Neues Projekt"); //Window to set up the id card.
	
	private JPanel contentPane = new JPanel(); // Here you add Window-Components
	
	private JMenuBar menuBar = new JMenuBar(); 
	private JMenu fileMenu = new JMenu( "Datei" );
	private JMenuItem newProject = new JMenuItem("Neues Projekt");
	
	private JPanel idCard = new JPanel();
	
	private int widthIDCard;
	private int heightIDCard;
	
	private ComponentManager compManager = new ComponentManager();
	
	public Window(){
		super("Ausweis-Ersteller"); //Titel
		
		contentPane.setBackground(Color.GRAY);
		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Programm exits on pressing Exit-Button
			
		this.setContentPane(contentPane); //Setting contentpane
		
		this.setMenu();
	    
	    this.setSize(700, 700);
	    this.setLocationRelativeTo(null); //Sets the window in the middle of the screen
	    this.setVisible( true );
	}
	
	private void setMenu(){
		this.setJMenuBar( menuBar );
		
		menuBar.add( fileMenu ); 
		fileMenu.add(newProject);    
	    
	    newProject.addActionListener(new AbstractAction(){
	    	public void actionPerformed(ActionEvent e){
	    		newProject();
	    	}
	    });
	    
	}
	
	private void newProject(){
		
		JPanel contentPane2 = new JPanel();
		jfNewProject.setContentPane(contentPane2);
		
		JLabel jlWidth = new JLabel("Breite in Pixel");
		JLabel jlHeight= new JLabel("Höhe in Pixel");
		
		JButton jbOK = new JButton("OK");
		JButton jbCancel = new JButton("Abbrechen");
		
		final JTextField jtfWidth = new JTextField(5);
		final JTextField jtfHeight = new JTextField(5);
		
		contentPane2.add(jlWidth);
		contentPane2.add(jtfWidth);
		contentPane2.add(jlHeight);
		contentPane2.add(jtfHeight);
		contentPane2.add(jbOK);
		contentPane2.add(jbCancel);
		
		jfNewProject.setSize(100, 100);
		jfNewProject.setLocationRelativeTo(null);
		jfNewProject.setVisible( true );
		jfNewProject.pack();
		jbOK.addActionListener(new AbstractAction(){
	    	public void actionPerformed(ActionEvent e){
	    		
	    		widthIDCard = Integer.parseInt(jtfWidth.getText());
	    		heightIDCard = Integer.parseInt(jtfHeight.getText());
	    		idCard.setPreferredSize(new Dimension( widthIDCard, heightIDCard ));
	    		idCard.setBackground(Color.white);
	    		idCard.setBorder(BorderFactory.createLineBorder(Color.black));
	    		
	    		
	    		contentPane.add(idCard);
	    		
	    		compManager.addComponent("idCard", idCard);
	    		
	    		repaintWindow();
	    		
	    		jfNewProject.dispose();
	    	}
	    });
		
		jbCancel.addActionListener(new AbstractAction(){
	    	public void actionPerformed(ActionEvent e){
	    		jfNewProject.dispose();
	    	}
	    });
	}
	
	private void repaintWindow(){
		this.validate();
	}
	
}
```


```
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ComponentManager {
	
	private boolean isMarked = false;
	
	private HashMap map = new HashMap <String, Component> ();
	
	private Component component;
	
	public ComponentManager(){

	}
	
	public void addComponent(String name, Component comp){
		this.component = comp;
		
		this.component.addMouseMotionListener(new MouseMotionAdapter(){
			public void mouseDragged(MouseEvent e){
				int x = e.getX();
				int y = e.getY();
				
				component.setLocation(x, y);
			}
		});
		map.put(name, comp);
	}
	
	private Component getComponent(String name){ //Wird momentan nicht verwendet
		return (Component) map.get(name);
	}

}
```

Falls mir jemand weiterhelfen könnte, wäre ich sehr dankbar!

Liebe Grüße
Reality


----------



## SlaterB (11. Mai 2008)

x/y vom MouseEvent sind relativ zur Location des JPanels, nicht zum JFrame, das bringst du durcheinander,
etwas besser wirds mit
				int x = e.getX()+component.getLocation().x;
				int y = e.getY()+component.getLocation().y;

aber dann hast du immer noch leichte Sprünge,
die linke obere Ecke des JPanels springt zum Mauszeiger,

du musst bei mousePressed() die x/y-Werte speichern (Versatz zur linken oberen Ecke des JPanels) und bei den folgenden mouseDragged()-Events miteinberechnen


----------



## Reality (11. Mai 2008)

Hi SlaterB,
danke, darauf wäre ich wirklich nicht von alleine gekommen! :-D

Ich finde den Code jedoch etwas aufgebläht:


```
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ComponentManager {
	//Will be initialized when the mouse on a component was been pressed.
	//Saves the coordinates and will be calculated with the coordinates of the panel to move the panel exactly
	private int pressedMouseOnX;
	private int pressedMouseOnY;
	
	private boolean isMarked = false;
	
	private HashMap map = new HashMap <String, Component> ();
	
	private Component component;
	
	public ComponentManager(){

	}
	
	public void addComponent(String name, Component comp){
		this.component = comp;
		
		this.component.addMouseListener(new MouseAdapter(){
			public void mousePressed(MouseEvent e){
				pressedMouseOnX = e.getX();
				pressedMouseOnY = e.getY();
				System.out.println(pressedMouseOnX + " " + pressedMouseOnY);
			}
		});
		
		this.component.addMouseMotionListener(new MouseMotionAdapter(){
			public void mouseDragged(MouseEvent e){
				int x = e.getX()+component.getLocation().x;
				int y = e.getY()+component.getLocation().y; 
				
				int tmpX = x - pressedMouseOnX;
				int tmpY = y - pressedMouseOnY;
				
				System.out.println(e.getX() + " " + e.getY());
				System.out.println(tmpX + " " + tmpY);
				component.setLocation(tmpX, tmpY);
			}
		});
		map.put(name, comp);
	}
	
	private Component getComponent(String name){ //Wird momentan nicht verwendet
		return (Component) map.get(name);
	}

}
```

Wieso bewegt sich der Panel eigentlich nicht, wenn man NUR component.getLocation() anwendet? Denn, wie ich herausfand, sind die Koordinaten von getX() und getY von mouseDragged und mousePressed identisch und das was ich effektiv anwende, ist ein component.getLocation, denn das getX und das getY, das ich hinzuaddiere, wird weiter unten wieder subtrahiert.
Nur geht ein component.getLocation nicht alleine. Der JPanel bewegt sich dann überhaupt nicht!

Liebe Grüße
Reality


----------



## SlaterB (12. Mai 2008)

wenn du die Maus einen Pixel wegbewegst vom Ursprungsklick,
dann wirst du auch andere x/y in deiner Ausgabe sehen,
dann ist eben y nicht mehr pressedMouseOnY und das JPanel bewegt sich um einen Pixel,

je nachdem wie schnell gezeichnet wird, gilt danach schon die neue Location,
aber das ist egal:
wenn du dich zwei Pixel bewegt hast, dann könnte die Berechnung entweder um zwei Pixel von der Urspungslocation ausgeführt werden oder um einem Pixel von der letzen Bewegung, es kommt das gleiche heraus, kein Flimmern möglich


----------



## Reality (12. Mai 2008)

Hi SlaterB!
Danke, für deine Antwort!

Jetzt habe ich ein neues Problem:

Wenn ich mehrere JPanels hinzufüge (z. B. einmal ein Bild in einem JPanel oder JLabel und einmal ein JPanel mit weißen Hintergrund), dann ist immer nur das JPanel ansprechbar, das zuletzt hinzugefügt wurde.

Wie kann ich diesen Bug beheben?

Liebe Grüße
Reality


----------



## SlaterB (12. Mai 2008)

was fürn Bug? 'Programmdesign' vielleicht,

der Listener arbeitet mit
private Component component;
welches ja immer nur eines sein kann,
lass den Listener dagegen Component comp bearbeiten, das ist jeweils das eingefügte Element,

solche Dinge sind aber unterste Grundlagen bzw. einfach nur Denken,
ohne das kannst du so ein Programm nicht schreiben,

lange werde ich das nicht mehr mitmachen


----------



## Reality (13. Mai 2008)

Sorry, die Regeln von Java kenne ich noch nicht sonderlich gut.



> der Listener arbeitet mit
> private Component component;
> welches ja immer nur eines sein kann



Wieso klappt das dann mit mehreren Buttons in einer GUI auch? Die sind ja auch Ableitungen von Component.

Liebe Grüße
Reality


----------



## André Uhres (13. Mai 2008)

Vielleicht hilft ja dieses Beispiel: ShapeEditor.jar (Quellcode im jar)


----------



## SlaterB (13. Mai 2008)

ob Component oder nix, hat nix zu sagen,

es geht darum mit WELCHEM Objekt der Listener arbeitet,
im Moment sagst du allen Listenern, dass sie, wenn sie mal dran kommen, mit dem Objekt arbeiten sollen, welches unter 
private Component component; 
gespeichert ist,
und das kann nunmal immer nur eins sein, das zuletzt registrierte,

du musst die Listener umstellen, so dass sie mit dem Parameter  'Component comp' arbeiten,
der muss dafür final sein,

pressedMouseX/Y sollte besser auch in ein eigenes Objekt pro Komponente, 
da man aber eh nur ein Objekt gleichzeitig bewegen kann ist das erstmal kein Fehler


----------

