3

jframe内に複数のパネルがあるアプリケーションをセットアップしようとしています。それらのうちの 3 つが純粋に表示目的であり、そのうちの 1 つが制御目的であるとしましょう。私はborderLayoutを使用していますが、レイアウトが実際にここに影響を与えるべきではないと思います。

私の問題は次のとおりです。3 つのディスプレイ パネルの再描画をコントロール パネルのボタンで制御し、コントロール パネルのボタンが押されるたびにすべて同期して実行する必要があります。これを行うには、この小さなメソッドを設定します:

public void update(){
            while(ButtonIsOn){
                a.repaint();
                b.repaint()
                c.repaint();
                System.out.println("a,b, and c should have repainted");

                }
    }

ここで、a、b、および c はすべて表示パネルであり、ボタンをもう一度押すまで、a、b、および c をすべて継続的に再描画する必要があります。問題は、ループを実行するとメッセージが無限ループに出力されますが、どのパネルも何もしません。つまり、どれも再描画しません。

イベントディスパッチスレッドとスイングマルチスレッドについて読んでいますが、これまでに見つけたものは何も私の問題を本当に解決していません. 誰かが私がここで間違っていることの要点を教えてくれますか、それとももっと良いことに、私が説明している状況を処理するサンプルコードを教えてもらえますか? ありがとう...

4

3 に答える 3

2

java.util.concurrentパッケージは、並行プログラミングのための非常に強力なツールを提供します。

以下のコードでは、a を使用していますReentrantLock(これは Java キーワードとよく似ておりsynchronized、複数のスレッドが 1 つのコード ブロックに相互に排他的にアクセスできるようにします)。提供する他の優れた点ReentrantLockは、続行する前に特定のイベントを待機Conditionsできることです。Threads

ここでは、RepaintManager単純にループrepaint()して、 を呼び出しますJPanel。ただし、toggleRepaintMode()が呼び出されるとブロックされ、再度呼び出されるmodeChanged Conditionまで待機します。toggleRepaintMode()

次のコードをすぐに実行できるはずです。JButtonのトグル再描画を押します(ステートメントJPanelで動作することがわかります)。System.out.println

一般に、 java.util.concurrentが提供する機能に慣れることを強くお勧めします。非常に強力なものがたくさんあります。http://docs.oracle.com/javase/tutorial/essential/concurrency/に優れたチュートリアルがあります。

import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class RepaintTest {
    public static void main(String[] args) {

        JFrame frame = new JFrame();
        JPanel panel = new JPanel()
        {
            @Override
            public void paintComponent( Graphics g )
            {
                super.paintComponent( g );

                // print something when the JPanel repaints
                // so that we know things are working
                System.out.println( "repainting" );
            }
        };

        frame.add( panel );

        final JButton button = new JButton("Button");
        panel.add(button);

        // create and start an instance of our custom
        // RepaintThread, defined below
        final RepaintThread thread = new RepaintThread( Collections.singletonList( panel ) );
        thread.start();

        // add an ActionListener to the JButton
        // which turns on and off the RepaintThread
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                thread.toggleRepaintMode();
            }
        });

        frame.setSize( 300, 300 );
        frame.setVisible( true );
    }

    public static class RepaintThread extends Thread
    {
        ReentrantLock lock;
        Condition modeChanged;
        boolean repaintMode;
        Collection<? extends Component> list;

        public RepaintThread( Collection<? extends Component> list )
        {
            this.lock = new ReentrantLock( );
            this.modeChanged = this.lock.newCondition();

            this.repaintMode = false;
            this.list = list;
        }

        @Override
        public void run( )
        {
            while( true )
            {
                lock.lock();
                try
                {
                    // if repaintMode is false, wait until
                    // Condition.signal( ) is called
                    while ( !repaintMode )
                        try { modeChanged.await(); } catch (InterruptedException e) { }
                }
                finally
                {
                    lock.unlock();
                }

                // call repaint on all the Components
                // we're not on the event dispatch thread, but
                // repaint() is safe to call from any thread
                for ( Component c : list ) c.repaint();

                // wait a bit
                try { Thread.sleep( 50 ); } catch (InterruptedException e) { }
            }
        }

        public void toggleRepaintMode( )
        {
            lock.lock();
            try
            {
                // update the repaint mode and notify anyone
                // awaiting on the Condition that repaintMode has changed
                this.repaintMode = !this.repaintMode;
                this.modeChanged.signalAll();
            }
            finally
            {
                lock.unlock();
            }
        }
    }
}
于 2012-04-09T04:36:13.510 に答える
1
jComponent.getTopLevelAncestor().repaint();
于 2012-04-09T08:22:06.250 に答える
0

これにはSwingWorkerを使用できます。SwingWorker は、イベント ディスパッチャー スレッドをブロックすることなく、長時間実行されるタスクをバックグラウンドで実行するように設計されています。SwingWorkerそのため、自分にとって意味のある特定のメソッドを拡張して実装する必要があります。長時間実行されるすべてのアクションはdoInBackground()メソッドで発生する必要があり、Swing UI 要素はメソッドでのみ更新する必要があることに注意してくださいdone()

だからここに例があります:

class JPanelTask extends SwingWorker<String, Object>{
    JPanel panel = null;
    Color bg = null;
    public JPanelTask(JPanel panel){
        this.panel = panel;
    }
    @Override
    protected String doInBackground() throws Exception {
        //loooong running computation.
        return "COMPLETE";
    }
    @Override
    protected void done() {
        panel.repaint();
    }

}

これで、「コントロール」ボタンのアクション実行イベントで、次のことができます。

    controlButton.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            JPanelTask task1 = new JPanelTask(panel1);
            task1.execute();
            JPanelTask task2 = new JPanelTask(panel2);
            task2.execute();
           //so on..
        }
    });

別の方法は、javax.swing.Timerを使用することです。タイマーを使用すると、タイムリーに UI 要素に変更を加えることができます。これは、最適な解決策ではない可能性があります。しかし、それは仕事も成し遂げます。ここでも、適切な場所で UI 要素を更新することに注意する必要があります。

于 2012-04-09T04:06:49.083 に答える