I am working on a project that uses MDI form in java. I have created a frame and then added a desktop pane to it. My project uses lot of internal frames. Also those internal frames require to show custom dialogs that i have created on my own. for it to be clear, i say, one jdialog has a table asking the user to select one row. but the problem is when i call the jdialog from the internal frame (with modality=true), the dialog is show on the top of main frame and not just on the top of internal frame. This makes it impossible to minimize the window when the jdialog is showing.
In my view there are 2 possible solutions (which may not possible!!).. Either the jdialog should be shown inside the dektop pane or i should create an internal frame instead of jdialog and make it appear to be modal to the parent internal frame. i.e, when i want to show the dialog, i may disable the internal frame and set the form unable to focus and then show a new internal frame on the top of this internal frame. I have been searching the forums for weeks.. but i couldn't find an answer. I hope you would have a solution. Thanks in advance, sir.
Wow!! I got the answer from webbyt... Just avoid using internal frames.. try using the class ModalityInternalFrame (subclass of JinternalFrame).. and everything works fine.. Here is the class
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
/**
* An extended
* <code>JInternalFrame</code> that provides modality in a child/parent
* hierarchy
*
* @author webbyit
*/
public class ModalityInternalFrame extends JInternalFrame {
protected JDesktopPane desktopPane;
protected JComponent parent;
protected ModalityInternalFrame childFrame;
protected JComponent focusOwner;
private boolean wasCloseable;
public ModalityInternalFrame() {
init(); // here to allow netbeans to use class in gui builder
}
public ModalityInternalFrame(JComponent parent) {
this(parent, null);
}
public ModalityInternalFrame(JComponent parent, String title) {
this(parent, title, false);
}
public ModalityInternalFrame(JComponent parent, String title, boolean resizable) {
this(parent, title, resizable, false);
}
public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable) {
this(parent, title, resizable, closeable, false);
}
public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable,
boolean maximizable) {
this(parent, title, resizable, closeable, maximizable, false);
}
public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable,
boolean maximizable,
boolean iconifiable) {
super(title, resizable, closeable, maximizable, iconifiable);
setParentFrame(parent);
//setFocusTraversalKeysEnabled(false);
if (parent != null && parent instanceof ModalityInternalFrame) {
((ModalityInternalFrame) parent).setChildFrame(ModalityInternalFrame.this);
/*
* set focus to the new frame and show the frame Code added by Jasir
*/
try {
((ModalityInternalFrame) parent).setSelected(false);
setSelected(true);
setVisible(true);
} catch (PropertyVetoException ex) {
Logger.getLogger(ModalityInternalFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
// Add glass pane
ModalityInternalGlassPane glassPane = new ModalityInternalGlassPane(this);
setGlassPane(glassPane);
// Add frame listeners
addFrameListener();
// Add frame veto listenr
addFrameVetoListener();
init();
// calculate size and position
}
private void setParentFrame(JComponent parent) {
desktopPane = JOptionPane.getDesktopPaneForComponent(parent);
this.parent = parent == null ? JOptionPane.getDesktopPaneForComponent(parent) : parent; // default to desktop if no parent given
}
public JComponent getParentFrame() {
return parent;
}
public void setChildFrame(ModalityInternalFrame childFrame) {
this.childFrame = childFrame;
}
public ModalityInternalFrame getChildFrame() {
return childFrame;
}
public boolean hasChildFrame() {
return (childFrame != null);
}
protected void addFrameVetoListener() {
addVetoableChangeListener(new VetoableChangeListener() {
public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY)
&& evt.getNewValue().equals(Boolean.TRUE)) {
if (hasChildFrame()) {
//childFrame.setSelected(true);
if (childFrame.isIcon()) {
childFrame.setIcon(false);
}
throw new PropertyVetoException("no!", evt);
}
}
}
});
}
/**
* Method to control the display of the glass pane, dependant on the frame
* being active or not
*/
protected synchronized void addFrameListener() {
addInternalFrameListener(new InternalFrameAdapter() {
@Override
public void internalFrameActivated(InternalFrameEvent e) {
if (hasChildFrame() == true) {
getGlassPane().setVisible(true);
grabFocus();
} else {
getGlassPane().setVisible(false);
}
}
@Override
public void internalFrameOpened(InternalFrameEvent e) {
getGlassPane().setVisible(false);
try {
setSelected(true);
} catch (PropertyVetoException ex) {
Logger.getLogger(ModalityInternalFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void internalFrameClosing(InternalFrameEvent e) {
if (parent != null && parent instanceof ModalityInternalFrame) {
((ModalityInternalFrame) parent).childClosing();
}
}
});
}
/**
* Method to handle child frame closing and make this frame available for
* user input again with no glass pane visible
*/
protected void childClosing() {
setClosable(wasCloseable);
getGlassPane().setVisible(false);
if (focusOwner != null) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
moveToFront();
setSelected(true);
focusOwner.grabFocus();
} catch (PropertyVetoException ex) {
}
}
});
focusOwner.grabFocus();
}
getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
setChildFrame(null);
getDesktopPane().setSelectedFrame(this);
System.out.println(getDesktopPane().getSelectedFrame());
}
/*
* Method to handle child opening and becoming visible.
*/
protected void childOpening() {
// record the present focused component
wasCloseable = isClosable();
setClosable(false);
focusOwner = (JComponent) getMostRecentFocusOwner();
grabFocus();
getGlassPane().setVisible(true);
getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
@Override
public void show() {
if (parent != null && parent instanceof ModalityInternalFrame) {
// Need to inform parent its about to lose its focus due
// to child opening
((ModalityInternalFrame) parent).childOpening();
}
calculateBounds();
super.show();
}
protected void init() {
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 394, Short.MAX_VALUE));
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 274, Short.MAX_VALUE));
pack();
}
public void calculateBounds() {
Dimension frameSize = getPreferredSize();
Dimension parentSize = new Dimension();
Dimension rootSize = new Dimension(); // size of desktop
Point frameCoord = new Point();
if (desktopPane != null) {
rootSize = desktopPane.getSize(); // size of desktop
frameCoord = SwingUtilities.convertPoint(parent, 0, 0, desktopPane);
parentSize = parent.getSize();
}
//setBounds((rootSize.width - frameSize.width) / 2, (rootSize.height - frameSize.height) / 2, frameSize.width, frameSize.height);
// We want dialog centered relative to its parent component
int x = (parentSize.width - frameSize.width) / 2 + frameCoord.x;
int y = (parentSize.height - frameSize.height) / 2 + frameCoord.y;
// If possible, dialog should be fully visible
int ovrx = x + frameSize.width - rootSize.width;
int ovry = y + frameSize.height - rootSize.height;
x = Math.max((ovrx > 0 ? x - ovrx : x), 0);
y = Math.max((ovry > 0 ? y - ovry : y), 0);
setBounds(x, y, frameSize.width, frameSize.height);
}
/**
* Glass pane to overlay. Listens for mouse clicks and sets selected on
* associated modal frame. Also if modal frame has no children make class
* pane invisible
*/
class ModalityInternalGlassPane extends JComponent {
private ModalityInternalFrame modalFrame;
public ModalityInternalGlassPane(ModalityInternalFrame frame) {
modalFrame = frame;
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (modalFrame.isSelected() == false) {
try {
modalFrame.setSelected(true);
if (modalFrame.hasChildFrame() == false) {
setVisible(false);
}
} catch (PropertyVetoException e1) {
//e1.printStackTrace();
}
}
}
});
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(new Color(255, 255, 255, 100));
g.fillRect(0, 0, getWidth(), getHeight());
}
}
}
But there are some problems still with focus and something else..