I'm having trouble understanding the behaviour of a modal JDialog.
When the dialog is set to visible all works fine until the user clicks back on the parent JFrame that was used to launch it. Although the dialog remains on top as expected, all subsequent mouse clicks back on the JDialog are ignored. The form items in the JDialog can still be filled in, but only if you navigate using tab. Is this normal or am I missing something obvious?
Below is a simple example that illustrates the behaviour:
import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.EventQueue;
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;
import javax.swing.JTextField;
public class TestApp {
private JFrame frame;
public TestApp() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btnRun = new JButton("run");
btnRun.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
JDialog dialog = getChildDialog();
dialog.setModalityType(ModalityType.APPLICATION_MODAL);
dialog.setVisible(true);
}
});
frame.getContentPane().add(btnRun, BorderLayout.CENTER);
}
public JDialog getChildDialog() {
JDialog dialog = new JDialog();
dialog.setModalityType(ModalityType.APPLICATION_MODAL);
dialog.setBounds(100, 100, 450, 300);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextField(), BorderLayout.CENTER);
panel.add(new JTextField(), BorderLayout.NORTH);
panel.add(new JTextField(), BorderLayout.SOUTH);
panel.add(new JLabel("Blah"), BorderLayout.EAST);
panel.add(new JLabel("Blah"), BorderLayout.WEST);
dialog.getContentPane().setLayout(new BorderLayout());
dialog.getContentPane().add(panel, BorderLayout.CENTER);
return dialog;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TestApp window = new TestApp();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Thank you for the feedback. I think this must be a bug in the JVM I'm using (OpenJDK 2.4.7 7u55-2.4.7-1ubuntu1).
I've just run the same code on a Windows Java 7 JVM and don't get the same behaviour. I will submit a bug report.
Related
My JLabel won't change to a blue background. The JLabel is already set to the blue background but it is not opaque until you press the button. Why is it still not opaque?
Does setOpaque work for if statements?
import java.awt.Color;
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.event.*;
public class TestOpaque {
public static void main (String args[])
{
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Label with blue background");
label.setBackground(Color.BLUE);
label.setOpaque(false);
frame.add(label, BorderLayout.WEST);
JButton button = new JButton("Button");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
if (label.isOpaque() == false) {
label.setOpaque(true);
label.revalidate();
}
}
});
frame.add(button, BorderLayout.EAST);
frame.pack();
frame.setVisible(true);
}
}
The if statement works fine, although better to use if (!label.isOpaque()) {
You need to redraw the GUI component via repaint() for the background to show:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!label.isOpaque()) {
label.setOpaque(true);
label.revalidate();
label.repaint();
}
}
});
I had a CardLayout example working correctly with a button, then tried to convert it to work with keypress. I think the problem is that I don't have focus, but I can't set the focus to frame or panel successfully. Thanks!
I tried requestFocusInWindow from the frame and from the first panel shown, and that didn't help. I asked frame.getFocusOwner() and it returned null.
I thought that CardLayout would give the focus to the top element automatically, but while that worked when I had a button, it is not working now.
public class MyCardLayoutExample3 {
public static void main(String[] args){
MyCardLayoutExample3 game = new MyCardLayoutExample3();
game.display();
}
void display() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(300, 200);
CardLayout cardLayout = new CardLayout();
frame.getContentPane().setLayout(cardLayout);
MyGamePanel3 mgp3 = new MyGamePanel3("minigame A", Color.red);
frame.getContentPane().add(mgp3);
frame.getContentPane().add(new MyGamePanel3("minigame B", Color.green));
frame.getContentPane().add(new MyGamePanel3("minigame C", Color.blue));
frame.setVisible(true);
System.out.println("owner: " + frame.getFocusOwner()); //this prints null
}
}
class MyGamePanel3 extends JPanel implements KeyListener{
MyGamePanel3(String text, Color bg){
JLabel textLabel = new JLabel(text);
this.setBackground(bg);
this.add(textLabel);
}
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("keyPressed worked");
}
#Override
public void keyReleased(KeyEvent e) {}
}
Changing to key bindings made the example work easily, thanks Abra. I never got the keyListener to work, despite trying the links above and many other links.
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
class MyGamePanel extends JPanel{
MyGamePanel(ActionListener alNext, String text, Color bg){
JButton buttonNext = new JButton("next");
buttonNext.addActionListener(alNext);
JLabel textLabel = new JLabel(text);
this.setBackground(bg);
this.add(textLabel);
this.add(buttonNext);
}
}
public class MyCardLayoutKeyBindingExample {
public static void main(String[] args){
MyCardLayoutKeyBindingExample game = new MyCardLayoutKeyBindingExample();
game.display();
}
void display() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(300, 200);
CardLayout cardLayout = new CardLayout();
//frame.getContentPane().setLayout(cardLayout);
JPanel mainPanel = new JPanel(cardLayout);
frame.add(mainPanel);
ActionListener al1 = e -> cardLayout.next(mainPanel);
mainPanel.add(new MyGamePanel(al1, "minigame A", Color.red));
mainPanel.add(new MyGamePanel(al1, "minigame B", Color.green));
mainPanel.add(new MyGamePanel(al1, "minigame C", Color.blue));
mainPanel.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "space");
Action kp = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.out.println("key pressed");
}
};
mainPanel.getActionMap().put("space", kp);
frame.setVisible(true);
}
}
I have a JFrame with a button labelled as "order". When that button is clicked, a dialog box comes up. This dialog box is supposed to show a summary of items that are ordered as a text view. I thought of having a string as a way to view the order, but that did not work out...
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.SwingUtilities;
import javax.swing.JRadioButton;
public class PizzaOrder3 {
PizzaOrder3() {
JFrame frame = new JFrame();
JButton order = new JButton("Order");
JPanel panel1 = new JPanel();
panel1.add(order);
frame.getContentPane().add(panel1);
panel1.setBounds(350,632,110,40);
panel1.setOpaque(false);
//Action listener for showing summary of the order
order.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JDialog d = new JDialog(frame, "Hello", true);
//Where the coding for text view is meant to go
d.setSize(400, 300);
d.setVisible(true);
}
});
frame.setLayout(null);
frame.setSize(600, 700);
frame.getContentPane().setBackground(new Color(40, 80, 120));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) {
PizzaOrder3 PizzaOrder3 = new PizzaOrder3();
}
}
I have a very basic question on 'panel'.
I have my same program below, which I want to hit on a submit button on panel 1 and my program would print a hello you hit on a submit button on panel 2.
I do not see the program print hello you hit on a submit button on panel 2 while a hit a submit button on panel 2. But when I touch the frame, then magically the hello you hit on a submit button on panel 2 appear on panel 2.
What is going on ? I don't know the answer so I would like to ask if you know why?
Attached is my code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
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.JPanel;
public class Main {
private JFrame frame = new JFrame();
private JLayeredPane lpane = new JLayeredPane();
private JPanel panelBlue = new JPanel();
private JPanel panelGreen = new JPanel();
private JButton btn1 = new JButton ("Button1");
public Main()
{
frame.setPreferredSize(new Dimension(600, 400));
frame.setLayout(new BorderLayout());
frame.add(lpane, BorderLayout.CENTER);
lpane.setBounds(0, 0, 600, 400);
panelBlue.setBackground(Color.BLUE);
panelBlue.setBounds(0, 0, 600, 400);
panelBlue.setOpaque(true);
panelBlue.add (btn1);
panelGreen.setBackground(Color.GREEN);
panelGreen.setBounds(200, 100, 100, 100);
panelGreen.setOpaque(true);
btn1.addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
panelGreen.add(new JLabel ("You click button1"));
}});
lpane.add(panelBlue, new Integer(0), 0);
lpane.add(panelGreen, new Integer(1), 0);
frame.pack();
frame.setVisible(true);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new Main();
}
}
Call panelGreen.revaliate() and panelGreen.repaint() after you add the label. Swing layouts are lazy.
#Override
public void actionPerformed(ActionEvent e) {
panelGreen.add(new JLabel ("You click button1"));
panelGreen.revaliate();
panelGreen.repaint();
}});
Calling setOpaque is irrelevant as the components are opaque to start with
My question is similar to this one: JTable Cell Update doesn't work.
However, I am using JDialog instead of a JTable specified in above link. I have a custom class which extends JDialog. I use JEditorPane as a text-component in that dialog and create simple OK, Cancel buttons. Now the problem is, when I enter something in the JEdiorPane and presses OK button, the value is not applied to the text-component until I move the focus out of a JDialog or hit tab/ENTER.
I want the container to be notified that I am done with editing as soon as I press the OK button. In short I want to explicitly have a feature similar to stopCellEditing(). How can I do that?
See this example which seems to work correctly and does the same thing as you described:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class TestEditorPaneDialog {
public void init() {
final JFrame frame = new JFrame();
JButton clickMe = new JButton("Click me");
clickMe.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
showDialog(frame);
}
});
frame.add(clickMe);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
showDialog(frame);
}
private void showDialog(final JFrame frame) {
final JDialog dialog = new JDialog(frame, true);
final JEditorPane pane = new JEditorPane();
pane.setText("Type something here");
JPanel south = new JPanel();
JPanel buttons = new JPanel(new GridLayout(1, 0, 10, 10));
JButton ok = new JButton("OK");
ok.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
JOptionPane.showMessageDialog(frame, "You have typed in: " + pane.getText());
}
});
JButton cancel = new JButton("Cancel");
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
buttons.add(ok);
buttons.add(cancel);
south.add(buttons);
dialog.add(new JScrollPane(pane));
dialog.add(south, BorderLayout.SOUTH);
dialog.setSize(250, 150);
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestEditorPaneDialog().init();
}
});
}
}