Flackerndes Window beim DnD

Sunchezz

Bekanntes Mitglied
Guten Morgen.


Ich habe ein JPanel in dem ich dynamisch Componenten hin und her schieben will...
Joa, mit dem Null-Layout klappt das soweit auch super einfach, mit nem MouseListener und nem einfachen setLocation()

Nun wollte ich das aber auch auf andere Layouts übertragen.
Meine Krieterien:
1. Es sollte beim verschieben angezeigt werden was verschoben wird (is ja eigentlich bekannt)
2. Es sollte während des Drags (Maus gedrückt halten [auch bekannt]) die nächste verankerung angezeigt werden wo die Komponente hinverschoben wird, sollte man nun loslassen.

Meine Lösungen kollidieren da allerdings mit diesen beiden Kriterien.

1. Lösungsidee:
Verschiebungsvorschau: Komponente mit setLocation() verschieben
Verankerungsanzeige: Temproräres sehr kurzes JPanel mit dicker grüner Border
Problem: jPanel. validate() lässt die verschobene Komponente an der Maus zucken und flackern, ohne validate() wird aber die Verankerungsvorschau nicht bei jeder Mausbewegung aktualisiert.

2. Lösungsidee:
Verschiebungsvorschau: Komponente mit getGraphics() und customCorsor als Vorschau anbieten
Verankerungsanzeige: Temproräres sehr kurzes JPanel mit dicker grüner Border
Problem: Es sieht einfach nur lächerlich aus, und verursacht Augenkrebs -> verständlich bei 32x32 Pixel

3. Lösungsidee:
Verschiebungsvorschau: Komponente auf GlassPane verschieben
Verankerungsanzeige: das selbe wie schon zuvor
Problem: Komponente wird im GlassPane garnicht erst angezeigt

4. Lösungsidee:
Verschiebungsvorschau: Komponente in ein Window packen und mitverschieben
Verankerungsanzeige: wie auch zuvor
Problem: wie im Threadtitel, das Window flackert enorm, selbst wenn ich die Maus nicht bewege
ich schätze das Liegt am validate des Panels.

Hat irgendjemand noch andere Ideen?

Ich hatte auch ganz kurz probiert die Verankerungsanzeige nicht mit einer Border, sondern über drawLine zu realisieren, doch das hat in der Dragbewegung ebenso geflackert.

Ich hoffe keiner will den Code sehn, denn das ist pures verzweiflungsschreiben mit wilden Ideen gewesen. Ich kann ja schonmal anfangen aufzuräumen!
 

Sunchezz

Bekanntes Mitglied
hmm... naja, mal eben aus dem Ärmel schütteln wollte ich das nicht, es sollte ja auch nicht so komplex werden!
Ist aber auch ziemlich verwirrend dieses Docking Frames!

Ich muss mal sehen ob ich das benutzen kann, aber im grunde wollte ich ja eigentlich nur nen paar Komponenten hin und her schieben,
Genau genommen funktioniert das ja auch schon sehr gut!
Nur diese Flackergeschichten müssen ja irgendwie umgangen werden können.
Hab bei meiner Recherche ja auch schon einige gefunden die das selbe gemacht haben, und die habens auch irgendwie gelöst, nur stehen nirgendwo (jedenfalls das was ich gefunden habe) konkrete Hinweise.
 

Marco13

Top Contributor
Es gibt auch noch andere Docking-Frameworks, das sollte nur ein Beispiel sein. Vielleicht ist das, was du vorhast, auch SO viel "weniger" als das, was durch solche Frameworks erlaubt wird, dass sich der Einsatz eines Frameworks nicht lohnt und man es besser per Hand macht. Aber diese "Vorschau" des Verschobenen und der "Einrastpositionen" klang schon nach etwas, wo man mit einigen GlassPane-getrickse usw. drangehen müßte. Kann man dazu schon irgendwelchen compilier- und testbaren Code posten? Dann kann man vielleicht eine einfache Lösung für das konkrete Problem (ohne Framework) finden...
 

Sunchezz

Bekanntes Mitglied
Joa, dann werde ich hier mal den MouseInputAdapter hinhauen...
Der wird jedem Objekt was auf dem Panel liegt beim adden hinzugefügt, sowohl als mouseListener als auch MMotionL.

Wie bereits erwähnt, wegen dem vielen rumprobieren bin ich noch zu keiner vernünftigen übersicht gekommen und habe bis jetzt auch auf die Doku verzichtet.
Fragt! :)

Java:
package tests.gui;

IMPORTS....

public class ComponentMover extends MouseInputAdapter {
	private JComponent selectedComponent; // the actual selected Component to move
	private MobileContainerPanel container; // the parentContainer of selectedComponent
	private Point offset; // Point when selected a Component
	private int actualPos; // ZOrderPosition of the selectedComponent
	private JPanel anchor; // Visual Anchor for Possible new Position
	private int newZOrderPosition = -1; // the possible new ZOrderPosition
	private boolean anchorIsVisible;
	private Border anchorBorder;
	private Border editBorder;
	private Border selectionBorder;
	private boolean dragging;
	private boolean movingAllowed;

	public ComponentMover(MobileContainerPanel parent, Border edit) {
		dragging = false;
		container = parent;
		anchorBorder = BorderFactory.createLineBorder(Color.GREEN, 1);
		selectionBorder = BorderFactory.createLineBorder(Color.GREEN, 2);
		editBorder = edit;
	}

	public void mousePressed(MouseEvent e) {
		selectedComponent = (JComponent) e.getSource();
		offset = e.getPoint();
		dragging = true;
		selectedComponent.setBorder(selectionBorder);
		if (container.getLayout() != null) {
			actualPos = container.getComponentZOrder(selectedComponent);
			//container.validate();
		}
		container.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
		super.mousePressed(e);
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseMoved(MouseEvent e) {
		if (!e.getSource().equals(Cursor.DEFAULT_CURSOR)) {
			movingAllowed = false;
		} else {
			movingAllowed = true;
		}
	}

	public void mouseReleased(MouseEvent e) {
		dragging = false;
		if (container.getLayout() instanceof FlowLayout) {			
			if (newZOrderPosition != -1) {
				container.add(selectedComponent);
				container.setComponentZOrder(selectedComponent,
						newZOrderPosition);
			}
			if (anchorIsVisible) {
				container.remove(anchor);
				anchorIsVisible = false;
			}
		}
		selectedComponent.setBorder(editBorder);
		setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		container.validate();
		actualPos = -1;
		newZOrderPosition = -1;
		super.mouseReleased(e);
	}

	public void mouseDragged(MouseEvent e) {
		if (dragging) {
			if (container.getLayout() == null) {
				selectedComponent.setBounds(calculateRect(e.getPoint()));
			}
			if (container.getLayout() != null) {
				if (anchorIsVisible) {
					removeAnchor();
					container.validate();
				}
				int newPosition = this.getPossibleNewPosition(e);
				if (newPosition != -1 && newPosition != actualPos
						&& newPosition != actualPos + 1) {
					showAnchorAt(newPosition);
					container.validate();
				}
			}
		}
		super.mouseDragged(e);
	}

	private Rectangle calculateRect(Point p) {
		Rectangle r = selectedComponent.getBounds();
		r.x += p.getX() - offset.x;
		r.y += p.getY() - offset.y;
		return r;
	}

	private void showAnchorAt(int position) {
		if (!anchorIsVisible) {
			anchor = new JPanel();
			anchor.setBorder(anchorBorder);
			anchor.setName("Anchor");
			anchor.setPreferredSize(new Dimension(2, 20));
			container.add(anchor);
			container.setComponentZOrder((Component) anchor, position);
			anchorIsVisible = true;
		}
	}

	private void removeAnchor() {
		container.remove(anchor);
		anchorIsVisible = false;
	}

	private int getPossibleNewPosition(MouseEvent e) {
		Point p = e.getPoint();
		Point newP = SwingUtilities.convertPoint((Component) e.getSource(), p,
				container);
		Component underLayingComponent = container.getComponentAt(newP);
		newZOrderPosition = actualPos;
		if (underLayingComponent != this.anchor) {
			if (underLayingComponent != container) {
				if (underLayingComponent != null) {
					int xposition = isOverXHalfOfComponent(newP,
							underLayingComponent);
					int actualZOrderPos = container
							.getComponentZOrder(underLayingComponent);
					switch (xposition) {
					case 1: // onLeftSideOverHalf = 1;
						if (actualZOrderPos == 0) {

						}
						newZOrderPosition = actualZOrderPos;
						break;
					case 2: // onRightSideOverHalf = 2;
						newZOrderPosition = actualZOrderPos + 1;
						break;
					default:
						break;
					}
				}
			}
		}
		return newZOrderPosition;
	}

	private int isOverXHalfOfComponent(Point p, Component c) {
		int onLeftSideOverHalf, onRightSideOverHalf;
		onLeftSideOverHalf = 1;
		onRightSideOverHalf = 2;

		try {
			int C_x;
			C_x = c.getX();
			int c_x_length = c.getWidth();
			int halfPointX = (c_x_length / 2) + C_x;
			if (p.getX() <= halfPointX) {
				return onLeftSideOverHalf;
			} else {
				return onRightSideOverHalf;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}

	private void setCursor(Cursor c) {
		try {
			container.setCursor(Cursor
					.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		} catch (HeadlessException e1) {
			e1.printStackTrace();
		}
	}
}


Ich hab jetzt irgendwie schon ziemlich viel mit dem "GlassPane-Getrickse" gehört, und hab das auch selbst versucht, aber wie oben beschrieben, bei mir führt das nur zu ekligen Zuckungen der Komponenten -.-
Vielleicht hab ich ja was falsch gemacht, bzw. nich nur vielleicht, bei anderen scheints ja zu gehen, aber ich weiß halt nich was.
Und der Entwurf mit dem GlassPane ist auch schon einige Versionen alt^^

Wär trotzdem Nett wenn vielleicht jemand nen Ansatz für mich hat! :)
 

Marco13

Top Contributor
Ja, so viel zu "compilier- und testbar" ;) Aber nochmal zum Eingangsbeitrag bzw. dem Glasspane: Ich würde spontan sagen, dass der Ansatz 3 (mit dem Glasspane) eben am vielversprechendsten ist. Wenn die verschobene Component dort nicht angezeigt wird, würde ich mal versuchen, herauszufinden, warum das so ist. Das GlassPane hätte ja ein null-Layout, hast du da vielleicht die Bounds nicht richtig gesetzt oder so...? (Und kann man DAvon ein testbares KSKB posten?)
 

Sunchezz

Bekanntes Mitglied
arg... ein testbares ja? ^^
hmm naja, das ist der komplette MouseInputAdapter oben, der is schon soweit aufgeräumt und gekürzt wie ich Zeit hatte!

ähm, mit dem GlassPane bin ich mir sehr sich das es nullLayout hatte und die bounds richtig gesetzt waren, aber ich probiere es gerne noch mal!

werde wohl gleich zurück sein^^
 

Sunchezz

Bekanntes Mitglied
Gut:

Hier der Neue Adapter:
- hinzugekommen ist die Methode createGlassPane(JComponent)
- ein aufruf in mouseDragged() zum setzen der Bounds
- und ein übergeben der selectedComponent an das GlassPane in mousePressed()

Java:
package tests.gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.HeadlessException;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.event.MouseInputAdapter;

public class ComponentMover extends MouseInputAdapter {
	private JComponent selectedComponent; // the actual selected Component to
											// move
	private JPanel container; // the parentContainer of
											// selectedComponent
	private Point offset; // Point when selected a Component
	private int actualPos; // ZOrderPosition of the selectedComponent
	private JPanel anchor; // Visual Anchor for Possible new Position
	private int newZOrderPosition = -1; // the possible new ZOrderPosition
	private boolean anchorIsVisible;
	private Border anchorBorder;
	private Border editBorder;
	private Border selectionBorder;
	private boolean dragging;
	private boolean movingAllowed;
	private JPanel glassPane;

	public ComponentMover(JPanel parent, Border edit) {
		dragging = false;
		container = parent;
		anchorBorder = BorderFactory.createLineBorder(Color.GREEN, 1);
		selectionBorder = BorderFactory.createLineBorder(Color.GREEN, 2);
		editBorder = edit;
	}

	public void mousePressed(MouseEvent e) {
		selectedComponent = (JComponent) e.getSource();
		offset = e.getPoint();
		dragging = true;
		selectedComponent.setBorder(selectionBorder);
		createGlassPane(selectedComponent);
		if (container.getLayout() != null) {
			actualPos = container.getComponentZOrder(selectedComponent);
			//container.validate();
		}
		container.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
		super.mousePressed(e);
	}
	
	private void createGlassPane(JComponent c) {
		((JFrame)JFrame.getFrames()[0]).setGlassPane(null);
		JPanel p = new JPanel();
		p.setBackground(new Color(255, 255, 255, 200));
		p.setVisible(true);
		p.setLayout(null);
		p.add(c);
		((JFrame)JFrame.getFrames()[0]).setGlassPane(p);
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseMoved(MouseEvent e) {
		if (!e.getSource().equals(Cursor.DEFAULT_CURSOR)) {
			movingAllowed = false;
		} else {
			movingAllowed = true;
		}
	}

	public void mouseReleased(MouseEvent e) {
		dragging = false;
		if (container.getLayout() instanceof FlowLayout) {			
			if (newZOrderPosition != -1) {
				container.add(selectedComponent);
				container.setComponentZOrder(selectedComponent,
						newZOrderPosition);
			}
			if (anchorIsVisible) {
				container.remove(anchor);
				anchorIsVisible = false;
			}
		}
		selectedComponent.setBorder(editBorder);
		setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		container.validate();
		actualPos = -1;
		newZOrderPosition = -1;
		super.mouseReleased(e);
	}

	public void mouseDragged(MouseEvent e) {
		if (dragging) {
			if (container.getLayout() == null) {
				selectedComponent.setBounds(calculateRect(e.getPoint()));
			}
			if (container.getLayout() != null) {
				Rectangle r = calculateRect(e.getPoint());
				selectedComponent.setBounds(r);
				if (anchorIsVisible) {
					removeAnchor();
					container.validate();
				}
				int newPosition = this.getPossibleNewPosition(e);
				if (newPosition != -1 && newPosition != actualPos
						&& newPosition != actualPos + 1) {
					showAnchorAt(newPosition);
					container.validate();
				}
			}
		}
		super.mouseDragged(e);
	}

	private Rectangle calculateRect(Point p) {
		Rectangle r = selectedComponent.getBounds();
		r.x += p.getX() - offset.x;
		r.y += p.getY() - offset.y;
		return r;
	}

	private void showAnchorAt(int position) {
		if (!anchorIsVisible) {
			anchor = new JPanel();
			anchor.setBorder(anchorBorder);
			anchor.setName("Anchor");
			anchor.setPreferredSize(new Dimension(2, 20));
			container.add(anchor);
			container.setComponentZOrder((Component) anchor, position);
			anchorIsVisible = true;
		}
	}

	private void removeAnchor() {
		container.remove(anchor);
		anchorIsVisible = false;
	}

	private int getPossibleNewPosition(MouseEvent e) {
		Point p = e.getPoint();
		Point newP = SwingUtilities.convertPoint((Component) e.getSource(), p,
				container);
		Component underLayingComponent = container.getComponentAt(newP);
		newZOrderPosition = actualPos;
		if (underLayingComponent != this.anchor) {
			if (underLayingComponent != container) {
				if (underLayingComponent != null) {
					int xposition = isOverXHalfOfComponent(newP,
							underLayingComponent);
					int actualZOrderPos = container
							.getComponentZOrder(underLayingComponent);
					switch (xposition) {
					case 1: // onLeftSideOverHalf = 1;
						if (actualZOrderPos == 0) {

						}
						newZOrderPosition = actualZOrderPos;
						break;
					case 2: // onRightSideOverHalf = 2;
						newZOrderPosition = actualZOrderPos + 1;
						break;
					default:
						break;
					}
				}
			}
		}
		return newZOrderPosition;
	}

	private int isOverXHalfOfComponent(Point p, Component c) {
		int onLeftSideOverHalf, onRightSideOverHalf;
		onLeftSideOverHalf = 1;
		onRightSideOverHalf = 2;

		try {
			int C_x;
			C_x = c.getX();
			int c_x_length = c.getWidth();
			int halfPointX = (c_x_length / 2) + C_x;
			if (p.getX() <= halfPointX) {
				return onLeftSideOverHalf;
			} else {
				return onRightSideOverHalf;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}

	private void setCursor(Cursor c) {
		try {
			container.setCursor(Cursor
					.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		} catch (HeadlessException e1) {
			e1.printStackTrace();
		}
	}
}

TestKlasse:
Java:
package tests.gui;

import java.awt.BorderLayout;

public class Test extends JFrame {

	private JPanel contentPane;

	public static void main(String[] args) {
		Test frame = new Test();
		frame.setVisible(true);			
	}


	public Test() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 360, 119);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		JPanel panel = new JPanel();
		contentPane.add(panel, BorderLayout.CENTER);
		
		ComponentMover listener = new ComponentMover(panel, BorderFactory.createLineBorder(
				Color.RED, 3));
		
		JLabel lblNewLabel = new JLabel("LABEL1");
		lblNewLabel.addMouseListener(listener);
		lblNewLabel.addMouseMotionListener(listener);
		panel.add(lblNewLabel);
		
		JLabel lblNewLabel_1 = new JLabel("LABEL2");
		lblNewLabel_1.addMouseListener(listener);
		lblNewLabel_1.addMouseMotionListener(listener);
		panel.add(lblNewLabel_1);
		
		JLabel lblNewLabel_2 = new JLabel("LABEL3");
		lblNewLabel_2.addMouseListener(listener);
		lblNewLabel_2.addMouseMotionListener(listener);
		panel.add(lblNewLabel_2);
	}

}


also mir ist gut bewusst das der kleine Test noch grausam aussieht, ich habe eigentlich noch ein abgeleitetes Panel auf dem die Komponenten normaler weise liegen, das tut aber für das eigentlich Problem hier nichts zur sache, bitte ignoriere auch die Borders, die haben eben genau was mit dem ParentPanel zu tun ;)

jedenfalls bewegt sich da nicht viel auf GlassPane!


Ich hoffe ich hab auf die schnelle nichts vergessen, sieht aber vom verhalten so ungefähr aus wie vorhin!
 

Marco13

Top Contributor
Ja, hab's nur mal kurz getestet - und der Test IST "grausam", ich glaube kaum, dass man ohne eine systematischere, strukturiertere Herangehensweise da weit kommt. Scheint als würden da etliche Sachen gemacht, ohne genau zu wissen, was sie bewirken sollen. Sowas wie
Java:
   public void mouseMoved(MouseEvent e) {
        if (!e.getSource().equals(Cursor.DEFAULT_CURSOR)) {
hat ja schon fast einen gewissen Unterhaltungswert, aber ... was soll die Prüfung auf FlowLayout? Und was soll das Z-Order-Gehacke? Was auch immer da bisher zu funktionieren scheint, ist vermutlich nicht viel mehr als Zufall. Ich gehe davon aus, dass es SEHR schwierig ist, das "vernünftig" zu machen, und wenn man das macht, kommt eben etwas komplexeres raus...

Mit einer festen GlassPane würde es wohl eher funktionieren, aber .... man sollte dann (vermutlich! ist auch nur geraten) die aktuelle Component tatsächlich auf der GlassPane herumschieben. Wie man dann die Einfügeposition berechnet (die für jedes Layout verschieden sein muss, und deren Berechnung schon für's FlowLayout wahnsinnig kompliziert wäre) müßte man sich noch überlegen. Vom Anzeigen dieser Einfügeposition mal ganz abgesehen.

Wie viele Personenmonate willst du da rein investieren?
 

Sunchezz

Bekanntes Mitglied
Also ich darf behaupten das ich alles ziemlich gut verstanden habe!
Wüsste jetzt auch nicht was das so aussehen lässt!

Sowas wie
...
public void mouseMoved(MouseEvent e) {
if (!e.getSource().equals(Cursor.DEFAULT_CURSOR)) {


Ich hatte vorher gesagt das ich viel einfach nur rumprobiert habe...
Und beim aufräumen vielleicht was übersehen habe.
Im übrigen is die obere Prüfung dafür gut gewesen, da ich noch ein anderen Listener habe der dann noch für das einstellen der größe für die Komponenten zuständig ist!
und wenn ein resize-cursor drauf is, soll er nich anfangen beim gedrückt halten die komponente zu verschieben, sondern die größe ändern -.-

sorry, das ichs übersehen habe

Ich nehem gerne Tips an für blödsinnigen Quellcode und wie mans besser machen kann.

Aber funktionieren tuts jetzt bei mir so wie ich das wollte, bis auf eine kurze Positionenberechnung wofür ich noch keine Zeit hatte!

Wenns dich interessiert kann ich dir gerne eine PM für die Jar schicken!


EDIT:
wenn das Null-Layout an ist, brauch ich keine Komponenten auf ein glasspane schieben, auch keine Verankerungsanzeige hinhauen...
Also wenn ich nicht auf FlowLayout prüfe, wie soll ichs dann machen?

Was meinst du bitte mit dem "Z-Order gehacke"?
"ZOrder" is der von Sun geprägte begriff für die position im FlowLayout.
Code:
setComponentZOrder(Component comp, int pos)
wie soll ich denn die komponente sonst an eine andere stelle verschieben, wenn nich über
 
Zuletzt bearbeitet:

Marco13

Top Contributor
wenn das Null-Layout an ist, brauch ich keine Komponenten auf ein glasspane schieben, auch keine Verankerungsanzeige hinhauen...
Also wenn ich nicht auf FlowLayout prüfe, wie soll ichs dann machen?

Was meinst du bitte mit dem "Z-Order gehacke"?
"ZOrder" is der von Sun geprägte begriff für die position im FlowLayout.
Code:
setComponentZOrder(Component comp, int pos)
wie soll ich denn die komponente sonst an eine andere stelle verschieben, wenn nich über

Ja... es sah eben recht unstrukturiert aus... ob der Vergleich einer Event-Quelle mit einem Cursor nun eine Altlast oder unverstanden zusammenkopierte Zeilen sind, kann man eben nicht unterscheiden - und ob die Verwendung der ComponentZOrder eine Altlast oder unverstanden zusammenkopierte Zeilen sind, auch nicht - zumindest erkenne ich keinen Zusammenhang zwischen FlowLayout und Z-Order (die Z-Order ist die Reihenfolge in Z-Richtung - sagt also AFAIK nichts darüber aus, ob die Component im FlowLayout links oder rechts landet). Das IST ja das "wahnsinnig komplizierte" was ich oben meinte: Wenn man von den drei Labels das mittlere verschiebt, sollen die beiden Äußeren sich dann zusammenbewegen, als wäre das mittlere nicht da? Wenn man das Mittlere dann nach links bewegt, sollen die anderen beiden sich dann nach rechts bewegen? Wie soll man das machen, außer alle Components zu entfernen, das bewegte als erstes (und damit ganz links) und die anderen beiden dann hinterher wieder einzufügen? Aber dem Layout kann man die Positionierung nicht überlassen, man hält das Label ja noch mit der Maus fest, also muss dort ein "Dummy" eingefügt werden, und erst wenn man losläßt das echte Label. Bei einem BorderLayout hätte man da mehr Freiheiten, aber obwohl das Platzieren dort konzeptuell "ganz anders" ist, stellen sich ähnliche Fragen.
Ich stelle es mir jedenfalls so kompliziert vor, dass man es nicht an einem Tag mit 200 Zeilen schreibt. Aber wenn es jetzt zu deiner Zufriedenheit funktioniert, ist ja alles in Ordnung, vielleicht hattes du gar nicht vor, das so "ausgearbeitet" zu machen, wie ich vermutet habe.
 
Zuletzt bearbeitet:

Sunchezz

Bekanntes Mitglied
Doch, habe schon noch vor das ein wenig auszuarbeiten...
Sitze jetzt aber auch schon drei Tage dran!

Ähm, ja, hatte ich oben gesagt das alles nen bischen unstrukturiert is.
Aber ich denke schon das ich alles verstanden hab was ich geschrieben hab, und kopiert war da absolut nichts.

Dann habe ich den Sinn von ZOrder wohl missverstanden, aber erfüllen tuts beim FlowLayout ja seinen Zweck oder nicht?
Hab dir die Version ja geschickt und da reicht ja ZOrder aus.

Bis auf die Point-Konvertierung läufts ja erstmal fast Bugfrei.
 

Marco13

Top Contributor
Ja, hab's gesehen... wie und warum das mit der Z-Order funktionieren sollte, weiß ich nicht, aber wie gesagt: Wenn's so für dich passt, und es nicht wichtig ist, ist es ja OK
 

Sunchezz

Bekanntes Mitglied
API:
"Returns the z-order index of the component inside the container. The higher a component is in the z-order hierarchy, the lower its index. The component with the lowest z-order index is painted last, above all other child components."

War für mich der anlass das zu nehemen^^
Was passenderes hab ich garnich erst gefunden, vor allem is das aus Container, und wenn ich Glück habe, dürfte das sogar für alle anderen Layouts auch funktionieren :)

Du scheinst damit aber nich zufrieden zu sein, hättest du insgesamt Verbesserungsvorschläge?
Es sind noch einige Erweiterungen geplant, und mein Ziel ist eigentlich das vielleicht doch noch als eigenes Framework zusammen zu hacken :)

Aber ich bedanke mich jetzt hier trotzdem schonmal für deine Unterstützung!
Hat mir hier sehr geholfen!
 

Marco13

Top Contributor
Nochmal: Das Layout und die Z-Order haben nichts miteinander zu tun. Wenn man ein Flow-Layout mit 3 Labels hat, ist egal, ob die Zeichenreihenfolge "Links-Mitte-Rechts" oder "Links-Rechts-Mitte" ist: Was Links ist, ist Links, was Rechts ist, ist Rechts, und was tautologisch ist, ist taustologisch. Ich sehe keine Möglichkeit, die Reihenfolge der Components in einem Flow-Layout zu ändern, außer, alle Components zu entfernen und in der neuen Reihenfolge wieder einzufügen. Kannst ja mal einen Frame mit 3 Labels erstellen, und mal die Z-Order der 3 Labels ändern, und schauen, ob das auswirkungen auf's Layout hat...

Vielleicht schaut Beni mal hier rein, der hat DockingFrames nämlich geschrieben, und nachdem er damit fertig ist, sich über die bisherigen Aussagen (deine und meine) kauputt-zu :lol: en, kann er da vielleicht ein paar Tipps geben ;) Ingesamt gehe ich davon aus, dass es SEHR aufwändig ist, wenn man das "gut" machen will....
 

Sunchezz

Bekanntes Mitglied
also ich bin ja immer gerne selbstkritisch, aber ich finde ich habs schon halbwegs "gut" gemacht ;)

Klar, besser geht immer alles, aber für drei tage arbeit und ohne Vorkenntnisse, bin ich ganz zufrieden.


hmm... interessant:
Java:
package tests.gui;

import java.awt.BorderLayout;

public class Test extends JFrame {

	private JPanel contentPane;
	private JTextField textField;
	private JPanel panel;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Test frame = new Test();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	public Test() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		panel = new JPanel();
		contentPane.add(panel, BorderLayout.CENTER);
		panel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
		
		JLabel lblNewLabel = new JLabel("New label");
		panel.add(lblNewLabel);
		
		JLabel lblLabel = new JLabel("Label2");
		panel.add(lblLabel);
		
		textField = new JTextField();
		panel.add(textField);
		textField.setColumns(10);
		
		JPanel panel_1 = new JPanel();
		contentPane.add(panel_1, BorderLayout.NORTH);
		
		JButton btnChange = new JButton("Change");
		btnChange.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				panel.setComponentZOrder(textField, 1);
				panel.validate();
			}
		});
		panel_1.add(btnChange);
	}

}

also bei mir gehts einwandfrei...
oder anders gesagt: Genau das was ich von Anfang an erwartet hatte.

Also mag ja sein das ichs nich komplett gerafft habe, aber ohne dir nahe treten zu wollen, vielleicht hast dus auch missverstanden? (Bitte nich falsch verstehen :noe:)
Das is zumindest grade meine einzige erklärung^^


Dann hoff ich mal das Beni vorbei kommt, hätte gerne noch ein paar tips :)
 

Marco13

Top Contributor
Ja, ich hab' mal geschaut: Die ComponentZOrder verändert gerade die Reihenfolge der Components im Container (d.h. die Reihenfolge in der sie gezeichnet werden). Dass das auch gerade die Reihenfolge der Components beim FlowLayout ist, ist "Zufall" und nirgendwo spezifiziert. Auf jeden Fall gibt es keine Entsprechung dazu in anderen LayoutManagern.
 

Sunchezz

Bekanntes Mitglied
Ok, stimmt wohl so :)

Hab das mal näher überprüft...
Layouts bei denen das zufällig zu gehen scheint:
GridLayout, FlowLayout, BoxLayout

Joa, jetzt sind wa schlauer xD

um die Positionen auf dem "normalen" weg neu zu setzen müsste ich dann mit den Mangern kommunizieren, und Positionen wie "CENTER" und so angeben oder?
 

Marco13

Top Contributor
Positionen wie "CENTER" und so angeben oder?

Genau das meinte ich: Beim FlowLayout geht das nicht. Man könnte sich mal anschauen, ob es die Layout-Constraints irgendwie berücksichtigt, aber meines Wissens nicht. Zumindest kann man nicht davon ausgehen, dass es eine allgemeine Möglichkeit gibt, für ein Beliebiges Layout die Einfügeposition anzugeben (... und noch viel Spaß beim GridBagLayout :D ). Die einzige Möglichkeit, die ich sehen würde, wäre, das für jedes Layout spezifisch auszuprogrammieren - aber wenn man die Einfügeposition (einschließlich der Abmessungen der Component NACH dem Einfügen, also quasi eine komplette "Vorschau") anzeigen wollte, würde es richtig kompliziert werden...
 

Sunchezz

Bekanntes Mitglied
Ja, es für jedes Layout spezifisch einzuhacken war bis jetzt sowieso mein Plan...
zumal die Berechnung für jede neue Position ja sowieso Layoutabhängig ist!

"Constraints" war das Wort was mir gefehlt hat^^
Darauf wirds wohl hinauslaufen...

Naja, ich glaube wenn dann lass ich das GridBag aus...
oder füge es mal noch hinzu wenn ich nen Jahr lang langeweile habe und arbeitslos bin :D

Das mit den Abmessungen der Komponente für die neue Position hatte ich schonmal drin, war jetzt nicht so kompliziert.
Dem Anchor die gleichen abmasse geben, das validate hat den rest der aktualisierung abgenommen, jedenfalls funktioniert das mit der aktuellen methode. Sollte ja aber auch kein Ding sein (Gesetz dem fall das mit den Constraints funktioniert) die selektierte Komponente zu entfernen, über Constraints den Anchor mit den Maßen zu setzen und dann wieder zu validaten.

Aber diesen Ansatz habe ich verworfen, da das ein umso Größeres hinund hergespringe der Komponenten nachsich zieht.

Für bessere Komponentenplatzierung war meine Idee eigentlich, die Möglichkeit "unsichtbare" platzhalter einzufügen, die in Ihrer größe verstellbar sind. Das sollte jedenfalls für die "unkomplexen" Layouts ausreichen.

So wie das momentan aussieht, hab ich noch einen heiden spaß vor mir :)
Werden wohl noch ein paar threads dazu folgen :D
 

Marco13

Top Contributor
Das mit den Abmessungen der Komponente für die neue Position hatte ich schonmal drin, war jetzt nicht so kompliziert.
...
Für bessere Komponentenplatzierung war meine Idee eigentlich, die Möglichkeit "unsichtbare" platzhalter einzufügen, die in Ihrer größe verstellbar sind.

Wieder: Im einfachsten Fall, ja. Aber die Frage, ob die bei getMinimumSize, getPreferredSize und getMaximumSize zurückgelieferten Werte vom LayoutManager berücksichtigt werden (und wie) hängt auch wieder vom LayoutManager ab. D.h. selbst wenn man an die Zielposition eine "Dummy-Component" einfügt, um eine Vorschau zu haben, kann es sein, dass die Component eine andere Größe bekommt, wenn sie denn tatächlich dort losgelassen wird. Nahe liegend wäre dann, die besagten Methoden der Dummy-Component an die aktuell bewegte Component weiterzudelegieren, aber das kann auch hakelig sein. Abgesehen davon...
Aber diesen Ansatz habe ich verworfen, da das ein umso Größeres hinund hergespringe der Komponenten nachsich zieht.
... könnte das natürlich beliebig häßlich werden. Man kann ja versuchen, sich bei sowas wie Eclipse und seiner Docking-Funktionalität was abzuschauen, aber auch nur konzeptuell - die Implementierung dürfte da ein paar Größenordnungen aufwändiger sein.
Naja. Mal schauen was da noch draus wird... :)
 
B

Beni

Gast
Ich weiss ja nicht genau wo du jetzt stehst, und was für eine Hilfe du gerade brauchst/erwartest, aber meine Meinung ist folgende:

Mit den Standard-LayoutManagern wirst du immer das Problem haben, dass jedesmal wenn du die Component umplazierst das ganze Layout springt. Wenn du unbedingt die Standard-LayoutManager benutzen willst, dann würde ich das etwa so lösen:

1. Ausrechnen wo die verschobene Componente etwa hinkommt, ohne sie tatsächlich zu verschieben. D.h. Methoden wie "validate" werden nie aufgerufen. Das kann man entweder machen, indem man sich den LayoutManager genau anschaut und den Code analysiert (z.B. beim GridLayout wäre das möglich). Oder indem man sich eine unsichtbare Kopie der Oberfläche zusammenbaut, und dort eine Kopie der Component verschiebt.

2. Je nachdem wie gut die Berechnung ist, kann man in einem GlassPanel ein paar Markierungen (z.B. ein Rechteck) zeichnen, dort wo die Component etwa hinkommen würde.


Noch eine Stufe härter:

3. Den LayoutManager temporär entfernen und das "null" Layout verwenden. Dann berechnen wo die Componenten landen könnten, wenn der Benutzer seine Component verschieben würde. Da erhälst du mehr als ein Resultat, da der Benutzer die Component an mehr als eine Stelle schieben könnte. Aber damit kannst du eine Art Animation bauen: der Benutzer hat die Component etwas nach rechts geschoben? Also 25% der "rechten" Lösung + 75% der "linken" Lösung nehmen, und die Componenten entsprechend verschieben. Dann machst du statt einem riesigen Sprung viele kleine, und das sieht besser aus. Wenn der Benutzer die Maus los lässt, kannst du den LayoutManager wieder installieren.


Und ums sich das Leben einfacher zu machen:

4. Verzichte auf die Standard-LayoutManager. Implementier selber LayoutManager, die dürfen sich aber wie ihre Vorbilder benehmen. Diesen LayoutManagern kannst du Methoden einbauen um verschiedene Vorschauen zu berechnen. Da du sie selbst schreibst, ist das wesentlich einfacher als wenn du die existierenden LayoutManager entschlüsseln musst.
 
B

Beni

Gast
Danke für das Beispiel.

Ich finde es ein bisschen komisch, dass die Maus immer oben links von der Component ist, und nicht dort wo man die Componente ergriffen hat.

Und das Resize das Höhen-Breiten-Verhältnis beibehält finde ich nicht intuitiv.

Dass da noch was rumspringt hast du ja selbst bemerkt. Ich bleibe bei meiner Behauptung, dass du mit den Standard-LayoutManagern nie glücklich wirst...



Den Code selbst finde ich so lala (ist nicht böse gemeint). Du bist ganz klar kein Anfänger mehr, aber auch noch nicht der Überprofi ;-) Ich denke so wie das Programm jetzt ist, kann man es als Prototyp bezeichnen. Vielleicht lohnt es sich noch ein paar Tage in den Prototyp zu investieren, bis alles halbwegs brauchbar funktioniert, und dann erst mit dem "echten" Programm beginnen. Beim zweiten Start hast du soviel Vorwissen, dass das Projekt automatisch 100 mal besser wird. Für mein Framework hatte ich ebenfalls einen Prototypen, und im Rückblick war das eine gute Idee.

Ein bisschen mehr Abstraktion, und Möglichkeiten alles zu konfigurieren wären sicherlich nett. Persönlich gehe ich immer davon aus, dass ein Interface zuviel besser als eines zuwenig ist. Also habe keine Angst viele Interfaces und Klassen zu machen. z.B. der ComponentMover ist bereits ein bisschen komplex, er sollte nicht gleichzeitig ein Border setzen, Mouse überwachen, und GlassPane verwalten. Ich sehe hier Potential für mindestens 3 Klassen (GlassPane, Border-Configuration, ComponentMover, ...).


Falls ich dir etwas anders als Allgemeinplätze liefern solle, musst du noch ein passende Frage stellen ;-)
 

Sunchezz

Bekanntes Mitglied
Ich finde es ein bisschen komisch, dass die Maus immer oben links von der Component ist, und nicht dort wo man die Componente ergriffen hat.
Das hat nen gewissen Grund:
Wenn das zu bearbeitende Panel nicht allzugroß ist, oder man eine Große Komponente (und der Rest nur kleine), dann ists mit der übersicht nich so dolle, wenn man die zuverschiebene Komponente irgendwo greift. Hauptsächlich deswegen, weil es dann schnell passieren kann das man den Anker nicht mehr sehen kann!


Und das Resize das Höhen-Breiten-Verhältnis beibehält finde ich nicht intuitiv.
Das hab ich heute schon behoben, hat mich auch ein wenig genervt.


Mit dem nicht mehr Anfänger, seh ich jetzt mal definitiv als Kompliment :D
Aber ich geb dir Recht, das war von Anfang an auch nur als Prototyp geplant, vielleicht ist das auch am Packagenamen aufgefallen: "gui.tests" xD
Angefangen hats als Schnapsidee :D
Ich wollte einfach erstmal die Funktionalität erproben, denn ich seh mich noch nicht als "nicht-Anfänger" und wusste nich obs überhaupt so einfach machbar is.
Irgendwie muss ich mich hier ja für diesen unstrukturierten Quelltext rechtfertigen :D


Ein bisschen mehr Abstraktion, und Möglichkeiten alles zu konfigurieren wären sicherlich nett. Persönlich gehe ich immer davon aus, dass ein Interface zuviel besser als eines zuwenig ist. Also habe keine Angst viele Interfaces und Klassen zu machen. z.B. der ComponentMover ist bereits ein bisschen komplex, er sollte nicht gleichzeitig ein Border setzen, Mouse überwachen, und GlassPane verwalten. Ich sehe hier Potential für mindestens 3 Klassen (GlassPane, Border-Configuration, ComponentMover, ...).
Steht alles noch auf der ToDoList :)
Geplant sind ne Menge Einstellungsmöglichkeiten...
Ich will eigentlich auch ne Magnetfunktion einbauen. Damit zwei Komponenten als eine gehandelt wird. (Darüber hab ich mir bisher aber noch keine Gedanken gemacht, war bisher nur Ideenspielrei)

Komplette Neustrukturierung erfolgt jetzt demnächst wohl noch, wenn ich alle Funktionen durchgeplant habe!


Also eine konkrete Frage habe ich schon noch:
Es funktioniert jetzt zwar über meine GlassPane methode, aber eigentlich ist mir die irgendwie unsympatisch.
Also wenn ich jetzt alles richtig verstanden habe, meinst du ich soll das Verschiebungsproblem (Anker und SourceComponent gleichzeitig aktualisieren) über ein LayoutManager lösen?
Wenn du das so meinst, dann versteh ichs nich so ganz. Ich müsste ja dann in nem Geerbten Layout "layoutContainer(Container target)" überschreiben oder? aber was ändert das an dem ursprünglichen Problem?


Wenn nein, was genau bringen mir dann eigene Layouts, und gibts dann noch ne andere Lösung (bzgl. der aktualisierung)?
 
B

Beni

Gast
Mit dieser Lösung wirst du "layoutContainer(Container target)" und andere Methoden komplett neu schreiben müssen. Das ist durchaus ein nicht zu unterschätzender Aufwand. Um nicht zu sagen, du wirst elend viel Zeit dafür benötigen. ;-) Vielleicht ist es auch nicht die beste Lösung und du findest was viel besseres und einfacheres.

Wenn du selbst einen LayoutManager schreibst, kannst du ihn intelligenter als ein Standard-LayoutManager machen. z.B.:

- Du kannst deinen LayoutManager fragen, wo eine Component hinkommt wenn man sie an einer bestimmten Stelle einfügt. Damit kannst du einer Vorschau zeichnen, ohne wirklich Components hin und her zu schieben.
- Du kannst deinen LayoutManager fragen, wo überall eine Component auftauchen könnte. Damit kannst du einfach rausfinden welche Position am nächsten zu der Maus ist. Damit hast du mehr Möglichkeiten als nur den "componentZ" - Wert. Wiederum ist das alles möglich ohne Components hin und her zu schieben.
- Du kannst soweit gehen, dass deine LayoutManager Animationen ausführen. Statt das alles rumspringt gleiten die Componenten elegant in ihre neue Position.

Mit diesem Ansatz brauchst du am Ende diese Anker-component nicht mehr. Du kannst dann die Vorschaut direkt auf dem GlassPane zeichnen (und sparst damit "validate" Aufrufe, in grossen Mengen sind die nämlich nicht so toll).
 

Sunchezz

Bekanntes Mitglied
Ok, das klingt bis auf den Zeitfaktor ziemlich gut!
Werde mich damit auf jeden Fall mal etwas näher beschäftigen.

Auch wenn mir die layoutMethode des Managers mir grad nen bischen Angst macht auf den ersten Blick^^
Wird wohl aber nur der erste Blick sein, hoffe ich :)


Aber anscheinend muss ich wohl auf jeden Fall über das GlassPane gehen oder?
Gibts echt keinen Weg das auszulassen?
Das was ich aufs Glasspane zeichne, könnte ich doch auch direkt aufs Panel zeichnen oder?
 
B

Beni

Gast
Das GlassPane garantiert dir halt einfach, dass alles was du zeichnest niemals verdeckt sein wird. Wenn du direkt auf das Panel zeichnest, dann ist deine Zeichnung unter den anderen Componenten versteckt. Das ist ok wenn du auf einer leeren Fläche zeichnest, aber in deinem Fall willst du das vielleicht nicht immer.
 

Sunchezz

Bekanntes Mitglied
Gibt es eine Möglichkeit so etwas ähnliches wie das Glasspane zu erstellen?
Sozusagen ein JPanel was unsichtbar über dem anderen liegt, nur das es nicht als glassPane gesetzt wird?

Hab die Angst das es zu einem unwarscheinlichen Fall kommt, wo das GlassPane zu anderen Zwecken gebraucht wird...
Für das jetzige Projekt kann ich das zwar auschlißen, aber ich möchte mich ja doch so flexibel halten, das ich es eventuell irgendwann anders mal anders benutzen kann^^
 
B

Beni

Gast
Gibt es eine Möglichkeit so etwas ähnliches wie das Glasspane zu erstellen?
Sozusagen ein JPanel was unsichtbar über dem anderen liegt, nur das es nicht als glassPane gesetzt wird?

Das kannst du problemlos machen. Solange dein panel mit den Componenten und das unsichtbare JPanel denselben Container als Elter haben, wird das funktionieren. Musst nur noch dafuer sorgen, dass das unsichtbare JPanel auch wirklich ueber dem anderen panel gezeichnet wird (dazu musst du mit LayoutManagern rumspielen, und das component-z beachten).
 

Sunchezz

Bekanntes Mitglied
Mit anderen Worten ich müsste das ParentLayout temporär auf null setzen, das "invisiblePane" auf die selbe location setzen, und dann die paint reihenfolge ändern...

Werds morgen mal auf dem Weg probieren!
Danke!
 

Sunchezz

Bekanntes Mitglied
Ok, habs auf diesem Weg Porbiert...
Es funktioniert auch, nur bin ich jetzt beim alten Problem das die PrewiewComponent flackert^^

Habe jetzt die eine Klasse erstellt die von JPanel erbt (PrewiewPanel), die wird einmal im Konstruktor des Listeners initialisiert.
1. mousePressed() ruft showPreview auf und übergibt die Komponente, wie ihr seht wird hier auch das previewPanel auf das Parent gesetzt.
2. mouseReleased() ruft hidePreview auf.
3. mouseDragged () ruft getPreviewComponent() auf und setzt die neuen Bounds.

Java:
         private void prepareParent() {
		this.parent = containerToOverlay.getParent();
		this.previousParentLayout = parent.getLayout();
		Point originalPosition = containerToOverlay.getLocation();
		Dimension originalSize = containerToOverlay.getSize();
		parent.setLayout(null);		
		this.setLocation(originalPosition);
		this.setSize(originalSize);
		parent.add(this);
		parent.validate();
		parent.repaint();
		this.validate();
	}

	private void showPrewiew(JComponent c, Border b) {
		this.prepareParent();
		this.setPrewiewComponent(c);
		prewiewComponent.setBorder(b);
		prewiewComponent.getParent().remove(getPrewiewComponent());
		this.setVisible(true);
		this.add(prewiewComponent);
	}

	public void hidePrewiew() {
		this.setVisible(false);
		this.remove(getPrewiewComponent());
		this.validate();
	}

Ist die Ursache für das Flackern irgendwo hier zu finden?
 
B

Beni

Gast
Wie soll dir blos jemand helfen, wenn du nichtmal deine ganze Preview-Klasse zeigst. Ohne Code kann man nur rumraten...

Vielleicht stimmt die Position deiner Component nicht? Springt die Position die ganze Zeit hin und her? Allenfalls beachtest du bei der Position nicht, dass die Component sich bewegt und deshalb der Punkt 0/0 an einer anderen Stelle ist.
 

Sunchezz

Bekanntes Mitglied
Also genau genommen hat sich nicht viel geändert, ich habe nur angefangen im Code aufzuräumen, und habe die GlassPane vorschau extrahiert...
Da hat noch alles funktioniert!
Dann hab ich die GlassPane Prewiew kopiert und modifiziert, um das mit dem überlappenden JPanel zu versuchen.
Und nein, wenn ich das richtig sehe, Springt es nicht hin und her, es flackert nur bei der Mausbewegung. Bleibt die Maus unbewegt, aber die Taste noch gehalten, verschwindet es komplett, und taucht nur zur nächsten Bewegung wieder auf!



Dann hier mal beide Klassen und der Listener:
(Zur besseren Übersicht wurden überall selbsterklärende Methoden wie getter usw. entfernt!)


Die GlassPane Vorschau:
Java:
package tests.gui;

import java.awt.Color;

public class PrewiewPanel extends JPanel{
	private JFrame frame = (JFrame) JFrame.getFrames()[0];
	private JComponent prewiewComponent;
	private JPanel oldGlassPane;
	private Border prewiewBorder;
	
	public PrewiewPanel() {
		setBackground(new Color(255, 255, 255, 0));
		setOpaque(false);
		setVisible(true);
		setLayout(null);
	}
	
	public void showPrewiew(JComponent c) {
		this.showPrewiew(c, prewiewBorder);
	}
	
	public void showPrewiew(JComponent c, Border b) {
		this.oldGlassPane = (JPanel)frame.getGlassPane();
		this.setPrewiewComponent(c);
		getPrewiewComponent().setBorder(b);
		getPrewiewComponent().getParent().remove(getPrewiewComponent());
		setVisible(true);
		add(getPrewiewComponent());

		frame.setGlassPane(this);
		frame.getGlassPane().setVisible(true);
	}

	public void hidePrewiew() {
		setVisible(false);
		remove(getPrewiewComponent());
		frame.setGlassPane(oldGlassPane);
		repaint();
		validate();
	}
}

Die JPanel Vorschau:
Java:
package tests.gui;

public class OverlayerPanel extends JPanel {
	private JFrame frame = (JFrame) JFrame.getFrames()[0];
	private JComponent prewiewComponent;
	private Container parent;
	private LayoutManager previousParentLayout;
	private JPanel containerToOverlay;
	private Border prewiewBorder;

	public OverlayerPanel(JPanel original) {
		this.parent = original.getParent();
		this.containerToOverlay = original;
		this.setBackground(new Color(55, 255, 255, 0));
		this.setBackground(Color.RED);
		this.setOpaque(true);
		this.setVisible(true);
		this.setLayout(null);
	}

	private void prepareParent() {
		this.parent = containerToOverlay.getParent();
		this.previousParentLayout = parent.getLayout();
		Point originalPosition = containerToOverlay.getLocation();
		Dimension originalSize = containerToOverlay.getSize();
		parent.setLayout(null);		
		this.setLocation(originalPosition);
		this.setSize(originalSize);				
		//((JPanel)parent).setBorder(prewiewBorder);
		this.setBorder(prewiewBorder);
		parent.add(this);
		parent.validate();
		parent.repaint();
		this.validate();
	}

	public void showPrewiew(JComponent c, Border b) {
		this.prewiew(c, b);
	}

	public void showPrewiew(JComponent c) {
		this.prewiew(c, prewiewBorder);
	}

	private void prewiew(JComponent c, Border b) {
		this.prepareParent();
		this.setPrewiewComponent(c);
		this.prewiewComponent.setOpaque(true);
		prewiewComponent.setBorder(b);
		prewiewComponent.getParent().remove(getPrewiewComponent());
		this.setVisible(true);
		this.add(prewiewComponent);
	}

	public void hidePrewiew() {
		try {
			parent.setLayout(previousParentLayout);
		} catch (NullPointerException e) {
			parent.setLayout(null);
		}
		parent.validate();
		this.setVisible(false);		
		this.remove(getPrewiewComponent());
		this.validate();
	}
}

Der Listener:
Java:
package tests.gui;

public class ComponentMover extends MouseInputAdapter {
	private JComponent selectedComponent; // the actual selected Component to
											// move
	private JPanel container; // the parentContainer of
								// selectedComponent
	private int actualPos; // ZOrderPosition of the selectedComponent
	private JPanel anchor; // Visual Anchor for Possible new Position
	private int newZOrderPosition = -1; // the possible new ZOrderPosition
	private int lastAnchorPosition;
	private boolean anchorIsVisible;
	private Border anchorBorder;
	private Border editBorder;
	private Border selectionBorder;
	private boolean dragging;
	private boolean movingAllowed;
	private Component layeredComponent;
	private Point convertedPoint;
	private OverlayerPanel viewer;

	public ComponentMover(JPanel container, Border edit) {
		dragging = false;
		this.container = container;
		anchorBorder = BorderFactory.createLineBorder(Color.RED, 4);
		selectionBorder = BorderFactory.createLineBorder(Color.RED, 2);
		editBorder = edit;
		viewer = new OverlayerPanel(container);
		viewer.setPrewiewBorder(selectionBorder);
	}	

	public void mousePressed(MouseEvent e) {
		selectedComponent = (JComponent) e.getSource();
		convertPoint(e);
		if (selectedComponent != null) {
			//offset = e.getPoint();
			dragging = true;
			if (container.getLayout() != null) {
				actualPos = container.getComponentZOrder(selectedComponent);
				lastAnchorPosition = container
						.getComponentZOrder(selectedComponent);
				
				selectedComponent.setBounds(calculateRect(convertedPoint));
				viewer.showPrewiew(selectedComponent);
				container.validate();
			}
			viewer.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
		}		
		super.mousePressed(e);
	}

	public void mouseReleased(MouseEvent e) {
		dragging = false;
		if (container.getLayout() instanceof FlowLayout) {
			if (newZOrderPosition != -1) {
				container.add(selectedComponent);
				container.setComponentZOrder(selectedComponent,
						newZOrderPosition);
			}
			if (anchorIsVisible) {
				container.remove(anchor);
				anchorIsVisible = false;
			}
			viewer.hidePrewiew();
		}
		container.add(selectedComponent,
				newZOrderPosition == -1 ? lastAnchorPosition
						: newZOrderPosition);
		selectedComponent.setBorder(editBorder);
		viewer.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		container.validate();
		actualPos = -1;
		newZOrderPosition = -1;
		super.mouseReleased(e);
	}

	public void mouseDragged(MouseEvent e) {
		convertPoint(e);
		if (dragging) {
			if (container.getLayout() == null) {
				selectedComponent.setBounds(calculateRect(e.getPoint()));
			}
			if (container.getLayout() != null) {
				Rectangle r = calculateRect(e.getPoint());
				viewer.getPrewiewComponent().setBounds(r);
				if (anchorIsVisible) {
					removeAnchor();
				}
				int newPosition = this.getNewAnchorPosition(e);
				if (newPosition != -1) {
					showAnchorAt(newPosition);
				}
			}
		}
		super.mouseDragged(e);
	}
	
	private void convertPoint(MouseEvent e) {
		convertedPoint = SwingUtilities.convertPoint(container,
				e.getPoint(), viewer);
	}

	private Rectangle calculateRect(Point p) {
		Rectangle r = selectedComponent.getBounds();
		r.x += p.getX() + 5;
		r.y += p.getY() + 5;
		return r;
	}
}


Wenn ich jetzt den Objekttyp von "viewer" wieder auf das alte PrewiewPanel umstelle, funktionierts wieder blendend (GlassPane).
Aber irgendwas scheint der an meinem neuen Panel nicht zu mögen.

Hoffe ich hab jetzt nichts vergessen!

Grüße und ein schönes WE
Sunchezz
 
Zuletzt bearbeitet:
B

Beni

Gast
Wenn du auf deinem neuen Glass-Pane einfach irgendwas zeichnest, z.B. ein paar Rechtecke, flackern die auch? Wenn ja, dann ist vielleicht das Glass-Pane selbst falsch auf seinem Vater (falsche z-Order?). Wenn nein, dann ist irgendwas mit der Vorschau-Component falsch.
 

Sunchezz

Bekanntes Mitglied
Also mal nebenbei, habe mich mit Graphics bisher eigentlich noch überhaupt nicht näher beschäftigt.

Allerdings glaube ich das innheralb der methode showPrewiew():
Java:
this.getGraphics().drawRect(einRect);
ja eigentlich ausreichen sollte um was zu zeichnen oder?
Aber auf jeden Fall passiert da auch nichts!
wird nichts angezeigt...

Wär dankbar für ne Idee, probiere aber auch selbst noch nen bischen weiter rum!
 
B

Beni

Gast
Ne, du musst "paintComponent" überschreiben. Vergiss, dass die Methode "getGraphics" existiert, benutze sie niemals, es ist immer falsch.
 

Sunchezz

Bekanntes Mitglied
also paintComponent hat mich jetzt auch ich soviel weiter gebracht.
das Rechteckt wurde gezeichnet, aber sobald sich nach dem Drag die Maus bewegt verschwindet es wieder!

ich habe die Vermutung das irgendwo nen unangebrachtes repaint oder sowas zuviel ist.
aber ich komm absolut nicht dahinter.
Habe jetzt in prepareParent nen bischen mit der Z-Order der beiden panels die sich überlagern rumgespielt (und auch noch mit einigen anderen sachen), und habe es zumindest geschafft das flackern zu minimieren.

Wo sich nun aber der rest versteckt ist mir absolut nen Rätsel.
Zumal ich die minimierung mehr durch rumprobieren als durch wissen geschafft habe.

Das interessante ist, die Bewegungsschnelligkeit der Maus spielt irgendeine Rolle.
Wird sie nur enorm langsam bewegt, flackert es überhaupt nicht!
Ich könnte deshalb vermuten, das zwischen den Bewegungen zuviele Berechnungen angestellt werden, bis es zum Repaint kommt, allerdings müsste ja dann eher die Komponente "springen", und es würde auf dem Originalglasspane genauso aussehen, tut es aber nicht.


Ich hoffe ich nerve nicht langsam -.-
 

Sunchezz

Bekanntes Mitglied
Soo... hab das jetzt anders gelöst :D
Zauberformel lautet JLayeredPane!

Jetzt also das Vorschaupanel bei bedarf in den Vordergrund geschoben.
Das hat das Flackern im Prinzip eigentlich gelöst, dachte ich jedenfalls -.-

Jetzt kommt ein neuer Flackerfaktor.
Da Container auf dem eigentlich Panel ebenfalls verschoben werden können sollen, musste ich ja diverse Subkomponenten deaktivieren. Da man zum Beispiel eine JTable in einem ScrollPane immer noch anwählen kann, obwohl die ScrollPane deaktiviert ist, daher musste man die ScrollPane direkt greifen, oder irgendwo am Rand. Das ist natürlich nicht wünschenswert.
Meine erste Idee war, rekursiv zu prüfen ob die jeweilge Komponente ein Container is, bis mir schnell aufgefallen is, das ja alle JComponenten von Container erben -.-. Nächster ansatz war, bei speziellen Containern (JPanel, JScrollPane etc.) weiter rekursiv die subKomponenten zu deaktivieren. Hat aber auch irgendwann gehakt, da er versuch hat irgendwelche defaulteditor in einer JTable oder so zu deaktivieren. Da ich nich jede eventuelle Möglichkeit abfragen will, hab ich mir gedacht, man kann ja zur bearbeitungszeit aus der Komponente nen Bild machen, und das dann Verschieben.
Sieht klasse aus, und funktioniert weitestgehend bis auf folgenden Fehler:
Wird das Bild nicht angefasst, sondern eine andere Komponente und schwebt man nun beim ziehen über das Bild, fangen beide Komponenten an sich abwechselnd zu überlappen (Flackert böse, bleibt man jedoch stehen, ist die zu ziehende komponente mal unter, mal über dem Bild).
Is mir irgendwie nen Rätsel, vielleicht war das ja von anfang an das Flackerproblem???

Hier mal die Klasse für ein Bild (ich benutze es als normales JComponent)

Java:
public class Picture extends JComponent {

	private static final long serialVersionUID = 1992007953073696720L;
	private Image img;
	private int oldComponentPosition = -1;
	
	private String identifier;
	
	public Picture(Component c) {
		this.img = getComponentPicture(c);
		oldComponentPosition = c.getParent().getComponentZOrder(c);
	}
	
	public Picture(Image img) {
		this.img = img;
		int w = img.getWidth(this);
		int h = img.getHeight(this);
		setPreferredSize(new Dimension(w, h));
	}	

	protected void paintComponent(Graphics g) {
		g.drawImage(img, 0, 0, this);
	}
	
	protected Image getComponentPicture(Component c) {
		BufferedImage img = new BufferedImage(c.getWidth(),
				c.getHeight(), BufferedImage.TYPE_INT_RGB);
		img.flush();
		c.paint(img.getGraphics());
		return img;
	}
	
	public Image getImg() {
		return img;
	}

	public void setImg(Image img) {
		this.img = img;
	}
}

Gibts da was was ich auf anhieb nich kapiere?
Eigentlich sollte es sich doch wie ein normales JComponent verhalten oder?
BTW: mit Bildern, paintComponent, Graphics etc. hab ich mich noch nie stark auseinander Gesetzt, vielleicht liegts daran :(
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
1 2D-Grafik Flackerndes Hintergrund AWT, Swing, JavaFX & SWT 1
izoards Java FX Window Event SHOWING AWT, Swing, JavaFX & SWT 17
ruutaiokwu SWT "Google Window Builder" tut keine jar's ins Projekt rein bei SWT-Projekt AWT, Swing, JavaFX & SWT 22
L JavaFX AnchorPane an die Größe der Scene oder Window binden? AWT, Swing, JavaFX & SWT 3
A Objekt von einem Window erstellen? AWT, Swing, JavaFX & SWT 8
S Window Builder AWT, Swing, JavaFX & SWT 20
I Modal Window AWT, Swing, JavaFX & SWT 26
ralfb1105 JavaFX Wie Text Label in neuem Window von Main Stage setzen? AWT, Swing, JavaFX & SWT 6
C JavaFX Window-Position AWT, Swing, JavaFX & SWT 3
Neumi5694 java.awt.Window nach javafx.stage.Window AWT, Swing, JavaFX & SWT 1
T Custom Window ohne Swing / AWT / FX..?! AWT, Swing, JavaFX & SWT 1
Ghostman1711 GUI Java von Klasse mit Application Windows anderes Application Window aufrufen AWT, Swing, JavaFX & SWT 6
Z Window Builder - Labels mit setText befüllen AWT, Swing, JavaFX & SWT 11
B JavaFX Werte aus eingefügtem Window lesen AWT, Swing, JavaFX & SWT 0
EisKaffee Swing Window Builder installieren AWT, Swing, JavaFX & SWT 1
D SWT Window passt Größe nicht an AWT, Swing, JavaFX & SWT 4
H Drag component out of window AWT, Swing, JavaFX & SWT 1
B Swing "Window Manager" - Gedankenprobleme AWT, Swing, JavaFX & SWT 9
G Window aus anderer Klasse aufrufen AWT, Swing, JavaFX & SWT 4
J Swing Window-Builder-Projekt richtig übertragen AWT, Swing, JavaFX & SWT 2
H Swing Google Window-Builder AWT, Swing, JavaFX & SWT 4
D SWT CheckBox auslesen (Window Builder Pro) AWT, Swing, JavaFX & SWT 2
frankred Swing Canvas nach "Window-resize" neu Zeichnen lassen wegen Anzeigefehler AWT, Swing, JavaFX & SWT 4
B Swing Window nur bedingt im Vordergrund AWT, Swing, JavaFX & SWT 5
N Window transparent, Komponenten nicht transparent AWT, Swing, JavaFX & SWT 11
R Swing Sequenz aus farbigen Quadraten in Window anzeigen AWT, Swing, JavaFX & SWT 11
J Fehlermeldung adding a window to a container AWT, Swing, JavaFX & SWT 9
L AWT Window, Dialog und verschiedene Betriebssysteme AWT, Swing, JavaFX & SWT 2
3 Eigenes Frame/Window programmieren AWT, Swing, JavaFX & SWT 2
T SWT Window Builder Pro File Dialog anzeigen AWT, Swing, JavaFX & SWT 10
J Swing kann window nicht übergeben AWT, Swing, JavaFX & SWT 14
L Fenster inaktiv setzen / deaktivieren (unable to close window) AWT, Swing, JavaFX & SWT 16
data89 Code-completion-window erzeugen - wie? AWT, Swing, JavaFX & SWT 2
Spin Window Event Beispiel AWT, Swing, JavaFX & SWT 6
H Eclipse View / Window Layout AWT, Swing, JavaFX & SWT 3
T Exception: Adding a window to a container AWT, Swing, JavaFX & SWT 14
M "Window"-Bibilotheck AWT, Swing, JavaFX & SWT 4
I JFrame-Anmerkung "Java Applet Window" entfernen AWT, Swing, JavaFX & SWT 4
T Synchrones Window-verschieben AWT, Swing, JavaFX & SWT 4
K Prompt window in Java? AWT, Swing, JavaFX & SWT 3
S Window über beide Bildschirme maximieren AWT, Swing, JavaFX & SWT 8
F Window#setAlwaysOnTop und Java 1.4.x AWT, Swing, JavaFX & SWT 5
M createImage in Window-Unterklasse AWT, Swing, JavaFX & SWT 4
M Window unterteilen AWT, Swing, JavaFX & SWT 9
R JFrame -- Variable Positionierung durch Window Manager? AWT, Swing, JavaFX & SWT 2
G Window in Taskleiste AWT, Swing, JavaFX & SWT 13
G Window wird angezeigt, nur der Inhalt nicht AWT, Swing, JavaFX & SWT 5
S Window Listener, Exit, bin am Verzweifeln AWT, Swing, JavaFX & SWT 24
U Reaktion auf closing window AWT, Swing, JavaFX & SWT 7
G Listener fuer Window Close AWT, Swing, JavaFX & SWT 2
M not serializable: sun.awt.window.WImage AWT, Swing, JavaFX & SWT 8
N frage ueber D&D von window wie in einige IDE AWT, Swing, JavaFX & SWT 7
P Transparentes Window/JFrame (mit SkinLF?) AWT, Swing, JavaFX & SWT 10
R "Statusbar" - JFrame mit 'Java Applet Window' AWT, Swing, JavaFX & SWT 18
S Performance-Problem: JTextArea als Logging-Window AWT, Swing, JavaFX & SWT 8
J Window Listener funzt nicht richtig AWT, Swing, JavaFX & SWT 5
R Die (J)Frame window listener AWT, Swing, JavaFX & SWT 7
MartinNeuerlich Kann mir jemand, der einen Mac mit einem m1 oder m2-Chip hat, eine POM geben mit der Javafx-Fullscreen beim Mac mit m-Chip funktioniert? AWT, Swing, JavaFX & SWT 1
berserkerdq2 Wie greife ich auf ein Element zu, welches ich beim Scenebuilder erstellt habe AWT, Swing, JavaFX & SWT 10
H AWT Dialog Größe ändern - Schwarzer Inhalt beim groß ziehen AWT, Swing, JavaFX & SWT 1
L jComboBox Actionlistener wird beim erstmaligen Befüllen getriggert AWT, Swing, JavaFX & SWT 7
B Output GUI funktioniert nur beim ersten Mal richtig. AWT, Swing, JavaFX & SWT 4
A JavaFX exportierte Jar ohne beim starten die Libs hinzufügen? AWT, Swing, JavaFX & SWT 2
TheWhiteShadow JavaFX ListView Problem beim Entfernen von Elementen AWT, Swing, JavaFX & SWT 1
S Fehler beim Öffnen weiterer FXML AWT, Swing, JavaFX & SWT 11
I Probleme beim Drucken auf einen PDF-Drucker AWT, Swing, JavaFX & SWT 8
G Gui updated beim zweiten Aufruf nicht mehr AWT, Swing, JavaFX & SWT 15
K JavaFX Resizing-Problem beim BorderLayout (Center Component) beim Arbeiten mit mehreren FXMLs AWT, Swing, JavaFX & SWT 2
W Nullpointer Exception beim übertragen von Daten von Scene zu Scene AWT, Swing, JavaFX & SWT 6
missy72 JavaFX Wiederholen einer IF-Abfrage beim erneuten Öffnen einer Stage AWT, Swing, JavaFX & SWT 11
D JavaFX Probleme beim nachtäglichen hinzufügen der jfx dependency AWT, Swing, JavaFX & SWT 7
R NullPointerException beim Start des Fensters AWT, Swing, JavaFX & SWT 1
D JavaFX Label flackert beim aktualisieren AWT, Swing, JavaFX & SWT 12
J Kann mir jemand beim MediaPlayer helfen ? AWT, Swing, JavaFX & SWT 2
S JavaFx Zufallsfarbe beim Button-Klick AWT, Swing, JavaFX & SWT 22
L Swing JDialog ton beim klicken ausstellen AWT, Swing, JavaFX & SWT 1
sascha-sphw JavaFX ListCell höhe verändert sich beim ändern der Text-Farbe AWT, Swing, JavaFX & SWT 14
H Beim JFrame erstellen ein anderes schließen AWT, Swing, JavaFX & SWT 0
L Swing JLabel wird beim ändern der Schriftart immer neu gezeichnet. AWT, Swing, JavaFX & SWT 2
M AWT Kann meinen Fehler beim ActionListener nicht finden AWT, Swing, JavaFX & SWT 5
R 2D-Grafik Massive Frame Drops beim Benutzen von AffineTransformOp AWT, Swing, JavaFX & SWT 2
ruutaiokwu Swing windowStateChanged macht exakt das Gegenteil beim Verändern der Fenstergrösse AWT, Swing, JavaFX & SWT 3
J Exception beim JFrame erstellen AWT, Swing, JavaFX & SWT 6
B 2D-Grafik paintcomponent Probleme beim zeichnen AWT, Swing, JavaFX & SWT 10
D JInternalFrame wechselt Position beim ersten Click AWT, Swing, JavaFX & SWT 0
steven789hjk543 Swing Verstehe etwas beim GUI nicht AWT, Swing, JavaFX & SWT 3
L JavaFX Probleme beim Installieren JavaFX11 / JavaFX12 -- Eclipse 2019-03 AWT, Swing, JavaFX & SWT 3
H JavaFX Probleme Beim Wechseln der scene als .fxml AWT, Swing, JavaFX & SWT 7
A Fehler beim Hintergrund AWT, Swing, JavaFX & SWT 17
F JavaFX Probleme beim automatischen Konvertieren AWT, Swing, JavaFX & SWT 4
J Hilfe beim tablevies AWT, Swing, JavaFX & SWT 2
L JavaFX Fehler beim setzen von Farben AWT, Swing, JavaFX & SWT 16
T LookAndFeel LookAndFeel funktioniert nicht beim JFrame wechsel AWT, Swing, JavaFX & SWT 3
L Java FX Exception beim start AWT, Swing, JavaFX & SWT 2
L JSplitPane Divider Location beim Maximieren AWT, Swing, JavaFX & SWT 6
L JavaFX Problem beim Aufrufen einer Methode AWT, Swing, JavaFX & SWT 5
J ObservableList wirft exception beim zweiten füllen. AWT, Swing, JavaFX & SWT 4
emma_louisa JavaFX Werte beim Aufrufen des Fensters übernehmen (SceneBuilder) AWT, Swing, JavaFX & SWT 3
Tronert JavaFX Fehler beim Ändern der font-weight AWT, Swing, JavaFX & SWT 7
W Swing Hilfe beim Einbinden von Bildern in einem JFrame AWT, Swing, JavaFX & SWT 8

Ähnliche Java Themen

Neue Themen


Oben