Modalität von JDialog nachträglich in JFrame implementieren?

X5-599

Top Contributor
Hallo,

Gibt es mittlerweile eine brauchbare Möglichkeit die Modalität des JDialog einem JFrame hinzuzufügen? Die bisherigen "Lösungen", die ich gefunden habe sind nicht so das Wahre. Aufrufende Frames zu disablen gefällt mir nicht, da es so aussieht als ob das Programm nicht mehr reagiert (kein blinken des aktiven Frames, wie es ein Dialog machen würde...)

Alternativ ginge natürlich auch die Decorations des Frames (maximize Button) auf ein Dialog zu übertragen. Beides ist im Internet bereits oft angesprochen worden. Doch bisher anscheinend nicht zufriedenstellend gelöst.

Wie handhabt ihr das Problem so?

Gruß,
X5
 

Marco13

Top Contributor
Was spricht dagegen, statt des JFrames eben einen JDialog zu nehmen? Das sind ja zwei komplett unterschiedliche Dinge, aber ähnlich zu verwenden...
 

X5-599

Top Contributor
Danke für die Antwort.

Usability soll sein, dass man den Dialog auch maximieren können soll. Damit der User nicht ständig (mehrere Auswahlmöglichkeiten bezüglich der Anzeige auf dem Dialog) resizen muss.
Überall heisst es das breche mit Konventionen. Aber man kann das Dingen doch vergrössern/verkleinern. Warum also keine Möglichkeit eine Maximize Decoration zu setzen? Ich verstehe die Philosophie dahinter nicht und wollte mal nachfragen, ob es nicht mittlerweile eine Elegante Lösung gibt.

Schönen Dank aber trotzdem.
 

Volvagia

Top Contributor
Warum packst du den Dialog nicht einfach bevor du ihm anzeigst? Ein Subfenster - egal ob möglich oder nicht - musste ich soweit ich mich zurückerrinnere noch nie resizen.
 

X5-599

Top Contributor
In dem Dialog ist eine SplitPane. Links wird ein EIntrag ausgewählt und rechts wird ein entsprechendes Panel angezeigt. Dieses ist abhängig von gewählten Eintrag unterschiedlich groß.

Mal abgesehen davon, dass das packen nicht immer dieselbe Größe des Dialogs bewirkt, ist das ständige Ändern der Dialoggröße (bei Auswahl eines neues Eintrages im linken SplitPane) sehr sehr unschön.

Wäre ja alles kein Problem könnte ich einfach ein Frame nehmen. Aber wie gesagt, ich brauche dringend die Modalität des Dialogs.
 

Volvagia

Top Contributor
Ist vielleicht etwas übertrieben, aber was hältst du davon?

Java:
package org.javaforum.x5599;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

public class ModalFrameExample {
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				buildGui();				
			}
		});
	}
	private static void buildGui() {
		final JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		frame.add(new JButton(new AbstractAction("Show modal frame") {
			public void actionPerformed(ActionEvent e) {
				showModalFrame(frame);
			}
		}));
		
		frame.pack();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}
	private static void showModalFrame(JFrame parent) {
		final JFrame modalFrame = new ModalFrame(parent);
		modalFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		modalFrame.add(new JLabel("Modal Frame"));
		modalFrame.pack();
		modalFrame.setLocationRelativeTo(null);
		modalFrame.setVisible(true);
				
		JOptionPane.showMessageDialog(null, "Modal Frame geschlossen");
	}
}
Java:
package org.javaforum.x5599;

import java.awt.AWTEvent;
import java.awt.ActiveEvent;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.MenuComponent;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.concurrent.ExecutionException;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class ModalFrame extends JFrame {
	private final Object EVENT_DISPATCH_SYNC_LOCK = new Object();
	
	private boolean prevParentGlassPaneVisibly;
	private int prevParentCloseOp;
	private Component prevParentGlassPane;
	
	private JFrame parent;
	
	public ModalFrame(JFrame parent) {
		this.parent = parent;
	}
	public void setVisible(boolean b) {
		checkModal(b);
        super.setVisible(b);
        checkDispatchEvents(b);
        parentToFront(b);
	}
	public void dispose() {
		checkModal(false);
        checkDispatchEvents(false);
        parentToFront(false);
	}
	private void parentToFront(boolean b) {
        if(parent != null && !b) {
        	parent.setState(Frame.NORMAL);
        	parent.setVisible(true);
        	parent.requestFocus();
        	parent.toFront();
        }		
	}
	private void checkDispatchEvents(boolean b) {
		if(b) {
			EventDispatcher dispatcher = new EventDispatcher() {
				protected void doing() throws Exception {
					synchronized(EVENT_DISPATCH_SYNC_LOCK) {
						EVENT_DISPATCH_SYNC_LOCK.wait();
					}
				}
			};
			
			try {
				dispatcher.execute();
			} catch (ExecutionException e) {
				Throwable cause = e.getCause();
				if(!(cause instanceof InterruptedException)) {
					cause.printStackTrace();
				}
			}
		} else {
			synchronized(EVENT_DISPATCH_SYNC_LOCK) {
				EVENT_DISPATCH_SYNC_LOCK.notify();
			}
		}
	}
	private void checkModal(boolean b) {
		if(parent != null) {
        	if(b) {
        		setModal();
        	} else {
        		setUnmodal();
        	}
        }		
	}
	private void setUnmodal() {
		parent.setGlassPane(prevParentGlassPane);
		parent.getGlassPane().setVisible(prevParentGlassPaneVisibly);
		parent.setDefaultCloseOperation(prevParentCloseOp);
	}
	private void setModal() {
		prevParentGlassPane = parent.getGlassPane();
		prevParentGlassPaneVisibly = prevParentGlassPane.isVisible();
		parent.setGlassPane(createCatchEventsGlassPane());
		parent.getGlassPane().setVisible(true);
		
		prevParentCloseOp = parent.getDefaultCloseOperation();
		parent.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);		
	}
	private Component createCatchEventsGlassPane() {
		JPanel glassPane = new JPanel();
		glassPane.setOpaque(false);
		glassPane.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				Toolkit.getDefaultToolkit().beep();
				requestFocus();
			}
		});
		return(glassPane);
	}

	private static abstract class EventDispatcher {
		private static enum State {
			Init,
			Dispatching,
			Exiting,
			Terminated
		}
		
		private State state;
		private ExecutionException exception;
		
		public EventDispatcher() {
			super();
			state = State.Init;
		}
		
		protected abstract void doing() throws Exception;
		
		public synchronized void execute() throws ExecutionException {
			state = State.Dispatching;
			
			if(!EventQueue.isDispatchThread()) {
				try {
					doing();
				} catch (Exception e) {
					throw new ExecutionException(e);
				}
				state = State.Terminated;
				return;
			}
			
			new Thread("EventDispatcher Background Thread") {
				public void run() {
					try {
						doing();
					} catch (Exception e) {
						exception = new ExecutionException(e);
					}
					state = EventDispatcher.State.Exiting;
					sendEmptyEvents();
				}
			}.start();
			
			dispatchEvents();

			if(exception != null) {
				throw exception;
			}
			state = State.Terminated;
		}
		private void dispatchEvents() {
			EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue();
			while(state != State.Exiting && exception == null) {
				AWTEvent event = null;
				try {
					event = queue.getNextEvent();
				} catch (InterruptedException e) {
					Thread.interrupted();
				}
		
				if(event == null) {
					continue;
				}
				
				Object source = event.getSource();
		
				if (event instanceof ActiveEvent) {
					((ActiveEvent)event).dispatch();
				}
				else if (source instanceof MenuComponent) {
					((MenuComponent)source).dispatchEvent(event);
				}
				else if (source instanceof Component) {
					((Component)source).dispatchEvent(event);
				}
				else {
					System.err.println("Not dispatchable Event \"" + event + "\" with source \""+ source+"\"");
				}
			}
		}
		private void sendEmptyEvents() {
			while(state != State.Terminated) {
				final Object lockObj = new Object();
							
				EventQueue.invokeLater(new Runnable() {
					public void run()
					{
						synchronized(lockObj) {
							lockObj.notify();
						}
					}
				});

				synchronized(lockObj) {
					try {
						lockObj.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}
 
Zuletzt bearbeitet:

X5-599

Top Contributor
Sieht schonmal vielversprechend aus. Danke. Eine Frage vorab:

Wie verhält sich das Frame wenn in den Hintergrund geklickt wird? Ein modaler Dialog würde Rückmeldung geben indem er blinkt etc. Sowas wäre nämlich auch dringend nötig. Denn wenn die im Hintergrundliegenden Fenster einfach nicht mehr reagieren würden könnte das (und wird wohl auch) den User gewaltig verwirren...
 

Volvagia

Top Contributor
Es beepst und das modale Frame bekommt den Focus. Denke schon, dass man sieht, dass umspringt, aber falls es dir nicht gefällt kannst du es ja noch modifizieren.

btw. hab vergessen in dispose super.dispose als letzte Zeile aufzurufen.
 

Paddelpirat

Bekanntes Mitglied
Bevor ich anfange solchen fehleranfälligen Code zu schreiben, würde ich mir wohl eher mal ein paar Gedanken darüber machen, wie ich das Layout so abändern kann, dass ich solche Dialoge nicht mehr benötige. Nur so als Anregung :).
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
kodela JDialog zeigt Text nicht an Allgemeine Java-Themen 5
L Exception/Error auf JDialog umleiten Allgemeine Java-Themen 2
T Code durch eigenes Frame pausieren (ähnlich JDialog) Allgemeine Java-Themen 4
S JDialog Daten ins JFrame übergeben Allgemeine Java-Themen 5
T JDialog vor Hauptfenster beim Start Allgemeine Java-Themen 5
P Trotz setModal, der JDialog ist nicht modal ? Allgemeine Java-Themen 18
B gridbaglayout und modaler jdialog Allgemeine Java-Themen 7
C Speicherverbrauch von JDialog enorm Allgemeine Java-Themen 6
D Probleme mit Browserfenster und modaler JDialog Allgemeine Java-Themen 17
J JDialog Bild als Hintergrund Allgemeine Java-Themen 19
S visible prob mit JFrame und JDialog Allgemeine Java-Themen 4
C In DefaultTableModel nachträglich Werte einfügen Allgemeine Java-Themen 2
D Best Practice Prüfen ob jar nachträglich geändert wurde Allgemeine Java-Themen 2
W LayoutManager Position der Componenten nachträglich ändern Allgemeine Java-Themen 12
C Serialisierung - Standardwert für nachträglich hinzugefügtes Feld Allgemeine Java-Themen 2
E Nachträglich umgestellt auf zusätzlichen Thread Allgemeine Java-Themen 3
M Objekt nachträglich verändern Allgemeine Java-Themen 12
D zu String[] nachträglich hinzufügen? Allgemeine Java-Themen 5

Ähnliche Java Themen

Neue Themen


Oben