JMenuItem - how to figure out if action was invoked by accelerator? - java

So I have to create a simple GUI in Swing for my Java class and I've stumbled upon this minor cosmetic issue.
I have the following code:
JMenuItem mntmQuit = new JMenuItem("Quit");
mntmQuit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getModifiers() == MouseEvent.BUTTON1_MASK) {
System.out.println("You should fire.");
} else if (e.getModifiers() == MouseEvent.BUTTON2_MASK || e.getModifiers() == MouseEvent.BUTTON3_MASK) {
System.out.println("Why do you fire this event?");
} else {
System.out.println("And how can I catch when the accelerator was used?");
}
}
});
mntmQuit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0));
I've never seen a menu item that was invoked when right clicking or using any other mouse button than button 1. As it seems Swing sees this differently and sends an action event no matter which mouse button was pressed - in contrary to a JButton which wont fire anything unless it's clicked with mouse button 1.
Now I could live with that as I can easily catch mouse button 1 and perform my actions, but how about catching the usage of the accelerator? It will fire the action event but I don't see any possibility of catching it as it returns '0' as modifier (same as any other mouse buttons except 1, 2 and 3).
Is there any way that I can tell the JMenuItem that it should only react to mouse button 1 and it's accelerator? Similar to the way JButton does it?

JMenuItem mntmQuit = new JMenuItem("Quit");
mntmQuit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!(e.getModifiers() == InputEvent.BUTTON3_MASK)) {
System.out.println(e.getActionCommand());
}
}
});
mntmQuit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0));
Edit:
I've changed my answer, instead of checking for when the event is fired, you should be checking for when to NOT fire it. So in this case, Button3 or right click. The event will always fire when you press "q" or any mouse click.
The previous answer was bad, you don't want to use e.getModifiers() because it can potentially return true for events that you don't want to return true. e.g. if you had "q" and "w" set to the same button, but they do different things, both events would trigger on the first if statement checking e.getModifiers() == 0
Sorry for the confusion, hopefully this makes more sense.

if (event.getModifiers() == AWTEvent.MOUSE_EVENT_MASK)

Related

How will I be able to compare two button presses from a choice of three?

I have 3 buttons
b1
b2
b3
I want to now have these buttons be pressed in turns.
So turn one I press and turn 2 another person presses.
So after turn two, I will compare the names of the buttons.
b1.addActionListener(new ActionListener() {
public void actionPerformed( ActionEvent event ) {
b1.setEnabled(false);
if (!b1.isEnabled() && !b2.isEnabled()) {
//computeWinner(b1.getText(), b2.getText());
} else if(!b1.isEnabled() && !b3.isEnabled()) {
//computeWinner(b1.getText(), b2.getText());
}
}
});
This was what I thought would work, but there are many things wrong with this,
First, since I disable the buttons the second user always has one less option. and second the if statements do not seem to work? how should I compare the
JButton b3 = new JButton ("hello"); <- hello lable of the buttons?
EDIT:
I was able to successfully compare the two buttons. Now my only problem is that for the second player one of the buttons are disabled(how can I capture the first button press and the second without disabling them?). And that after the comparison I don't know how to reset the board to go again. (for a set number of loops.)
Thank you for the help!
The following code will print the label of the button which has been pressed. I hope, you should be able to proceed from here. Feel free to let me know if you face any further issue.
ActionListener actionListener = new ActionListener(){
public void actionPerformed(ActionEvent actionEvent) {
System.out.println(actionEvent.getActionCommand());
}
};
There are several options.
Store the buttons in a map<Integer, String>. the integer would be a count for keeping track of pushes. The string would be the actionCommand of the button pressed.
Store the button actionCommands in a list or array.
In either of the above you can provide appropriate logic to compare the buttons and then reset the arrays or map and count.
Note: The actionCommand defaults to the button label unless it explicitly set.

doClick(), and Simon: All buttons will unpress at the same time instead of individually

Hi I'm new to stackoverflow so bear with me if I make mistakes.
I'm making this Java Simon Says Game for a class project. It works by a random number generator for each sequence#. I show the sequence through doClick() but remove the actionlisteners beforehand and add it afterwards.
The problem is the buttons won't unpress or unarm until all other buttons have been pressed. I've tried using thread.sleep to put a delay between each if...else statements yet it only stays pressed for longer. I've tried updating the gui through repaint(), revalidate(), updateUI() within the try... catch of the thread.sleep but that didn't work either.
I've realized this issue is mainly cosmetic because when I tried implementing setPressed or setArmed it said it wasn't being pressed but it looked pressed.
Here is the code snippet in it's most simplest form without thread.sleep or my previous attempts in comments.
public void sequence2() //This is where the issue happens. The buttons won't unpress until every button has been pressed.
{
level.setText(" Level 2"); //Level indicator
Green.removeActionListener(Listener);
Red.removeActionListener(Listener);
Yellow.removeActionListener(Listener);
Blue.removeActionListener(Listener);
if(sequence1 == 1)
{
Green.doClick(300); //Programmatically clicks the button
}
else if(sequence1 == 2)
{
Red.doClick(300);
}
else if(sequence1 == 3)
{
Yellow.doClick(300);
}
else if(sequence1 == 4)
{
Blue.doClick(300);
}
if(sequence2 == 1)
{
Green.doClick(300);
}
else if(sequence2 == 2)
{
Red.doClick(300);
}
else if(sequence2 == 3)
{
Yellow.doClick(300);
}
else if(sequence2 == 4)
{
Blue.doClick(300);
}
Green.addActionListener(Listener);
Red.addActionListener(Listener);
Yellow.addActionListener(Listener);
Blue.addActionListener(Listener);
}
I'm very new to java so I'm not skilled in multithreading or working on the Event Dispatch Thread for that manner. But if that's the only solution I'll need some more help with that.
I have the full code in a zip file with previous attempts commented out if that will help.
https://drive.google.com/file/d/0Bxg4WleC9jD2VFhoZmZBNjV6Vkk/view?usp=sharing
Invoking doClick() may be an awkward choice for this, as it uses a Timer internally. Instead, use a JToggleButton, which will allow you to control each button's appearance based on its selected state using setSelected(). A complete example is shown in the game Buttons. In the ActionListener of your Swing Timer, select the current button, play its note and increment the sequence index. When all notes have been played, unselect all the buttons.
Addendum: Can you show how you implement the timer?
In outline, given a suitable list of toggle buttons:
private static final int MAX = 4;
List<JToggleButton> buttons = new ArrayList<JToggleButton>(MAX);
private int i;
The timer's listener might look like this:
#Override
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
JToggleButton b = buttons.get(i);
if (i > MAX) { // reset i and all the buttons
for (JToggleButton b : buttons) {
b.setSelected(false);
}
timer.stop();
i = 0;
} else {
b.setSelected(true);
// play tone i
i++;
}
}
A toggle button's item listener should update the button's appearance as indicated by its state:
#Override
public void itemStateChanged(ItemEvent e) {
JToggleButton b = (JToggleButton) e.getItem();
if (b.isSelected()) {
// change icon, color etc.
} else {
// restore icon, color etc.
}
}

ListSelectionEvent, firing an event when clicking the currently selected item in JList

Let 'x' be an item in the JList. When I click it for the first time, the event fires, when I click it again, the event does not fire. I have to click some other item and then come back to 'x'.
How can I fire the event repeatedly from 'x' without having to deal with other items.
This is my code:
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
if (list.getSelectedIndex() == -1) {} else {
String clicked = (String)list.getSelectedValue();
//method to fire is here
}
}
updateDisplays();
}
The ListSelectionListener reflects changes to the lists selection, you could use a MouseListener instead...
For example...
MouseListener ml = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent evt) {
if (SwingUtilities.isLeftMouseButton(evt) && evt.getClickCount() == 1) {
if (list.getSelectedIndex() != -1) {
int index = list.locationToIndex(evt.getPoint());
System.out.println("You clicked item # " + index);
}
}
}
}
list.addMouseListener(ml);
You can add a MouseListener and watch for clicks. Note that a click that changes the selection will fire both the MouseListener and your ListSelectionListener.
Another option is to immediately clear the selection from your ListSelectionListener; that way the next click will reselect and retrigger, although you will lose the ability to navigate through items with the keyboard.
It seems like sort of an unusual UX decision, though, to assign significance to a click on an already selected item in a list.
Adding based on your question comments: If you go the MouseListener route, I recommend looking for double-clicks instead of single-clicks if the click is going to execute an action (especially if the action changes data and is not undoable). Also note that your ListSelectionListener will execute actions as you navigate through the list with the keyboard, which may not be what you intend.
If your commands in your history list are typed, you could also consider using a drop-down combo box for both command entry and the history list, where a selection from history fills in the command text but does not execute. You'd also have an opportunity to add auto-complete from command history.

Java MouseListener not always working

I find it odd that in my project, the mouselistener is not always heard. Has anyone else come across this? Or am I doing something wrong? I have to sometimes click it several times before it opens. I do wait between clicks to see if it is a performance issue.
JButton btnPin = new JButton("Pin");
btnPin.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent arg0) {
if(staffPinDialog == null || staffPinDialog.isShowing() == false)
staffPinDialog = new StaffPinDialog(idClicked);
}
});
StaffPinDialog is a JDialog, where the reference has been created elsewhere. idClicked is also always initialized.
You're not supposed to use a MouseListener to detect button clicks. Use an ActionListener instead.
This will also have the additional advantage of being able to click the button using the keyboard.

Simulating enter key in Swing (without using Robot)

So I'm trying to write a JButton that will act like an enter key when pressed. It must be able to fool a JTextField that is in focus into calling its action listeners. It can not use the robot framework, because that will make every program think enter is pressed, which is a problem.
Here is the backstory:
I have a program (written in Swing) which allows someone to enter data in many textfields and other things by hitting enter after typing in the data. It works great.
However, most people that use it are using a second program at the same time which automatically listens for an enter key and shuts off a robot (for those of you who are familiar with FIRST robotics, I'm talking about the SmartDashboard and the Driver Station). There have been quite a few complaints about this. People want to enter data without disabling the robot. As it turns out, the SmartDashboard (the program people want to hit enter on) allows custom swing components to be run along with it.
not entirely sure if I understand your requirement correctly (will delete this if not) ...
You can manually dispatch an event to whatever component you want to address. In the case of wanting to dispatch to the focusOwner
find the focusOwner by querying the KeyboardFocusManager
create a keyEvent with the focusOwner as sender
dispatch that event to the focusOwner
Something like:
Action action = new AbstractAction("fake enter") {
#Override
public void actionPerformed(ActionEvent e) {
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Component comp = manager.getFocusOwner();
KeyEvent event = new KeyEvent(comp,
KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0,
KeyEvent.VK_ENTER, KeyEvent.CHAR_UNDEFINED);
comp.dispatchKeyEvent(event);
}
};
JButton button = new JButton(action);
button.setFocusable(false);
Action textAction = new AbstractAction("text") {
#Override
public void actionPerformed(ActionEvent e) {
LOG.info("I'm the text action" + ((Component) e.getSource()).getName());
}
};
JComponent comp = Box.createVerticalBox();
for (int i = 0; i < 5; i++) {
JTextField field = new JTextField(20);
field.setName(": " + i);
field.setAction(textAction);
comp.add(field);
}
comp.add(button);
Edit
added some lines for actually playing with it (#Joe commented it's not working). Clicking the button triggers the action of the focused textField (here simply prints out the field's name) Local context is vista and jdk6u27.
You might try getRootPane().setDefaultButton() on the frame. There's an example here.
Grabbing the element with the focus and manually dispatching an enter event didn't quite work, but because I just wanted to effect various JTextField, I came up with a similar solution:
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if (focusOwner instanceof JTextField) {
((JTextField) focusOwner).postActionEvent();
}
}
});
Thanks for pointing me in the right direction.

Categories

Resources