Я делаю приложение для фортепиано на Java.Это одна из функций,
public void playOnce(int time) {
play();
doClick(time);
stop();
}
public void play() {
channel[0].noteOn(note, 60);
}
public void stop() {
channel[0].noteOff(note);
}
Я приведу минимальный рабочий пример, если необходимо, но я хотел убедиться, что это не очевидная проблема.Проблема в том, что playOnce вызывается в цикле while.playOnce находится в классе Key, и каждый Key имеет отдельную заметку.В каждой итерации цикла while playOnce вызывается для другого ключа.Как только все клавиши будут воспроизведены, он останавливается.
Метод doClick правильно нажал клавишу, но он не отпускается до тех пор, пока все клавиши не будут воспроизведены.На самом деле, во время игры на клавишах вы ничего не можете сделать, даже нажмите кнопку паузы.Для этой проблемы, я думаю, я мог бы поместить весь цикл в другой поток, но я не думаю, что этот тип решения позволит освободить ключ.
РЕДАКТИРОВАТЬ: Да, я понял, что мне нужноновый поток, чтобы заставить другие действия работать, но мне все еще нужно исправить для doClick ().Это может быть сложнее, чем я думал, вот рабочий пример:
Main.java
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.text.DecimalFormat;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.SpinnerNumberModel;
public class Main implements ActionListener {
final int WHITE_KEY_WIDTH, WHITE_KEY_HEIGHT, BLACK_KEY_WIDTH,
BLACK_KEY_HEIGHT;
final int WIDTH;
final JFileChooser fc;
{
WHITE_KEY_WIDTH = Key.WHITE_KEY_WIDTH;
BLACK_KEY_WIDTH = Key.BLACK_KEY_WIDTH;
WHITE_KEY_HEIGHT = Key.WHITE_KEY_HEIGHT;
BLACK_KEY_HEIGHT = Key.BLACK_KEY_HEIGHT;
WIDTH = 3 * (WHITE_KEY_WIDTH * 7) + WHITE_KEY_WIDTH;
fc = new JFileChooser();
}
public static Key keys[] = new Key[48];
private static int index = 0;
private String prevText = "";
JTextArea shabadEditor = null;
JSpinner tempoControl;
JFrame frame;
File curFile;
public static void main(String[] args) {
new Main();
}
public Main() {
frame = new JFrame();
JPanel mainPanel = new JPanel();
JPanel controlPanel = new JPanel();
JLayeredPane pianoPanel = new JLayeredPane();
mainPanel.setLayout(new GridBagLayout());
JButton playButton = new JButton("Play");
JButton pauseButton = new JButton("Pause");
playButton.addActionListener(this);
playButton.setActionCommand("play");
pauseButton.addActionListener(this);
pauseButton.setActionCommand("pause");
SpinnerNumberModel model = new SpinnerNumberModel(1, 0, 2, .1);
tempoControl = new JSpinner(model);
JSpinner.NumberEditor editor = (JSpinner.NumberEditor) tempoControl
.getEditor();
DecimalFormat format = editor.getFormat();
format.setMinimumFractionDigits(1);
Dimension d = tempoControl.getPreferredSize();
d.width = 40;
tempoControl.setPreferredSize(d);
GridBagConstraints c = new GridBagConstraints();
// Construct each top level component
controlPanel.add(playButton);
controlPanel.add(pauseButton);
controlPanel.add(tempoControl);
shabadEditor = new JTextArea(20, 78);
constructKeyboard(pianoPanel);
// Add the piano panel and shabad editor to the window
c.gridx = 0;
c.gridy = 0;
c.weightx = 1.0;
c.anchor = GridBagConstraints.NORTHWEST;
mainPanel.add(controlPanel, c);
c.gridx = 0;
c.gridy = 1;
c.weightx = 1.0;
// c.weighty = 1.0;
c.anchor = GridBagConstraints.NORTHWEST;
pianoPanel
.setPreferredSize(new Dimension(WIDTH - 18, WHITE_KEY_HEIGHT));
mainPanel.add(pianoPanel, c);
c.gridx = 0;
c.gridy = 2;
c.weightx = 1.0;
c.weighty = 1.0;
c.anchor = GridBagConstraints.NORTHWEST;
mainPanel.add(shabadEditor, c);
frame.add(mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(WIDTH, WHITE_KEY_HEIGHT * 3 + 30);
frame.setLocation(250, 60);
frame.setVisible(true);
}
void constructKeyboard(Container panel) {
int i = 0;
int j = 0;
for (int k = 0; k < 3; k++) {
addWhiteKey(panel, i++);
addBlackKey(panel, j++);
addWhiteKey(panel, i++);
addBlackKey(panel, j++);
addWhiteKey(panel, i++);
addWhiteKey(panel, i++);
j++;
addBlackKey(panel, j++);
addWhiteKey(panel, i++);
addBlackKey(panel, j++);
addWhiteKey(panel, i++);
addBlackKey(panel, j++);
j++;
addWhiteKey(panel, i++);
}
}
void addWhiteKey(Container panel, int i) {
WhiteKey b = new WhiteKey();
b.setLocation(i++ * WHITE_KEY_WIDTH, 0);
panel.add(b, 0, -1);
keys[index++] = b;
}
void addBlackKey(Container panel, int factor) {
BlackKey b = new BlackKey();
b.setLocation(WHITE_KEY_WIDTH - BLACK_KEY_WIDTH / 2 + factor
* WHITE_KEY_WIDTH, 0);
panel.add(b, 1, -1);
keys[index++] = b;
}
@Override
public void actionPerformed(ActionEvent arg0) {
String action = arg0.getActionCommand();
if (action.equals("play")) {
System.out.println("working");
for (int i = 0; i < 10; i++) {
keys[i].playOnce(500);
}
}
}
}
Key.java
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Synthesizer;
import javax.swing.JButton;
public class Key extends JButton implements MouseListener {
private static final long serialVersionUID = 1L;
public static final int WHITE_KEY_HEIGHT = 200;
public static final int WHITE_KEY_WIDTH = 40;
public static final int BLACK_KEY_WIDTH = 20;
public static final int BLACK_KEY_HEIGHT = 120;
private static int noteCount = 40;
public int note;
private static Synthesizer synth = null;
static {
try {
synth = MidiSystem.getSynthesizer();
synth.open();
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
}
MidiChannel channel[];
public Key() {
note = noteCount++;
// Instrument[] instruments = synth.getAvailableInstruments();
// for (Instrument instrument : instruments) {
// System.out.println(instrument.getName());
// System.out.println(instrument.getPatch().getBank());
// System.out.println(instrument.getPatch().getProgram());
// }
channel = synth.getChannels();
channel[0].programChange(20);
addMouseListener(this);
}
public void playOnce(int time) {
play();
doClick(time);
stop();
}
public void play() {
channel[0].noteOn(note, 60);
}
public void stop() {
channel[0].noteOff(note);
}
@Override
public void mouseClicked(MouseEvent e) {
System.out.println(this.note);
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
play();
}
@Override
public void mouseReleased(MouseEvent e) {
stop();
}
}
BlackKey.java
import java.awt.Color;
public class BlackKey extends Key {
private static final long serialVersionUID = 1L;
public BlackKey() {
super();
setBackground(Color.BLACK);
setSize(BLACK_KEY_WIDTH, BLACK_KEY_HEIGHT);
}
}
WhiteKey.java
import java.awt.Color;
public class WhiteKey extends Key {
private static final long serialVersionUID = 1L;
public WhiteKey() {
super();
setBackground(Color.WHITE);
setSize(WHITE_KEY_WIDTH, WHITE_KEY_HEIGHT);
}
}
РЕДАКТИРОВАТЬ: После небольшой работы с потоками, это то, что у меня есть
Поместив цикл for в другой поток,Клавиши отпускаются в нужное время:
@Override
public void actionPerformed(ActionEvent arg0) {
String action = arg0.getActionCommand();
if (action.equals("play")) {
System.out.println("working");
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 20; i++) {
keys[i].playOnce(100);
}
}
}).start();
}
}
}
Теперь проблема в том, что клавиатура глючит.Клавиатура создается с использованием многоуровневой панели, и по какой-то причине, когда клавиши отпущены, слои, которые должны быть внизу, становятся верхними.Когда я наводю на них мышь, глюк исчезает.Есть идеи?
EDIT2: я исправил глюки.Мне просто нужно было добавить
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
после doClick ();