JPopupMenu Behavior OSX 10.6.7 - java

My problem is when I right click on the JFrame in the example below, the JPopupMenu shows up but if I click anywhere outside the JFrame, the menu does not disappear. I have to click somewhere on the JFrame to get rid of it which is not the expected behavior. Here are the steps to reproduce:
Run the window class from Eclipse (JFrame appears)
Click into the Eclipse workspace (JFrame loses focus and is hidden behind eclipse)
Minimize Eclipse (JFrame appears)
Go with your mouse over JFrame and make a right click (Popup appears)
Click somewhere (Not into JFrame or Popup). The Popup will not disappear
I'm running OS X 10.6.7 and Java full version 1.6.0_24-b07-334
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class test
{
static class window extends JFrame implements MouseListener,
MouseMotionListener
{
JPopupMenu popMenu;
JPanel panel = new JPanel();
Point location;
MouseEvent pressed;
public window()
{
addMouseListener(this);
addMouseMotionListener(this);
JLabel label = new JLabel("JFrame", JLabel.CENTER);
initPopMenu();
add(label);
setUndecorated(true);
setVisible(true);
// setAlwaysOnTop(true);
setLocationRelativeTo(null);
pack();
}
public void initPopMenu()
{
popMenu = new JPopupMenu();
JMenuItem item;
item = new JMenuItem("Title");
item.setEnabled(false);
popMenu.add(item);
popMenu.addSeparator();
item = new JMenuItem("Item One");
popMenu.add(item);
item = new JMenuItem("Item 2");
popMenu.add(item);
item = new JMenuItem("Item 3");
popMenu.add(item);
}
public void mousePressed(MouseEvent e)
{
pressed = e;
int nModifier = e.getModifiers();
if (((nModifier & InputEvent.BUTTON2_MASK) != 0)
|| ((nModifier & InputEvent.BUTTON3_MASK) != 0))
popMenu.show( this, e.getX(), e.getY() );
}
public void mouseClicked(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseDragged(MouseEvent me)
{
}
public void mouseMoved(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
}
public static void main(String[] args)
{
window dw = new window();
}
}

you can add a windowFocusListener, hide the menu when window lost focus
this.addWindowFocusListener(new WindowFocusListener() {
#Override
public void windowLostFocus(WindowEvent e) {
if(popMenu != null){
popMenu.setVisible(false);
}
}
#Override
public void windowGainedFocus(WindowEvent e) {
//System.out.println(e);
}
});

Related

KeyListener does not work when exported as a runnable jar file [duplicate]

I am trying to do something when one of the arrow keys are pressed using the KeyListener in my JPanel class. Here is my code:
public class TestPanel extends JPanel implements KeyListener{
public TestPanel(){
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocusInWindow();
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left");
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
}
My main method adds a new instance of this panel to a frame and displays it. Do I need to add the keylistener to the JFrame? In my case, this would be difficult and inefficient, so I would like to make it work with this JPanel if possible. Anyone know what I am doing wrong?
EDIT: Key Bindings code that does not work either:
public class GamePanel extends JPanel implements ActionListener{
//Constructor
public GamePanel(){
setupKeyBinding();
this.setFocusable(true);
this.requestFocusInWindow();
}
private void setupKeyBinding() {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inMap = getInputMap(condition);
ActionMap actMap = getActionMap();
inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "Left");
actMap.put("Left", new leftAction());
}
private class leftAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
System.out.println("test");
}
}
public void actionPerformed(ActionEvent e) {
//some other game info
}
}
Can someone tell me why this doesnt work either? (my second action listener is for other stuff needed for my game)
If you search this problem, you'll see that it is asked and has been solved many times.
KeyListeners need to be on the focused component to work. One solution is to give your component the focus after first making it focusable.
Better by a long shot however is to use Key Bindings. Google the tutorial on this.
Please have a look at my answer to this question for more on this, including many of the gory details.
For reference, I've create an example using your approach; while it works, it also suggests a focus problem elsewhere in your code. Key Bindings avoid this, as shown here.
Addendum: Here's my working key binding.
private static class TestPanel extends JPanel {
private static final String LEFT = "Left";
private Action left = new AbstractAction(LEFT) {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(LEFT);
}
};
private static final String RIGHT = "Right";
private Action right = new AbstractAction(RIGHT) {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(RIGHT);
}
};
public TestPanel() {
this.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
this.getActionMap().put(LEFT, left);
this.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
this.getActionMap().put(RIGHT, right);
}
}
Original SSCCE:
import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/a/16531380/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TestPanel());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class TestPanel extends JPanel implements KeyListener {
public TestPanel() {
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocusInWindow();
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left");
}
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
For receives key events on JPanel you must set focus:
setFocusable(true);
requestFocus();
the JPanel now has focus, so it receives key events
I had to do two things: I added comp.setFocusable(true); to the component comp that listens to key events, and I added comp.requestFocus(); to each action which caused comp to lose the focus.

Java: check if the mouse has clicked

i am in trouble with checking if the mouse has clicked with a JFrame. When i use public void mousePressed(MouseEvent e) to print something and i click with the mouse it doesn't print anything. It doesn't gives a error, it just prints nothing out. Here is my code :
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class tuna extends JFrame
{
private JTextArea textArea;
public static void main(String[] args)
{
//Run the program
tuna run = new tuna();
run.setDefaultCloseOperation(3);
run.setSize(1200, 1000);
run.setVisible(true);
}
public tuna()
{
super("Simple JFrame");
//add a simple JScrollPane
textArea = new JTextArea(10,10);
JScrollPane scrollPane = new JScrollPane(textArea);
textArea.setEditable(true);
add(scrollPane);
}
//This doesn't print anything when i am clicking in the JFrame
public void mousePressed(MouseEvent e)
{
if(e.getButton() == MouseEvent.BUTTON1)
{
System.out.println("left");
}
else if(e.getButton() == MouseEvent.BUTTON3)
{
System.out.println("right");
}
}
}
Thank you in advance.
You can make you own Mouse Listener and add it to textArea or another component.
For example like this:
public class tuna extends JFrame
{
private JTextArea textArea;
public static void main(String[] args)
{
//Run the program
tuna run = new tuna();
run.setDefaultCloseOperation(3);
run.setSize(1200, 1000);
run.setVisible(true);
}
public tuna()
{
super("Simple JFrame");
//add a simple JScrollPane
textArea = new JTextArea(10,10);
JScrollPane scrollPane = new JScrollPane(textArea);
textArea.setEditable(true);
textArea.addMouseListener(new CustomListener());
add(scrollPane);
}
//This doesn't print anything when i am clicking in the JFrame
public class CustomListener implements MouseListener {
#Override
public void mouseClicked(MouseEvent mouseEvent) {
if(mouseEvent.getButton() == MouseEvent.BUTTON1)
{
System.out.println("left");
}
else if(mouseEvent.getButton() == MouseEvent.BUTTON3)
{
System.out.println("right");
}
}
#Override
public void mousePressed(MouseEvent mouseEvent) {
}
#Override
public void mouseReleased(MouseEvent mouseEvent) {
}
#Override
public void mouseEntered(MouseEvent mouseEvent) {
}
#Override
public void mouseExited(MouseEvent mouseEvent) {
}
}
}
Well there are few issues, in your concept and source code
First you need a MouseListener, so in your case either you can
create a separate MouseListener or use the current JFrame class
itself, like this
public class Tuna extends JFrame implements MouseListener
Also I would recommend to follow proper naming convention and use Tuna instead of tuna.
Then the element you want to respond on the MouseEvents should be
register with the MouseListener created in first step, in your constructor.
textArea.addMouseListener(this);
Also make sure on what element you want to register your
MouseListener, currently your entire Frame is covered by TextArea,
so registering listener on JFrame won't help, instead add it on
JTextArea
Try using #Override annotation where ever possible, editor shows
appropriate compiler errors then, in your case you just wrote,
public void mousePressed(MouseEvent e)
instead of
#Override
public void mousePressed(MouseEvent e)
As this methods works only if you implement an MouseListener
Refer this link for more understanding,
https://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html

Popupmenu wont work in java?

i am constructing a word processor program as an assignment for my Java class in school and i am having a really hard time getting the popupmenu to work when i right click on my text area. I have already constructed the popup menu and have my textarea listening to my popuplistener and i have overridden the mouse pressed and mouse released functions with
class popupframe extends JFrame{
JMenuItem copy;
JMenuItem paste;
JTextArea textarea = new JTextArea();
JPopupMenu pop;
popupframe(){
Container cpane = getContentPane();
setSize(300 , 300);
setLocation(300, 300);
setTitle("Test");
JPopupMenu pop = new JPopupMenu();
copy = new JMenuItem("copy");
paste = new JMenuItem("paste");
textarea = new JTextArea("something goes here", 5, 5);
pop.add(copy);
pop.add(paste);
PopupListener popuplistener = new PopupListener();
textarea.addMouseListener(popuplistener);
}
class PopupListener extends MouseAdapter{
public void MousePressed(MouseEvent e){
popit(e);
}
public void MouseReleased(MouseEvent e){
popit(e);
}
private void popit(MouseEvent e){
if(e.isPopupTrigger()){
pop.show(e.getComponent(), e.getX(), e.getY());
}
}
}
}
I cannot see why it is not working but perhaps i am missing something crucial, please help!! much appreciated
Add the #Override annotation to the methods you think your are overriding...
class PopupListener extends MouseAdapter {
#Override
public void MousePressed(MouseEvent e) {
System.out.println("Pressed");
popit(e);
}
#Override
public void MouseReleased(MouseEvent e) {
System.out.println("Pressed");
popit(e);
}
You will now find that this fails to compile, but why? Because Java is case sensitive, and by convention, method names start with a lower case character
You'll find that something like...
class PopupListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
popit(e);
}
#Override
public void mouseReleased(MouseEvent e) {
popit(e);
}
#Override
public void mouseClicked(MouseEvent e) {
popit(e);
}
private void popit(MouseEvent e) {
if (e.isPopupTrigger()) {
pop.show(e.getComponent(), e.getX(), e.getY());
}
}
}
will work better. But having said that, you'll generally find
textarea.setComponentPopupMenu(pop);
significantly easier and less error prone (and it won't cause a NullPointerException like your example code will.

Different behavior in WindowsLookAndFeel

I want to show a popupmenu, while using Metal L&F it will do these behavior.
single click: it printed "pressed" and show menu
double pressed: it printed "pressed" and show menu too.
Yes it is I needed. But when using WindowsLookAndFeel, it not same as those.
when twice pressed it just hide menu and not printed "pressed". why it have difference behavior between two L&F?
import javax.swing.*;
import java.awt.event.*;
public class Popup {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(300, 300);
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception ex) {
ex.printStackTrace();
}
JPopupMenu menu = new JPopupMenu();
menu.add("item");
f.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
System.out.println("pressed");
}
});
f.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
menu.show(f, e.getX(), e.getY());
}
});
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
boolean consumeEvent = UIManager.getBoolean("PopupMenu.consumeEventOnClose");
// Consume the event so that normal processing stops.
if(consumeEvent && !(src instanceof MenuElement)) {
me.consume();
}
I have found the problems, because of this property is different
so end it

MouseListener on button rendered on a JTree Row in Java

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);
}
}
}

Categories