How can I change JLabel text during work of JButton? - java

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

Related

JOptionPane.showMessageDialog having to quit twice

So I have a JOptionPane that appears when a certain condition isn't met and for some reason when I press "Ok" it appears again, but then when pressing "Ok" on the second dialog it goes way.
Below is the method where the dialog gets made:
public boolean checkBet()
{
if(currentPlayer.getBet() <= 0)
{
JOptionPane.showMessageDialog(null, "You must place a bet before you can roll your dice!.",
"Bet Required!",
JOptionPane.ERROR_MESSAGE);
return false;
}
else
return true;
}
and this is where the above method gets called:
#Override
public void actionPerformed(ActionEvent e) {
checkBet();
if(checkBet())
{
setRollingPlayer(currentPlayer);
new Thread() {
#Override
public void run() {
gameEngine.rollPlayer(rollingPlayer, 500, 2000, 500);
}
}.start();
}
}
You're call checkBet twice in the actionPerformed method
#Override
public void actionPerformed(ActionEvent e) {
checkBet(); // Here
if(checkBet()) // And here
{
When you are calling function checkBet() in actionPerformed(), it has been mentioned two times. Function checkBet() will also execute inside if().
Remove calling once and it will execute once.

Replace many "else if" with something else

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
}
...

Why can't I get to mouse click count == 2 first in Java?

In my Java Swing app, I have a JList, and when I double click on an item in the list, it always does click count == 1 things first then do things in click count == 2, why ?
list.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
if (SwingUtilities.isLeftMouseButton(e))
{
if (e.getClickCount()==1) Out("Left-ClickCount()==1");
else if (e.getClickCount()==2) Out("Left-ClickCount()==2");
}
else if (SwingUtilities.isRightMouseButton(e))
{
if (e.getClickCount()==2) Out("Right-ClickCount()==2");
else if (e.getClickCount()==1) Out("Right-ClickCount()==1");
}
}
});
No matter how fast I click, I intentionally put "if (e.getClickCount()==2)" before "else if (e.getClickCount()==1)", it still catches ClickCount==1 first ? Why ? How to fix it ?
OK, after some Goggling and my own enhancement, here is the code that works to my original expectations :
boolean isAlreadyOneClick=false;
...
DefaultListModel xlistModel=new DefaultListModel();
JList xlist=new JList(xlistModel);
xlist.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
int index=xlist.locationToIndex(e.getPoint());
String item=xlistModel.getElementAt(index).toString();
if (SwingUtilities.isLeftMouseButton(e))
{
if (isAlreadyOneClick)
{
System.out.println("Left double click : "+item);
isAlreadyOneClick=false;
}
else
{
isAlreadyOneClick=true;
Timer t=new Timer("doubleclickTimer",false);
t.schedule(new TimerTask()
{
#Override
public void run()
{
if (isAlreadyOneClick) System.out.println("Left single click : "+item);
isAlreadyOneClick=false;
}
},250);
}
}
else if (SwingUtilities.isRightMouseButton(e))
{
if (isAlreadyOneClick)
{
System.out.println("Right double click : "+item);
isAlreadyOneClick=false;
}
else
{
isAlreadyOneClick=true;
Timer t=new Timer("doubleclickTimer",false);
t.schedule(new TimerTask()
{
#Override
public void run()
{
if (isAlreadyOneClick) System.out.println("Right single click : "+item);
isAlreadyOneClick=false;
}
},250);
}
}
}
});
xlistModel.addElement("123");
xlistModel.addElement("abc");
JFrame f=new JFrame("Test Clicks");
f.add(xlist);
f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { } });
f.setBackground(SystemColor.control);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);

Java : detect triple-click without firing double-click

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

JOptionPane.showMessageDialog wait until OK is clicked?

This might be a very simple thing that I'm overlooking, but I just can't seem to figure it out.
I have the following method that updates a JTable:
class TableModel extends AbstractTableModel {
public void updateTable() {
try {
// update table here
...
} catch (NullPointerException npe) {
isOpenDialog = true;
JOptionPane.showMessageDialog(null, "No active shares found on this IP!");
isOpenDialog = false;
}
}
}
However, I don't want isOpenDialog boolean to be set to false until the OK button on the message dialog is pressed, because if a user presses enter it will activate a KeyListener event on a textfield and it triggers that entire block of code again if it's set to false.
Part of the KeyListener code is shown below:
public class KeyReleased implements KeyListener {
...
#Override
public void keyReleased(KeyEvent ke) {
if(txtIPField.getText().matches(IPADDRESS_PATTERN)) {
validIP = true;
} else {
validIP = false;
}
if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
if (validIP && !isOpenDialog) {
updateTable();
}
}
}
}
Does JOptionPane.showMessageDialog() have some sort of mechanism that prevents executing the next line until the OK button is pressed? Thank you.
The JOptionPane creates a modal dialog and so the line beyond it will by design not be called until the dialog has been dealt with (either one of the buttons have been pushed or the close menu button has been pressed).
More important, you shouldn't be using a KeyListener for this sort of thing. If you want to have a JTextField listen for press of the enter key, add an ActionListener to it.
An easy work around to suite your needs is the use of showConfirmDialog(...), over showMessageDialog(), this lets you take the input from the user and then proceed likewise. Do have a look at this example program, for clarification :-)
import javax.swing.*;
public class JOptionExample
{
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
int selection = JOptionPane.showConfirmDialog(
null
, "No active shares found on this IP!"
, "Selection : "
, JOptionPane.OK_CANCEL_OPTION
, JOptionPane.INFORMATION_MESSAGE);
System.out.println("I be written" +
" after you close, the JOptionPane");
if (selection == JOptionPane.OK_OPTION)
{
// Code to use when OK is PRESSED.
System.out.println("Selected Option is OK : " + selection);
}
else if (selection == JOptionPane.CANCEL_OPTION)
{
// Code to use when CANCEL is PRESSED.
System.out.println("Selected Option Is CANCEL : " + selection);
}
}
});
}
}
You can get acces to the OK button if you create optionpanel and custom dialog. Here's an example of this kind of implementation:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author OZBORN
*/
public class TestyDialog {
static JFrame okno;
static JPanel panel;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
zrobOkno();
JButton przycisk =new JButton("Dialog");
przycisk.setSize(200,200);
panel.add(przycisk,BorderLayout.CENTER);
panel.setCursor(null);
BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
przycisk.setCursor(Toolkit.getDefaultToolkit().createCustomCursor(
cursorImg, new Point(0, 0), "blank cursor"));
final JOptionPane optionPane = new JOptionPane(
"U can close this dialog\n"
+ "by pressing ok button, close frame button or by clicking outside of the dialog box.\n"
+"Every time there will be action defined in the windowLostFocus function"
+ "Do you understand?",
JOptionPane.INFORMATION_MESSAGE,
JOptionPane.DEFAULT_OPTION);
System.out.println(optionPane.getComponentCount());
przycisk.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
final JFrame aa=new JFrame();
final JDialog dialog = new JDialog(aa,"Click a button",false);
((JButton)((JPanel)optionPane.getComponents()[1]).getComponent(0)).addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
aa.dispose();
}
});
dialog.setContentPane(optionPane);
dialog.pack();
dialog.addWindowFocusListener(new WindowFocusListener() {
#Override
public void windowLostFocus(WindowEvent e) {
System.out.println("Zamykam");
aa.dispose();
}
#Override public void windowGainedFocus(WindowEvent e) {}
});
dialog.setVisible(true);
}
});
}
public static void zrobOkno(){
okno=new JFrame("Testy okno");
okno.setLocationRelativeTo(null);
okno.setSize(200,200);
okno.setPreferredSize(new Dimension(200,200));
okno.setVisible(true);
okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel=new JPanel();
panel.setPreferredSize(new Dimension(200,200));
panel.setLayout(new BorderLayout());
okno.add(panel);
}
}
Try this,
catch(NullPointerException ex){
Thread t = new Thread(new Runnable(){
public void run(){
isOpenDialog = true;
JOptionPane.setMessageDialog(Title,Content);
}
});
t.start();
t.join(); // Join will make the thread wait for t to finish its run method, before
executing the below lines
isOpenDialog = false;
}

Categories