2012-03-26 8 views
1

私はJavaでピアノアプリケーションを作っています。これは、機能の一つ、doループを終了するまでクリックしないでください。

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クラスにあり、各キーには異なるメモがあります。 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); 
    } 

} 

EDIT:スレッドでの作業のビットを行った後、これは私が別のスレッドでのループのために置くことで

を持っているもので、キーが適切なタイミングでリリースされています

@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:グリッチを修正しました。 doClick()の後に追加するだけです。

 try { 
     Thread.sleep(10); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

答えて

1

あなたのアプローチの問題は、イベントスレッドをブロックしていることです。このスレッドは、ユーザーの入力、ペイント、およびウィンドウの更新を行います。私の推測は今、doClickのタイムアウトがイベントスレッド(論理的なように見える)の内部でチェックされるので、actionPerformedメソッドが終了するまで解放されない(イベントスレッドはイベント処理を続けることができる)。

この問題を解決するには、すでに述べたようにforループを別のスレッドに移動し、doClickSwingUtilities.invokeLaterと呼んでください。

+0

forループが別のスレッドにあり、doClickがそのスレッド内で呼び出された場合、なぜinvokeLaterを呼び出す必要がありますか?他のスレッドのすべてが自動的に非同期で自動的に実行されるはずです。 – gsingh2011

+0

Java Swingは(ほとんどのGUIフレームワークのように)スレッドセーフではありません。'invokeLater'は、Swingコンポーネントを他のスレッドから更新するための推奨メソッドです。単に' invokeLater'に提供した 'Runnable'がイベントスレッドで実行されるようにします。 – Neet

+0

私は一番下の編集を見ることができますか?私はループを 'Runnable'に入れていますが、現在は動作していますが、キーはうんざりしています。 invokeLaterを使用すると、キーが解放されないようにするだけで問題が悪化しました。 – gsingh2011

関連する問題