Question

I am designing a virtual piano using Java7. I am having an issue with event calls however on mouse clicks. the JFrame (Piano) contains the JPanel (PianoKeyboard) which in turn contains several piano keys as JComponent(PianoKey). i would like the Piano class (jframe) to know which key was pressed when the respective icon is pressed.

Hence i have done the following the PianoKey has a MouseListener, who's methods are implemented within PianoKeyboard. PianoKeyboard has a KeyListener who's methods are implemented within Piano. The Key listener events are fired when an event is received from piano key.

The issue however is that when the icons are clicked on, none of the mouse event listener methods within piano keyboard are being triggered.

The Piano Class:

public class Piano extends JFrame implements KeyListener {

    public Piano() {
        super();
        this.setTitle("Piano");
        this.setName("Piano");      
        this.setSize(850,200);  
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);       
        PianoKeyboard s = new PianoKeyboard(0);
        s.addListener(this);
        this.getContentPane().add(s);
        this.setVisible(true);
    }
}

the Piano Keyboard Class:

public class PianoKeyboard extends JPanel implements MouseListener{
    ArrayList<KeyListener> listeners = new ArrayList<KeyListener>();
    public PianoKeyboard(int tempo){
        super();
        this.tempo = tempo;     
        this.setBackground(Color.WHITE);
        this.setEnabled(true);
        this.setSize(Piano.FRAME_SIZE);
        this.setVisible(true);
        this.setLayout(new OverlayLayout(this));
        createKeyboard();
    }
    public void addListener(KeyListener listener){
        listeners.add(listener);
    }

    private void createKeyboard() {
    ........ code ......
    for (int i = 0; i < 25; i++) {
            PianoKey k = new PianoKey(i+1, tempo);
            k.addMouseListener(this);           
            ..... code .....
            keys.add(k);
        }
    }

   /** the followign methods are also available:
         mouseClicked, mouseExited, mousePressed, mouseReleased
         which contain the following code when neeed:
         for(KeyListener k : listeners){
        k.keyPressed();
    }
   */

   public void paint(Graphics g){
        for(int i = 0; i < keys.size(); i++){
            g.drawImage(keys.get(i).getImage(),positions.get(i),0,54,150,null);
        }
    }
}

The Piano Key Class:

public class PianoKey extends JComponent {
    public PianoKey(int pitch,int tempo) {
        super();
    ....code....
    this.setImage(ImageIO.read(cl.getResource(IMAGE_DIRECTORY + "/key/white.png")));
}

The Key Listener:

public interface KeyListener {
    public void keyPressed();
}
Was it helpful?

Solution

I think what is going on is you haven't actually added the keys to any GUI to register mouse clicks. I see you adding them to what appears to be some kind of List but that's all. They 'appear' because the panel is painting images from them but that's not the same thing as actually being a visible part of the interface.

class PianoKey
extends JComponent {

    PianoKey(/* args */) {

        BufferedImage key = ImageIO.read(
            cl.getResource(IMAGE_DIRECTORY + "/key/white.png")
        );

        final Dimension sz = new Dimension(key.getWidth(), key.getHeight());
        setPreferredSize(sz);
        setMinimumSize(sz);
        setMaximumSize(sz);

        setImage(key);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        BufferedImage key = getImage();

        g.drawImage(key, 0, 0, key.getWidth(), key.getHeight(), null);
    }
}

class PianoKeyBoard
extends JPanel
implements MouseListener {

    PianoKeyBoard(/* args */) {

        setLayout(new GridLayout(25, 0));

        for( int i = 1; i <= 25; i++ ) {
            PianoKey key = new PianoKey(/* args */);

            key.addMouseListener(this);

            add(key);
        }
    }

    @Override
    public void mousePressed(MouseEvent me) {
        System.out.println("pressed");
    }
    @Override
    public void mouseClicked(MouseEvent me) {
        System.out.println("clicked");
    }
    @Override
    public void mouseReleased(MouseEvent me) {
        System.out.println("released");
    }
    @Override
    public void mouseEntered(MouseEvent me) {
        System.out.println("entered");
    }
    @Override
    public void mouseExited(MouseEvent me) {
        System.out.println("exited");
    }
}

class Piano
extends JFrame {

    Piano() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setContentPane(new PianoKeyBoard(/* args */));

        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Piano().setVisible(true);
            }
        });
    }
}

Something like that will work. Here, PianoKey paints the image and PianoKeyBoard just adds them to itself. Also, as a side note, make sure you are overriding paintComponent in Swing, not paint.

OTHER TIPS

implement this on your piano class :

public void keyTyped(KeyEvent e) {
    System.out.println("am i working?");
}

what happens now?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top