2009-11-04 12 views
5

Ho un JDialog modale non decorato che voglio impostareVisibile (falso) quando l'utente fa clic all'esterno della finestra di dialogo modale.Come chiudere un JDialog modale quando l'utente fa clic all'esterno di JDialog?

È possibile in Swing?

Quello che sto facendo è spuntare un editor personalizzato per un campo di testo come un selettore di date. C'è un modo più semplice per fare ciò che voglio?

EDIT

Ricordate che i blocchi modali sulla chiamata a setVisible (vero), quindi non si può solo dire "non utilizzare una finestra di dialogo modale"

e ho provato attenzione ascoltatori nella finestra di dialogo, non si attivano quando sono modali.

+0

Hai provato il metodo addAWTEventListener, questo dovrebbe fornire eventi per tutti i tipi di eventi specificati, ad es. nell'esempio che ho fornito di seguito, si tratterà di tutti gli eventi del mouse. – vickirk

+0

So che hai detto "quindi non puoi semplicemente dire" non usare una finestra di dialogo modale "", presumibilmente perché hai un codice che viene eseguito subito dopo la chiamata setVisible? Non potresti spostare questo in forse un ascoltatore per quando il dialogo è chiuso? Senza conoscere i dettagli della tua app, può fornire un design più pulito, specialmente quando si tratta di test delle unità, mi piace spostare i dialoghi in una strategia per ottenere risposte degli utenti, in modo da poter iniettare strategie fittizie senza appendere un test unitario quando viene eseguito senza testa o senza dover scherzare con la creazione di eventi programmaticamente. – vickirk

risposta

3

Non è una finestra di dialogo modale se è possibile fare clic al di fuori di esso e "qualcosa" accade. Tutte le risposte sono corrette, dovresti creare una finestra di dialogo non modale e poi gestire il caso d'uso tramite FocusListener.

+0

Questa è la risposta più vicina a "No". Questo è tutto ciò che stavo chiedendo. Non come posso ottenere questo senza un dialogo non modale. – Pyrolistical

0

Non proprio una finestra di dialogo modale se poi cliccando altrove lo chiude, forse si vuole setAlwaysOnTop

Tuttavia, qualcosa come il seguente dovrebbe fare il trucco (non testato). Nota, raccomanderei di spostare il codice in qualcosa di meglio progettato che usare come previsto.

static JDialog dialog = ... 

Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { 
    public void eventDispatched(AWTEvent e) { 
     dialog.setVisible(false); 

     SwingUtils.invokeLater(new Runnable(){ 
      public void run(){ 
       Toolkit.getDefaultToolkit().removeAWTEventListener(this); 
      } 
     });   
    } 
}, AWTEvent.MOUSE_EVENT_MASK); 

dialog.setVisible(true); 
+0

Ho appena provato questo e sembra che questo tipo di ascoltatore non ottenga alcun evento del mouse dall'esterno della finestra di dialogo modale. – Zalumon

0

Probabilmente aggiungere un FocusListener e nascondere la finestra quando si perde la messa a fuoco. Può essere complicato se alcuni elementi nella finestra di dialogo possono essere focalizzati. Comunque, sperimentalo.

+0

Può una finestra di dialogo modale (e componenti figlio) perdere lo stato attivo per qualcosa di diverso dal passaggio a un'altra applicazione? – vickirk

+0

Ah, hai capito cosa intendevi, invece di un dialogo modale! Non so perché questo è stato votato in ribasso – vickirk

10

EDIT:modificata per utilizzare WindowFocusListener invece di focusListener, oltre che di controllo per la discesa dei componenti sul fuoco persa al fine di non nascondere se un componente bambino viene attivato.

Un modo semplice sarebbe aggiungere un listener di messa a fuoco finestra nella finestra di dialogo che lo nasconde quando si perde lo stato attivo. In questo caso, non vedo la necessità di una modalità. Ad esempio:

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.WindowEvent; 
import java.awt.event.WindowFocusListener; 
import java.awt.event.ActionListener; 
import java.awt.event.ActionEvent; 

public class ClickAwayDialog extends JDialog { 

    public ClickAwayDialog(final Frame owner) { 
     super(owner); 
     JPanel pnl = new JPanel(new BorderLayout()); 
     pnl.add(new JLabel("Click outside this dialog in the parent frame to close it"), BorderLayout.NORTH); 
     JButton btn = new JButton("Click Me"); 
     btn.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       JOptionPane.showMessageDialog(ClickAwayDialog.this, "New Child Window"); 
      } 
     }); 
     pnl.add(btn, BorderLayout.CENTER); 
     this.setContentPane(pnl); 
     this.pack(); 
     this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
     this.setLocationRelativeTo(owner); 
     this.setAlwaysOnTop(true); 
     this.addWindowFocusListener(new WindowFocusListener() { 

      public void windowGainedFocus(WindowEvent e) { 
       //do nothing 
      } 

      public void windowLostFocus(WindowEvent e) { 
       if (SwingUtilities.isDescendingFrom(e.getOppositeWindow(), ClickAwayDialog.this)) { 
        return; 
       } 
       ClickAwayDialog.this.setVisible(false); 
      } 

     }); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       JFrame parent = new JFrame(); 
       parent.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
       parent.setSize(300, 300); 
       parent.setLocationByPlatform(true); 
       parent.setVisible(true); 
       ClickAwayDialog dlg = new ClickAwayDialog(parent); 
       dlg.setVisible(true);     
      } 
     }); 
    } 
} 
+0

Focus perso avrebbe dovuto garantire che il componente che ha ottenuto lo stato attivo non fosse un componente figlio della finestra di dialogo, quindi dovrai cercare la gerarchia dei componenti tramite 'getParent()' – vickirk

+0

@vickirk - - buon punto. Ho modificato l'esempio precedente per verificare la presenza di componenti discendenti (probabilmente un caso limite, ma ho migliorato l'esempio per consentire la creazione di una finestra secondaria della finestra di dialogo). L'ho anche modificato per usare un ascoltatore di finestre. –

+0

Sì Capisco perfettamente come si possa fare questo senza una finestra di dialogo modale, ma il punto della domanda era se fosse possibile farlo con una finestra di dialogo modale. Il vantaggio principale dell'uso di una finestra di dialogo modale sono i blocchi quando setVisible (true). Il mio obiettivo era non aver bisogno di ristrutturare il programma per usare una finestra di dialogo non modale o scrivere un'utilità per emulare la natura di blocco in una finestra di dialogo non modale. – Pyrolistical

0

Utilizzare un WindowListener e gestire l'evento windowDeactivated().

+0

Ho appena provato questo e per me questo approccio sembrava funzionare solo quando si fa clic completamente fuori dall'applicazione java, ma non quando si cerca di fare clic sul frame principale java che ha generato la finestra di dialogo modale. – Zalumon

+0

@Zalumon, immagino che questa risposta non sia stata molto chiara. Questo era un suggerimento per NON usare un JDialog modale. Quando si utilizza un JDialog modale come popup, non è possibile chiudere la finestra di dialogo se si fa clic all'esterno della finestra di dialogo. Questa è una soluzione che consente di chiudere una 'finestra di dialogo non modale 'quando si fa clic all'esterno dell'area di dialogo, in modo che la" finestra di pop-up "venga chiusa. – camickr

1

Non è necessario essere una finestra di dialogo modale (modale significa che impedisce di utilizzare la finestra del proprietario finché non si nasconde la finestra di dialogo). Meglio provare questo:

final JDialog dlg ... 
dlg.setModal(false); 

dlg.addWindowFocusListener(new WindowFocusListener() {    
    public void windowLostFocus(WindowEvent e) { 
     dlg.setVisible(false); 
    }    
    public void windowGainedFocus(WindowEvent e) { 
    } 
}); 
1

tenta di impostare il modal su false, e quindi utilizzare windowsDeactivated() per chiudere de finestra (dialog.dispose()), funziona per me.

Problemi correlati