I'm trying to use Java's KeyListener to update a JLabel as I type. Essentially, I'm making my own text field. Here's what I have:
/**
* Constructor for objects of class Dictionary
*/
public Dictionary()
{
frame = new JFrame();
frame.setTitle("Shori Dictionary");
frame.setLayout(new GridBagLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void createWord()
{
frame.remove(pane);
pane = new PaintPane(field.getImage());
pane.setLayout(new BorderLayout());
frame.add(pane);
frame.pack();
newWord = new JLabel(text);
newWord.setFont(newWord.getFont().deriveFont(Font.BOLD, 28));
newWord.setForeground(Color.BLACK);
newWord.setHorizontalTextPosition(JLabel.LEFT);
newWord.setVerticalAlignment(JLabel.TOP);
newWord.setVerticalTextPosition(JLabel.TOP);
newWord.setBorder(BorderFactory.createEmptyBorder(445, 150, 0, 0));
pane.add(newWord);
frame.pack();
frame.setLocationRelativeTo(null);
pane.setFocusable(true);
updateInteraction();
}
private void keyPress()
{
pane.addKeyListener(new KeyListener()
{
public void keyTyped(KeyEvent e) {
for(int i = 97; i <= 122; i++){
//Cycles through every lowercase letter
if(e.getKeyChar() == (char)(i)&& pane.returnImage() == field.getImage()){
text += (char)(i);
break;
}
}
//Even in the Debugger, these next if-elses have never worked
if(e.getKeyCode() == KeyEvent.VK_SPACE&& pane.returnImage() == field.getImage()) text += " ";
else if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE&& pane.returnImage() == field.getImage()){
int x = text.length();
text = text.substring(0,x-1); //Not sure if this works, haven't been able to test it yet
}
else if(e.getKeyCode() == KeyEvent.VK_ENTER&& pane.returnImage() == field.getImage()){
//do something with the text
text = "";
//exit the word creator
}
newWord.setText(text);
newWord.repaint(); //Apparently this isn't necessary...
}
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
);
}
private void mouseAction()
{
pane.addMouseListener(new MouseListener()
{
public void mouseClicked(MouseEvent arg0) {
//cover page
if(open.contains(arg0.getPoint())&& pane.returnImage() == cover.getImage()) displayPages();
else if(search.contains(arg0.getPoint())&& pane.returnImage() == cover.getImage()) searchWord();
else if(enter.contains(arg0.getPoint())&& pane.returnImage() == cover.getImage()) createWord();
//inner pages
else if(nextPage.contains(arg0.getPoint())&& pane.returnImage() == pages.getImage()) pageFlip("next");
else if(prevPage.contains(arg0.getPoint())&& pane.returnImage() == pages.getImage()) pageFlip("previous");
else if(cancel.contains(arg0.getPoint())&& pane.returnImage() == field.getImage()) coverPage();
frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent arg0) {
}
public void mouseReleased(MouseEvent arg0) {
}
}
);
}
private void mouseMovement()
{
pane.addMouseMotionListener(new MouseMotionListener()
{
#Override
public void mouseMoved(MouseEvent e) {
if(search.contains(e.getPoint())&& pane.returnImage() == cover.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(enter.contains(e.getPoint())&& pane.returnImage() == cover.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(open.contains(e.getPoint())&& pane.returnImage() == cover.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(nextPage.contains(e.getPoint())&& pane.returnImage() == pages.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(prevPage.contains(e.getPoint())&& pane.returnImage() == pages.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else if(cancel.contains(e.getPoint())&& pane.returnImage() == field.getImage()){
frame.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
else{
frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
#Override
public void mouseDragged(MouseEvent e) {
}
}
);
}
private void updateInteraction(){
mouseMovement();
mouseAction();
keyPress();
}
public class PaintPane extends JPanel {
private Image background;
private Graphics g2d;
public PaintPane(Image image) {
background = image;
}
#Override
public Dimension getPreferredSize() {
return background == null ? new Dimension(0, 0) : new Dimension(background.getWidth(this), background.getHeight(this));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
Insets insets = getInsets();
int width = getWidth() - 1 - (insets.left + insets.right);
int height = getHeight() - 1 - (insets.top + insets.bottom);
int x = (width - background.getWidth(this)) / 2;
int y = (height - background.getHeight(this)) / 2;
g.drawImage(background, x, y, this);
}
//g.fillRect(654, 798, 358, 77); //for testing rectangle positioning
}
public Image returnImage() {
return background;
}
}
I'm using BluJ to write this, and it has a built in Debugger. I just tried adding keyPress(); before the updateInteraction(); in createWord(), and ran the Debugger to go through each method step by step. Everything worked perfectly. Then I tried without the Debugger, and it wouldn't display any text while I was typing. So, I turned on the Debugger again. It didn't detect any keys being typed at all. I don't know why it only worked that once, but it was definitely working. This is my first time working with KeyListener, MouseListener, and MouseMotionListener. Is there a better way to get this program to run properly?
and it wouldn't display any text while I was typing
A component needs to have focus in order to respond to KeyEvents. A JPanel is not focusable by default.
I'm making my own text field
Why? What functionality is missing from JTextField?
I would just use JTextField and then add a DocumentListener to the document from the text field. Read the section from the Swing tutorial on How to Write a Document Listener for more information.
Your Component must have the focus for keyboard input on Key Event. However, to check it in action, first make your JPanle focus-able by panel.setFocusable(true). Then try with panel.requestFocusInWindow()
to get the focus to panel on application start-up.
However, in your code:
for(int i = 97; i <= 122; i++){
//Cycles through every lowercase letter
if(e.getKeyChar() == (char)(i)&& pane.returnImage() == field.getImage()){
text += (char)(i);
break;
}
}
Why do you have to use a loop here? Just simply putting:
if(evt.getKeyChar() >=97 && evt.getKeyChar() <=122 && pane.returnImage() == field.getImage())
text += evt.getKeyChar()
Should do the work.
If you are just doing a learning exercise, then it's OK to make your own implementation instead of using JTextField. You can make a JPanel receive key events by calling setFocusable(true) on it.
Even after that, you should be aware of something that will probably trip you up: keyTyped callbacks don't fill out the keyCode property of KeyEvents. This is because it's possible to type in characters that do not have a single associated key. For example, on Windows you can fire keyPressed once by typing ALT+0160. You hit 5 keys but entered one character (a space) and got a single keyPressed callback.
To summarize: keyPressed and keyReleased deliver keyCodes and might deliver keyChar. keyTyped never gets a keyCode, and always gets a keyChar.
public class PanelKeyListener extends JFrame {
private JPanel _contentPane;
StringBuilder _stringBuilder = new StringBuilder();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
PanelKeyListener frame = new PanelKeyListener();
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public PanelKeyListener() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
_contentPane = new JPanel() {
protected void paintComponent(java.awt.Graphics g) {
g.drawString(_stringBuilder.toString(), 10, 20);
}
};
setContentPane(_contentPane);
_contentPane.setFocusable(true);
_contentPane.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
System.out.println("keyTyped char[" + e.getKeyChar()
+ "] code[" + e.getKeyCode() + "]");
_stringBuilder.append(e.getKeyChar());
_contentPane.repaint();
}
public void keyReleased(KeyEvent e) {
System.out.println("keyReleased char[" + e.getKeyChar()
+ "] code[" + e.getKeyCode() + "]");
}
public void keyPressed(KeyEvent e) {
System.out.println("keyPressed char[" + e.getKeyChar()
+ "] code[" + e.getKeyCode() + "]");
}
});
}
}
You shouldn't reinvent the wheel if you can avoid it. Use/extend JTextField if it's practical to do so and meets your needs.
Related
I'm trying to make a game in java, just a simple platformer, but I'm having difficulty when running the code. I can't seem to get any response from key presses. The only thing I can think hasn't been working properly is the keyPressed and keyReleased functions. Below is the relevant code.
public ReflexPanel() {
initBoard();
setFocusable(true);
addKeyListener(this);
Timer timer = new Timer(1000/120, this);
timer.start();
}
private void initBoard() {
loadMenu();
int w = menu.getWidth(this);
int h = menu.getHeight(this);
setPreferredSize(new Dimension(w, h));
}
private void step() {
if(mainMenu){
if(ePressed) {
System.exit(0);
}
if(hPressed) {
loadScores();
repaint();
}
}
}
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 'e') {
ePressed = true;
}
if (e.getKeyCode() == 'h') {
hPressed = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == 'e') {
ePressed = false;
}
if (e.getKeyCode() == 'h') {
hPressed = false;
}
}
#Override
public void actionPerformed(ActionEvent e) {
step();
}
The ePressed and hPressed variables are just booleans set to false by default, and loadScores calls a png file.
You can't do this:
if(e.getKeyCode() == 'e'){
// code logic
}
KeyEvent::getKeyCode doesn't return the char you press on the keyboard. It "returns the integer keyCode associated with the key in this event". When using KeyEvent::getKeyCode you have to use the KeyEvent key constants values predefined in the class. So for example:
if(e.getKeyCode() == KeyEvent.VK_E){
// code logic
}
Or you can use KeyEvent::getKeyChar which "returns the character associated with the key in this event".
You're using getKeyCode() which returns an int value with constants given in KeyEvent class, such as KeyEvent.VK_E.
You're looking to use getKeyChar() which returns 'e' directly.
if (e.getKeyChar() == 'e') { // Now it has an actual chance of working
Supposedly whenever you press a key, it should access the code, but it doesn't and neither do I or my teacher know why. Here's the code:
class KeyInput implements KeyListener{
Actor player;
Graphics gBuffer;
public KeyInput(Actor player, Graphics gBuffer){
JTextField typingArea = new JTextField(20);
typingArea.addKeyListener(this);
this.player = player;
this.gBuffer = gBuffer;
}
public void keyReleased(KeyEvent e){
}
public void keyTyped(KeyEvent e){
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
player.modActor(1);
gBuffer.drawString("ENTER",150,100);
}
if (key == KeyEvent.VK_RIGHT) {
player.modActor(2);
gBuffer.drawString("ENTER",150,100);
}
if (key == KeyEvent.VK_UP) {
player.modActor(3);
gBuffer.drawString("ENTER",150,100);
}
if (key == KeyEvent.VK_DOWN) {
player.modActor(4);
gBuffer.drawString("ENTER",150,100);
}
}
}
And this is the while that plays during the program:
public void paint(Graphics g){ //main method to be called to play(g);
do{
drawBackground(gBuffer);
gBuffer.setFont(new Font("Calibri",Font.BOLD,20));
gBuffer.setColor(Color.CYAN);
gBuffer.drawString("Score: " + (int)score,18,20);
gBuffer.drawString("Score: " + (int)score,22,20);
gBuffer.drawString("Score: " + (int)score,20,22);
gBuffer.drawString("Score: " + (int)score,20,18);
gBuffer.setColor(Color.BLACK);
gBuffer.drawString("Score: " + (int)score,20,20);
play(gBuffer);
g.drawImage(virtualMem,0,0,this);
if(lose==false){
gBuffer.setFont(new Font("Calibri",Font.BOLD,50));
gBuffer.setColor(Color.CYAN);
gBuffer.drawString("GAME OVER",42,200);
gBuffer.drawString("GAME OVER",38,200);
gBuffer.drawString("GAME OVER",40,202);
gBuffer.drawString("GAME OVER",40,198);
gBuffer.setColor(Color.BLACK);
gBuffer.drawString("GAME OVER",40,200);
gBuffer.drawString("Final Score: " + (int)score,20,260);
}
}while(lose);
}
The key inputs need to move an actor I have, but it doesn't move at all, and yes, I click inside the applets every time. Any idea of whats going on?
EDIT: I have now gave up on keyListener and tried keyBindings, but I'm new with them and probably have something wrong, please help me...
public void init() {
panel = new JPanel();
this.setSize(400,700);
this.setFocusTraversalKeysEnabled(false);
this.addKeyListener(this);
player = new Actor(180,500);
virtualMem = createImage(400,800);
gBuffer = virtualMem.getGraphics();
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "up");
panel.getActionMap().put("up", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
gBuffer.drawString("IT WORKS", 150, 150);
repaint();
}
});
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "down");
panel.getActionMap().put("down", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
gBuffer.drawString("IT WORKS", 150, 150);
repaint();
}
});
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
panel.getActionMap().put("left", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
gBuffer.drawString("IT WORKS", 150, 150);
repaint();
}
});
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");
panel.getActionMap().put("right", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
gBuffer.drawString("IT WORKS", 150, 150);
repaint();
}
});
}
The while is still the same (play). When ever I click something it doesn't access the methods either.
I am afraid that maybe that infinite loop inside paint() is interfering with the events management (remember that there is a single thread for those 2 things to be done). Why don't you just fire a repaint() on every significant event (for example, a key press)?
This is my code for a simple arrow sequencing application.
It generates a random sequence of size 4 which comprise of UP, DOWN, LEFT and/or RIGHT arrow keys and displays them one at a time. If they user repeats the sequence correctly, it displays another sequence of 5 keys. The size of the sequence keeps incrementing as long as the user enters the correct sequence but decrements if an invalid sequence has been entered.
The problem I'm encountering is, the first execution is flawless, it even displays the sequence the second time, but it doesn't accept my keyboard inputs during the second iteration.
For a better understanding of the problem I have broken it down into the main action performing blocks and the full code as well at the end.
Sequence Generation
for(int flag=1;flag<size;flag++)
{
random = randomGenerator.nextInt(4);
generated[flag]=random;
setVisible(true);
switch(random)
{
case 0:
left();
break;
case 1:
up();
break;
case 2:
right();
break;
case 3:
down();
break;
}
delaybig();
}
User Input Sequence
public void keyPressed(KeyEvent e)
{
if(cflag<=size)
{
if(e.getKeyCode()==37)
{
entered[cflag]=0;
cflag++;
Keys.setText("LEFT");
left();
}
else if(e.getKeyCode()==38)
{
entered[cflag]=1;
cflag++;
Keys.setText("UP");
up();
}
else if(e.getKeyCode()==39)
{
entered[cflag]=2;
cflag++;
Keys.setText("RIGHT");
right();
}
else if(e.getKeyCode()==40)
{
entered[cflag]=3;
cflag++;
Keys.setText("DOWN");
down();
}
else
{
Keys.setText("INVALID");
}
}
Sequence Comparision using Arrays.equals
if(cflag==size)
{
boolean check = Arrays.equals(generated, entered);
if(check)
{
delaysmall();
Keys.setText("PERFECT");
size++;
cflag=1;
delaysmall();
Keys.setText("GO AGAIN");
delaybig();
restart();
}
else
{
delaysmall();
Keys.setText("FAILED");
if(size>5)
{
delaybig();
restart();
size--;
cflag=1;
}
}
}
Looping Thread
public void restart()
{
Thread goagain = new Thread()
{
#Override
public void run()
{
launchframe();
}
};
goagain.start();
}
I've spent quite some time on this to no avail so here is the full code just incase you suspect the error likes elsewhere.
import java.io.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.Random;
import java.util.Arrays;
class ArrowSorrow extends Frame implements KeyListener{
int flag;
Image img;
int random;
int cflag=1,size=5;
boolean ShowImage=true;
int entered[]=new int[50];
int generated[]=new int[50];
TextField Keys=new TextField(8);
Random randomGenerator = new Random();
MediaTracker mt = new MediaTracker(this);
public ArrowSorrow(String title)
{
super(title);
}
public void restart()
{
// Create a new thread
Thread goagain = new Thread()
{
// Override run() to provide the running behavior of this thread.
#Override
public void run()
{
launchframe();
}
};
goagain.start();
}
public void launchframe()
{
for(int flag=1;flag<1;flag++)
generated[flag]=0;
for(int flag=1;flag<1;flag++)
entered[flag]=0;
splash();
add(Keys);
delaybig();
setSize(400,400);
Keys.setEditable(false);
Keys.setText("MEMORIZE");
Keys.addKeyListener(this);
setBackground(Color.black);
setLayout(new FlowLayout());
for(int flag=1;flag<size;flag++)
{
random = randomGenerator.nextInt(4);
generated[flag]=random;
setVisible(true);
switch(random)
{
case 0:
left();
break;
case 1:
up();
break;
case 2:
right();
break;
case 3:
down();
break;
}
delaybig();
}
String sequence=new String("");
for(flag=1;flag<size;flag++)
{
sequence=sequence+(Integer.toString(generated[flag]));
}
Keys.setText(sequence);
delaysmall();
Keys.setText("REPEAT");
delaysmall();
setVisible(true);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
dispose();
}
});
}
public void splash()
{
img = ToolKit.getDefaultToolkit().getImage("image address for splashscreen.jpg");
mt.addImage(img,0);
repaint();
setVisible(true);
}
public void left()
{
img = Toolkit.getDefaultToolkit().getImage("image address for left.jpg");
mt.addImage(img,0);
repaint();
setVisible(true);
}
public void right()
{
img = Toolkit.getDefaultToolkit().getImage("image address for right.jpg");
mt.addImage(img,0);
repaint();
setVisible(true);
}
public void up()
{
img = Toolkit.getDefaultToolkit().getImage("image address for up.jpg");
mt.addImage(img,0);
repaint();
setVisible(true);
}
public void down()
{
img = Toolkit.getDefaultToolkit().getImage("image address down.jpg");
mt.addImage(img,0);
repaint();
setVisible(true);
}
//minor delay
public void delaysmall()
{
try
{
Thread.sleep(600);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
//major delay
public void delaybig()
{
try
{
Thread.sleep(1200);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
public void paint(Graphics g)
{
super.paint(g);
if(img != null)
g.drawImage(img,70,70, this);
else
g.clearRect(0, 0, getSize().width, getSize().height);
}
public void keyPressed(KeyEvent e)
{
if(cflag<size)
{
if(e.getKeyCode()==37)
{
entered[cflag]=0;
cflag++;
Keys.setText("LEFT");
left();
}
else if(e.getKeyCode()==38)
{
entered[cflag]=1;
cflag++;
Keys.setText("UP");
up();
}
else if(e.getKeyCode()==39)
{
entered[cflag]=2;
cflag++;
Keys.setText("RIGHT");
right();
}
else if(e.getKeyCode()==40)
{
entered[cflag]=3;
cflag++;
Keys.setText("DOWN");
down();
}
else
{
Keys.setText("INVALID");
}
}
//comparing generated sequence and user input sequence
if(cflag==size)
{
boolean check = Arrays.equals(generated, entered);
if(check)
{
delaysmall();
Keys.setText("PERFECT");
size++;
cflag=1;
delaysmall();
Keys.setText("GO AGAIN");
delaybig();
restart();
}
else
{
delaysmall();
Keys.setText("FAILED");
if(size>5)
{
delaybig();
restart();
size--;
cflag=1;
}
}
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e){}
}
class ArrowSorrowLaunch{
public static void main(String args[])
{
ArrowSorrow instance=new ArrowSorrow("Arrow Sorrow");
instance.launchframe();
}
}
You call launchFrame to start each iteration of the game. However, you are doing a lot of work in launchFrame that should be done only once. You should move that initialization code out of launchFrame and do it only once. In particular you should not repeatedly call Keys.addKeyListener(this); or add multiple window listeners.
change Thread.sleep(int) to Swing Timer, otherwise you'll bothering with Concurency in Swing
Thread.sleep(int) freeze Swing GUI until ended, during this sleep any Mouse or Key events aren't dispatched or consumed
don't paint directly to the JFrame, put there JPanel or JComponent
for JPanel or JComponent have to use paintComponent instead of paint()
don't use KeyListener, use Keybindings instead, otherwise have to setFocusable()
Solution by OP.
Fix, thanks to Ted Hopp.
Created this new method by moving them out of launchframe()
void oneTime()
{
add(Keys);
setSize(400,400);
Keys.requestFocus();
Keys.setEditable(false);
Keys.setText("MEMORIZE");
Keys.addKeyListener(this);
setBackground(Color.black);
setLayout(new FlowLayout());
launchframe();
}
Replaced
instance.launchframe();//this
instance.oneTime();//with this in main
I search the forum and see this codes:
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
System.out.println(" and it's a double click!");
wasDoubleClick = true;
} else {
Integer timerinterval = (Integer) Toolkit.getDefaultToolkit().getDesktopProperty(
"awt.multiClickInterval");
timer = new Timer(timerinterval.intValue(), new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (wasDoubleClick) {
wasDoubleClick = false; // reset flag
} else {
System.out.println(" and it's a simple click!");
}
}
});
timer.setRepeats(false);
timer.start();
}
}
but the code runs incorrectly(Sometime it prints out " and it's a single click!" 2 times . It should print out " and it's a double click!"). Can anybody show me why? or can you give me some better ways to do this?
Thank you!
Sometime it prints out " and it's a single click!" 2 times . It should print out " and it's a double click!").
That is normal. A double click only happens if you click twice within the specified time interval. So sometimes if you don't click fast enough you will get two single clicks in a row.
Integer timerinterval = (Integer) Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
The above line of code determines how fast the double click must be.
For what its worth here is some code I have used to do the same thing. Don't know if its any better or worse than the code you have:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ClickListener extends MouseAdapter implements ActionListener
{
private final static int clickInterval = (Integer)Toolkit.getDefaultToolkit().
getDesktopProperty("awt.multiClickInterval");
MouseEvent lastEvent;
Timer timer;
public ClickListener()
{
this(clickInterval);
}
public ClickListener(int delay)
{
timer = new Timer( delay, this);
}
public void mouseClicked (MouseEvent e)
{
if (e.getClickCount() > 2) return;
lastEvent = e;
if (timer.isRunning())
{
timer.stop();
doubleClick( lastEvent );
}
else
{
timer.restart();
}
}
public void actionPerformed(ActionEvent e)
{
timer.stop();
singleClick( lastEvent );
}
public void singleClick(MouseEvent e) {}
public void doubleClick(MouseEvent e) {}
public static void main(String[] args)
{
JFrame frame = new JFrame( "Double Click Test" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.addMouseListener( new ClickListener()
{
public void singleClick(MouseEvent e)
{
System.out.println("single");
}
public void doubleClick(MouseEvent e)
{
System.out.println("double");
}
});
frame.setSize(200, 200);
frame.setVisible(true);
}
}
public void mouseClicked(MouseEvent evt) {
if (evt.getButton()==MouseEvent.BUTTON1){
leftClick = true; clickCount = 0;
if(evt.getClickCount() == 2) doubleClick=true;
Integer timerinterval = (Integer)Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
timer = new Timer(timerinterval, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(doubleClick){
System.out.println("double click.");
sb = new StringBuffer();
sb.append("Double Click");
clickCount++;
if(clickCount == 2){
clickCount=0;
doubleClick = false;
}
} else {
sb = new StringBuffer();
sb.append("Left Mouse");
System.out.println("single click.");
}
}
});
timer.setRepeats(false);
timer.start();
if(evt.getID()==MouseEvent.MOUSE_RELEASED) timer.stop();
}
I would like to ask the same thing than this question but using SWT: Is there a way to make a Button with your own button graphic not just with an image inside the button? If not is another way to create a custom button in java?
public class ImageButton extends Canvas {
private int mouse = 0;
private boolean hit = false;
public ImageButton(Composite parent, int style) {
super(parent, style);
this.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
switch (mouse) {
case 0:
// Default state
e.gc.drawString("Normal", 5, 5);
break;
case 1:
// Mouse over
e.gc.drawString("Mouse over", 5, 5);
break;
case 2:
// Mouse down
e.gc.drawString("Hit", 5, 5);
break;
}
}
});
this.addMouseMoveListener(new MouseMoveListener() {
public void mouseMove(MouseEvent e) {
if (!hit)
return;
mouse = 2;
if (e.x < 0 || e.y < 0 || e.x > getBounds().width
|| e.y > getBounds().height) {
mouse = 0;
}
redraw();
}
});
this.addMouseTrackListener(new MouseTrackAdapter() {
public void mouseEnter(MouseEvent e) {
mouse = 1;
redraw();
}
public void mouseExit(MouseEvent e) {
mouse = 0;
redraw();
}
});
this.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
hit = true;
mouse = 2;
redraw();
}
public void mouseUp(MouseEvent e) {
hit = false;
mouse = 1;
if (e.x < 0 || e.y < 0 || e.x > getBounds().width
|| e.y > getBounds().height) {
mouse = 0;
}
redraw();
if (mouse == 1)
notifyListeners(SWT.Selection, new Event());
}
});
this.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (e.keyCode == '\r' || e.character == ' ') {
Event event = new Event();
notifyListeners(SWT.Selection, event);
}
}
});
}
}
No, you can add a PaintListener to a button, but it will probably look really strange.
What you would need to do is to set the style of the window to "owner drawn" and than add your drawing code in the Button#wmDrawChild method. This means you need to add dependencies on internal SWT-classes and it will only work for Windows.