How to create a Piano using JScrollPane and JLayeredPane

蹲街弑〆低调 提交于 2019-11-28 10:26:19

问题


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 see the other octaves. My code displays only one octave and does not show the scrollbar and the other octaves. What is the problem with the following code?

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:


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.



来源:https://stackoverflow.com/questions/29314733/how-to-create-a-piano-using-jscrollpane-and-jlayeredpane

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!