# Fenster inaktiv setzen / deaktivieren (unable to close window)



## lisaaa17 (27. Dez 2009)

ich schreibe gerade eine gui um fotos zu konvertieren.
das konvertieren selbst übernimmt ein fremdes programm. ich erstelle lediglich die gui.
irfan view wär so ein fremdes programm, dass ich mit Runtime.getRuntime().exec("irfanview.exe ... " aufrufe.

gibt es in java ähnlich wie in c# die möglichkeit mein programm *solange der cmd prozess läuft zu "deaktivieren"*, also solange das konvertieren läuft grau hinterlegte buttons, ...


um sich besser vorzustellen, was ich meine hier der c# code:

```
Process sortProcess = new Process();
sortProcess.StartInfo.FileName = "irfanview.exe";
sortProcess.StartInfo.UseShellExecute = false;
sortProcess.StartInfo.RedirectStandardOutput = true;
```


----------



## Paddelpirat (27. Dez 2009)

Du müsstest bevor du den Prozess startest alle Komponenten, die ausgegraut werden sollen, mit 
	
	
	
	





```
setEnabled(false)
```
 deaktivieren. Anschließend rufst du deinen 
	
	
	
	





```
exec
```
-Befehl und die Methode 
	
	
	
	





```
waitFor()
```
 des Prozesses auf. Wenn diese zurückkommt, kannst du dein GUI wieder aktivieren. 

Achte aber darauf, dass du die Ausführung des Prozesses in einem eigenen Thread durchführst, sonst friert dir die GUI durch die 
	
	
	
	





```
waitFor()
```
-Methode ein.


----------



## lisaaa17 (27. Dez 2009)

Paddelpirat hat gesagt.:


> Du müsstest bevor du den Prozess startest alle Komponenten, die ausgegraut werden sollen, mit
> 
> 
> 
> ...



danke für deine tipps.

allerdings hat sich herausgestellt, dass man durch die waitfor funktion meinen könnte, das programm hat sich aufgehängt. 
ist es möglich eine ladebalken parallel zum prozess zu implementieren (wenn ja wie). da ich die zeit der konvertierung nicht weiß, wär ein balken der in einem rechteck aus und abfährt (wie wenn windows gebootet wird) die einfaste variante.

eine 2. frage hab ich auch noch: gibt es eine möglichkeit die tabreihenfolge zu bestimmen.
meine gui sieht in etwa so aus

```
< JLABEL_sourcefiles >    < JTEXTFIELD_sourcefiles >    < JBUTTON_sourcefiles >
< JLABEL_destfiles >      < JTEXTFIELD_destfiles >      < JBUTTON_destfiles >
```
ich möchte nun sofern ich meine textfeld_source eingabe beendet habe, durch drücken des tabulators zum nächsten jtextfield_dest gelangen und nicht so wie bis jz zu JBUTTON_sourcefiles.


----------



## Paddelpirat (28. Dez 2009)

lisaaa17 hat gesagt.:


> danke für deine tipps.
> 
> allerdings hat sich herausgestellt, dass man durch die waitfor funktion meinen könnte, das programm hat sich aufgehängt.



Deswegen hatte ich geschrieben, dass du den Aufruf in einem seperaten Thread ablaufen lassen musst  Dann bleibt nicht deine gesamte GUI hängen.

Ein bisschen Beispiel-Code:


```
button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				t = new Thread() {
					public void run() {
						try {
							execute();
						} catch(Exception e) {e.printStackTrace();}
					}
				};
				t.start();
			}
		});
```

und:

```
private void execute() {
		try {
			Process eclipse = Runtime.getRuntime().exec("C:\\Program Files\\eclipse\\eclipse.exe");
			button.setEnabled(false);
			
			eclipse.waitFor();
			button.setEnabled(true);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
```

Das ist jetzt nur schnell mal hingeklatscht, nicht schön aber funktioniert ;-)

Zum Thema Ladebalken: Ich glaube nicht dass das funktioniert, weil du nicht weißt wie lange der Prozess für die Ausführung braucht, von daher ist es schwer den Balken fortschreiten zu lassen.

Zu deiner 2. Frage: Laut Doku sollte dir das hier weiter helfen: FocusTraversalPolicy (Java 2 Platform SE v1.4.2)


----------



## lisaaa17 (29. Dez 2009)

Paddelpirat hat gesagt.:


> Das ist jetzt nur schnell mal hingeklatscht, nicht schön aber funktioniert ;-)




ja hat funktioniert, danke.
mit dem balken meinte ich keinen fortschrittsbalken, sondern einfach nur ein bewegendes element, damit man sieht, das programm hat sich nicht aufgehängt. (siehe windows boot bei dem auch keine fortschritt angezeigt wird).
ich könnte mir eventuell auch 3 abwechselnd aufleuchtende punkte vorstellen. 

da der thread sowieso parallel abläuft kann ich das auch ganz einfach in meinem eigentlichen programm realisieren.
die frage ist nur kann ich den thread irgendwie abprüfen, ob gerade konvertiert wird?
ich könnte auch einfach abprüfen ob die buttons enabled sind, das halte ich jedoch für keine schöne lösung.


----------



## Paddelpirat (30. Dez 2009)

Klar könntest du so ein sich bewegendes Element einbauen. Du könntest ja z.B. eine Art Statusleiste in deinem Programm unterbringen, in der sich ein Label befindet (welches nicht disabled wird). Anschließend rufst du an der Stelle, an der du das GUI disablest, für dein Label z.B. die Methode 
	
	
	
	





```
startProcessInWorkAnimation()
```
 und da wo du das GUI wieder aktivierst halt entsprechend 
	
	
	
	





```
endProcessInWorkAnimation()
```
 auf. Wie das ganze dann optisch aussehen soll, ist deiner Kreativität überlassen ;-)


----------



## lisaaa17 (2. Jan 2010)

so mein programm funktioniert, fast . 

hab mich für eine loading animation entschieden während mein prozess im hintergrund läuft.


```
ConvertPanel.setVisible(false); // 
DisableButtons();   
Animation.startAnimation();  // animation starten
Animation.setVisible(true);
window.getContentPane().add(Animation, BorderLayout.CENTER); // animations panel anzeigen

execute(cmd);   // konvertieren beginnen

Animation.closeAnimation();
ConvertPanel.setVisible(true);
Animation.setVisible(false);
f.getContentPane().add(ConvertPanel, BorderLayout.CENTER);
EnableButtons();
```


hier die Animations Klasse:


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

public class animation
  extends JPanel implements Runnable
{
  Thread th;
  Image arImg[];
  int actimage;
  int NumberOfAnimationImages=8;
  
  Dimension windowSize;

  public animation(Dimension windowSize)
  {
    this.windowSize = windowSize;
    this.setBackground(Color.white);
  }

  public void startAnimation()
  {
    th = new Thread(this);
    actimage = -1;
    
    //Bilder laden
    arImg = new Image[NumberOfAnimationImages];
    MediaTracker mt = new MediaTracker(this);
    Toolkit tk = getToolkit();
    for (int i = 1; i <= NumberOfAnimationImages; ++i)
    {
      arImg[i - 1] = tk.getImage("Kopie"+i + ".gif");
      mt.addImage(arImg[i - 1], 0);
      actimage = -i;
      repaint();
      try
      {
        mt.waitForAll();
      }
      catch (InterruptedException e)
      {      }
    }
    th.start();
  }

  public void closeAnimation()
  {
    for(int n=1; n<NumberOfAnimationImages; ++n)
      arImg[n-1].flush();
    this.setVisible(false);
  }

  public void run()
  {
    //Animation beginnen
    actimage = 0;
    while (true)
    {
      repaint();
      actimage = (actimage + 1) % NumberOfAnimationImages;
      System.out.println("actimage - " + actimage);
      try
      {
        Thread.sleep(100);
      }
      catch (InterruptedException e)
      {}
    }
  }

  
  public void paint(Graphics g)
  {
    if (actimage > 0)
    {
      System.out.println("paint - "+actimage);
      g.drawImage(arImg[actimage], 105, 14, this);
    }
  }
}
```

Die Animation funktioniert bis zum 6. Bild, dann wird 2mal das gleiche Bild angezeigt, obwohl er bis zum 8. bild in die paint methode geht. 
Die Bilder sind keine 5kB groß.
Ich hab auch schon die Reihenfolge der Bilder vertauscht, auch dann hängt die animation beim 6. bild.

Die animation läuft also wie folgt ab:
Bild1  -- 100ms --> Bild2  -- 100ms --> Bild3  -- 100ms --> Bild4  -- 100ms --> Bild5  -- 100ms --> Bild6  -- 100ms --> Bild6  -- 100ms --> Bild6  -- 100ms --> Bild1  -- 100ms --> Bild2  -- 100ms -->


Ausgabe:

```
actimage - 0
actimage - 1
paint - 1
actimage - 2
paint - 2
actimage - 3
paint - 3
actimage - 4
paint - 4
actimage - 5
paint - 5
actimage - 6
paint - 6
actimage - 7
paint - 7
actimage - 0
actimage - 1
paint - 1
actimage - 2
paint - 2
actimage - 3
paint - 3
actimage - 4
paint - 4
...
```


----------



## javimka (2. Jan 2010)

Ich sehe keinen Fehler. Bist du sicher, dass "Kopie7.gif" existiert (auch Gross-/Kleinschreibung)? Wenn nicht, kriegst du nämlich null und bei null zeichnet die Methode paint() einfach nichts. Wenn "Kopie7.gif" exisitiert, bist du sicher, dass es nicht einfach dasselbe wie "Kopie6.gif" ist?


----------



## lisaaa17 (2. Jan 2010)

javimka hat gesagt.:


> Ich sehe keinen Fehler. Bist du sicher, dass "Kopie7.gif" existiert (auch Gross-/Kleinschreibung)? Wenn nicht, kriegst du nämlich null und bei null zeichnet die Methode paint() einfach nichts. Wenn "Kopie7.gif" exisitiert, bist du sicher, dass es nicht einfach dasselbe wie "Kopie6.gif" ist?




ja bin mir sicher, habe die reihenfolge verändert, auch dann passiert es beim 7. bild.


----------



## javimka (2. Jan 2010)

Überprüfe doch mal, ob im Array arImg überall ein Bild drin ist, also dass kein Eintrag null ist.

Was macht eigentlich genau Zeile 33 [c]actimage = -i;[/c]?


----------



## Paddelpirat (2. Jan 2010)

Ganz ehrlich? Ich würde mir die Arbeit sparen und z.B. in Gimp ein animiertes gif machen, was du dann anzeigst...

Edit: Ansonsten schau mal dieses Beispiel zum MediaTracker: MediaTracker (Java Platform SE 6)

Dort wird das Hochzählen in der run-Methode synchronisiert.


----------



## lisaaa17 (2. Jan 2010)

Paddelpirat hat gesagt.:


> Ganz ehrlich? Ich würde mir die Arbeit sparen und z.B. in Gimp ein animiertes gif machen, was du dann anzeigst...
> 
> Edit: Ansonsten schau mal dieses Beispiel zum MediaTracker: MediaTracker (Java Platform SE 6)
> 
> Dort wird das Hochzählen in der run-Methode synchronisiert.



wusste nicht, dass animated gifs auch angezeigt werden können, funktioniert einwandfrei vielen dank.

jz hab ich nur noch einen fehler, bevor mein programm fertig wird 
ein button wird im animationspanel angezeigt!
Ich verwende ein Borderlayout, wobei die Buttons auf BorderLayout.SOUTH geadded werden und das Hauptpanel, da wo der Fehler auftritt im BorderLayout.CENTER ist.


```
public class animation extends JPanel
{
  Image img;
  public animation()
  {}

  public void startAnimation()
  {
    img = getToolkit().getImage("animation.gif");  // animated gif
    repaint();
  }

  public void closeAnimation()
  {
    img.flush();
  }

  public void paint(Graphics g)
  {
    g.drawImage(img, 105, 14, this);
  }
}
```



```
....
try
{
	DisableButtons();
	DisplayPanel(Animation);
	Animation.startAnimation();

	execute(cmd;

	Animation.closeAnimation();
	f.getContentPane().add(ConvertPanel, BorderLayout.CENTER);
	EnableButtons();
}
catch (Exception e)
{
	e.printStackTrace();
}
...


public void DisplayPanel(JPanel CenterPanel)
{
    Animation.setVisible(false);
    infopanel.setVisible(false);
    ConvertPanel.setVisible(false);
    CenterPanel.setVisible(true);
    fenster.getContentPane().add(CenterPanel, BorderLayout.CENTER);
}
```


----------



## javimka (2. Jan 2010)

Schreibe in die Methode paint(g) hinein:

```
Rectangle clip = g.getClipBounds();
g.clearRect(clip.x,clip.y,clip.width,clip.height);
```
Das sollte klappen.


----------



## lisaaa17 (3. Jan 2010)

javimka hat gesagt.:


> Schreibe in die Methode paint(g) hinein:
> 
> ```
> Rectangle clip = g.getClipBounds();
> ...



hat geklappt, weißt du auch wieso dieser fehler auftritt?


----------



## Paddelpirat (3. Jan 2010)

Kann zwar gerade nicht sagen, wieso dieser Fehler auftritt, aber wenn er behoben ist ist es ja gut *g*.

Wollte aber nochmal zwei Anmerkungen machen:
1. Klassennamen werden groß geschrieben! 
	
	
	
	





```
public class animation
```
 ;-)

2. Könntest du mal probieren, statt dem JPanel ein JLabel zu verwenden. Dann musst du auch glaub ich nicht mehr die paint Methode überschreiben, weil das JLabel dafür ausgelegt ist ein Bild oder Text anzuzeigen. (Siehe Konstruktoren hier: JLabel (Java 2 Platform SE v1.4.2))

Vielleicht wäre das eine schönere Variante.


----------



## javimka (3. Jan 2010)

Das kommt wahrscheinlich durch den Bufferungs-Effekt zustande. Der Button zeichnet sich auf das Graphics auf die Position 0,0 und wenn du das nicht mehr löschst, bleibt es dort und ist dann im Fenster am falschen Ort zu sehen. Wenn du mit clear alles löschst, ist es weg.


----------



## lisaaa17 (3. Jan 2010)

Paddelpirat hat gesagt.:


> Kann zwar gerade nicht sagen, wieso dieser Fehler auftritt, aber wenn er behoben ist ist es ja gut *g*.
> 
> Wollte aber nochmal zwei Anmerkungen machen:
> 1. Klassennamen werden groß geschrieben!
> ...




ja gefällt mir persönlich besser.
bin jz mit dem programm fertig, nur noch beim jar archiv erstellen funktioniert noch eine kleinigkeit nicht, dafür werde ich aber einen neuen thread aufmachen.

vielen dank an alle die mir geholfen haben.


----------

