Bei Mausklick außerhalb des Fensters JWindow schließen

January

Mitglied
Hallo zusammen.

Ich habe mal wieder ein Problem, dass ich nicht lösen kann:
Ich habe ein JWindow, dass bei einem Klick auf ein Tray-Icon über diesem erscheint. Das Fenster soll anfangs voll sichbar sein, also auf vorderster Ebene liegen. Um das Fenster auch noch vor der Trayleiste (Windows7)anzuzeigen, habe ich setAlwaysOnTop() auf true gesetzt, was natürlich zur Folge hat, dass es immer sichbar ist. Anders habe ich es nicht hinbekommen, wenn ich es weglassen, liegt das Fenster hinter allen anderen (Browser, etc.).

Was ich letztendlich erreichen möchte, ist dass das Fenster so lange voll sichbar ist, bis ich irgendwo anders auf den Bildschirm klicke (im Prinzip so wie bei den meinsten Tray-Icons, z.B. Rechtsklick auf Lautsprechersymbol). Im Prinzip gilt die Frage für JWindows ganz allgemein, auch ohne das Tray-Icon.

Hier ein stark zusammengekürzte Beispielcode:

Java:
package beispiel;

public class START {
	public static void main(String[] args) {
		new Tray();
	}
}

Klasse um das Symbol in die TrayLeiste zu bingen
Java:
package beispiel;

import java.awt.Image;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class Tray{

	private static final long serialVersionUID = 1L;
	private static TrayIcon myTrayIcon;
	private static SystemTray trayLeiste;
	private MeinFenster fenster;
	
	public Tray(){
		try {
			Image iconGruen = Toolkit.getDefaultToolkit().getImage(
					getClass().getResource("/icons/UhrGruen16x16.png"));
			myTrayIcon = new TrayIcon(iconGruen);
			trayLeiste = SystemTray.getSystemTray();
			trayLeiste.add(myTrayIcon);
			myTrayIcon.addMouseListener(new MouseListener() {
				
				@Override
				public void mouseReleased(MouseEvent e) {
					if (fenster != null){
						fenster.dispose();
						fenster = null;
					} else{
						fenster = new MeinFenster();
						fenster.positioniereFensterAnTray(e);
					}
				}

				@Override
				public void mousePressed(MouseEvent e) {}
				@Override
				public void mouseExited(MouseEvent e) {}
				@Override
				public void mouseEntered(MouseEvent e) {}
				@Override
				public void mouseClicked(MouseEvent arg0) {}
			});
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Fenster-Klasse --> Hierum geht es hauptsächlich
Java:
package beispiel;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;

public class MeinFenster extends JWindow{

	private static final long serialVersionUID = 1L;

	public MeinFenster(){
		JPanel grundPanel = (JPanel)this.getContentPane();
		JLabel beispiel = new JLabel("SICHTBAR");
		JLabel beispiel2 = new JLabel("KEIT");
		grundPanel.setLayout(new GridBagLayout());
		grundPanel.add(beispiel, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER,
				GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		grundPanel.add(beispiel2, new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER,
				GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
		pack();
		
		this.setAlwaysOnTop(true); // Hierum gehts
		this.setVisible(true);	
	}
	
	// Fuer mein Problem nicht gross relevant
	public void positioniereFensterAnTray(MouseEvent mausEvent) {
		int MonitorBreite = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
		int MonitorHoehe = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
		int FensterBreite = (int) this.getSize().getWidth();
		int FensterHoehe = (int) this.getSize().getHeight();
		int xKlickPunkt = mausEvent.getX();
		int yKlickPunkt = mausEvent.getY();
		int PufferZumKlickPunkt = 10;
		if (xKlickPunkt + FensterBreite > MonitorBreite) {
			xKlickPunkt = xKlickPunkt + (MonitorBreite - (xKlickPunkt + FensterBreite));
		}
		if (yKlickPunkt + FensterHoehe > MonitorHoehe) {
			yKlickPunkt = yKlickPunkt + (MonitorHoehe - (yKlickPunkt + FensterHoehe));
		}
		if (yKlickPunkt > MonitorHoehe / 2) {
			yKlickPunkt = yKlickPunkt - SystemTray.getSystemTray().getTrayIconSize().height
					- PufferZumKlickPunkt;
		} else {
			yKlickPunkt = yKlickPunkt + PufferZumKlickPunkt;
		}
		if (xKlickPunkt > MonitorBreite / 2) {
			xKlickPunkt = xKlickPunkt - SystemTray.getSystemTray().getTrayIconSize().width
					- PufferZumKlickPunkt;
		} else {
			xKlickPunkt = xKlickPunkt + PufferZumKlickPunkt;
		}
		setLocation(xKlickPunkt, yKlickPunkt);
	}
}

Ich habe es mit Focus-Listener versucht, jedoch ohne Erfolg. Ich könnte mir vorstellen, dass ich einfach noch nicht die Richtige Methode gefunden habe (,oder?). Vieleicht kann mir ja jemand von euch helfen.

Schon jetzt vielen Dank;
January
 
Hast du auch versucht das Window mit Request Focus in den Vordergrund zu bekommen? Wenn es nämlich damit klappen würde könntest du mit dem FocusListener prüfen ob woanders hin geklickt wird.
 
Du musst sogar mit dem FocusListener arbeiten. Anders bekommst du es nicht mit wenn dein JWindow den Focus verliert. Und das ist nunmal genau das was passiert wenn man ein TrayIcon-PopupMenu hat und nach dem Öffnen wo anderst hinklickt. Der FocusListener bekommt das Signal FocusLost und ruft dadurch auf das PopupMenu dispose() auf ...
So und nicht anderst funktioniert das bei den "originalen" Tray-Menüs ... hättest du auch rausbekommen können wenn du dir das src.zip mitinstalliert und dann die entsprechende Klasse geöffnet und durchsucht hättest.
 
Hallo Technoblade , hallo SPiKEe.

Danke für eure Antworten! Mit Request Focus habe ich es versucht, ebenso mit FocusListener. Hat beides nicht geklappt.
Jetzt habe ich gerade gemerkt, dass der FocusListener funktioniert, wenn ich statt einem JWindow ein JFrame benutze. Das kann ich zwar auf setUndecorated setzen, allerdings besteht dann das Problem, dass das Fenster in der Taskleiste erscheint. Das wollte ich vermeiden.
Vielleicht kann mir ja jemand (vielleicht SPiKEe? :) ) kurz erklären , wie man ein FocusListener für ein JWindow hinbekommt, bzw. was man im Vergleich zu einem JFrame anders machen muss? Werde auch versuchen am WE mal durchs src.zip zu steigen...


Danke!
January
 
Ich glaube es hat sich erledigt. Habe jetzt statt dem JWindow einen undekorierten JDialog genommen. Bei dem funktioniert der FocusListener und auch sonst wird das gemacht, was ich möchte. Ich werde das in den nächsten Tagen mal weiter testen...

Gruß, January
 
Unter http://download.oracle.com/javase/tutorial/uiswing/misc/focus.html
steht:
JWindow and focus: To use a JWindow component in your GUI, you should know that the JWindow component's owning frame must be visible in order for any components in the window to get the focus. By default, if you do not specify an owning frame for a JWindow component, an invisible owning frame is created for it. The result is that components in the JWindow component might not be able to get the focus. The solution is either to specify a visible owning frame when creating the JWindow component, or to use an undecorated JFrame component instead.
Also bleibt dir nur der Weg, einen JFrame zu nehmen, oder das Fenster im selben Prozess laufen zu lassen, in dem auch schon ein anderer JFrame läuft.
 
Um das mit der Taskleiste in den Griff zubekommen würde mir auch nur ein JDialog einfallen der als parent-Object einfach "null" an den Kopf gedonnert bekommt. Aber darauf bist du ja alleine gekommen xD
 
Zurück