# nicht modaler Dialog verdeckt modalen Dialog



## hupfdule (16. Nov 2007)

Hi,

unter Java 1.5 habe ich das Problem, dass ein aufpoppender nicht modaler Dialog einen bereits vorhandenen modalen Dialog verdeckt. Das führt dazu, dass die GUI scheinbar nicht mehr bedient werden kann. Ein Klick in den nun obersten (nicht modalen) Dialog hat keine Auswirkungen, da ja der modale Dialog die Hoheit über die GUI besitzt. Allerdings ist dieser u.U. verdeckt. 

Wer es ausprobieren möchte, kann den Code von unten verwenden.

Mit Java 1.6 scheint dieses Problem behoben zu sein. Der modale Dialog bleibt auf oberster Ebene. (Allerdings verschwindet der neue Dialog ganz in den Hintergrund, was auch nicht gerade meinen Vorstellungen entspricht.)

Kennt jemand eine Lösung, wie man das geschickt auch in Java 1.5 umsetzen kann? Die einzige Lösung, die mir einfällt, wäre jedes Öffnen von Dialogen von einer zentralen Instanz verwalten zu lassen, die anschließend immer die modalen Dialog in den Vordergrund holt. Aber einerseits ist das auch nicht gerade schick, andererseits wäre der Aufwand zu Umsetzung höher als gewünscht. Irgendwelche anderen Vorschläge?



Hier der Code:
Ein Klick auf den Button im Hauptfenster lässt einen Thread starten, der nach einer Wartepause einen nicht modalen Dialog öffnet. Sofort danach wird ein modaler Dialog geöffnet, der anschließend von dem anderen Dialog teilweise überdeckt wird. Der nicht modale Dialog ist mit der Maus nicht mehr bedienbar, obwohl er im Vordergrund steht.


```
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;

public class ST extends javax.swing.JFrame{

    final JButton btnMain= new JButton("Los geht's");
    final BGThread thread= new BGThread();

    public static void main(String[] args){
        final ST st= new ST();
        st.setSize(800, 600);
        st.setLocationRelativeTo(null);
        st.setVisible(true);
    }
    
    public ST(){
        this.btnMain.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ST.this.thread.start();
                JOptionPane.showMessageDialog(ST.this, "Bin ein modaler Dialog");
            }
        });
        
        this.setContentPane(this.btnMain);
        this.setDefaultCloseOperation(JDialog.EXIT_ON_CLOSE);
    }
    
    private class BGThread extends Thread{
        public void run(){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            
            final JDialog d= new JDialog();
            final JButton btnBla= new JButton("Ich überdecke den modalen Dialog, kann aber nicht bedient werden");
            btnBla.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    btnBla.setText("Bedienung erfolgreich");
                }
            });
            d.setContentPane(btnBla);
            d.setLocationRelativeTo(ST.this);
            d.setSize(450, 300);
            d.setVisible(true);
        }
    }

}
```


----------



## Niki (16. Nov 2007)

Ich vermute das ist ein Problem des Parents. Es gibt die möglichkeit über KeyboardFocusManager#getGlobalFocusedWindow
das aktive Fenster zu ermitteln. Ich weiß aber nicht wie das Funktioniert wenn das aktive Fenster ein JOptionPane-Dialog ist. Einfach mal ausprobieren


----------



## Niki (16. Nov 2007)

Verdammt, es tut mir leid, ich habe gerade gesehen das die Methode getGlobatActiveWinder protected Zugriff hat. Du kannst über Reflection die Methode aufrufen, ist aber keine saubere Lösung


```
Method m = KeyboardFocusManager.class.getDeclaredMethod(
						"getGlobalFocusedWindow", null);
				m.setAccessible(true);
				Window w = (Window) m.invoke(KeyboardFocusManager
						.getCurrentKeyboardFocusManager(), null);

				JDialog d = null;
				if (w instanceof JFrame)
					d = new JDialog((JFrame) w);
				else if (w instanceof JDialog)
					d = new JDialog((JDialog) w);
				else
					d = new JDialog();
```


----------



## hupfdule (16. Nov 2007)

Kann sein, dass ich dich falsch verstanden habe, aber der Parent ist schon korrekt gesetzt. Das Hauptfenster (ST) soll der Parent für sämtliche anderen Dialoge sein. Der modale und der nicht modale Dialog sind somit quasi "gleichberechtigt". Da aber der modale Dialog immer zuerst bedient werden will, sollte dieser auch oben liegen, selbst dann, wenn anschließend ein nicht modaler Dialog geöffnet wird.
SUN hat offenbar auch gemerkt, dass da was im Argen liegt und das Verhalten in Java 1.6 entsprechend geändert. ;-)

Falls ich dich falsch verstanden habe, dann bitte ich dies zu entschuldigen.


----------



## Niki (17. Nov 2007)

Du sagst ja new JDialog(); ohne einen Parent mitzusetzen, daher hast du keinen Parent, ich hab deinen Code ausprobiert mit und ohne meinen Änderungen. Mit Änderungen sollte das Verhalten eigentlich stimmen. Das Fenster ist bedienbar, jedoch kannst du den modalen Dialog auch bedienen. Probiers einfach mal aus und schau ob das Verhalten so ist wie du es erwartest.


----------



## hupfdule (19. Nov 2007)

Ah, stimmt. Das ist mir gar nicht aufgefallen.
Zeile 40 muss stattdessen heißen 
	
	
	
	





```
final JDialog d= new JDialog(ST.this);
```

Mit deiner Methode ist zwar tatsächlich möglich, den obersten Dialog bedienbar zu halten, jedoch ist es trotzdem nicht für mich brauchbar. Wird doch der modale Dialog zuerst geschlossen, dann werden ja auch dessen Kinder mitgeschlossen. Das darf natürlich nicht passieren. Von daher hilft auch deine Methode nicht wirklich weiter. Trotzdem danke.


----------

