I am using an ActionListener and have lots of else if statements in order to know which button is pressed and run some code depending on the button.
Is there a way to make the code nicer? I have nearly 10 else if statements following each other, is there something else I could use instead?
Sample of code:
class BtnListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == menu.getOpen()) {
getFile();
} else if (e.getSource() == btnPlay) {
} else if (e.getSource() == btnQuit)) {
}
}
Thanks.
You can fill Map<Object, Consumer<ActionEvent>> before using of listener, for example in constructor, where key is source and value is a consumer for action event. In action perform just get consumer by key and invoke it.
class BtnListener implements ActionListener {
Map<Object, Consumer<ActionEvent>> eventsMap = new HashMap<>();
public BtnListener() {
eventsMap.put(menu.getOpen(), actionEvent -> this.getFile());
eventsMap.put(btnPlay, actionEvent -> { //do something
});
eventsMap.put(btnQuit, actionEvent -> { //do something else
});
}
#Override
public void actionPerformed(ActionEvent e) {
Optional.of(e)
.map(ActionEvent::getSource)
.map(eventsMap::get)
.ifPresent(
actionEventConsumer -> actionEventConsumer.accept(e)
);
}
}
You may use the action command of the button, and a switch-case block :
public void actionPerformed(ActionEvent e){
switch(e.getActionCommand()) {
case "Open":
open();
break;
case "Delete":
delete();
break;
default :
break;
}
}
Of course you will have to set the action command of each button first, like :
openButton.setActionCommand("Open");
Note that switch-case with String objects only exists since JDK 7 : Strings in switch Statements
You can switch statement instead lot of else if ladder.
class BtnListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == menu.getOpen()) {
getFile();
}
switch( e.getSource() ){
case btnPlay:
break;
case btnQuit:
break;
default:
}
}
}
the best way to avoid all the "overheads" is to Lambda-Expressioned the buttons. Example:
JButton b1 = new JButton("Play");
b1.addActionListener(e -> play());
...
JButton bn = new JButton("Stop");
bn.addActionListener(e -> stop());
...
private void play() {
....// playing codes
}
...
private void stop() {
...// stopping codes
}
...
Related
I would like my button 'licz' to: change text value of info to ''loading'', do something and change 'info' to "done". ('licz' is here a JButton, 'info' JLabel)
licz.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
info.setText("Loading..."); // Here
if(go())
{
brute(0);
info.setText("Done!"); //here
if(odwrot)
JOptionPane.showMessageDialog(frame, "good");
else
JOptionPane.showMessageDialog(frame, "bad");
}
else
{
JOptionPane.showMessageDialog(frame, "bad");
info.setText("Done"); // And here
}
}
});
But the program makes "something" first, changes 'info' label to "loading" and immediately to "done", how to keep these in case?
The event of actionPerformed is handled on the event handling thread, and should terminate fast to have a responsive GUI. Hence call invokeLater.
licz.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
info.setText("Loading...");
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
boolean good = false;
if (go())
{
brute(0);
good = odwrot;
}
JOptionPane.showMessageDialog(frame, good ? "good" : "bad");
info.setText("Done");
}
});
}
});
Or in java 8:
licz.addActionListener((e) -> {
info.setText("Loading...");
EventQueue.invokeLater(() -> {
boolean good = false;
if (go())
{
brute(0);
good = odwrot;
}
JOptionPane.showMessageDialog(frame, good ? "good" : "bad");
info.setText("Done");
});
});
I have two JButtons called "Left" and "Right".
The "Left" button moves a rectangle object to the left and the "Right" button moves it to the right.
I have one ActionListener in the class that acts as the listener for when either button is clicked.
However I want different actions to happen when each are clicked. How can I distinguish, in the ActionListener, between which was clicked?
Set actionCommand to each of the button.
// Set the action commands to both the buttons.
btnOne.setActionCommand("1");
btnTwo.setActionCommand("2");
public void actionPerformed(ActionEvent e) {
int action = Integer.parseInt(e.getActionCommand());
switch(action) {
case 1:
//doSomething
break;
case 2:
// doSomething;
break;
}
}
UPDATE:
public class JBtnExample {
public static void main(String[] args) {
JButton btnOne = new JButton();
JButton btnTwo = new JButton();
ActionClass actionEvent = new ActionClass();
btnOne.addActionListener(actionEvent);
btnTwo.addActionListener(actionEvent);
btnOne.setActionCommand("1");
btnTwo.setActionCommand("2");
}
}
class ActionClass implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
int action = Integer.parseInt(e.getActionCommand());
switch (action) {
case 1:
// DOSomething
break;
case 2:
// DOSomething
break;
default:
break;
}
}
}
Quite easy with the getSource() method available to ActionEvent:
JButton leftButton, rightButton;
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if (src == leftButton) {
}
else if (src == rightButton) {
}
}
I have a JTable in which I want to call a function when a cell is double-clicked and call another function when the cell is triple-clicked.
When the cell is triple-clicked I do not want to call the double-click-function.
What I have right now is (mgrdAlarm is the JTable) :
mgrdAlarm.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("getClickCount() = " + e.getClickCount());
if (e.getClickCount()==2)
{
doubleClick();
System.out.println("Completed : doubleClick()");
}
if (e.getClickCount()==3)
{
tripleClick();
System.out.println("Completed : tripleClick()");
}
}
});
When double-clicked the console shows :
getClickCount() = 1
getClickCount() = 2
Completed : doubleClick()
When triple-clicked the console shows :
getClickCount() = 1
getClickCount() = 2
Completed : doubleClick()
getClickCount() = 3
Completed : tripleClick()
When triple-clicked I want the console to show :
getClickCount() = 1
getClickCount() = 2
getClickCount() = 3
Completed : tripleClick()
So I do not want to call the function doubleClick() when the cell is triple-clicked, but I do want to call the function doubleClick() when the cell is double-clicked.
[EDIT]
As all replies suggest the solution seems to be to delay the double-click-action and wait a certain time for the triple-click.
But as discussed here that might lead to a different type of problem :
The user might have set his double-click-time quite long, which might overlap with the timeout of my triple-click.
It is no real disaster if my double-click-action is executed before my triple-click-action, but it does generate some extra overhead, and especially some extra data traffic which I would like to prevent.
As the only solution so far might lead to other problems, which might actually be worse than the original problem, I will leave it as it is right now.
public class TestMouseListener implements MouseListener {
private boolean leftClick;
private int clickCount;
private boolean doubleClick;
private boolean tripleClick;
public void mouseClicked(MouseEvent evt) {
if (evt.getButton()==MouseEvent.BUTTON1){
leftClick = true; clickCount = 0;
if(evt.getClickCount() == 2) doubleClick=true;
if(evt.getClickCount() == 3){
doubleClick = false;
tripleClick = true;
}
Integer timerinterval = (Integer)Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
Timer timer = new Timer(timerinterval, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(doubleClick){
System.out.println("double click.");
clickCount++;
if(clickCount == 2){
doubleClick(); //your doubleClick method
clickCount=0;
doubleClick = false;
leftClick = false;
}
}else if (tripleClick) {
System.out.println("Triple Click.");
clickCount++;
if(clickCount == 3) {
tripleClick(); //your tripleClick method
clickCount=0;
tripleClick = false;
leftClick = false;
}
} else if(leftClick) {
System.out.println("single click.");
leftClick = false;
}
}
});
timer.setRepeats(false);
timer.start();
if(evt.getID()==MouseEvent.MOUSE_RELEASED) timer.stop();
}
}
public static void main(String[] argv) throws Exception {
JTextField component = new JTextField();
component.addMouseListener(new TestMouseListener());
JFrame f = new JFrame();
f.add(component);
f.setSize(300, 300);
f.setVisible(true);
component.addMouseListener(new TestMouseListener());
}
}
The previous answers are correct: you have to account for the timing and delay recognizing it as a double click until a certain amount of time has passed. The challenge is that, as you have noticed, the user could have a very long or very short double click threshold. So you need to know what the user's setting is. This other Stack Overflow thread ( Distinguish between a single click and a double click in Java ) mentions the awt.multiClickInterval desktop property. Try using that for your threshold.
You can do something like that, varying delay time:
public class ClickForm extends JFrame {
final static long CLICK_FREQUENTY = 300;
static class ClickProcessor implements Runnable {
Callable<Void> eventProcessor;
ClickProcessor(Callable<Void> eventProcessor) {
this.eventProcessor = eventProcessor;
}
#Override
public void run() {
try {
Thread.sleep(CLICK_FREQUENTY);
eventProcessor.call();
} catch (InterruptedException e) {
// do nothing
} catch (Exception e) {
// do logging
}
}
}
public static void main(String[] args) {
ClickForm f = new ClickForm();
f.setSize(400, 300);
f.addMouseListener(new MouseAdapter() {
Thread cp = null;
public void mouseClicked(MouseEvent e) {
System.out.println("getClickCount() = " + e.getClickCount() + ", e: " + e.toString());
if (cp != null && cp.isAlive()) cp.interrupt();
if (e.getClickCount() == 2) {
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("Double click processed");
return null;
}
}));
cp.start();
}
if (e.getClickCount() == 3) {
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("Triple click processed");
return null;
}
}));
cp.start();
}
}
});
f.setVisible(true);
}
}
You need to delay the execution of double click to check if its a tripple click.
Hint.
if getClickCount()==2 then put it to wait.. for say like 200ms?
It's exactly the same problem as detecting double-click without firing single click. You have to delay firing an event until you're sure there isn't a following click.
There's a tutorial for this
here
Edit: It fires click events individually though, so you would get:
Single Click THEN
Double Click THEN
Triple Click. So you would still have to do some timing trickery.
The code is:
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class Main {
public static void main(String[] argv) throws Exception {
JTextField component = new JTextField();
component.addMouseListener(new MyMouseListener());
JFrame f = new JFrame();
f.add(component);
f.setSize(300, 300);
f.setVisible(true);
component.addMouseListener(new MyMouseListener());
}
}
class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 3) {
System.out.println("triple-click");
} else if (evt.getClickCount() == 2) {
System.out.println("double-click");
}
}
}
Here is what i have done to achieve this, this actually worked fine for me. A delay is necessary to detect the type of click. You can choose it. The following delays if a triple click can be happened within 400ms. You can decrease it to the extent till a consecutive click is not possible. If you are only worrying about the delay, then this is a highly negligible delay which must be essential to carry this out.
Here flag and t1 are global variables.
public void mouseClicked(MouseEvent e)
{
int count=e.getClickCount();
if(count==3)
{
flag=true;
System.out.println("Triple click");
}
else if(count==2)
{
try
{
t1=new Timer(1,new ActionListener(){
public void actionPerformed(ActionEvent ae)
{
if(!flag)
System.out.println("Double click");
flag=false;
t1.stop();
}
});
t1.setInitialDelay(400);
t1.start();
}catch(Exception ex){}
}
}
How can i prevent a user from copying the contents of a JTextField?
i have the following but i cannot figure a way to get multiple keys at the same time?
myTextField.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
char c = e.getKeyChar();
if (!Character.isDigit(c)) {
e.consume();
}
}
});
For this, you will have to modify your KeyAdapter so that it can register when a key was pressed and when it was released, so that we may know when both keys were pressed simultaneously, the following code should do the trick:
textfield.addKeyListener(new KeyAdapter() {
boolean ctrlPressed = false;
boolean cPressed = false;
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_C:
cPressed=true;
break;
case KeyEvent.VK_CONTROL:
ctrlPressed=true;
break;
}
if(ctrlPressed && cPressed) {
System.out.println("Blocked CTRl+C");
e.consume();// Stop the event from propagating.
}
}
#Override
public void keyReleased(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_C:
cPressed=false;
break;
case KeyEvent.VK_CONTROL:
ctrlPressed=false;
break;
}
if(ctrlPressed && cPressed) {
System.out.println("Blocked CTRl+C");
e.consume();// Stop the event from propagating.
}
}
});
i was just adding this to one of my JTextFields.
I am trying to write a piece of code so that when a key is pressed it will execute something, but then the key will have to be released and then repressed again in order to retrigger the event. So if the user just holds down the key, it wont keep doing it over and over, instead they will have to press and release repeatedly.
So far, I have:
if(keyLifted)
{
if(Keyboard.isKeyDown(45))
{
keyLifted = false;
dostuff;
}
else if(Keyboard.isKeyDown(46))
{
keyLifted = false;
dostuff();
}
else
{
keyLifted = true;
}
}
but this is flawed for obvious reasons (it will only reset the key to being unlifted if the key is already lifted: if the key was pressed, it wont be set to unpressed). I have tried a couple variations, but I just cant get it to work.
Thanks in advance for any help!
You should use a KeyListener to capture keyboard events. Here you go:
public class KeyListenerExample extends JFrame {
public KeyListenerExample() {
addKeyListener(new KeyAdapter() {
private boolean keyLifted;
public void keyReleased(KeyEvent e) {
keyLifted = true;
}
public void keyPressed(KeyEvent e) {
keyLifted = false;
switch (e.getKeyChar()) {
case 45:
doStuff();
break;
case 46:
doStuff();
break;
}
}
});
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void doStuff() {
System.out.println("stuff");
}
/**
* #param args
*/
public static void main(String[] args) {
new KeyListenerExample();
}
}
I just kept the keyLifted because it is in your example. But I think for the usual keyboard stuff you don't need it.