如何使用JScrollPane和JLayeredPane创建钢琴

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

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

但我只是更改了代码以实现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; } } 

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