JPopupMenu bugged in JScrollPane - java

I have written a program, which displays a table inside of a JScrollPane. The reason for this is that, if the table gets to long the user should be able to use the scrollbar. Further I want the user to be able to open a popup menu on right click to edit or delete data. At first I thought my implementation works as shown in this image:
Later I realized that if I use the scollbar something gets wrong with the mouseposition and the popup is at the wrong location as shown here:
The mouse is located at the highlighted entry.
Here is my code for this:
table.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()){
rightClickPopUpOnTable(tablePanel.getComponentAt(e.getX(), e.getY()), e.getX(), e.getY());
//rightClickPopUpOnTable(tablePanel.getComponentAt(e.getXOnScreen(), e.getYOnScreen()), e.getXOnScreen(), e.getYOnScreen());
}
}
#Override
public void mouseReleased(MouseEvent e) {
int r = table.rowAtPoint(e.getPoint());
if (r >= 0 && r < table.getRowCount()) {
table.setRowSelectionInterval(r, r);
} else {
table.clearSelection();
}
if (e.isPopupTrigger()){
rightClickPopUpOnTable(tablePanel.getComponentAt(e.getX(), e.getY()), e.getX(), e.getY());
//rightClickPopUpOnTable(tablePanel.getComponentAt(e.getXOnScreen(), e.getYOnScreen()), e.getXOnScreen(), e.getYOnScreen());
}
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
public void rightClickPopUpOnTable(Component component, int x, int y){
JPopupMenu pop = new JPopupMenu();
pop.setVisible(true);
pop.setFocusable(false);
JMenuItem item = new JMenuItem("Edit");
item.addActionListener(new ActionListener() {
#java.lang.Override
public void actionPerformed(ActionEvent e) {
handler.getData().showData(table.getValueAt(table.getSelectedRow(),0).toString());
}
});
JMenuItem item2 = new JMenuItem("Delete");
item2.addActionListener(new ActionListener() {
#java.lang.Override
public void actionPerformed(ActionEvent e) {
int dialogResult = JOptionPane.showConfirmDialog (null, "Are you sure you want to delete "+table.getValueAt(table.getSelectedRow(), 0).toString()+"?","Delete Confirmation",JOptionPane.YES_NO_OPTION);
if(dialogResult == JOptionPane.YES_OPTION){
//DO STUFF
}
}
});
pop.add(item);
pop.add(item2);
pop.show(component, x, y);
}
I found a way to "fix" the problem partially by using e.getXOnScreen() as you can see in the code . Now the popup is displayed at the right location, but it won't highlight the items anymore AND it wont close as shown here:
I would be nice if someone knowns a solution for this.

Related

Creating JButton that knows whether it was right or left clicked [duplicate]

This question already has answers here:
Java Mouse Event Right Click
(3 answers)
Closed 6 years ago.
I am trying to create a JButton that will know whether or not it was right or left clicked when it was pressed. Here is my action listener for the JButton
buttons[i][j].addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
JButton button=(JButton)e.getSource();
StringTokenizer st=new StringTokenizer(button.getName());
}
});
And here is my code for the Mouse listener
public void mouseClicked(MouseEvent event){
if(event.getButton()==1)
{
startPosition.move(event.getX(),event.getY());
System.out.println(startPosition.getLocation());
System.out.println("row="+row+" column="+column);
}
else
{
endPosition.move(event.getX(),event.getY());
System.out.println("row="+row+" column="+column);
}
}
I know how to tell whether or now the mouse was right or left clicked, but I can't figure out how to combine that with the action event of the button being pressed. Any help would be much appreciated. Thanks.
You can make a custom mouse listener class that will do this:
public class CustomMouseListener implements MouseListener {
public void mouseClicked(MouseEvent e) {
if (event.getButton() == MouseEvent.BUTTON1) { // left click
// do stuff
}
if (event.getButton() == MouseEvent.BUTTON3) { //right click
// do stuff
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
In the class with your JButtons:
buttons[i][j].addMouseListener(new CustomMouseListener());

Change JButton's click color?

I've created some swing applications involving JButtons, and noticed whenever one is clicked, it turns white. Example here.
How would I change it so when, and only when, the button is clicked, it turns RED instead of the usual white, and when it is released, it goes back to its normal look? Is there a method for this?
Example code:
JButton b = new JButton("foo");
b.addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent e) {
//turn red
}
#Override
public void mouseReleased(MouseEvent e) {
//go back to original state
}
});
change color of button text using setForeground method
like this
#Override
public void mousePressed(MouseEvent e) {
b.setForeground(Color.red); // button text color
// b.setBackground(Color.red); // button background color
}
#Override
public void mouseReleased(MouseEvent e) {
b.setForeground(Color.black); // button text color
}
JButton b = new JButton("foo");
b.addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent e) {
b.setBackground(Color.red);
}
#Override
public void mouseReleased(MouseEvent e) {
//go back to original state
}
});
For more details look at this example

How do I make a JPopupMenu appear when any one of 3 JButtons is clicked, right-clicked, or dragged upon?

I am trying to make a set of navigation buttons for a file browser. I want it so that if the user clicks the dedicated history button, a JPopupMenu appears. However, I also want that exact same menu to appear when the user right-clicks or drags the cursor down the back or forward button. How can I make that exact same JPopupMenu (not a copy, but the same exact one) appear for multiple GUI components for different gestures?
So far I've tried the following:
histButton.addMouseListener(new MouseAdapter()
{
#Override public void mouseClicked(MouseEvent e)
{
showPopup(e);
}
#Override public void mouseDragged(MouseEvent e)
{
showPopup(e);
}
private void showPopup(MouseEvent e)
{
histPopupMenu.show(e.getComponent(), e.getX(), e.getY());
}
});
forwardButton.addMouseListener(new MouseAdapter()
{
#Override public void mouseClicked(MouseEvent e)
{
if (e.isPopupTrigger())
showPopup(e);
}
#Override public void mouseDragged(MouseEvent e)
{
showPopup(e);
}
private void showPopup(MouseEvent e)
{
histPopupMenu.show(e.getComponent(), e.getX(), e.getY());
}
});
backButton.addMouseListener(new MouseAdapter()
{
#Override public void mouseClicked(MouseEvent e)
{
if (e.isPopupTrigger())
showPopup(e);
}
#Override public void mouseDragged(MouseEvent e)
{
showPopup(e);
}
private void showPopup(MouseEvent e)
{
histPopupMenu.show(e.getComponent(), e.getX(), e.getY());
}
});
All components are added and display correctly, and debugging shows me that they register the events, but no menu appears.
Bringing Up a Popup Menu shows the traditional implementation using mousePressed(), mouseReleased() and isPopupTrigger(). Note that "The exact gesture that should bring up a popup menu varies by look and feel." You might compare what's shown with your implementation, which uses mousePressed().
Addendum: For reference, #mKorbel recalls this client property that may prove useful.
import java.awt.Component;
import java.awt.event.*;
import javax.swing.*;
/** #author mKorbel */
public class ComboBoxAction extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private JComboBox comboBox;
private JFrame frame;
public ComboBoxAction() {
comboBox = new JComboBox();
comboBox.addActionListener(this);
comboBox.addItem("Item 1");
comboBox.addItem("Item 2");
comboBox.addItem("Item 3");
comboBox.addItem("Item 4");
for (Component component : comboBox.getComponents()) {
if (component instanceof AbstractButton) {
if (component.isVisible()) {
comboBox.remove(component);
}
}
}
//This prevents action events from being fired when the
//up/down arrow keys are used on the dropdown menu
comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
comboBox.firePopupMenuWillBecomeVisible();
frame = new JFrame();
frame.add(comboBox);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(comboBox.getSelectedItem());
//make sure popup is closed when 'isTableCellEditor' is used
comboBox.hidePopup();
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ComboBoxAction();
}
});
}
}

How to change the mouse cursor in java?

I have a list of words inside the JList. Every time I point the mouse cursor at a word, I want the cursor to change into a hand cursor. Now my problem is how to do that?
Could someone help me with this problem?
Use a MouseMotionListener on your JList to detect when the mouse enters it and then call setCursor to convert it into a HAND_CURSOR.
Sample code:
final JList list = new JList(new String[] {"a","b","c"});
list.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseMoved(MouseEvent e) {
final int x = e.getX();
final int y = e.getY();
// only display a hand if the cursor is over the items
final Rectangle cellBounds = list.getCellBounds(0, list.getModel().getSize() - 1);
if (cellBounds != null && cellBounds.contains(x, y)) {
list.setCursor(new Cursor(Cursor.HAND_CURSOR));
} else {
list.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
#Override
public void mouseDragged(MouseEvent e) {
}
});
You probably want to look at the Component.setCursor method, and use it together with the Cursor.HAND constant.
You can also add MouseListener to the jList (or any ui component). Then implement the methods that mouseEntered, mouseExited
jList.addMouseListener(new MouseListener() {
#Override
public void mouseEntered(MouseEvent e) {
cw.list.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
}
#Override
public void mouseExited(MouseEvent e) {
cw.list.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
});

Showing/hiding a JPopupMenu from a JButton; FocusListener not working?

I needed a JButton with an attached dropdown style menu. So I took a JPopupMenu and attached it to the JButton in the way you can see in the code below. What it needs to do is this:
show the popup when clicked
hide it if clicked a second time
hide it if an item is selected in the popup
hide it if the user clicks somewhere else in the screen
These 4 things work, but because of the boolean flag I'm using, if the user clicks somewhere else or selects an item, I have to click twice on the button before it shows up again. That's why I tried to add a FocusListener (which is absolutely not responding) to fix that and set the flag false in these cases.
EDIT: Last attempt in an answer post...
Here are the listeners: (It's in a class extending JButton, so the second listener is on the JButton.)
// Show popup on left click.
menu.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
System.out.println("LOST FOCUS");
isShowingPopup = false;
}
#Override
public void focusGained(FocusEvent e) {
System.out.println("GAINED FOCUS");
}
});
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("isShowingPopup: " + isShowingPopup);
if (isShowingPopup) {
isShowingPopup = false;
} else {
Component c = (Component) e.getSource();
menu.show(c, -1, c.getHeight());
isShowingPopup = true;
}
}
});
I've been fighting with this for way too long now. If someone can give me a clue about what's wrong with this, it would be great!
Thanks!
Code:
public class Button extends JButton {
// Icon.
private static final ImageIcon ARROW_SOUTH = new ImageIcon("ArrowSouth.png");
// Unit popup menu.
private final JPopupMenu menu;
// Is the popup showing or not?
private boolean isShowingPopup = false;
public Button(int height) {
super(ARROW_SOUTH);
menu = new JPopupMenu(); // menu is populated somewhere else
// FocusListener on the JPopupMenu
menu.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
System.out.println("LOST FOCUS");
isShowingPopup = false;
}
#Override
public void focusGained(FocusEvent e) {
System.out.println("GAINED FOCUS");
}
});
// ComponentListener on the JPopupMenu
menu.addComponentListener(new ComponentListener() {
#Override
public void componentShown(ComponentEvent e) {
System.out.println("SHOWN");
}
#Override
public void componentResized(ComponentEvent e) {
System.out.println("RESIZED");
}
#Override
public void componentMoved(ComponentEvent e) {
System.out.println("MOVED");
}
#Override
public void componentHidden(ComponentEvent e) {
System.out.println("HIDDEN");
}
});
// ActionListener on the JButton
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("isShowingPopup: " + isShowingPopup);
if (isShowingPopup) {
menu.requestFocus();
isShowingPopup = false;
} else {
Component c = (Component) e.getSource();
menu.show(c, -1, c.getHeight());
isShowingPopup = true;
}
}
});
// Skip when navigating with TAB.
setFocusable(true); // Was false first and should be false in the end.
menu.setFocusable(true);
}
}
Here's a variant of Amber Shah's "big hack" suggestion I just made. Without the isShowingPopup flag...
It's not bulletproof, but it works quite well until someone comes in with an incredibly slow click to close the popup (or a very fast second click to reopen it...).
public class Button extends JButton {
// Icon.
private static final ImageIcon ARROW_SOUTH = new ImageIcon("ArrowSouth.png");
// Popup menu.
private final JPopupMenu menu;
// Last time the popup closed.
private long timeLastShown = 0;
public Button(int height) {
super(ARROW_SOUTH);
menu = new JPopupMenu(); // Populated somewhere else.
// Show and hide popup on left click.
menu.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent arg0) {
timeLastShown = System.currentTimeMillis();
}
#Override public void popupMenuWillBecomeVisible(PopupMenuEvent arg0) {}
#Override public void popupMenuCanceled(PopupMenuEvent arg0) {}
});
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ((System.currentTimeMillis() - timeLastShown) > 300) {
Component c = (Component) e.getSource();
menu.show(c, -1, c.getHeight());
}
}
});
// Skip when navigating with TAB.
setFocusable(false);
}
}
As I said in comments, that's not the most elegant solution, but it's horribly simple and it works in 98% of the cases.
Open to suggestions!
Here is another approach which is not too bad of a hack, if not elegant, and which, as far as I could tell, works. First, at the very top, I added a second boolean called showPopup.
The FocusListener has to be as follows:
menu.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
System.out.println("LOST FOCUS");
isShowingPopup = false;
}
#Override
public void focusGained(FocusEvent e) {
System.out.println("GAINED FOCUS");
isShowingPopup = true;
}
});
The isShowingPopup boolean does not get changed anywhere else--if it gains focus, it assumes it's shown and if it loses focus, it assumes it isn't.
Next, the ActionListener on the button is different:
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("isShowingPopup: " + isShowingPopup);
if (showPopup) {
Component c = (Component) e.getSource();
menu.show(c, -1, c.getHeight());
menu.requestFocus();
} else {
showPopup = true;
}
}
});
Now comes the really new bit. It's a MouseListener on the button:
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
System.out.println("ispopup?: " + isShowingPopup);
if (isShowingPopup) {
showPopup = false;
}
}
#Override
public void mouseReleased(MouseEvent e) {
showPopup = true;
}
});
Basically, mousePressed gets called before the menu loses focus, so isShowingPopup reflects whether the popup was shown before the button is pressed. Then, if the menu was there, we just set showPopup to false, so that the actionPerformed method does not show the menu once it gets called (after the mouse is let go).
This behaved as expected in every case but one: if the menu was showing and the user pressed the mouse on the button but released it outside of it, actionPerformed was never called. This meant that showPopup remained false and the menu was not shown the next time the button was pressed. To fix this, the mouseReleased method resets showPopup. The mouseReleased method gets called after actionPerformed, as far as I can tell.
I played around with the resulting button for a bit, doing all the things I could think of to the button, and it worked as expected. However, I am not 100% sure that the events will always happen in the same order.
Ultimately, I think this is, at least, worth trying.
You could use the JPopupMenu.isVisible() instead of your Boolean variable to check the current state of the popup menu.
Have you tried adding a ComponentListener to the JPopupMenu, so that you know when it's been shown and hidden (and update your isShowingPopup flag accordingly)? I'm not sure listening for focus changes is necessarily the right approach.
What you need is a PopupMenuListener:
menu.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent arg0) {
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent arg0) {
System.out.println("MENU INVIS");
isShowingPopup = false;
}
#Override
public void popupMenuCanceled(PopupMenuEvent arg0) {
System.out.println("MENU CANCELLED");
isShowingPopup = false;
}
});
I inserted this into your code and verified that it works.
Well, I can't be sure without seeing all of your code, but is it possible that the popup never actually gets focus at all? I've had problems with things' not getting focus properly in Swing before, so it could be the culprit. Try calling setFocusable(true) on the menu and then calling requestFocus() when you make the menu appear.
I tried the Answer of Tikhon Jelvis (introducing a smart combination of focusListener and mouseListener). It does not work for me on Linux (Java7/gtk). :-(
Reading http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#requestFocus%28%29 there is written "Note that the use of this method is discouraged because its behavior is platform dependent."
It may be that the order of listener calls changed with Java7 or it changes with GTK vs Windows. I would not recommend this solution if you want to be platform independent.
BTW: I created a new account on stackoverflow to give this hint. It seems I am not allowed to comment to his answer (because of reputation). But it seems I have a button to edit it. This stackoverflow is a very funny thing. :-)

Categories

Resources