如何使用JScrollPane和JLayeredPane创建钢琴

时间:2015-03-28 07:21:33

标签: java swing jscrollpane jlayeredpane piano

我需要在JScrollPane中使用JLayeredPane创建一个包含四个八度的虚拟钢琴,这样最初会显示一个八度音阶,并且可以水平滚动以查看其他八度音阶。我的代码只显示一个八度音,不显示滚动条和其他八度音程。以下代码有什么问题? Piano using JScrollPane and JLayeredPane

class PianoLayout extends JScrollPane
{
public PianoLayout()
{
    initComponents();

}

private void initComponents()
{
    JLayeredPane layer = new JLayeredPane();
    //ScrollableLayeredPane layer = new ScrollableLayeredPane();
    layer.setSize(1120,150);
    JButton[] keys = new JButton[48];
    int keyIndex = 0, i;

    for(i=0;i<28;i++)
    {
        keys[keyIndex] = createWhiteKey(i);
        layer.add(keys[keyIndex], 0, -1);
        keyIndex+=1;
        if(i%7!=2 && i%7!=6)
        {
            keys[keyIndex] = createBlackKey(i);
            layer.add(keys[keyIndex], 1, -1);
            keyIndex+=1;
        }
    }
    this.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    this.setViewportView(layer);
    setSize(280, 150);     
    setLocation(110,100);


}

private JButton createWhiteKey(int i)
{
    JButton whiteKey = new JButton();
    whiteKey.setBackground(Color.WHITE);
    whiteKey.setLocation(i*40,0);
    whiteKey.setSize(40, 150);
    return whiteKey;
}

private JButton createBlackKey(int i)
{
    JButton blackKey = new JButton();
    blackKey.setBackground(Color.BLACK);
    blackKey.setLocation(25 + i*40,0);
    blackKey.setSize(30, 90);
    return blackKey;
}

}

public class VirtualPiano 
{

public static void main(String[] args)
{
    JPanel panel = new JPanel(null);
    JFrame mainFrame = new JFrame();
    PianoLayout pianoLayout = new PianoLayout();
    mainFrame.add(panel);
    panel.add(pianoLayout);
    mainFrame.setSize(500,500);
    mainFrame.setVisible(true);
}

1 个答案:

答案 0 :(得分:1)

这是我很久以前在论坛上发现的一个例子。我对音乐一无所知,所以我不明白逻辑如何创造声音和键。

但我只是更改了代码以实现getPreferredSize()方法,以便滚动窗格正常工作:

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;
    }
}

这不是一个纯粹的解决方案,因为真的应该使用自定义布局管理器来布局组件并确定首选大小。