Java 如何使用JScrollPane和JLayeredPane创建钢琴

Java 如何使用JScrollPane和JLayeredPane创建钢琴,java,swing,jscrollpane,jlayeredpane,piano,Java,Swing,Jscrollpane,Jlayeredpane,Piano,我需要在JScrollPane中使用JLayeredPane创建一个包含四个八度音阶的虚拟钢琴,这样一个八度音阶最初会显示,并且可以水平滚动以查看其他八度音阶。我的代码只显示一个八度,不显示滚动条和其他八度。以下代码有什么问题? class PianoLayout扩展了JScrollPane { 公共钢琴 { 初始化组件(); } 私有组件() { JLayeredPane层=新的JLayeredPane(); //ScrollableLayeredPane layer=新的Scrollabl

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

class PianoLayout扩展了JScrollPane
{
公共钢琴
{
初始化组件();
}
私有组件()
{
JLayeredPane层=新的JLayeredPane();
//ScrollableLayeredPane layer=新的ScrollableLayeredPane();
图层设置尺寸(1120150);
JButton[]键=新JButton[48];
int-keyIndex=0,i;

例如(i=0;i这是我很久以前在一个论坛上找到的一个例子。我对音乐一无所知,所以我不明白创建声音和键的逻辑是如何工作的

但我只是更改了代码以实现
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;
    }
}
import java.awt.*;
导入java.awt.event.*;
导入javax.sound.midi.Instrument;
导入javax.sound.midi.MidiChannel;
导入javax.sound.midi.midi系统;
导入javax.sound.midi.MidiUnavailableException;
导入javax.sound.midi.Synthesizer;
导入javax.swing.*;
公共类midistener{
最终整数倍频程=4;//根据需要更改
专用白键[]白色=新白键[7*八度+1];
专用黑键[]黑色=新黑键[5*八度];
中音信道;
公共MIDI钢琴(){
试一试{
合成器synth=MidiSystem.getSynthesizer();
synth.open();
synth.loadAllInstruments(synth.getDefaultSoundbank());
仪器[]仪器=synth.getLoadedInstruments();
MidiChannel channels[]=synth.getChannels();
对于(int i=0;i

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

不要从
JScrollPane
扩展,这不是该组件的工作方式,而是从
JPanel
扩展,然后将其应用于
JScrollPane
。有关更多详细信息,请参阅etails
JScrollPane
将使用首选尺寸的组件进行确定
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;
    }
}