How to create a Piano using JScrollPane and JLayeredPane

后端 未结 1 398
北荒
北荒 2020-12-20 09:10

I need to create a virtual piano containing four octaves using JLayeredPane inside a JScrollPane such that one octave is shown initially, and can be scrolled horizontally to

相关标签:
1条回答
  • 2020-12-20 09:50

    Here is an example I found on a forum a long time ago. I know nothing about music so I don't understand how the logic works to create the sounds and keys.

    But I did just change the code to implement the getPreferredSize() method so that the scrollpane will work properly:

    import java.awt.*;
    import java.awt.event.*;
    import javax.sound.midi.Instrument;
    import javax.sound.midi.MidiChannel;
    import javax.sound.midi.MidiSystem;
    import javax.sound.midi.MidiUnavailableException;
    import javax.sound.midi.Synthesizer;
    import javax.swing.*;
    
    public class MidiPiano implements MouseListener {
    
        final int OCTAVES = 4; // change as desired
    
        private WhiteKey[] whites = new WhiteKey [7 * OCTAVES + 1];
        private BlackKey[] blacks = new BlackKey [5 * OCTAVES];
    
        MidiChannel channel;
    
        public MidiPiano () {
    
            try {
                Synthesizer synth = MidiSystem.getSynthesizer ();
                synth.open ();
                synth.loadAllInstruments (synth.getDefaultSoundbank ());
                Instrument [] insts = synth.getLoadedInstruments ();
                MidiChannel channels[] = synth.getChannels ();
                for (int i = 0; i < channels.length; i++) {
                    if (channels [i] != null) {
                        channel = channels [i];
                        break;
                    }
                }
    
                for (int i = 0; i < insts.length; i++) {
                    if (insts [i].toString ()
                            .startsWith ("Instrument MidiPiano")) {
                        channel.programChange (i);
                        break;
                    }
                }
            } catch (MidiUnavailableException ex) {
                ex.printStackTrace ();
            }
        }
    
        public void mousePressed (MouseEvent e) {
            Key key = (Key) e.getSource ();
            channel.noteOn (key.getNote (), 127);
        }
    
        public void mouseReleased (MouseEvent e) {
            Key key = (Key) e.getSource ();
            channel.noteOff (key.getNote ());
        }
    
        public void mouseClicked (MouseEvent e) { }
        public void mouseEntered (MouseEvent e) { }
        public void mouseExited (MouseEvent e) { }
    
        private void createAndShowGUI () {
    
            JPanel contentPane = new JPanel(null)
            {
                @Override
                public Dimension getPreferredSize()
                {
                    int count = getComponentCount();
                    Component last = getComponent(count - 1);
                    Rectangle bounds = last.getBounds();
                    int width = 10 + bounds.x + bounds.width;
                    int height = 10 + bounds.y + bounds.height;
    
                    return new Dimension(width, height);
                }
    
                @Override
                public boolean isOptimizedDrawingEnabled()
                {
                    return false;
                }
            };
    
    
            for (int i = 0; i < blacks.length; i++) {
                blacks [i] = new BlackKey (i);
                contentPane.add (blacks [i]);
                blacks [i].addMouseListener (this);
            }
            for (int i = 0; i < whites.length; i++) {
                whites [i] = new WhiteKey (i);
                contentPane.add (whites [i]);
                whites [i].addMouseListener (this);
            }
    
            JFrame frame = new JFrame("Midi Piano");
            frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
            //frame.add( contentPane );
            frame.add( new JScrollPane(contentPane) );
            frame.pack();
            frame.setLocationRelativeTo (null);
            frame.setVisible(true);
        }
    
        public static void main (String[] args) {
            SwingUtilities.invokeLater (new Runnable () {
                public void run () {
                    new MidiPiano ().createAndShowGUI ();
                }
            });
        }
    }
    
    interface Key {
        // change WD to suit your screen
        int WD = 16;
        int HT = (WD * 9) / 2;
        // change baseNote for starting octave
        // multiples of 16 only
        int baseNote = 48;
    
        int getNote ();
    }
    
    
    class BlackKey extends JButton implements Key {
    
        final int note;
    
        public BlackKey (int pos) {
            note = baseNote + 1 + 2 * pos + (pos + 3) / 5 + pos / 5;
            int left = 10 + WD
                    + ((WD * 3) / 2) * (pos + (pos / 5)
                    + ((pos + 3) / 5));
            setBackground (Color.BLACK);
            setBounds (left, 10, WD, HT);
        }
    
        public int getNote () {
            return note;
        }
    }
    
    
    class WhiteKey  extends JButton implements Key {
    
        static int WWD = (WD * 3) / 2;
        static int WHT = (HT * 3) / 2;
        final int note;
    
        public WhiteKey (int pos) {
    
            note = baseNote + 2 * pos
                    - (pos + 4) / 7
                    - pos / 7;
            int left = 10 + WWD * pos;
            // I think metal looks better!
            //setBackground (Color.WHITE);
            setBounds (left, 10, WWD, WHT);
    
        }
    
        public int getNote () {
            return note;
        }
    }
    

    This is not a pure solution, because a custom layout manager really should be used to lay out the components and determine a preferred size.

    0 讨论(0)
提交回复
热议问题