Zum Inhalt springen

keine weiteren Events während Drag&Drop Operation möglich?


Empfohlene Beiträge

Geschrieben

Hallo,

meine Umgebung ist folgende:

Windows XP Pro SP3

JRE 1.6.0_21

CrossPosting Hinweis: ich habe das ganze auch bei tutorials.de und java-forum.org gespostet

Und ich habe folgendes Problem (egal ob AWT oder SWING):

ich habe ein DnD von Datein außerhalb meiner Anwendung (z.B. %DESKTOP%\datei.txt) auf das Hauptfenster meiner Anwendung realisiert. Das funktioniert alles optimal.

Nun möchte ich aber das das ganze auch visulalisiert wird, sprich ich möchte mein Fenster animieren, wenn ein dragEnter() bzw. ein dragExit() stattfindet. Z.B. soll das Fenster bei einem dragEnter() verbreitert und bei einem dragExit() wieder verkleinert werden. Das scheint aber nicht sauber zu funktionieren. Die Animation beim dragEnter() funktioniert sauber. Beim dragExit() jedoch wird zwar das Fenster verkleinert, jedoch scheint das nicht bis "Windows" durchzudringen, da eine Art Schatten bzw. Ghost des Fensters immernoch zu sehen ist.

Wenn ich die Animation (ohne DnD) nur über mouseEnter() bzw. mouseExited() realisiere funktioniert es wunderbar. Alles wird korrekt gezeichnet. Nun dachte ich mir ich feuere einfach ein MouseEvent bei dragEnter() und dragExit() ab. Naja so leicht ist es nun auch wieder nicht.

Es scheint also an der noch stattfindenden DnD Operation zu liegen, die bestimmte Events blockiert.

Ja ich weiß... EventQueue etc. Aber ich kann genau 1 MouseEvent dispatchen während eines DnD. Egal ob MouseEvent.MOUSE_PRESSED oder MouseEvent.MOUSE_EXITED etc., es wird immer nur ein MouseEvent.MOUSE_ENTERED dispatched.

Ich habe nirgends etwas darüber gefunden wie DnD genau abläuft, und warum bestimmte Events zum Teil blockiert werden.

Ich denke mal ein DnD auf ein DropTarget ist ein MouseEvent. Wenn der DnD also in ein DropTarget "entered" und solange der Drop nicht abgeschlossen ist ist es nur ein MouseEvent.MOUSE_ENTERED. Und den kann man auch nur genau einmal per Hand weiter-dispatchen!?

Wie kann ich die Animation sauber realisieren. Habt ihr Ideen?

Ein händisches repaint aller Komponenten habe ich auch schon probiert. Evtl. aber an der falschen Stelle!?

Hier das Fenster:


public class FrameController implements MouseListener, DropTargetListener {


	private static FrameController self;


	public static synchronized FrameController getInstance() {

		if (self == null) {

			FrameController.self = new FrameController();

			return FrameController.self;

		}

		return FrameController.self;

	}


	private Frame frame;

	private boolean isDragAndDropEvent;


	public void show() {

		frame = new Frame();

		frame.setUndecorated(true);

		frame.setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth()/2-50),0,100,40);

		frame.addMouseListener(this);

		frame.add(new Label("TEST"));

		frame.setDropTarget(new DropTarget(frame, this));

		frame.setVisible(true);

	}


	@Override

	public void mouseClicked(MouseEvent e) {

		//Point mousePointer = frame.getMousePosition(true);

		//frame.dispatchEvent(new MouseEvent(frame, MouseEvent.MOUSE_EXITED, GregorianCalendar.getInstance().getTimeInMillis(), MouseEvent.BUTTON1_DOWN_MASK, mousePointer.x, mousePointer.y, MouseEvent.BUTTON1, false));

	}


	@Override

	public void mouseEntered(MouseEvent e) {

		Animator.setAnimation(Animator.ANIMATE_WIDTH_ENLARGE, frame, 40);

		Animator.start(1, 100);

	}


	@Override

	public void mouseExited(MouseEvent e) {

		Animator.setAnimation(Animator.ANIMATE_WIDTH_SHRINK, frame, 40);

		Animator.start(1, 100);

	}


	@Override

	public void mousePressed(MouseEvent e) {

		// TODO Auto-generated method stub


	}


	@Override

	public void mouseReleased(MouseEvent e) {


	}


	@Override

	public void dragEnter(DropTargetDragEvent dtde) {

		this.isDragAndDropEvent = true;

		Point mousePointer = frame.getMousePosition(true);

		//docklet.dispatchEvent(new MouseEvent(frame, MouseEvent.MOUSE_DRAGGED, GregorianCalendar.getInstance().getTimeInMillis(), MouseEvent.BUTTON1_DOWN_MASK, mousePointer.x, mousePointer.y, MouseEvent.BUTTON1, false));

		this.mouseEntered(new MouseEvent(frame, MouseEvent.MOUSE_ENTERED, GregorianCalendar.getInstance().getTimeInMillis(), MouseEvent.BUTTON1_DOWN_MASK, mousePointer.x, mousePointer.y, MouseEvent.BUTTON1, false));


	}


	@Override

	public void dragExit(DropTargetEvent dte) {

		//dte.getDropTargetContext().dropComplete (true);

		//Point mousePointer = frame.getMousePosition(true);

		//docklet.dispatchEvent(new MouseEvent(frame, MouseEvent.MOUSE_EXITED, GregorianCalendar.getInstance().getTimeInMillis(), MouseEvent.BUTTON1_DOWN_MASK, mousePointer.x, mousePointer.y, MouseEvent.BUTTON1, false));

		this.mouseExited(null);


/*		SwingUtilities.invokeLater(new Runnable(){


			@Override

			public void run() {

				Point mousePointer = frame.getMousePosition(true);

				//docklet.dispatchEvent(new MouseEvent(frame, MouseEvent.MOUSE_DRAGGED, GregorianCalendar.getInstance().getTimeInMillis(), MouseEvent.BUTTON1_DOWN_MASK, mousePointer.x, mousePointer.y, MouseEvent.BUTTON1, false));

				FrameController.getInstance().mouseExited(null);

			}

		});

*/	}


	@Override

	public void dragOver(DropTargetDragEvent dtde) {

		// TODO Auto-generated method stub


	}


	@Override

	public void drop(DropTargetDropEvent dtde) {

		// TODO Auto-generated method stub


	}


	@Override

	public void dropActionChanged(DropTargetDragEvent dtde) {

		// TODO Auto-generated method stub


	}




}

Die Animation.java Klasse ist eigentlich zum Verständnins nicht wichtig, da sie nur einen neuen Thread öffnet in dem die Animation abgearbeitet wird. Wie gesagt über Mouse Events geht es wunderbar. Falls ihr sie doch sehen wollt einfach bescheid geben.

So... danke schonmal für jegliche Hinweise.

Geschrieben

Ich kann das Problem leider so richtig nicht nachstellen. Ich arbeite hier auch an einem Windows XP und sobald ich in die Methode dragEnter() ein Vergrößern des Fenster mit setSize() und in dragExit() und drop() (es kann ja nur eine der Methode ausgeführt werden, entweder der Benutz verlässt mit dem drag wieder das Fenster oder der drop landet im Fenster) ein Verkleinern eintrage, funktioniert das einwandfrei.

Folgender Code macht also das was du machen wolltest:


import java.awt.*;

import java.awt.dnd.*;


public class FrameController implements DropTargetListener {


	private static FrameController self;


	public static synchronized FrameController getInstance() {

		if (self == null) {

			FrameController.self = new FrameController();

			return FrameController.self;

		}

		return FrameController.self;

	}


	private Frame frame;


	public void show() {

		frame = new Frame();

		frame.setUndecorated(true);

		frame.setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth()/2-50),0,100,40);

		frame.add(new Label("TEST"));

		frame.setDropTarget(new DropTarget(frame, this));

		frame.setVisible(true);

	}


	public void dragEnter(DropTargetDragEvent dtde) {

		frame.setSize(frame.getWidth()*2, frame.getHeight()*2);

	}


	public void dragExit(DropTargetEvent dte) {

		frame.setSize(frame.getWidth()/2, frame.getHeight()/2);

	}



	public void drop(DropTargetDropEvent dtde) {

		frame.setSize(frame.getWidth()/2, frame.getHeight()/2);

	}


	public void dragOver(DropTargetDragEvent dtde) {}

	public void dropActionChanged(DropTargetDragEvent dtde) {}

}

Bei mir wird das Fenster auch sauber vergrößert oder verkleinert. Kannst du vielleicht mal einen Screenshot posten, der zeigt wie das bei dir nach dem Verkleinern aussieht?

Geschrieben (bearbeitet)

Danke für die Antworten!

Ich dachte das Prinzip wäre klar geworden als ich die Animation Klasse erwähnt habe, denn die macht nicht nur ein einfaches setSize(). Wie der Name schon sagt, wird das Fenster Schritt für Schritt auf die gewünschte Größe vergrößert. Eine Animation eben. Also z.B. von 100 auf 120, aber eben alle 100 Millisekunden um 1.

Ein SwingUtilities.invokeLater() wird in der Animation Klasse realisiert. Auch das direkte zurückgeben in den EDT mit EventQueue.invokeLater() bringt das selbe Ergebnis.

Selbst wenn der Drop außerhalb des Fensters beendet wird, wird das Fenster nur teilweise auf die richtige Größe zurück animiert. Das sieht dann sehr seltsam aus:

759531b24d22f2d47ce6609a7c8e5239.jpg

Wenn ich dann aber einen Desktop-Link nahe des Fenster ablege, so daß er vom System unterhalb des Fensters positioniert wird, wird das Fenster wieder richtig dargestellt (neu gezeichnet?).

Es liegt irgendwie am DnD Event-Dispatching denke ich, denn wie gesagt wenn ich das ohne DnD nur mit mouseEnter() bzw. mouseExited realisiere funktioniert es wunderbar.

Weitere Ideen?

Bearbeitet von MrRock
Geschrieben

Dass deine Größenänderungen über die Animator-Klasse geschehen, habe ich mir schon gedacht. In Ermangelung dieser Klasse bin ich aber erstmal den einfacheren Weg gegangen und habe die Größenänderung direkt vorgenommen.

Um dem Fehler auf den Grund zu gehen, wäre es also noch gut zu wissen, was denn in deiner Animator-Klasse genau passiert. Der Quelltext würde also helfen ;)

Ich habe erstmal mit einer eigenen Animator-Klasse weiter gemacht, den Quelltext der Klassen findest du am Ende des Posts. Einen Zustand wie bei dir, konnte ich damit aber auch nicht erzeugen. Das einzige was mir dabei aufgefallen ist:

Wenn ich dich richtig verstanden habe, wird dein Frame von 100px auf 120px vergrößert, bzw umgekehrt verkleinert. Und das alle 100 ms um 1px. Wenn das wirklich der Fall ist, dauert das meiner Meinung nach viel zu lange. Ich habe bei mir eine Gesamtlänge der Animation von 1s genommen, aber selbst dabei dürfte ein normaler Anwender schneller mit dem Drag&Drop fertig sein, als dass deine Animation fertig ist. Das kommt natürlich noch auf die Größe des Frames an, und wie lange der Anwender braucht um in deinem Frame an die Stelle zu kommen, wo er die Drop-Aktion beenden muss....aber 2s sind denke ich trotzdem zu lange.

Eine Größeränderung alle 10ms und 100ms lang fand ich bei mir passend.

Wenn nämlich bei dir der Anwender die Drop-Aktion zu schnell beendet, und die Animation noch nicht beendet ist, wird, denke ich, auch bei dir die Verkleinerung wieder angestartet, wodurch 2 Animation auf einmal auf den Frame einwirken. Das Ergebnis sieht zwar etwas komisch aus...aber selbst das führte bei mir nicht zu deinem Ergebnis...bei mir war der Frame am Ende wieder auf der passenden Größe.

Du siehst also, ohne Quelltext der Animator-Klasse kommen wir glaube ich nicht weiter ;)

Quelltexte:


import java.awt.*;

import java.awt.dnd.*;


public class FrameController implements DropTargetListener {


	private static FrameController self;


	public static synchronized FrameController getInstance() {

		if (self == null) {

			FrameController.self = new FrameController();

			return FrameController.self;

		}

		return FrameController.self;

	}


	private Frame frame;


	public void show() {

		frame = new Frame();

		frame.setUndecorated(true);

		frame.setBounds((int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth()/2-50),0,100,40);

		frame.add(new Label("TEST"));

		frame.setDropTarget(new DropTarget(frame, this));

		frame.setVisible(true);

	}


	public void dragEnter(DropTargetDragEvent dtde) {

		SizeAnimator sa = new SizeAnimator(frame, 200, 80);

		sa.start();

	}


	public void dragExit(DropTargetEvent dte) {

		SizeAnimator sa = new SizeAnimator(frame, 100, 40);

		sa.start();

	}



	public void drop(DropTargetDropEvent dtde) {

		SizeAnimator sa = new SizeAnimator(frame, 100, 40);

		sa.start();

	}


	public void dragOver(DropTargetDragEvent dtde) {}

	public void dropActionChanged(DropTargetDragEvent dtde) {}

}


import java.awt.*;

import java.awt.event.*;

import javax.swing.*;




public class SizeAnimator extends Timer implements ActionListener{

	private Component target;

	private double[] widthSteps = new double[10];

	private double[] heightSteps = new double[10];

	private int loops = 0;


	public SizeAnimator(Component target, int toWidth, int toHeight) {

		super(10, null);

		this.target = target;

		Dimension d = this.target.getSize();

		double sWidth = (toWidth - d.getWidth())/10;

		double sHeight = (toHeight - d.getHeight())/10;

		widthSteps[0] = d.getWidth() + sWidth;

		widthSteps[9] = toWidth;

		heightSteps[0] = d.getHeight() + sHeight;

		heightSteps[9] = toHeight;


		for(int x = 1; x < widthSteps.length-1; x++) {

			widthSteps[x] = widthSteps[x-1] + sWidth;

			heightSteps[x] = heightSteps[x-1] + sHeight;

		}

		this.addActionListener(this);

	}


	public void start() {

		this.loops = 0;

		super.start();

	}


	public void restart() {

		this.loops = 0;

		super.restart();

	}

	public void actionPerformed(ActionEvent e) {

		target.setSize((int)widthSteps[loops], (int)heightSteps[loops]);

		loops++;


		if(loops >= widthSteps.length) 

			this.stop();

	}

}

Geschrieben

Danke Dragon8,

aber deine Variante funktioniert leider genauso wie meine. Nämlich garnicht.

Auch bei deinen Klassen passiert das gleiche wie bei mir, ein dragExited() scheint das Objekt zu verkleinern, doch auf dem Bildschirm hat es noch die selbe Größe. Windows scheint es nicht richtig zu zeichnen. Wie gesagt ein Shortcut drunter gelegt läßt dann die Teile des Fensters die eigentlich nicht mehr da sein dürften auch tatsälich wieder verschwinden. Selbst wenn das Programm längst terminiert ist, scheint immernoch eine Art Ghost auf dem Bildschirm zu sein. Das muss doch an Windows liegen, oder?

3b977797c82874b513fa5876da988e57.jpg

Theoretisch ist deine SizeAnimator Klasse ähnlich wie meine. Deine erweitert die Timer Klasse und meine startet ein Runnable Objekt, welches die entsprechende Aufgabe mittels SwingUtilities.invokeLater() genau wie ein Timer durchführt.

Animator Klasse:


import java.awt.Frame;


public class Animator {


	public static final int ANIMATE_WIDTH_ENLARGE = 0x000001;

	public static final int ANIMATE_WIDTH_SHRINK = 0x000002;

	public static final int ANIMATE_HEIGHT_ENLARGE = 0x000003;

	public static final int ANIMATE_HEIGHT_SHRINK = 0x000004;

	public static final int ANIMATE_COMPONENTS_ENLARGE = 0x000010;

	public static final int ANIMATE_COMPONENTS_SHRINK = 0x000011;


	private static RAnimatorSize runnable;

	static boolean isAnimating = false;


	public static void setAnimation(final int animation, Frame frame, final int value) {

		switch (animation) {

		case (Animator.ANIMATE_WIDTH_ENLARGE): {

			runnable = new RAnimatorSize(frame, value, 1);

			break;

		}

		case (Animator.ANIMATE_WIDTH_SHRINK): {

			runnable = new RAnimatorSize(frame, value, -1);

			break;

		}

		}

	}


	public static void start(final int speed, final int delay) {

		runnable.setSpeed(speed);

		runnable.setDelay(delay);

		SwingUtilities.invokeLater(runnable);


		//EventQueue.invokeLater(runnable);

		//Thread thread = new Thread(runnable);

		//thread.start();

	}


	public static boolean isAnimating() {

		return Animator.isAnimating;

	}


}

und die RAnimatorSize Klasse:

import java.awt.Frame;


public class RAnimatorSize implements Runnable {


	private int delay;

	private int speed;

	private Frame window;

	private int width;

	private int step;


	public RAnimatorSize(Frame frame, final int width, final int step) {

		this.window = frame;

		this.width = width;

		this.step = step;

	}


	public void setDelay(final int delay) {

		this.delay = delay;

	}


	public void setSpeed(final int speed) {

		this.speed = speed;

	}


	public void run() {

		Animator.isAnimating = true;

		synchronized (this) {

			try {

				this.wait(delay);

			} catch (InterruptedException e) {

				e.printStackTrace();

			}

		}		

		for (int counter = this.step; counter <= width;) {

			int xCoordinate = (counter % (this.step*2) == 0) ? window.getX()- this.step : window.getX();			

			window.setBounds(xCoordinate, window.getY(), window.getWidth() + this.step, window.getHeight());


			synchronized (this) {

				try {

					this.wait(speed);

				} catch (InterruptedException e) {

					e.printStackTrace();

				}

			}

			counter+= Math.abs(this.step);

		}

		Animator.isAnimating = false;

	}


}

Wie gesagt ich glaube ja nun schon fast das es an der "bescheidenen" Kommunikation der DnD Events mit Windows und seinem (meinem) Graphiksystem liegt.

Geschrieben

Das ist dann natürlich wirklich sehr komisch....auf dem Rechner, auf dem ich das gerade teste, läuft auch Windows XP, aber mit SP2 und Java 1.6.0_10, und trotzdem scheint es bei mir einwandfrei zu funktionieren, auch deine Variante.

An welchen Stellen hast du denn ein repaint() versucht?

Das einzige was ich jetzt an deinem Quelltext feststellen konnte:

Dein Fenster verkleinert sich nicht wieder wenn die Drop Aktion im Fenster endet. Wenn das natürlich so gewollt ist, weil sich das Fenster erst wieder verkleinern soll, sobald der Anwender wieder aus dem Fenster eine Drag Aktion startet, habe ich nichts gesagt.

Außerdem, wenn ich deine FrameController Klasse 1 zu 1 so übernehme wie du sie im 1. Post gepostet hast, wird bei mir das Fenster 2x verkleinert sobald die Drop Aktion im Fenster endet, aber während der Laufzeit der Vergrößern-Animation der Mauszeiger das Fenster verlässt. Ich denke mal, das wird an der Mischung aus Mouse- und DnD Events in der FrameController-Klasse liegen.

Außer dem repaint() fällt mir aber leider zu dem Verhalten gerade nichts mehr ein. Eine weitere Möglichkeit wäre vll zu schauen ob es dazu einen Bug gibt. Die Suche dürfte aber sehr schwierig werden.

Geschrieben

OK danke, wenn es bei dir funktioniert dann ist es wohl ein Bug hinsichtlich meines Systems.

Ich werde mal weiterforschen, ansonsten wird dieses Feature wohl nicht in das neue Release eingehen.

Und ja so wie die FrameController Klasse hier gepostet ist funktioniert es nicht ganz. Wie du siehst habe ich ziemlich viel auskommentiert, also schon jede Menge wunderliches ausprobiert. Das ganze sollte (und war ja auch anfangs so) nur wie bei dir in den implementierten DnD-Methoden stattfinden.

Also gut...dann ist dass auf Grund eines noch nicht zu identifizierenden Bugs nicht zu lösen und dieser Thread kann geschlossen werden.

Falls jemand das selbe Problem hat bitte eine PN an mich.

Vielen Dank nochmal Dragon8.

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...