I have a window, which is the main window in my app and it contains buttons. On clicking on one of them, a child JFrame appears and if I click again another frame appears and this can be continuous depending on how many clicks are made. What I want, is when I click on the JButton once only one frame should open and since this frame is open no other similar frames can be opened upon clicking on the button for the second time until the first child frame is closed.
This can be done by opening a Modal dialog box instead of a jFrame. See How to Use Modality in Dialogs for more information.
Here is a simple example from A Simple Modal Dialog:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class AboutDialog extends JDialog implements ActionListener {
public AboutDialog(JFrame parent, String title, String message) {
super(parent, title, true);
if (parent != null) {
Dimension parentSize = parent.getSize();
Point p = parent.getLocation();
setLocation(p.x + parentSize.width / 4, p.y + parentSize.height / 4);
}
JPanel messagePane = new JPanel();
messagePane.add(new JLabel(message));
getContentPane().add(messagePane);
JPanel buttonPane = new JPanel();
JButton button = new JButton("OK");
buttonPane.add(button);
button.addActionListener(this);
getContentPane().add(buttonPane, BorderLayout.SOUTH);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
setVisible(false);
dispose();
}
public static void main(String[] a) {
AboutDialog dlg = new AboutDialog(new JFrame(), "title", "message");
}
}
Related
I want to add a JPanel to a JLayeredPane when the user clicks enter, but the JPanel is not showing up.
If i add the JPanel to the JLayeredPane in the JFrame's constructor, everything is working correctly.
What do i have to do, that the JPanel is showing up, when the user clicks 'enter'?
Here's the code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Test extends javax.swing.JFrame {
public static void main(String[] args) {
Test test = new Test();
test.setSize(800, 500);
test.setVisible(true);
}
public Test() {
setLayout(new BorderLayout());
//LayeredPane on JFrame
JLayeredPane jlp = new JLayeredPane();
jlp.setLayout(new BorderLayout());
this.add(jlp, BorderLayout.CENTER);
//Adds a JPanel to the North
JPanel jPNorth = new JPanel();
jPNorth.setBackground(Color.RED);
jlp.add(jPNorth, BorderLayout.NORTH, JLayeredPane.DEFAULT_LAYER);
//Adds Enter Keybinding
InputMap key_input_map = jlp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap key_action_map = jlp.getActionMap();
key_input_map.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "add_jpanel");
key_action_map.put("add_jpanel", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
JPanel jPSouth = new JPanel();
jPSouth.setBackground(Color.YELLOW);
jlp.add(jPSouth, BorderLayout.SOUTH, JLayeredPane.DEFAULT_LAYER);
System.out.println("enter");
}
});
}
}
Thanks,
Jumagoro
You did everything correct, the solution is very simple. When you dynamically add swing Components to each other, you must to use component.repaint(); and component.revalidate(); to redraw the elements. Add the two commands after everything is added. So your actionPerformed method should be changed to the following:
public void actionPerformed(ActionEvent e) {
JPanel jPSouth = new JPanel();
jPSouth.setBackground(Color.YELLOW);
jlp.add(jPSouth, BorderLayout.SOUTH, JLayeredPane.DEFAULT_LAYER);
//Need these to here!
jlp.repaint();
jlp.revalidate();
System.out.println("enter");
}
What I want is like:
But the button must be clickable. Now with my SSCCE, this button cannot be clicked. But if I add the button out of this area, e.g. set the y of the bounds of this button to 0, it's no more behind the JTabbedPane's "tabs row", and thus can be clicked.
So:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
public class MigLayoutWithJTabbedPaneButton extends JFrame {
public MigLayoutWithJTabbedPaneButton() {
begin();
}
private void begin() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(null);
JTabbedPane tabsPane = new JTabbedPane();
tabsPane.setBounds(20, 20, 300, 400);
panel.add(tabsPane);
JLayeredPane tab = new JLayeredPane();
tab.setLayout(new MigLayout("insets 2 2 2 2, fillx, debug", "[]5[]5[]", "[]5[]"));
JButton button1 = new JButton("In the grid");
JButton button2 = new JButton("Out of the grid");
ActionListener ls = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(MigLayoutWithJTabbedPaneButton.this, "This can be clicked. ");
}
};
button1.addActionListener(ls);
button2.addActionListener(ls);
tab.add(button1, "cell 0 0, grow");
tabsPane.addTab("This is a tab", tab);
button2.setBounds(200, 20, 80, 20);
panel.add(button2);
getContentPane().add(panel);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MigLayoutWithJTabbedPaneButton frame = new MigLayoutWithJTabbedPaneButton();
}
});
}
}
Why? it's not the desired behaviour. The "tabs row" should not block any elements if they are at the same height of the tabs, but without any actual tabs in front of them.
My colleague told me the reason.
It has nothing to do with the layout, but just the order of adding the components. It seems that the Z axis of Java Swing behaves in a nonintuitive way: from the top layer to the bottom layer, meaning that if you add component A first and then component B, A will block B if they are in the same place. I reread the Oracle DOC and am sure that it's not mentioned anywhere!
So to get the button to work, I must first add the button and then the JTabbedPane, so the blank space of the "tabs row" will be behind the button. How strange. Swing just sucks....
I am pretty new to Swing, any help appreciated.
I have the following situation:
A "Main" Class where I define my main JPanel and default Label text.
A "GUILabel" Class (extends JLabel) where I define the look of the Text Labels.
A "popupmenu" Class (extends JPopupMenu) where I define the content of the popupmenu.
Target:
When I right-click on a panel the popupMenu should appear (this already works).
When I choose a menu item of this popupMenu, the text of the label I clicked on should change.
I guess its currently not working (I am sorry this code isn't complete - this is my 5th attempt), because I create the popup menu Once in the Main Class. Then I am adding this popup menu to each Label. So I guess thats why getInvoker() returns null in the popup menu class.
But do I really have to create a new popupmenu for each JLabel? Cant this single menu just handle all Components assigned to?
Main Frame:
package popupshit;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.border.BevelBorder;
public class Model implements ActionListener {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(0, 3));
frame.setVisible(true);
GUIPopupMenu popup = new GUIPopupMenu(9);
JLabel label1 = new GUILabel();
label1.setComponentPopupMenu(popup);
JLabel label2 = new GUILabel();
label2.setComponentPopupMenu(popup);
JLabel label3 = new GUILabel();
label3.setComponentPopupMenu(popup);
frame.add(label1);
frame.add(label2);
frame.add(label3);
frame.pack();
}
#Override
public void actionPerformed(ActionEvent e) {
((JLabel) e.getSource()).setText("" + e.getActionCommand());
}
}
PopupMenu:
package popupshit;
import java.awt.event.ActionListener;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
public class GUIPopupMenu extends JPopupMenu {
public GUIPopupMenu(int numbers) {
for (int i = 1; i < numbers; i++) {
JMenuItem popMenuItem = new JMenuItem("" + i);
popMenuItem.addActionListener ((ActionListener) this.getInvoker());
System.out.println(this.getParent());
this.add(new JMenuItem("" + i));
}
this.addSeparator();
this.add(new JMenuItem("remove"));
}
}
GUILabel:
package popupshit;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.border.BevelBorder;
import javax.swing.border.BevelBorder;
public class GUILabel extends JLabel implements ActionListener {
public GUILabel() {
this.setBorder(new BevelBorder(BevelBorder.LOWERED));
this.setVisible(true);
this.setPreferredSize(new Dimension(50, 50));
this.setText("0");
}
#Override
public void actionPerformed(ActionEvent e) {
this.setText((String) e.getActionCommand());
JOptionPane.showMessageDialog(null, "worked!" );
}
}
invoker is null because until the popup menu is a actually invoked, it has no invoker.
Instead, add a simple ActionListener to the menu item which, when invoked, uses the invoker property to determine which should occur.
My personal preference would be to create a new instance of the popup menu for each component separately, passing a reference of the component in question or some other controller as required...but that's me...
Add an ActionListener to the menu item something like:
#Override
public void actionPerformed(ActionEvent e)
{
Component c = (Component)e.getSource();
JPopupMenu popup = (JPopupMenu)c.getParent();
JLabel label = (JLabel)popup.getInvoker();
...
}
Don't extend JPopupMenu just to add a few menu items to the popup.
I have developed Swing application in which I have used JDialog to show popup.
But the problem is when I press alt+tab it shows only the dialog not the application. I also tried the modal for dialog.
My requirement is when the dialog opened on application and I press the alt+tab key it switch to another X application and again when I press alt+tab key it display dialog opened on my application. Currently it shows dialog opened but alone not with application.
How I can meet this requirement using JDialog?
Here is sample code
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
*$Id$
*/
public class Main
{
public static void main(final String[] args)
{
final JFrame jFrame = new JFrame();
jFrame.setSize(300, 200);
final JPanel panel = new JPanel();
final JButton button = new JButton("click here to open dialog");
final ProductDialog dialog = new ProductDialog();
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(final ActionEvent e)
{
dialog.setVisible(true);
}
});
panel.add(button);
jFrame.add(panel);
jFrame.setVisible(true);
}
}
And The dialog is as under
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ProductDialog extends JDialog
{
private static final long serialVersionUID = 1L;
public ProductDialog()
{
this.add(new JPanel().add(new JLabel("Test")));
this.setSize(150, 100);
this.setModal(true);
this.setLocationRelativeTo(null);
}
}
Here is an image of the visual effect of a small app. that is currently displaying a security dialog in alt+tab on Windows 7. The app. itself is already visible on-screen, though the security dialog (upper left) is all that is shown in the smaller icons.
You need to set the parent window of the dialog to the Frame of your application.
Small example:
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class TestDialog {
protected void initUI() {
JFrame frame = new JFrame(TestDialog.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JButton button = new JButton("Click me to open dialog");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window parentWindow = SwingUtilities.windowForComponent(button);
JDialog dialog = new JDialog(parentWindow);
dialog.setLocationRelativeTo(button);
dialog.setModal(true);
dialog.add(new JLabel("A dialog"));
dialog.pack();
dialog.setVisible(true);
}
});
frame.add(button);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestDialog().initUI();
}
});
}
}
I have pass the parent Frame to the Dialog as under.
final ProductDialog dialog = new ProductDialog(jFrame);
And set it as under
Call the constructor of super class with parent window as argument and set the modality type of dialog and it's work for me.
import java.awt.Dialog;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ProductDialog extends JDialog
{
private static final long serialVersionUID = 1L;
public ProductDialog(final JFrame jFrame)
{
super(jFrame);
this.add(new JPanel().add(new JLabel("Test")));
this.setSize(150, 100);
this.setModal(true);
this.setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);
}
}
This is just sample example that I have created for testing.
I am writing a small app that requires a ProgressBar to appear centred under the frame's TitleBar as is often seen in Mac OSX apps. I have two problems:
1. I have managed the positioning but I had to hard code the parent Frame's TitleBar height. Is there a 'soft' way to get the TitleBar's height?
In the Dialog's constructor:
Dimension dimensionParentFrame = parent.getSize();
Dimension dimensionDialog = getSize();
int x = parent.getX() + ((dimensionParentFrame.width - dimensionDialog.width)/2);
setLocation(x, parent.getY() + 22); // TODO HARD CODE WARNING TITLE HEIGHT
2. Even though the Dialog is modal, I can still click on the parent Frame and move it. How can I make the Dialog 'stick' to the parent Frame? That is, when the parent Frame is moved the Dialog moves with it as if attached.
Any help/pointers would be much appreciated.
Here is the code:
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ModalDialogDemoFrame extends JFrame
{
ModalDialogDemoFrame modalDialogDemo;
public ModalDialogDemoFrame()
{
modalDialogDemo = this;
setBounds(100, 100, 400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton buttonDialog = new JButton("Open Dialog");
buttonDialog.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
// Create a Modal Dialog with this Frame as Parent.
ModalDialog modalDialog = new ModalDialog(modalDialogDemo, true);
modalDialog.setVisible(true);
}
});
getContentPane().add(buttonDialog, BorderLayout.CENTER);
}
/**
* #param args
*/
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
ModalDialogDemoFrame window = new ModalDialogDemoFrame();
window.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
}
import java.awt.Dimension;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ModalDialog extends JDialog
{
public ModalDialog(JFrame parent, boolean modal)
{
super(parent, modal);
Dimension dimensionParentFrame = parent.getSize();
setSize(new Dimension((parent == null) ? 300 : dimensionParentFrame.width / 2, 75));
Dimension dimensionDialog = getSize();
int x = parent.getX() + ((dimensionParentFrame.width - dimensionDialog.width)/2);
setLocation(x, parent.getY() + parent.getInsets().top);
setUndecorated(true);
setModal(modal);
setModalityType(ModalityType.APPLICATION_MODAL);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JButton buttonClose = new JButton("Close");
buttonClose.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
dispose();
}
});
getContentPane().add(buttonClose, BorderLayout.CENTER);
}
}
int titleBarHeight = frame.getInsets().top;
Even though the Dialog is modal, I can still click on the parent Frame and move it.
Then you are doing something wrong because this should NOT happen.
Post your SSCCE that demonstrates the problem.