ERLEDIGT
NEIN
NEIN
ANTWORTEN
15
15
ZUGRIFFE
3042
3042
EMPFEHLEN
-
06.07.08 11:28 #1
- Registriert seit
- May 2004
- Beiträge
- 684
Hallo,
die setVisible Methode eines JDialogs hält den aktuellen Thread an und führt das Programm weiter, nachdem der Dialog geschlossen wurde (dabei ist das besondere, dass trotzdem noch Events verarbeitet werden, weil anscheinend eine Art neuer Event-Dispatch-Thread aufgemacht wird).
Wie kann ich dies nachbilden, mit einer Methode meiner eigenen Klasse? Ich hab wirklich überhaupt keine Idee, wie die das mit der setVisible aus JDialog machen?!
Für ein paar Tipps wäre ich sehr dankbar!
Danke für Eure Hilfe
-
06.07.08 12:05 #2
Du kannst deinen Thread über .wait() anhalten und dann in deinem Fenster beim Schließen-Event den Process wieder aufwecken.
Ich hoffe das reicht dir als Tipp.
-
06.07.08 15:38 #3
- Registriert seit
- May 2004
- Beiträge
- 684
Hallo Florian,
danke für Deine Antwort, aber
so trivial ist das Problem leider nicht. Wenn ich den EDT per wait anhalte, dann funktioniert die GUI nicht mehr, es werden also auch im Dialogfenster keine Events mehr verarbeitet. Deswegen sagte ich ja, dass man irgendwie einen neuen EDT aufmachen müsste, damit die Oberfläche überhaupt noch reagiert (denn beachte, son JDialog.setVisible ruft man ja aus dem EDT heraus auf, und genau sowas will ich nachbilden mit einer eigenen Methode).
-
06.07.08 16:52 #4
guck mal hier, wenn du die Methode in dein JFrame einbaust, kannst du durch modalize dein Programm anhalten, bis das Fenster geschlossen wird.
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
public void modalize() { final Object MODALLOCK = new Object(); addWindowListener (new WindowAdapter(){ public void windowClosed (WindowEvent e) { synchronized (MODALLOCK){ MODALLOCK.notifyAll(); } } }); synchronized (MODALLOCK){ try { MODALLOCK.wait(); }catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } }
-
06.07.08 17:49 #5
- Registriert seit
- May 2004
- Beiträge
- 684
Hallo Florian,
danke für das Codebeispiel. Wie soll das denn später verwendet werden, etwa so
Code java:1 2
myFrame.modalize(); myFrame.setVisible(true);
? Aber mit "MODALLOCK.wait();" wird ja der Thread angehalten, das heißt, "myFrame.setVisible(true);" wird nicht mehr erreicht.
Und ganz allgemein: wenn die modalize() Methode aufgerufen wird, und es handelt sich um den Event-Dispatch-Thread (EDT), dann werden doch keine Events mehr verarbeitet, oder? Bleibt die GUI dann nicht einfach stehen?
Ich habe Dein Beispiel noch nicht praktisch ausprobiert, ich würde mich sehr freuen, wenn Du mir bei den obigen Fragen nochmal auf die Sprünge helfen könntest.
Danke!
-
07.07.08 17:56 #6
genau anders herum
Code :1 2
myFrame.setVisible(true); myFrame.modalize();
Hab das schonmal verwendet, ohne Probleme. Dein Gui hängt nicht.
Du könntest auch die setVisible Methode überschreiben. Habs aber nicht getestet, ob das läuft, Hier mal aus dem Bauch heraus.
Code :1 2 3 4 5 6 7 8 9
public setVisible(boolean visible){ super.setVisible(visible); if(visible){ modalize(); }else{ //hier musst du testen ob bei setVisible(false) auch das closing event ausgelöst wird, ich //denke schon, falls nicht, musst du hier im else den lock selbst aufheben. } }
-
07.07.08 22:53 #7
- Registriert seit
- May 2004
- Beiträge
- 684
Es hängt nicht? Also das verstehe ich nicht. Ich meine, es ist grandios, dass das funktioniert, ich hätte sonst absolut nicht gewusst, wie ich so eine wartende Funktion im EDT machen kann.
Du rufst das aber auch aus dem EDT heraus auf, oder? Sprich, die Methode "EventQueue.isDispatchThread()" gibt true zurück?
Aber wieso stopp die Geschichte dann nicht. Wenn ich im EDT z.B. ne Schleife baue, die lange braucht um abzuarbeiten, dann steht die GUI ja auch, was ja auch logisch ist. Aber per .wait nicht? Achtet das Laufzeitsystem vielleicht explizit darauf, und macht in dem Fall tatsächlich einen neuen EDT im Hintergrund auf? Ich kann dazu aber in keiner Dokumentation etwas finden.
Also das Thema ist für mich gerade wirklich mysteriös
Edit:
Also ich habe es jetzt auch mal selbst ausprobiert, und es ist genau das Phänomen, was ich voraus gesagt habe. Leider reagiert die GUI dann nicht mehr. Also entweder, Du hast Dich irgendwie total vertan, oder ich mache etwas total falsch
Hier ist mein Test-Code, vielleicht hast Du ja Lust, den auch mal eben auszuprobieren:
Code java:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
public class ModalTest { @SuppressWarnings( "serial" ) class MyFrame extends JFrame { public void modalize() { final Object MODALLOCK = new Object(); addWindowListener( new WindowAdapter() { public void windowClosed( WindowEvent e ) { synchronized ( MODALLOCK ) { MODALLOCK.notifyAll(); } } } ); synchronized ( MODALLOCK ) { try { MODALLOCK.wait(); } catch ( InterruptedException ex ) { Thread.currentThread().interrupt(); } } } } public ModalTest() { JButton button = new JButton( "Fenster öffnen" ); button.setSize( 200, 80 ); button.addActionListener( new ActionListener() { @Override public void actionPerformed( ActionEvent arg0 ) { System.out.println( EventQueue.isDispatchThread() ); MyFrame frame = new MyFrame(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize( 400, 300 ); frame.setVisible( true ); frame.modalize(); } }); JFrame frame = new MyFrame(); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.setSize( 800, 600 ); frame.setLocationRelativeTo( null ); frame.setLayout( null ); frame.add( button ); frame.setVisible( true ); } public static void main( String[] args ) { new ModalTest(); } }
Das Programm öffnet ein Fenster mit einem Button. Beim Klick auf den Button soll sich das neue, modale Fenster öffnen (ich rufe ja auch modalize() auf). Aber siehe, der Inhalt des neuen Fensters wird nicht mehr gezeichnet, und es kann nicht geschlossen werden, weil der Event-Dispatch-Thread (EDT) geblockt wird.
Siehst Du, was ich meine? Mach ich etwas falsch?Geändert von DarthShader (07.07.08 um 23:23 Uhr)
-
08.07.08 18:08 #8
komisch... es ist zwar schon ne weile her, aber bei mir hat das geklappt... bin mir eigentlich sicher, dass es mit der modalize Funktion geklappt hat.
Falls ich heute noch mal dazu komme teste ich es mal.
-
08.07.08 18:50 #9
Habs mal schnell selber programmiert. Bei mir läuft es. Ich kann den Knopf drücken so viel ich will. Und wenn ich das Fenster schließe, dann kommt erst die fertig Meldung nach dem Aufruf der modalize Methode. Hier mein Code. Ich guck mal gleich noch dein Beispiel an.
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JPanel; import javax.swing.JFrame; import javax.swing.JButton; public class ModalTest extends JFrame { private static final long serialVersionUID = 1L; private JPanel jContentPane = null; private JButton jButton = null; /** * This is the default constructor */ public ModalTest() { super(); initialize(); } /** * This method initializes this * * @return void */ private void initialize() { this.setSize(300, 200); this.setContentPane(getJContentPane()); this.setTitle("JFrame"); this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); } /** * This method initializes jContentPane * * @return javax.swing.JPanel */ private JPanel getJContentPane() { if (jContentPane == null) { jContentPane = new JPanel(); jContentPane.setLayout(new BorderLayout()); jContentPane.add(getJButton(), BorderLayout.CENTER); } return jContentPane; } /** * This method initializes jButton * * @return javax.swing.JButton */ private JButton getJButton() { if (jButton == null) { jButton = new JButton(); jButton.setText("KLICK MICH!"); jButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Gui reagiert noch..."); } }); } return jButton; } public void modalize() { final Object MODALLOCK = new Object(); addWindowListener(new WindowAdapter() { public void windowClosed(WindowEvent e) { synchronized (MODALLOCK) { MODALLOCK.notifyAll(); } } }); synchronized (MODALLOCK) { try { MODALLOCK.wait(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } public static void main(String[] args) { ModalTest m = new ModalTest(); m.setVisible(true); m.modalize(); System.out.println("fertig"); System.exit(0); } }
-
08.07.08 19:03 #10
Komisch, bei dir liefert
System.out.println(EventQueue.isDispatchThread());
immer true zurück. Bei mir immer false...
Der einzige Unterschied ist, dass du das Fenster aus einem Fenster erzeugst... Jetzt bin ich auch Planlos.
-
08.07.08 21:05 #11
- Registriert seit
- May 2004
- Beiträge
- 684
Ist nicht böse gemeint, aber weißt Du überhaupt, was genau der EDT ist, und wann man sich "im" EDT befindet?
Dein modalize() rufst Du in der main Methode auf, und das ist NICHT der EDT. Wenn Du modalize() aber z.B. in einen action listener reinlegst, dann bist du im EDT, und sofort funktioniert es nicht.
Ich meine, das ist doch auch die typische Anwendung. Man drückt irgendwo man auf einen Button, und dann will ich ein modales Fenster haben, aber das wird so nicht funktionieren.
-
09.07.08 20:35 #12
was der EDT ist weiss ich. Wann sich in ihm befindet, darüber hatte ich mir bisher noch nicht so die Gedanken gemacht.
Aber jetzt habe ich wieder was dazu gelernt.
Als ich ein modales JFrame gebraucht habe, hat das so getaugt, wie ich es oben geschrieben habe.
Jetzt haste mich aber auch neugierig gemacht, wie das das JOptionPane das macht. Guck dir mal die Sourcen dazu an. Wenn du die Methode showMessageDialog(...) aufrufst, wird irgendwann die veraltete Methode show aufgerufen und dann wirds interessant.
Die checken da ob man im EDT ist oder nicht. Wenn nicht, siehe meine Lösung von oben. Wenn man im EDT ist, dann wirds etwas komplexer.
/*
* @(#)Dialog.java 1.127 07/06/19
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package java.awt;
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
public void show() { beforeFirstShow = false; if (!isModal()) { conditionalShow(null, null); } else { // Set this variable before calling conditionalShow(). That // way, if the Dialog is hidden right after being shown, we // won't mistakenly block this thread. keepBlocking = true; // Store the app context on which this dialog is being shown. // Event dispatch thread of this app context will be sleeping until // we wake it by any event from hideAndDisposeHandler(). showAppContext = AppContext.getAppContext(); AtomicLong time = new AtomicLong(); Component predictedFocusOwner = null; try { predictedFocusOwner = getMostRecentFocusOwner(); if (conditionalShow(predictedFocusOwner, time)) { // We have two mechanisms for blocking: 1. If we're on the // EventDispatchThread, start a new event pump. 2. If we're // on any other thread, call wait() on the treelock. modalFilter = ModalEventFilter.createFilterForDialog(this); final Runnable pumpEventsForFilter = new Runnable() { public void run() { EventDispatchThread dispatchThread = (EventDispatchThread)Thread.currentThread(); dispatchThread.pumpEventsForFilter(new Conditional() { public boolean evaluate() { return keepBlocking && windowClosingException == null; } }, modalFilter); } }; // if this dialog is toolkit-modal, the filter should be added // to all EDTs (for all AppContexts) if (modalityType == ModalityType.TOOLKIT_MODAL) { Iterator it = AppContext.getAppContexts().iterator(); while (it.hasNext()) { AppContext appContext = (AppContext)it.next(); if (appContext == showAppContext) { continue; } EventQueue eventQueue = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY); // it may occur that EDT for appContext hasn't been started yet, so // we post an empty invocation event to trigger EDT initialization Runnable createEDT = new Runnable() { public void run() {}; }; eventQueue.postEvent(new InvocationEvent(this, createEDT)); EventDispatchThread edt = eventQueue.getDispatchThread(); edt.addEventFilter(modalFilter); } } modalityPushed(); try { if (EventQueue.isDispatchThread()) { /* * dispose SequencedEvent we are dispatching on current * AppContext, to prevent us from hang. * */ // BugId 4531693 (son@sparc.spb.su) SequencedEvent currentSequencedEvent = KeyboardFocusManager. getCurrentKeyboardFocusManager().getCurrentSequencedEvent(); if (currentSequencedEvent != null) { currentSequencedEvent.dispose(); } /* * Event processing is done inside doPrivileged block so that * it wouldn't matter even if user code is on the stack * Fix for BugId 6300270 */ AccessController.doPrivileged(new PrivilegedAction() { public Object run() { pumpEventsForFilter.run(); return null; } }); } else { synchronized (getTreeLock()) { Toolkit.getEventQueue().postEvent(new PeerEvent(this, pumpEventsForFilter, PeerEvent.PRIORITY_EVENT)); while (keepBlocking && windowClosingException == null) { try { getTreeLock().wait(); } catch (InterruptedException e) { break; } } } } } finally { modalityPopped(); } // if this dialog is toolkit-modal, its filter must be removed // from all EDTs (for all AppContexts) if (modalityType == ModalityType.TOOLKIT_MODAL) { Iterator it = AppContext.getAppContexts().iterator(); while (it.hasNext()) { AppContext appContext = (AppContext)it.next(); if (appContext == showAppContext) { continue; } EventQueue eventQueue = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY); EventDispatchThread edt = eventQueue.getDispatchThread(); edt.removeEventFilter(modalFilter); } } if (windowClosingException != null) { windowClosingException.fillInStackTrace(); throw windowClosingException; } } } finally { if (predictedFocusOwner != null) { // Restore normal key event dispatching KeyboardFocusManager.getCurrentKeyboardFocusManager(). dequeueKeyEvents(time.get(), predictedFocusOwner); } } } }
-
10.07.08 09:10 #13
- Registriert seit
- May 2004
- Beiträge
- 684
Ja, mich interessiert das auch sehr, und zwar schon seit Monaten
Nicht nur JOptionPane macht das so, auch JDialog.
Vielleicht sage ich mal ein wenig was zum Hintergrund, warum ich das ganze überhaupt brauche. Ich möchte eine eigene Dialog-Klasse (abgeleitet von JDialog) haben, die eine Öffnen-Animation abspielt, ähnlich wie bei Windows, wenn das Fenster größer wird, wenn man es maximiert. Um dies zu erreichen, muss ich diese Animation als SwingWorker abspielen, aber der aktuelle Programmfluss muss dann gestoppt werden. Wenn die Animation fertig ist, soll das Programm weiter laufen und der JDialog wird geöffnet.
Das hat natürlich nicht direkt was mit einem modalen Fenster zu tun, aber es ist genau das, was setVisible macht - nämlich den Programmfluss zu stoppen und das direkt im EDT, ohne dass die GUI steht. Ich habe das in meinem aktuellen Programm zwar gelöst, aber unheimlich umständlich, durch Reflection, indem wir angebe, weile Methode nach der Animation aufgerufen werden soll. Das ist sehr unschön und fehleranfällig und ich würde sonstwas dafür geben, wenn ich das durch guten Code ersetzen kann
Und der setVisible Code ist da der Schlüssel dazu.
Ja, ich hatte mir den Code auch schonmal angeguckt, aber ich muss zugebeb, dass er sich mir nicht erschließen will. Aber vielleicht können wir uns ja gemeinsam ein wenig da rantasten. Ich werde ihn mir heute Abend nochmal ganz genau ansehen, vielleicht gewinnen wir ja wirklich ein paar Erkenntnisse darüber, würde mich freuen
-
14.07.08 22:43 #14
- Registriert seit
- May 2004
- Beiträge
- 684
Hallo Florian,
konntest Du inzwischen schon irgendwelche Erkenntnisse aus dem Code von Sun gewinnen? Ich weiß wirklich nicht wie die das machen, es funktionioert augenscheinlich, aber ich kappier den Code einfach nich :-/
-
Hallo!
Ich wollte heute nochmal fragen ob es dabei mittlerweile einen Fortschritt gibt.
Habe genau das gleiche Problem.
Bin auch dabei die show() Methode vom JDialog zu zerpflücken.
Ist aber nicht ganz so trivial...
Interessant z.B:
Code java:1 2 3 4 5 6 7 8 9 10 11
final Runnable pumpEventsForFilter = new Runnable() { public void run() { EventDispatchThread dispatchThread = (EventDispatchThread)Thread.currentThread(); dispatchThread.pumpEventsForFilter(new Conditional() { public boolean evaluate() { return keepBlocking && windowClosingException == null; } }, modalFilter); } };
Ähnliche Themen
-
IE wird einfach geschlossen!
Von BSA im Forum CSSAntworten: 8Letzter Beitrag: 14.11.05, 15:29 -
Popup soll geschlossen werden wenn das Hauptfenster geschlossen wird.
Von LiebHabSchafi im Forum PHPAntworten: 3Letzter Beitrag: 06.10.05, 23:21 -
PopUp, wenn Fenster geschlossen wird
Von Eiszwerg im Forum Javascript & AjaxAntworten: 13Letzter Beitrag: 18.06.05, 22:40 -
Java Prozess wird nicht geschlossen
Von Acki im Forum JavaAntworten: 9Letzter Beitrag: 13.04.05, 14:06 -
Tabelle wird bei Seriendruck geschlossen :(
Von droni im Forum Office-AnwendungenAntworten: 0Letzter Beitrag: 06.10.03, 07:50





Zitieren
Login





