How to create a Piano using JScrollPane and JLayeredPane
我需要使用JScrollPane内的JLayeredPane创建一个包含四个八度音阶的虚拟钢琴,以便最初显示一个八度音阶,并且可以水平滚动查看其他八度音阶。 我的代码仅显示一个八度,不显示滚动条和其他八度。 以下代码有什么问题?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | 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; } } |
这不是一个纯粹的解决方案,因为确实应该使用自定义布局管理器来布局组件并确定首选大小。