I want to update my look and feel by JRadioButtonMenuItem. And I searching in Stackoverflow but what I find was a big bunch of code in 1 class. For me as a beginner its easier to seperate function in a special class.
That is my Frame-Class.
public class CalenderFrame extends JFrame {
public CalenderFrame() throws HeadlessException {
createFrame();
}
public void createFrame() {
setJMenuBar(CalenderMenuBar.getInstance().createMenu());
setTitle("Calender");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(400, 300));
pack();
setLocationRelativeTo(null);
setVisible(true);
}
}
And that is my MenueBar Class. I just give a short one of Code that is specific for this question. This class is an Singleton.
public JMenuBar createMenu() {
JMenu lookAndFeelMenu = new JMenu("Look & Feel");
JRadioButtonMenuItem lAndFWindowsItem = new JRadioButtonMenuItem("Windows",true);
lAndFWindowsItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == lAndFWindowsItem) {
lAndFAction(1);
}
}
});
JRadioButtonMenuItem lAndFMetalItem = new JRadioButtonMenuItem("Metal",false);
lAndFMetalItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == lAndFMetalItem) {
lAndFAction(2);
}
}
});
JRadioButtonMenuItem lAndFMotifItem = new JRadioButtonMenuItem("Motif", false);
lAndFMotifItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == lAndFMotifItem) {
lAndFAction(3);
}
}
});
ButtonGroup group = new ButtonGroup();
group.add(lAndFWindowsItem);
group.add(lAndFMetalItem);
group.add(lAndFMotifItem);
lookAndFeelMenu.add(lAndFWindowsItem);
lookAndFeelMenu.add(lAndFMetalItem);
lookAndFeelMenu.add(lAndFMotifItem);
}
public void lAndFAction(int counter) {
try {
String plaf = "";
if (counter == 1) {
plaf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
} else if (counter == 2) {
plaf = "javax.swing.plaf.metal.MetalLookAndFeel";
} else if (counter == 3) {
plaf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
}
UIManager.setLookAndFeel(plaf);
//SwingUtilities.updateComponentTreeUI(this);
} catch (UnsupportedLookAndFeelException ue) {
System.err.println(ue.toString());
} catch (ClassNotFoundException ce) {
System.err.println(ce.toString());
} catch (InstantiationException ie) {
System.err.println(ie.toString());
} catch (IllegalAccessException iae) {
System.err.println(iae.toString());
}
}
}
I hope you guys can help me.
I'm not sure what your problem actually is. But, you must update your components after changing the LaF. According to the Look and Feel Documentation:
Changing the Look and Feel After Startup
You can change the L&F with setLookAndFeel even after the program's
GUI is visible. To make existing components reflect the new L&F,
invoke the SwingUtilities updateComponentTreeUI method once per
top-level container. Then you might wish to resize each top-level
container to reflect the new sizes of its contained components. For
example:
UIManager.setLookAndFeel(lnfName);
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();
Therefore, you would need a reference to the frame holding the components in your UI. An idea would be doing something like:
public class CalendarMenuBar {
// Add this field to tour factory
private static JFrame frameThatWillBeUpdated;
// ... (Your code goes here)
// update this method to receive the reference of the frame which will
// need to be refreshed (update the GUI)
public JMenuBar createMenu(JFrame frame) {
// sets the reference for the frame
frameThatWillBeUpdated = frame;
// ... (the rest of your code for this method)
}
// ...
// Update this method to refresh the frame
public void lAndFAction(int counter) {
try{
// ... (your code)
// Set the LaF
UIManager.setLookAndFeel(plaf);
// Update the component tree (frame and its children)
SwingUtilities.updateComponentTreeUI(frameThatWillBeUpdated);
// repack to resize
frame.pack();
} catch(Exception ex){
// Your catches
}
}
}
And here is how you use it when creating your frame (inside your CalenderFrame class):
public void createFrame() {
// use this frame as reference
setJMenuBar(CalenderMenuBar.getInstance().createMenu(this));
// ... (your code goes here)
}
I have a simple swing application with two JTextPanes. In the first I write a html code and in the second I get the appearance defined by this html. I want to have button which allows me to insert a table into the document.
Here is my code:
public class TestEditor extends JFrame {
public TestEditor(){
createConnection();
createGUI();
}
private void createGUI(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
JScrollPane scroll1=new JScrollPane(text);
JScrollPane scroll2=new JScrollPane(html);
JSplitPane split=new JSplitPane();
split.setLeftComponent(scroll1);
split.setRightComponent(scroll2);
split.setDividerLocation(0.5);
split.setResizeWeight(0.5);
getContentPane().add(split);
table=new JButton("Insert table");
table.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
StringBuilder builder=new StringBuilder("<table border=1>\n");
for(int i=0;i<4;i++){
builder.append("<tr>");
for(int j=0;j<4;j++){
builder.append("<td></td>");
}
builder.append("</tr>\n");
}
builder.append("</table>\n");
try{
text.getStyledDocument().insertString(text.getCaretPosition(), builder.toString(), null);
}catch(BadLocationException ex){
ex.printStackTrace();
}
}
});
getContentPane().add(table, BorderLayout.SOUTH);
setTitle("Test");
setPreferredSize(new Dimension(600,300));
pack();
}
private void createConnection(){
text=new JTextPane();
html=new JTextPane();
html.setContentType("text/html");
html.getStyledDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
update();
}
#Override
public void removeUpdate(DocumentEvent e) {
update();
}
#Override
public void changedUpdate(DocumentEvent e) {
update();
}
private void update(){
if(fromText) return;
fromHtml=true;
text.setText(html.getText());
fromHtml=false;
}
});
text.getStyledDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
update();
}
#Override
public void removeUpdate(DocumentEvent e) {
update();
}
#Override
public void changedUpdate(DocumentEvent e) {
update();
}
private void update(){
if(fromHtml) return;
fromText=true;
html.setText(text.getText());
fromText=false;
}
});
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new TestEditor().setVisible(true);
}
});
}
private JTextPane text;
private JTextPane html;
private boolean fromHtml, fromText;
private JButton table;
}
However, this inserts a table in the wrong place, most often after the ending tag </html>. My goal is to insert the table in the place in which caret is on the right editor.
What should I do? How to detect the proper position?
I tested your code, and it fails when you are editing the styled document, but it works when you edit the text document. The reason is simple: when a call to update() occurs, the use of setText() puts the caret at the end of the document. The html code is then naturally inserted at the end.
So ideally you would want to keep track of the caret position and cleverly update it after setText(). But this is not easy: How do you manage inserted or removed text?
So here is a proposal: When the "add table" button is clicked, detect which editor has focus (= where the caret position is relevant), and insert the html code in the corresponding one.
However, inserting html code in the styled document will be done slightly differently (to avoid being escaped):
HTMLEditorKit kit = (HTMLEditorKit) html.getEditorKit();
HTMLDocument doc = (HTMLDocument) html.getStyledDocument();
kit.insertHTML(doc, html.getCaretPosition(), builder.toString(), 0, 0, null);
So you should get something like that:
Component c = getFocusOwner();
if(c==html){
HTMLEditorKit kit = (HTMLEditorKit) html.getEditorKit();
HTMLDocument doc = (HTMLDocument) html.getStyledDocument();
kit.insertHTML(doc, html.getCaretPosition(), builder.toString(), 0, 0, null);
}else if(c==text){
text.getStyledDocument().insertString(text.getCaretPosition(), builder.toString(), null);
}
Also, make the button unfocusable to avoid getFocusOwner() to detect the button click:
table.setFocusable(false);
I'm blocked with a probelm about Java and the use of JTree:
I want to create a JTree with, node by node, some JButtons components (or Images, I don't mind), like in the following picture. It will be 3 or 4 buttons in the same row. I succeed to do that.
But where I'm blocked is when I want to add a mouselistener on each of this button to manage their tooltip or an action on them.
In fact the JTree component is most of the time used to manage the action on the full node, but not on its inside components.
I did a short code, in comparaison at the real big code I have to work in, to quickly test what I say:
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.event.*;
import java.awt.*;
import java.io.IOException;
import java.net.URL;
public class TreeWithPopup extends JPanel {
DefaultMutableTreeNode root, node1, node2, node3;
public TreeWithPopup() {
MyJTree tree;
root = new DefaultMutableTreeNode("root", true);
node1 = new DefaultMutableTreeNode("node 1", true);
node2 = new DefaultMutableTreeNode("node 2", true);
node3 = new DefaultMutableTreeNode("node 3", true);
root.add(node1);
node1.add(node2);
root.add(node3);
setLayout(new BorderLayout());
tree = new MyJTree(root);
tree.setCellRenderer(new PCellRenderer());
add(new JScrollPane((JTree) tree), "Center");
}
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
public static void main(String s[]) {
JFrame frame = new JFrame("Tree with button");
TreeWithPopup panel = new TreeWithPopup();
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setForeground(Color.black);
frame.setBackground(Color.lightGray);
frame.getContentPane().add(panel, "Center");
frame.setSize(panel.getPreferredSize());
frame.setVisible(true);
frame.addWindowListener(new WindowCloser());
}
}
class WindowCloser extends WindowAdapter {
public void windowClosing(WindowEvent e) {
Window win = e.getWindow();
win.setVisible(false);
System.exit(0);
}
}
class MyJTree extends JTree implements ActionListener {
MyJTree(DefaultMutableTreeNode dmtn) {
super(dmtn);
addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent arg0) {
System.out.println("JTree.MouseListener");
}
public void mouseEntered(MouseEvent arg0) {
System.out.println("JTree.MouseListener");
}
public void mouseExited(MouseEvent arg0) {
System.out.println("JTree.MouseListener");
}
public void mousePressed(MouseEvent arg0) {
System.out.println("JTree.MouseListener");
}
public void mouseReleased(MouseEvent arg0) {
System.out.println("JTree.MouseListener");
}
});
}
public void actionPerformed(ActionEvent ae) {
System.out.println("MyJTree.ActionPerformed");
}
}
class PCellRenderer extends DefaultTreeCellRenderer {
public Component getTreeCellRendererComponent(JTree ptree, Object pvalue, boolean psel, boolean pexpanded, boolean pleaf, int prow,
boolean phasFocus) {
Box myPanel = new Box(BoxLayout.X_AXIS);
JButton myButton = new JButton("test");
Image imgToUse = null;
Image imgRollOver = null;
try {
URL urlIcon = new URL("file:///C:/1.jpg"); // <===== change their the path to icons
imgToUse = ImageIO.read(urlIcon);
urlIcon = new URL("file:///C:/2.jpg"); // <===== change their the path to icons
imgRollOver = ImageIO.read(urlIcon);
} catch (IOException e) {
e.printStackTrace();
}
myButton.setRolloverIcon(new ImageIcon(imgRollOver));
myButton.setIcon(new ImageIcon(imgToUse));
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
System.out.println(" detected on ");
}
});
myButton.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent arg0) {
System.out.println("myButton.MouseListener");
}
public void mouseEntered(MouseEvent arg0) {
System.out.println("myButton.MouseListener");
}
public void mouseExited(MouseEvent arg0) {
System.out.println("myButton.MouseListener");
}
public void mousePressed(MouseEvent arg0) {
System.out.println("myButton.MouseListener");
}
public void mouseReleased(MouseEvent arg0) {
System.out.println("myButton.MouseListener");
}
});
myPanel.add(myButton);
return myPanel;
}
}
You just have to change the icon path or put the two following icons at "c:/"
I also searched to use the x/y position of the row event but I was unable to find the position of my button after rendering.
If anyone can have an idea how to do that, he could be very helpful.
Thanks, at least for read this question ;-)
Tooltip support is actually provided by the TableCellRenderer directly. Your TableCellRenderer is a little muddled. It extends from DefaultTreeCellRenderer but makes no use of any of it's features, instead creating a new Box, JButton and loading icons each time a cell is rendered...
This is going to increase your memory usage a slow you application down...
Instead, try something like...
class PCellRenderer extends Box implements TreeCellRenderer {
private Image imgToUse = null;
private Image imgRollOver = null;
public PCellRenderer() {
super(BoxLayout.X_AXIS);
JButton myButton = new JButton("test");
try {
URL urlIcon = new URL("file:///C:/1.jpg"); // <===== change their the path to icons
imgToUse = ImageIO.read(urlIcon);
urlIcon = new URL("file:///C:/2.jpg"); // <===== change their the path to icons
imgRollOver = ImageIO.read(urlIcon);
} catch (IOException e) {
e.printStackTrace();
}
myButton.setRolloverIcon(new ImageIcon(imgRollOver));
myButton.setIcon(new ImageIcon(imgToUse));
add(myButton);
}
public Component getTreeCellRendererComponent(JTree ptree, Object pvalue, boolean psel, boolean pexpanded, boolean pleaf, int prow,
boolean phasFocus) {
// set the tooltip text here...
// Maybe change the icon...
return this;
}
}
Now, actually doing something...
Renderers are rubber stamps. That are not actually life components. Think of them like photos. You can take a snap shot of your friends, but you can't interact with them...same thing here...
Your idea of a MouseListener on the JTree is a correct one, in fact the JavaDocs actually have a demonstration of this...
public void mousePressed(MouseEvent e) {
int selRow = tree.getRowForLocation(e.getX(), e.getY());
TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
if(selRow != -1) {
if(e.getClickCount() == 1) {
mySingleClick(selRow, selPath);
}
else if(e.getClickCount() == 2) {
myDoubleClick(selRow, selPath);
}
}
}
So I created a simple JFrame and added a JTextPane to it to create a sorta console..
I have the following methods and variables in my class which is supposed to change the colour of text in the JTextPane.
private static final Object CurrentConsoleAttributes[] = new Object[4];
private static final SimpleAttributeSet ConsoleAttributes = new SimpleAttributeSet();
public Object[] getConsoleAttributes() {
CurrentConsoleAttributes[0] = StyleConstants.getForeground(ConsoleAttributes);
CurrentConsoleAttributes[1] = StyleConstants.getBackground(ConsoleAttributes);
CurrentConsoleAttributes[2] = StyleConstants.isBold(ConsoleAttributes);
CurrentConsoleAttributes[3] = StyleConstants.isItalic(ConsoleAttributes);
return CurrentConsoleAttributes;
}
public void setConsoleAttributes(Color Foreground, Color Background, boolean Bold, boolean Italics) {
synchronized(ConsoleAttributes) {
StyleConstants.setForeground(ConsoleAttributes, Foreground);
StyleConstants.setBackground(ConsoleAttributes, Background);
StyleConstants.setBold(ConsoleAttributes, Bold);
StyleConstants.setItalic(ConsoleAttributes, Italics);
}
}
private void setOutputAreaText(final String Text) {
SwingUtilities.invokeLater(new Runnable() { //I read that I need to use this when dealing with swing and JTextPane is a swing component.
#Override
public void run() {
try {
StyledDocument Document = Frame.this.OutputArea.getStyledDocument();
Document.insertString(Document.getLength(), Text, ConsoleAttributes);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
});
}
public void WriteLine(Object Value) {
try {
System.out.print("Hey");
setConsoleAttributes(java.awt.Color.red, Color.white, true, false);
System.out.print("Testing");
setConsoleAttributes(java.awt.Color.blue, Color.white, true, false);
System.out.println("Printing");
} catch (Exception Ex) {
Ex.printStackTrace();
}
}
However, when I call WriteLine, the entire line is written in blue or whatever colour was used last. Any ideas what I'm missing?
I followed approach 2 of this guide, so now I have a ModalInternalFrame that blocks input to all other frames, just as I wanted. However, I made one change from the example, and now I have two problems.
The Change
I removed the JOptionPane, because the whole point is to show my own pane. In order to make it close, I set closeable to true, and added an InternalFrameListener with the same code as the example's listener for the JOptionPane. That doesn't work, so I also added code at the end of doDefaultCloseAction.
The Problems
The ModalInternal frame never goes away. I think some exception is being thrown but...
I can't see any thrown exceptions, and I don't know where they're going. Usually when in debug mode, Eclipse will stop right before the exception is given to the UncaughtExceptionHandler, but that isn't happening in this case.
The Code
If my description of the problem doesn't help, here's my version of the ModalInternalFrame. If you want more code, I can post that as well. Sorry it's so long, but I tried to make it as concise as possible.
public class ModalInternalFrame extends JInternalFrame {
public ModalInternalFrame(String title, JRootPane rootPane,
Component desktop) {
super(title, false, true, false, false);
// create opaque glass pane
final JPanel glass = new JPanel();
glass.setOpaque(false);
// Attach mouse listeners
MouseInputAdapter adapter = new MouseInputAdapter() { };
glass.addMouseListener(adapter);
glass.addMouseMotionListener(adapter);
this.addInternalFrameListener(new InternalFrameListenerAdapter() {
public void internalFrameClosed(InternalFrameEvent e) { close(); }
public void internalFrameClosing(InternalFrameEvent e){ close(); }
});
// Change frame border
putClientProperty("JInternalFrame.frameType", "optionDialog");
// Size frame
Dimension size = getPreferredSize();
Dimension rootSize = desktop.getSize();
setBounds((rootSize.width - size.width) / 2,
(rootSize.height - size.height) / 2, size.width, size.height);
desktop.validate();
try { setSelected(true); }
catch (PropertyVetoException ignored) { }
glass.add(this); // Add modal internal frame to glass pane
rootPane.setGlassPane(glass); // Change glass pane to our panel
glass.setVisible(true); // Show glass pane, then modal dialog
}
private void close(){
if (isVisible()) {
try { setClosed(true); }
catch (PropertyVetoException ignored) { }
setVisible(false);
rootPane.getGlassPane().setVisible(false);
}
}
#Override public void doDefaultCloseAction() {
super.doDefaultCloseAction();
close();
}
#Override public void setVisible(boolean flag) {
super.setVisible(flag);
if (flag) startModal();
else stopModal();
}
private synchronized void startModal() {
try {
if (SwingUtilities.isEventDispatchThread()) {
EventQueue theQueue = getToolkit().getSystemEventQueue();
while (isVisible()) {
AWTEvent event = theQueue.getNextEvent();
Object source = event.getSource();
if (event instanceof ActiveEvent) {
((ActiveEvent) event).dispatch();
} else if (source instanceof Component) {
((Component) source).dispatchEvent(event);
} else if (source instanceof MenuComponent) {
((MenuComponent) source).dispatchEvent(event);
} else {
System.err.println("Unable to dispatch: " + event);
}
}
} else { while (isVisible()) { wait(); } }
} catch (InterruptedException ignored) {
}
}
private synchronized void stopModal() { notifyAll(); }
}
Update: I've discovered that modal dialog boxes suit my needs fine, but if anyone does have an idea, I'd be glad to hear it. One thing I haven't tried is wrapping every method in a try {} catch (Exception e){} which would probably help a lot.
I can't quite get your code to run, but here's a simpler version, based on the Sun example, that does work -- the main frame has a button in it (taking up all the available space), but clicking the button is blocked until the internal frame has been closed.
You can see, pretty much all I did was replace the new JOptionPane().createInternalFrame() business with my own frame. My guess is that you're overcomplicating things when you try to do your own event dispatching.
Or am I missing something?
public class Foo {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(600, 400);
frame.setLocationByPlatform(true);
JButton desktop = new JButton(new AbstractAction("Click me if you can") {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("I have been clicked");
}
});
frame.getContentPane().add(desktop);
frame.setVisible(true);
JInternalFrame modal =
new JInternalFrame("Modal Popup", false, true, false, false);
JLabel popupContent = new JLabel("I am the popup");
popupContent.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
modal.add(popupContent);
modal.pack();
JPanel glass = new JPanel();
glass.setOpaque(false);
glass.add(modal);
frame.setGlassPane(glass);
glass.setVisible(true);
modal.setVisible(true);
modal.addInternalFrameListener(new ModalAdapter(glass));
}
}
class ModalAdapter extends InternalFrameAdapter {
Component glass;
public ModalAdapter(Component glass) {
this.glass = glass;
// Associate dummy mouse listeners
// Otherwise mouse events pass through
MouseInputAdapter adapter = new MouseInputAdapter() {
};
glass.addMouseListener(adapter);
glass.addMouseMotionListener(adapter);
}
public void internalFrameClosed(InternalFrameEvent e) {
glass.setVisible(false);
}
}
Try this. I got it from the Webby IT blog post on JInternal Frames: http://webbyit.blogspot.com/2011/03/managing-jinternalframes-within.html
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.
* source: webby it internal frames blog post
*
* #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());
}
}
}
I just had to do this thing for a project. All I did was passed the main window object to Jinternalframe. The main object has a semaphore that tracks whether modal is locked or not. Upon closing the Jinternalframe (extension) calls the main object's semaphore. Very simple.
This is not the main code but you get the idea :
//called frame
public CallingFrame parent;
public void setParent(CallingFrame parent_){
this.parent=parent_;
}
private void frameClosed(javax.swing.event.InternalFrameEvent evt) {
parent.modalLocked=false;
}
In my case the application uses a label with image-parts to call internalframes, so the code starts with
//calling frame
CalledFrame cf=new CalledFrame();
cf.setParent(this);
cf.setVisible(true);
modalLoacked=true;
private void jLabel1MouseReleased(java.awt.event.MouseEvent evt) {
if (modalLocked)
return;
else// (do your things)
}
I followed the tutorials but most of them are overcomplicating things when a single semaphore will do the tricks of not letting you click on any area while one Called Frame is not closed.
public void internalFrameClosing(InternalFrameEvent e){ close(); }
calling close() will cause internalFrameClosing() to be called again, until the stack overflows.
Try removing that listener altogether.
You can just add setClosable(true); in the constructor