Pregunta

Question:

I have a class implementing a KeyListener to collect a list of pressed keys. The list is then delegated to an instance of KeyListener to be handled. Each time a key is released, it must be removed from the list.

My issue is that they are not being removed from the list because the KeyEvent I store in the list when pressed is not the same as the KeyEvent generated when the Key is released. This results in none of the KeyEvents being removed and thus, they accumulate.

What changes must I make to ensure that I can remove a KeyEvent with only knowledge of a different KeyEvent for the same key (the remove method checks with .equals())?


Code:

KeyListener subject;
    ArrayList<KeyEvent> pressed = new ArrayList<KeyEvent>();

    public MultiKeyListener(KeyListener subject) {
        this.subject = subject;
    }

    @Override
    public void keyPressed(KeyEvent k) {
        pressed.add(k);
        if (subject != null && pressed.size() > 0) {
            for (int i = 0; i < pressed.size(); i++) {
                subject.keyPressed(pressed.get(i));
            }
        }
    }

    @Override
    public void keyReleased(KeyEvent k) {
        pressed.remove(k);
        if (subject != null && pressed.size() > 0) {
            for (int i = 0; i < pressed.size(); i++) {
                subject.keyPressed(pressed.get(i));
            }
        }
    }

    @Override
    public void keyTyped(KeyEvent k) {

    }
¿Fue útil?

Solución

Use a wrapper around KeyEvent.

public class KeyEventWrapper
 {
     private KeyEvent keyEvent;

     public KeyEventWrapper(KeyEvent keyEvent)
      {
         this.keyEvent = keyEvent;
      }  

     public KeyEvent getKeyEvent()
      {
         return keyEvent;
      }

     public boolean equals(Object object)
      {
          if(object instanceof KeyEventWrapper)
            {
                KeyEventWrapper wrapper = (KeyEventWrapper) (object);
                KeyEvent k = wrapper.getKeyEvent();

                return (this.keyEvent.getKeyCode() == k.getKeyCode());
            } 
          return false;
      }

     public int hashCode()
       {
           return this.keyEvent.getKeyCode();
       }
 }

Now, you can use an ArrayList of this wrapper object instead of KeyEvent.

ArrayList<KeyEventWrapper> pressed = new ArrayList<KeyEventWrapper>();
... 
pressed.add(new (KeyEventWrapper(k));
...
pressed.remove(new (KeyEventWrapper(k));

Otros consejos

You would want to be storing which Key is pressed, not the KeyEvent itself. A new event occurs every time a key is pressed, typed, or released. What you want to keep track of is either the KeyCode or KeyChar.

Edit: Just another suggestion, you might want to consider using a Set instead of a List to keep track of which keys have been pressed. A single key realistically cannot be pressed more than once.

I'd say you should iterate pressed List from the end to the start and remove the first occurrence of KeyEvent there that has the same KeyCode. Something like this:

@Override
    public void keyReleased(KeyEvent k) {
        for (int i=pressed.size()-1;i>=0;i--) {
             if (pressed.get(i).getKeyCode()==k.getKeyCode()) {
                 pressed.remove(i);
                 break;
             }
        }
    ......
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top