# Einschreiten vor anzeige eines Frames



## ATMega (31. Jan 2010)

hallo geehrte Java-Progger,

ich hoffe mir kann Jemand bei folgender Problemstellung weiterhelfen.
Ich benötige die Möglichkeit, auf das sichtbar werden eines Fensters zu reagieren. 
Da das Fenster, für die von mir gewollten Aktionen nicht sichtbar sein darf, setze ich es mit setVisible(false) und anschließend mit setVisible(true) innerhalb eines WindowListeners. 
Dies hat jedoch eine Endlosschleife aus Activated Events zur Folge.
Gibt es eine Möglichkeit, dass bevor das Fenster generell sichtbar gemacht wird, einzugreifen und die von mir gewollten Anweisungen auszuführen bei denen das Fenster noch nicht sichtbar sein darf?

Um die Problematik zu verdeutlich folgender Quellcode:

```
.....
           public void windowActivated(WindowEvent e) {
				System.out.println("Aktiviert");
				setVisible(false);
				setVisible(true);
	   }});
           .....
```

Über eine Antwort freue ich mich sehr!


----------



## Ark (31. Jan 2010)

Warum setzt du nicht einfach gerade vor der Operation das Fenster auf nicht sichtbar? Dazu benötigst du auch kein [c]windowActivated()[/c].

Ark


----------



## ATMega (31. Jan 2010)

da diese Aktion nur erforderlich ist, sofern das Fenster mal verdeckt, iconifiziert und dann wieder sichtbar wird.. :/


----------



## ATMega (31. Jan 2010)

anders formuliert:
sobald das Fenster sichtbar wird, möchte ich eine Operation ausführen welche zwingend erfordert, dass das Fenster nicht sichtbar ist ,)


----------



## Ark (31. Jan 2010)

Hm? Wenn du das Fenster genau dann unsichtbar machst, wenn es sichtbar werden könnte, dann ist es niemals sichtbar. Und genau diesen Umstand schreibst du so in deinen Quelltext nieder: Das Fenster ist niemals sichtbar: [c]fenster.setVisible(false);[/c].

Oder verstehe ich dich nicht richtig?

Ark


----------



## ATMega (31. Jan 2010)

Das Fenster wird sichtbar, darauf reagiere ich durch abfangen des Events und mache es wieder unsichtbar und anschließend sichtbar.
Daraus folgt, logischerweise eine endlosschleife aus ActivatedEvents, was zur Folge hat, das Fenster wird immer wieder sichtbar und unsichtbar gemacht.

Ich suche nach einer Möglichkeit, sobald das Fenster im begriff ist sichtbar zu werden einzugreifen?!
Hierfür gibt es leider nicht, wie z.B. beim schließen ein passendes Event. So kann man beim Schließen ja unterscheiden, ob ein Fenster geschlossen wird oder im Begriff ist geschlossen zu werden um vorher bspw. noch speicher freizugeben o.ä.

Alternativ suche ich nach einer Möglichkeit ein Fenster unsichtbar und wieder sichtbar zu machen, ohne das dabei ein WindowActivated Event ausgelöst wird?

Kann ich verhindern, das während einer Behandlung eines Events (also innerhalb des WindowListeners) weitere Events des selben Typs abgefangen werden? Auch dies würde mein Problem beseitigen.


----------



## Ark (31. Jan 2010)

Lass mal das [c]setVisible(false); setVisible(true);[/c] im gezeigten Code einfach weg. Wozu soll das überhaupt gut sein?

Ark


----------



## ATMega (31. Jan 2010)

Nocheinmal:
Sobald mein Fenster sichtbar wird, d.h. es war verdeckt, minimiert oder deaktiviert, möchte ich Operationen ausführen die ZWINGEND erfordern, dass das Fenster nicht sichtbar ist.
Diese Operationen stehen zwischen dem 
	
	
	
	





```
setVisible(false);
```
 und dem 
	
	
	
	





```
setVisible(true);
```
somit hat das Ganze schon einen Sinn...


----------



## Ark (31. Jan 2010)

Na ja, obwohl ich immer noch nicht so recht nachvollziehen kann, warum es so gemacht werden sollte:

Setze eine boolesche Variable so in den Kontext ein, dass sie vom Listener immer abgefragt werden kann. Vor dem ersten [c]setVisible()[/c] setzt du diese Variable auf [c]true[/c], nach dem letzten [c]setVisible()[/c] setzt du sie auf [c]false[/c], und genau am Anfang von [c]windowActivated()[/c] schreibst du [c]if(dieseBoolescheVariable) return;[/c].

Ark


----------



## ATMega (31. Jan 2010)

leider hilft ein boolean flag hier nicht weiter, da trotzdem das event ausgelöst wird, nur die behandlung übersprungen wird..
somit ist das ergebnis wieder eine endlosschleife..
hätte ich auch schon vorweg nehmen können, dies hilft logischerweise nicht!
aber danke für deine bemühung!


----------



## ModellbahnerTT (31. Jan 2010)

ATMega hat gesagt.:


> möchte ich Operationen ausführen die ZWINGEND erfordern, das dass Fenster nicht sichtbar ist.


So ein Quatsch, die einzige Operation die erfordert, dass ein Fenster nicht sichtbar ist, ist setUndecorated. Wenn du beim aktivieren den Rahmen entfernen und beim deaktivieren wieder hinzufügen willst oder andersrum hast du eh verloren, schon von der Usability her :toll:


----------



## ATMega (31. Jan 2010)

dann hab ich mir das wohl ausgedacht xD
danke für den hilfreichen beitrag...


----------



## ATMega (31. Jan 2010)

Da meine Fragestellung offensichtlich auf Missverständnis trifft, möchte ich diese anders stellen.

Folgender Quelltext:


```
@Override
	protected void processWindowEvent(WindowEvent e) {
	    super.processWindowEvent(e);
	    if (e.getID() == WindowEvent.WINDOW_ACTIVATED) {
	    	System.out.println("EVENT!!");
	      	setVisible(false);
	      	...
	      	disableEvents(AWTEvent.WINDOW_EVENT_MASK); 
	      	setVisible(true);
	      	enableEvents(AWTEvent.WINDOW_EVENT_MASK); 		
	    }
  }
```
Wieso wird nach dem aktivieren der Events, dass durch den setVisible(true) erzeugte Event abgearbeitet? Bei dem Aufruf waren die Events doch deaktiviert? Werden Sie automatisch aktiviert?
Dies kann eigtl. nicht sein, da sofern ich die Events nicht mehr aktiviere, also 
	
	
	
	





```
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
```
 auskommentiere, es zu keinen erneuten Aufrufen kommt.

Enthält das Frame ein, o. mehrere Register welche die letzten noch unbearbeiteten Events beeinhaltet und müsste dieses erst gelöscht werden? Was übersehe ich?
Ich spekuliere nur, Freund google kann mir da nicht helfen. Hoffe aber einer von Euch kann mir einen Tipp geben.

Viele Grüße


----------



## Empire Phoenix (31. Jan 2010)

Also ob du es dir ausgedacht hast oder nicht, wenn du das so implementierst (sprich mit dem unsichtbar amchen und so, das flackert dann nämlich kurz) ist es massive beschissenes design.

btw wieso kann man nicht einfach vor dem aufruf von setVisible();
eine funktion aufrufen, die dein unsichtbar only zeugs macht


----------



## ATMega (31. Jan 2010)

vielen dank für deine rückmeldung.
ja, das flackert dann einmal... Auch deshalb würde ich gerne bevor das Fenster erneut sichtbar wird ansetzen nur wie? Sollte dieses Vorrecht lediglich der WindowManager haben, ziehe ich die Alternative mit dem flackern vor, diese funktioniert aber aufgrund des geschilderten Problems leider auch nicht...;(


----------



## Tharsonius (1. Feb 2010)

Ich muss gestehen ich halte das ganze für einen ziemlich groben Designfehler.

Aber wenn es nun mal gar nicht anders geht, dann musst Du bei sowas mit Semaphoren arbeiten.

Wie Ark bereits vorgeschlagen hat brauchst Du eine boolean Variable ueberspringen. Diese setzt Du auf false beim Programmstart.
In dem Event welches Du beim ersten mal ausführen willst und beim 2. mal eben nicht schreibst Du an die erste Stelle:

```
if(ueberspringen)
  return;
```
Dies dient dazu Deine Endloskaskade zu verhindern.

Als 2. Schritt musst Du jetzt noch die Semaphore richtig verwenden. Dazu schreibst Du in eben das selbe Event direkt in der Zeile vor dem setVisible(false) diese Zeile rein:

```
ueberspringen = true;
```

Dann kommt Dein Manipulationscode und anschließend NACH dem setVisible(true) wieder das ueberspringen=false;

Das Event was durch das sichtbar werden ausgelöst wird wird dann durch das oben genannte if abgebrochen und führt zu keiner weiteren Ausführung / Endlosschleife.


Ich bin mir spontan nicht ganz sicher, ob die Events sich gegenseitig unterbrechen. Wenn dies aber nicht der Fall sein sollte, dann musst Du halt statt dem return ein ueberspringen=false schreiben und lässt das zurücksetzen dafür natürlich im Eventcode weg.


Solltest Du mehrere Positionen haben durch die Dein Event getriggert wird, dann musst Du die Semaphore natürlich an jeder Stelle einfügen.




Ganz andere Idee:
Vielleicht geht das ja, wenn Du Deine Aktionen (was auch immer es ist) auf ein Panel legst. Dieses Panel kannst Du beliebig sichtbar und unsichtbar schalten ohne dass das Event vom Fenster ausgelöst wird. Das Ergebnis ist ebenfalls, dass der Nutzer nicht sieht was passiert und Du hast kein lästiges Event mehr.


----------



## ATMega (1. Feb 2010)

vielen dank für die Rückmeldung und die bisherigen Bemühungen!!

Gerne habe ich den Vorschlag mit den Semiphoren erneut probiert. Im nachfolgenden eine kleine Testklasse..

```
import java.awt.*;
import java.awt.event.*;

class testFrame extends Frame{
	
	boolean ueberspringen;
	
	testFrame(){
		setSize(400,400);
		setVisible(true);
		ueberspringen=false;
		enableEvents(AWTEvent.WINDOW_EVENT_MASK); 
	}
	
	public void operationOfInterest(){}
	
//	@Override
//	protected void processWindowEvent(WindowEvent e) {
//	    super.processWindowEvent(e);
//	    if (e.getID() == WindowEvent.WINDOW_ACTIVATED) {
//	    	if(ueberspringen==true)
//	    		return;
//	    	System.out.println("EVENT!!");
//	    	ueberspringen=true;
//	      	setVisible(false);
//	 	operationOfInterest();
//	      	setVisible(true);
//	      	ueberspringen=false;
//	    }
//  	}
  	
  	@Override
	protected void processWindowEvent(WindowEvent e) {
	    super.processWindowEvent(e);
	    if (e.getID() == WindowEvent.WINDOW_ACTIVATED) {
	    	if(ueberspringen==false){
		    	System.out.println("EVENT!!");
		    	ueberspringen=true;
		      	setVisible(false);
		 	operationOfInterest();
		      	setVisible(true);
		      	ueberspringen=false;
	    	}
	    }
  	}
  	
  	public static void main(String [] args){
  		new testFrame();
  	}
}
```

Habe ich die Variable am falschen Zeitpunkt gesetzt? Spinnt mein WindowManager oder wieso habe ich noch immer das selbe Ergebnis?

Die Idee mit dem Panel finde ich sehr gut, befürchte zwar es lässt sich für meinem Anwendungsfall nicht einsetzen, werde es jedoch versuchen.

Viele Grüße


----------



## Ark (1. Feb 2010)

Zwischenfrage an alle: Könnte sich das Problem durch Verwendung von Swing statt AWT einfach so in Luft auflösen?

Ark

*EDIT:* Unabhängig davon halte ich das immer noch für ein Anzeichen von schweren Designfehlern, wie ja bereits festgehalten wurde. Mir ist nach wie vor schleierhaft, was du damit bezwecken willst.

Ark


----------



## Ebenius (2. Feb 2010)

Das mit dem "merken" ob man schon im Event-Processing ist, wird hier nicht funktionieren. WindowEvents sind AWTEvents. Diese werden in die EventQueue gelegt und von dort aus verteilt. Der neue Event (der durch das [c]setVisible[/c] im EventHandler hervorgerufen wird) wird also erst verteilt, *nachdem* der EventHandler fertig bearbeitet wurde. Es handelt sich hier also nicht um eine Rekursion. Dazu mal hübsch der Test: 
	
	
	
	





```
public class FrameFlickering {

  static int count;

  /**
   * Test main method.
   * 
   * @param args ignored
   */
  public static void main(String[] args) {

    final JFrame f = new JFrame("Test Frame: FrameFlickering"); //$NON-NLS-1$
    f.addWindowListener(new WindowAdapter() {

      @Override
      public void windowActivated(WindowEvent e) {
        final Window w = e.getWindow();
        ++count;
        final PrintStream o = System.out;
        o.printf("[%04d] ENTERING windowActivated()%n", count);
        o.printf("  [%04d] About to call setVisible(false)%n", count);
        w.setVisible(false);
        o.printf("  [%04d] Returned from calling setVisible(false)%n", count);
        o.printf("  [%04d] About to call setVisible(true)%n", count);
        w.setVisible(true);
        o.printf("  [%04d] Returned from calling setVisible(true)%n", count);
        o.printf("[%04d] EXITING windowActivated()%n", count);
        o.println();
        w.toFront();
      }
    });
    f.addComponentListener(new ComponentAdapter() {

      @Override
      public void componentShown(ComponentEvent e) {
        final Window w = (Window) e.getComponent();
        final PrintStream o = System.out;
        o.printf("[%04d] ENTERING componentShown()%n", count);
        o.printf("[%04d] EXITING componentShown()%n", count);
        o.println();
        w.toFront();
      }
    });
    f.setSize(640, 480);
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }
}
```
Diese Ausgabe: 
	
	
	
	





```
[0000] ENTERING componentShown()
[0000] EXITING componentShown()

[0001] ENTERING windowActivated()
  [0001] About to call setVisible(false)
  [0001] Returned from calling setVisible(false)
  [0001] About to call setVisible(true)
  [0001] Returned from calling setVisible(true)
[0001] EXITING windowActivated()

[0001] ENTERING componentShown()
[0001] EXITING componentShown()
```
Die einzige Möglichkeit wäre, das Rücksetzen der Merk-Variable mit [c]invokeLater[/c] ans Ende der Queue zu stellen. Aber das ist schon ganz schön ekelig. :autsch:


Dem Aktivieren eines Fensters kann man auch nicht vorgreifen, da dies ausschließlich in der Hohheit des jeweiligen Window-Managers liegt.

Erklär doch mal, was Du tun musst, während das Fenster unsichtbar ist. Vielleicht lässt sich da eine bessere Lösung finden.

Ebenius


----------



## Tharsonius (2. Feb 2010)

Ok, da sich Events nicht gegenseitig unterbrechen klappt das mit den Semaphoren leider nicht. blöd in dem Fall...




ATMega hat gesagt.:


> Die Idee mit dem Panel finde ich sehr gut, befürchte zwar es lässt sich für meinem Anwendungsfall nicht einsetzen, werde es jedoch versuchen.


Ich überlege bereits fieberhaft was das sein könnte was Du vor hast, was nur bei unsichtbarem Frame geht aber nicht in unsichtbarem Panel.

Wenn Du den kompletten Fensterinhalt auf das Panel legst und das dann sichtbar/unsichtbar schaltest, dann bleibt doch nur noch der Fensterrahmen. Alles andere ist unsichtbar, genau so als wäre der Frame ebenfalls unsichtbar...


----------



## ATMega (2. Feb 2010)

habe mittlerweile die idee mit dem panel realisiert und siehe da! it dont works!!!
aber es freut mich sehr, dass ich eine so detailierte, kompetente antwort auf die für mich unerklärliche reaktion, ausgelöst durch die Events erhalten habe! Danke Ebenius!!

Zu dem mysteriösen anwendungsfall,
im rahmen meines studiums bereite ich mich auf eine programmierklausur vor und habe mit dem Pixelgrabber und ändern des dadurch entstehenden arrays aus pixeln rumgespielt 
Damit es nicht ganz so sinnlos ist, ich bilder in einander überblende oder ähnliche tutorials bei denen ich wenig interessantes lerne, habe ich just for fun angefangen ein transparentes fenster selber zu implementieren, basierend auf einem screenshot des Hintergrunds.
Sinnlos? gibt es schon? Geht anders, performanter? Ja und?

Dabei bin ich dann auf diese "angebliche" rekursion der Events gestoßen und mir kam die Frage mit dem "Eingriff vor Auftreten eines Frames".

Da mir Diese nun eindeutig beantwortet wurde, ist dieses Thema für mich gegessen.
Bei dem erstellen eines Screenshots, darf logischerweise das Fenster, welches den Hintergrund aufnehmen soll, selber nicht zu sehen sein.

Eine andere Möglichkeit, einen Screenshot zu erstellen ohne dabei das aktive fenster mit "abzumalen"
abgesehen von setVisible habe ich nicht gefunden. 
Ändert ja auch an meiner Fragestellung nicht viel.

Nun dürft ihr mich gerne wegen meiner "doofen", nicht eleganten oder gar sinnlosen Anwendung kritisieren. 
Gelernt habe ich daraus, somit hat es seinen Sinn für mich erfüllt!

Nochmals VIELEN DANK an alle Beteiligten!


----------



## Ebenius (3. Feb 2010)

Hintergrund aufzeichnen war tatsächlich das einzige was mir einfiel. 

Na dann, happy hacking!
Ebenius


----------



## Tharsonius (3. Feb 2010)

> Nun dürft ihr mich gerne wegen meiner "doofen", nicht eleganten oder gar sinnlosen Anwendung kritisieren.
> Gelernt habe ich daraus, somit hat es seinen Sinn für mich erfüllt!


Einzig darauf kam es Dir doch an, also hat das Programm 99% seiner Aufgaben erfüllt.


Bezüglich des letzten 1 % (der Genugtuung es auch eben 100% hin bekommen zu haben):

Ok, in dem Fall ist das mit dem Panel wirklich Banane, weil ja dann das leere Fenster dennoch im Weg ist....

Eine Idee hätte ich da eventuell noch:
Wie wäre es, wenn Du das Fenster nicht sichtbar/unsichtbar machst sondern stattdessen verschiebst?
Hol Dir erst die Position, verschiebe das Fenster irgendwo in einen nicht sichtbaren Bereich und mach Deinen Screenshot und schiebe das Fenster anschließend zurück.


Ansonsten viel Erfolg bei der Klausur.


----------



## Ebenius (3. Feb 2010)

Das wird aber Murx, wenn der Benutzer das Fenster verschiebt, oder vergrößert.

Ebenius


----------



## ATMega (3. Feb 2010)

doch die idee ist wirklich gut!
iconifizieren klappte logischerweise auch nicht, aber verschieben ist eine möglichkeit, da ich das verschieben generell ja unterbinden kann.
Leider ist dies auch mit einschränkungen verbunden, je nach auflösung des anwenders und Fenstergröße ist es nicht möglich das fenster aus dem relevanten bereich zu schieben. Jedoch kann man die Auflösung des Frames ja in intedependenz zur Bildschirmauflösung setzen... xD


----------



## Ark (3. Feb 2010)

Also ich meine ja, dass ich zumindest bei Swing schon Code sah, wo ein Fenster nicht im EDT auf unsichtbar gestellt wurde. Insofern sollte es doch möglich sein, das in einen eigenen Thread auszulagern und von dort aus zu bewerkstelligen!? (Oder kam diese Idee schon und ich habe sie hier nur übersehen? xD)

Ark


----------



## ATMega (5. Feb 2010)

mit dem verschieben lässt es sich realisieren 
ist zwar ein wenig schade, verschieben/vergrößern ist nicht möglich.
Aber immerhin, it works! ^^

recht funktional, nicht elegant...


----------

