EDIT--CORRECTED CODE BASED ON ACCEPTED ANSWER IS SHOWN AT BOTTOM OF THIS POST.
I found a way (written by Andremoniy) to catch double- and triple-clicks without firing single- and double-clicks. It works very well for my purposes.
I modified it so that it could have the click interval tweaked by the implementation. That also works well.
My modifications include making it an abstract class
, defining the 5 abstract
methods that the implementation would have to define (methods for single, double, triple, and "many" clicks as well as the click interval tweaker).
Here is the modified version (the println
statements are instructive):
public abstract class Click123 extends JPanel
{
public abstract void singleClick();
public abstract void doubleClick();
public abstract void tripleClick();
public abstract void manyClick();
public abstract int getFreq();
public Click123()
{
addMouseListener
(
new MouseAdapter()
{
Thread cp = null;
public void mouseClicked(MouseEvent e)
{
if (cp != null && cp.isAlive())
cp.interrupt();
if (e.getClickCount() == 1)
{
cp = new Thread(new ClickProcessor(new Callable<Void>() {
@Override public Void call() throws Exception {
singleClick();
return null;
}
}));
cp.start();
}
else if (e.getClickCount() == 2)
{
cp = new Thread(new ClickProcessor(new Callable<Void>() {
@Override public Void call() throws Exception {
doubleClick();
return null;
}
}));
cp.start();
}
else if (e.getClickCount() == 3)
{
cp = new Thread(new ClickProcessor(new Callable<Void>()
{
@Override public Void call() throws Exception {
tripleClick();
return null;
}
})
);
cp.start();
}
else manyClick();
} // mouseClicked
} // new MouseAdapter
); // add mouseListener
} // Click123
class ClickProcessor implements Runnable
{
Callable<Void> eventProcessor;
ClickProcessor(Callable<Void> eventProcessor)
{
this.eventProcessor = eventProcessor;
}
@Override public void run()
{
try
{
Thread.sleep(getFreq());
eventProcessor.call();
} catch (InterruptedException e) { System.out.println(e);}
catch (Exception e) { System.out.println(e);}
} // run
} // class ClickProcessor
} // class Click123
Here's the implementing program:
public class NewMain1 {
static int INITIAL_CLICK_FREQUENCY = ((Integer)Toolkit.getDefaultToolkit()
.getDesktopProperty("awt.multiClickInterval"));
public static int CLICK_FREQUENCY;
static JSpinner spinner = new JSpinner();
static final JLabel ch = new JLabel("Click here to test");
public static void main(String[] args) {
CLICK_FREQUENCY = INITIAL_CLICK_FREQUENCY;
spinner = new JSpinner();
spinner.setModel(new SpinnerNumberModel(CLICK_FREQUENCY, 200, 900, 50));
spinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
CLICK_FREQUENCY = (int) spinner.getValue();
}
});
Click123 frame = new Click123(){
public void singleClick(){
JOptionPane.showMessageDialog(null,"Single click at " + CLICK_FREQUENCY);
}
public void doubleClick(){
JOptionPane.showMessageDialog(null,"Double click at " + CLICK_FREQUENCY);
}
public void tripleClick(){
JOptionPane.showMessageDialog(null,"Triple click at " + CLICK_FREQUENCY);
}
public void manyClick(){
JOptionPane.showMessageDialog(null,"Many clicks at " + CLICK_FREQUENCY);
}
public int getFreq(){
return CLICK_FREQUENCY;
}
};
frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.setSize(500, 300);
ch.setBorder(new EtchedBorder());
frame.add(ch);
frame.add(spinner);
frame.setVisible(true);
} // main
}
As originally written, Click123 extends JFrame
. I modified it (by changing the top line to extends JTextField
) to work with a grid of type JTextField
. Then I added a button to change the click interval on the fly. So now I have THREE identical (except for the extension type) huge hunks of code.
My question is this: How do I modify Click123
so that, without alteration, it can be used to make ANY component aware of single-, double-, and triple-clicks?
EDIT--SUMMARY OF NECESSARY CHANGES (For my own app, the abstract
methods need MouseEvent
to be passed in order to determine which component fired the clicks):
Class definition:
public abstract class Click123<T extends Component>
{
public abstract void singleClick(MouseEvent e); // same for 3 others
...
public Click123(T target)
{
target.addMouseListener
(
new MouseAdapter() ...
} ...
}
final
added as modifier in order to pass MouseEvent
:
public void mouseClicked(final MouseEvent e)
Pass MouseEvent
:
singleClick(e); // same for doubleClick and tripleClick and manyClick
Receive MouseEvent
in order to determine which component fired the clicks:
public void doubleClick(MouseEvent e)
Implementation:
frame = new JPanel();
new Click123(frame) {