JFrame stops receiving mouse events - java

I have a JFrame, which represents the GUI for my Java application.
I have a custom button, derived from JComponent and created and placed on this JFrame. On pressing this button a modal dialog appears.
The problem is, that after modal dialog appears, the JFrame stops receiving mouse events from mouse. I opened Spy++ and found out that MouseEvents from Windows are passed to the JFrame. So they are switched off somewhere in Java.
I need to receive button events for one thing - when mouse enters my custom button area, button changes color. And I need to know when the mouse exits the button area, to change the button to it's original color. The same problem is with standard JButton - it remains hovered after modal dialog appears.
Of course I can track the opening of modal dialog myself, and make my button unhovered, but just curious, if there is standard solution.
You see, that the button on the JFrame remains hovered as the dialog appears.
package quixote.sscce;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class FrameTop extends JFrame implements MouseListener, ActionListener {
private JButton button;
public FrameTop() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(200, 200);
setLocation(100, 100);
setLayout(new BorderLayout());
button = new JButton("Click me");
add(button, BorderLayout.CENTER);
button.addActionListener(this);
addMouseListener(this);
}
#Override
public void actionPerformed(ActionEvent arg0) {
JDialog dialog = new JDialog(this, "dialog");
dialog.setModal(true);
dialog.setLocation(150, 150);
dialog.setSize(100, 100);
dialog.setVisible(true);
}
private int aaa = 0;
#Override
public void mouseClicked(MouseEvent arg0) {
System.out.println("XXX " + aaa);
}
#Override
public void mouseEntered(MouseEvent arg0) {
System.out.println("XXX " + aaa);
}
#Override
public void mouseExited(MouseEvent arg0) {
System.out.println("XXX " + aaa);
}
#Override
public void mousePressed(MouseEvent arg0) {
System.out.println("XXX " + aaa);
}
#Override
public void mouseReleased(MouseEvent arg0) {
System.out.println("XXX " + aaa);
}
public static void main(String args[]) {
final FrameTop top = new FrameTop();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
top.setVisible(true);
}
});
}
}

I think you might have forgot set opaque ie. setOpaque(true).
This will allow you to change background colour of frame and for button button.setOpaque(true).
Try it, it may help you.

Use non modal dialog, and call dialog.setAlwaysOnTop(true);
hope this helps

Related

Avoid JOptionPane interference with action listeners

I have noticed that all JOptionPane method "interfere" with ActionListeners.
I need ActionListener to remain active after a JOptionPane has been opened.
For example:
I have a JButton, I register the mouse being pressed and draw the button red. Upon being released, I draw it blue.
If I just click it, the button will turn blue. Ok
If I hold it clicked, the button will stay red. Ok
If I click it and set it to open a JOptionPane dialog, it stays red, even though I have released the mouse. Not Ok
I haven't been able to find any documentation on this specific behaviour, can someone point me in the right direction?
I do really need to use JOptionPane.
One option -- queue the call to open the JOptionPane on the Swing event queue. This will delay the opening of the modal JOptionPane just a little bit, allowing other button actions to be performed.
Another option is to extract the JDialog from the JOptionPane, and call it in a non-modal way.
For example:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestOptionPane extends JPanel {
private static final Color FOREGROUND = Color.RED;
private static final Color PRESSED_FG = Color.BLUE;
private JButton button1 = new JButton(new Button1Action());
private JButton button2 = new JButton(new Button1Action());
public TestOptionPane() {
setPreferredSize(new Dimension(600, 450));
button1.getModel().addChangeListener(new ButtonModelListener(button1));
button1.setForeground(FOREGROUND);
add(button1);
button2.getModel().addChangeListener(new ButtonModelListener(button2));
button2.setForeground(FOREGROUND);
add(button2);
}
private class Button1Action extends AbstractAction {
public Button1Action() {
super("Queue JOptionPane on Swing event thread");
}
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(TestOptionPane.this, "hello");
});
}
}
private class Button2Action extends AbstractAction {
public Button2Action() {
super("Show non-modal JOptionPane");
}
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(() -> {
Component parentComponent = TestOptionPane.this;
JOptionPane optionPane = new JOptionPane("Hello", JOptionPane.PLAIN_MESSAGE);
JDialog dialog = optionPane.createDialog(parentComponent, "Fubars Rule!");
dialog.setModalityType(ModalityType.MODELESS);
dialog.setLocationRelativeTo(parentComponent);
dialog.setVisible(true);
});
}
}
private class ButtonModelListener implements ChangeListener {
private JButton button;
public ButtonModelListener(JButton button) {
this.button = button;
}
#Override
public void stateChanged(ChangeEvent e) {
ButtonModel model = (ButtonModel) e.getSource();
if (model.isPressed()) {
button.setForeground(PRESSED_FG);
} else {
button.setForeground(FOREGROUND);
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("TestOptionPane");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new TestOptionPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

Swing mouseEntered strange behavior

I have a jframe with some JComponents, with some mouseListener. My aim is to show a little jframe with a specified text, when the mouse enter on a jlabel, and to show off it when the mouse is exited.
Jframe is supposed to be shown near the mouse.
Anyway that does not happen, and the programm behaves in a very strange way.
Why?
the bug
That's my code
package finestrina;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class finestra implements MouseListener{
private JFrame finestra = new JFrame();
private JFrame pagina = new JFrame();
private JButton submit1 = new JButton("press");
private JTextField text = new JTextField();
finestra(){
pagina.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pagina.setSize(500, 500);
JPanel cont = new JPanel();
cont.setLayout(new GridLayout(3,4));
JLabel label = new JLabel();
label.setText("ON MOUSEROVER THIS");
cont.add(label);
label.addMouseListener(this);
submit1.addMouseListener(this);
text.addMouseListener(this);
cont.add(submit1);
cont.add(text);
pagina.add(cont);
pagina.setVisible(true);
finestra.setUndecorated(true);
}
#Override
public void mouseClicked(MouseEvent arg0) {}
#Override
public void mouseEntered(MouseEvent event) {
if(event.getSource() instanceof JLabel){
JLabel event_casted = (JLabel)event.getSource();
if(event_casted.getText().equals("ON MOUSEROVER THIS")){
Point punto = event.getLocationOnScreen();
punto.setLocation(punto.getX()+20, punto.getY()+20);
JLabel littlelabel = new JLabel();
littlelabel.setText("your mouse is on the jlabel");
finestra.add(littlelabel);
finestra.setLocation(punto);
finestra.setSize(100,100);
finestra.setVisible(true);
}
}
}
#Override
public void mouseExited(MouseEvent event) {
if(event.getSource() instanceof JLabel){
JLabel event_casted = (JLabel)event.getSource();
if(event_casted.getText().equals("ON MOUSEROVER THIS")){
finestra.setVisible(false);
}
}
}
#Override
public void mousePressed(MouseEvent event) {
}
#Override
public void mouseReleased(MouseEvent arg0) {}
public static void main(String[] args0){
new finestra();
};
}
There are a number of (possible) issues
The GridLayout will cause the component to occupy most of the space of the container, which might cause the window to "appear" to popup earlier then you expect
finestra.add(event_casted); is causing the label to be removed from it's current parent container (the main window), as a component can only belong to a single container
It would, generally be better to use the tooltip support provided by the API. Maybe have a look at How to Use Tool Tips, remember, they can also support HTML.
If that's not functionality what you want, then maybe a JPopupMenu might be better

KeyListener doesn't detect key presses

In my JFrame I have this listener:
this.addKeyListener(new KeyAdapter(){
#Override
public void keyPressed(KeyEvent arg0) {
//do stuff
}
});
This has been working fine until about 10 minutes ago. Now when I press a key, keyPressed() never even gets called. I tested this with eclipse debugger.
I have no idea what happened. Any ideas?
EDIT #1: This is also happening with a button that I have set up. the action listener does not recognize when the button is clicked.
EDIT #2: Ok So I was able to narrow it down. I have a JFrame, this frame has a main panel and also 2 action listeners (keyListener, the problematic one, and a mouse click listener, working fine). The main panel has two subpanels a and b. panel a has 2 buttons, one is not set up yet. It seems that these buttons are somehow conflicting with the keylistener making it so the key listener and buttons do not work. either way the mouse click listener still works.
Edit #3: Ok here is some simplified code:
The button is working, but the keyListener is not. I am hearing about focus a lot, if this is the problem how can I fix it?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ListenerTest extends JFrame {
private JPanel mainPanel;
private JPanel panelA;
private JPanel panelB;
private JButton buttonA;
private JButton buttonB;
public ListenerTest() {
mainPanel = new JPanel();
panelA = new JPanel();
panelB = new JPanel();
buttonA = new JButton("Button A");
buttonB = new JButton("Button B");
this.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent arg0) {
System.out.println(arg0.getKeyChar());
}
});
this.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e) {
System.out.println(e.getX() + ", " + e.getY());
}
});
buttonA.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Button A pressed!");
}
});
panelA.add(buttonA);
panelA.add(buttonB);
mainPanel.add(panelA);
mainPanel.add(panelB);
this.add(mainPanel);
this.setSize(300, 300);
this.setVisible(true);
}
public static void main(String args[]) {
new ListenerTest();
}
}
When you add an action for a specific key (for example: F2) to panelA, this seems to work:
public ListenerTest() {
// Create components...
panelA.getActionMap().put("saveAction", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("F2");
}
});
//panelA.getInputMap().put(KeyStroke.getKeyStroke("F2"), "saveAction");
panelA.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke("F2"), "saveAction");
//this.addKeyListener(new KeyAdapter() {
//mainPanel.addKeyListener(new KeyAdapter() {
panelA.addKeyListener(new KeyAdapter() {
//buttonA.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent arg0) {
System.out.println("Panel A: " + arg0.getKeyChar());
}
});
// Rest of the code...
}
Adding the action also seems to have a side effect: the KeyListener seems to work again for panelA. The focus no longer goes to one of the buttons by default.
Note: when using panelA.getInputMap(), the key action only works when the buttons do not have the focus. Use panelA.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) to make sure the action works when one of the buttons has the focus.

getRootPane() default button - Is this a bug?

I have made an SSCCE. Please note that it must be Windows Look&Feel.
import java.awt.*;
import javax.swing.*;
public class DefaultButtonBug {
private static final String LAF_WINDOWS = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(LAF_WINDOWS);
} catch (Exception ex) {
System.out.println("Setting the L&F failed so I cannot reproduce the bug.");
System.exit(1);
}
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JPanel content = new JPanel();
JButton defaultButton = new JButton("Default");
content.add(defaultButton);
JFrame frame = new JFrame();
frame.getRootPane().setDefaultButton(defaultButton);
frame.setContentPane(content);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
Launch this
The button should be focused. If not, click it.
Click on any other window, to make sure this current window loses the focus
The button keeps animating in blue tints, even when this window has no focus anymore!
The button 'pulsing' animation is something not present in the standard Java L&F.
Remark that when this button is no longer the default button (remove the appropriate line in the code), the button will be gray after the window loses focus and there is no animation whatsoever.
My question to you is: is this considered a bug? Because this makes the EDT keep doing stuff instead of being idle when the window is hidden behind another window too (I did some profiling). Indeed, that's the stuff that bothers me the most of all: hiding the window does not make the EDT go idle.
getRootPane() default button - Is this a bug?
not as described in a comment by #Guillaume Polet
but I'd be inclined to use KeyBindings, because any JComponents with FocusInWindow and added ActionListener can consume() ENTER key pressed, for all JButtons JComponents
focus is managable by getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT/*.WHEN_FOCUSED*/)
notice (Win OS) JButton has implemented TAB as an accelerator in KeyBindings, too.
from code
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class DefaultButtonBug {
private static final String LAF_WINDOWS = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(LAF_WINDOWS);
} catch (Exception ex) {
System.out.println("Setting the L&F failed so I cannot reproduce the bug.");
System.exit(1);
}
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JPanel content = new JPanel();
JButton focusedButton1 = new JButton("Focused");
focusedButton1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Focused pressed");
}
});
content.add(focusedButton1);
final JButton defaultButton2 = new JButton("Default");
defaultButton2.setIcon(UIManager.getIcon("OptionPane.informationIcon"));
defaultButton2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Default pressed");
}
});
defaultButton2.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
ButtonModel model = (ButtonModel) e.getSource();
if (model.isRollover()) {
defaultButton2.setIcon(UIManager.getIcon("OptionPane.errorIcon"));
} else {
defaultButton2.setIcon(UIManager.getIcon("OptionPane.informationIcon"));
}
}
});
content.add(defaultButton2);
JFrame frame = new JFrame();
frame.getRootPane().setDefaultButton(defaultButton2);
frame.getRootPane().getInputMap(
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT/*.WHEN_FOCUSED*/)
.put(KeyStroke.getKeyStroke("ENTER"), "clickButton");
frame.getRootPane().getActionMap().put("clickButton", new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
defaultButton2.doClick();
}
});
frame.getRootPane().setDefaultButton(defaultButton2);
frame.setContentPane(content);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
learning item of day
on Win7/8 (Java6/7) are allowed mouse event on un_focused Java Window (for all standard L&F), can be listener from ChangeListener added to ButtonModel
doesn't work on WinXP
focused
un_fosused firing the same events a
EDIT
in Win7 compiled in JDK7_011 flashing JButtons (focused in Java window) with blue Color
flashing with blue color on second period
and

Swing - Get new component under mouseReleased

This question probably belies underlying lack of Swing knowledge, but I can't seem to pin down what I'm doing wrong. Essentially I want to detect mousePressed in one component, and then receive the mouseReleased for whatever component is under the mouse when it is released, rather than the original component.
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;
import net.miginfocom.swing.MigLayout;
public class TestMouseListener extends MouseInputAdapter {
public void mouseEntered(MouseEvent arg0) {System.out.println("Entered " + arg0.getComponent());}
public void mouseExited(MouseEvent arg0) {System.out.println("Exited " + arg0.getComponent());}
public void mousePressed(MouseEvent arg0) {System.out.println("Pressed " + arg0.getComponent());}
public void mouseReleased(MouseEvent arg0) {System.out.println("Released " + arg0.getComponent());}
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setLayout(new MigLayout());
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TestPanel panel1 = new TestPanel("Panel 1");
TestPanel panel2 = new TestPanel("Panel 2");
panel1.add(new JLabel("Text1"));
panel2.add(new JLabel("Text2"));
frame.add(panel1);
frame.add(panel2);
TestMouseListener listener = new TestMouseListener();
panel1.addMouseListener(listener);
panel1.addMouseMotionListener(listener);
panel2.addMouseListener(listener);
panel2.addMouseMotionListener(listener);
frame.setVisible(true);
}
}
class TestPanel extends JPanel {
String name;
TestPanel(String name){ this.name = name; }
public String toString(){ return name; }
}
So when I mouse over panel 1, click, drag to panel 2, release, I get the following:
Entered Panel 1
Pressed Panel 1
Exited Panel 1
Entered Panel 2
Released Panel 1
How do I get the panel I released over? I was hoping the mouseReleased event would fire for Panel 2 but obviously it does not.
Store a variable that holds your most recently entered component. Keep overwriting it every time you trigger a MouseEntered event. Then have a method, so that when you release the mouse button, you can use whatever your most recently entered component is.
Component lastEntered;
private void MouseEntered(MouseEvent e) {
lastEntered = e.getComponent;
}

Categories