8

私はSwing、スレッド化、invokeLater()、SwingWorkerなどについてたくさん読んでいますが、すべてを理解することができないように思われるので、説明するための非常に単純なプログラムを作成しようとしました。私はたくさんの例を見てきましたが、どれも私がやろうとしていることを示しているようには見えません。

これが私の例でやろうとしていることです。ボタンとラベルがあり、ボタンをクリックすると、プログラムを3秒間一時停止してから、ラベルのテキストにピリオドを追加します。その3秒間、GUIを通常どおりに表示し、追加のクリックに応答し続けたいと思います。これが私が書いたものです:

import javax.swing.SwingWorker;

public class NewJFrame extends javax.swing.JFrame
{
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;

    public NewJFrame()
    {
        initComponents();
    }
    private void initComponents()
    {
        jButton1 = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        jButton1.setText("Button");
        jButton1.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                jButton1ActionPerformed(evt);
            }
        });
        getContentPane().add(jButton1, java.awt.BorderLayout.CENTER);
        jLabel1.setText("Text");
        getContentPane().add(jLabel1, java.awt.BorderLayout.PAGE_END);
        pack();
    }

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
    {
        SwingWorker worker=new SwingWorker()
        {
            protected Object doInBackground()
            {
                try{Thread.sleep(3000);}
                catch (InterruptedException ex){}
                return null;
            }
        };
        worker.execute();
        jLabel1.setText(jLabel1.getText()+".");
    }

    public static void main(String args[])
    {
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            public void run(){ new NewJFrame().setVisible(true); }
        });
    }
}

このコードでは、ボタンをクリックすると、ピリオドがラベルにすぐに追加されます。これは、バックグラウンドスレッドを作成してスリープしているため、EDTを使用してラベルをすぐに更新できるためです。だから私はこれを試しました:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
    Thread thread = new Thread();
    try{ thread.sleep(3000);}
    catch (InterruptedException ex){}
    jLabel1.setText(jLabel1.getText()+".");
}

これは、EDTをブロックして、ラベルのテキストにピリオドを追加する前にボタンを3秒間青色に変えることを除いて、ほとんど機能します。ボタンをすばやくクリックしただけで、ボタンが3秒間押されているように見せたくないので、これを試しました。

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
    SwingWorker worker=new SwingWorker()
    {
        protected Object doInBackground()
        {
            try{Thread.sleep(3000);}
            catch (InterruptedException ex){}
            jLabel1.setText(jLabel1.getText()+".");
            return null;
        }
    };
    worker.execute();
}

これは機能しているように見えますが、EDTではなくバックグラウンドスレッドからjLabel1.setText(...)を呼び出していないため、「Swingシングルスレッドルール」に違反していますか?もしそうなら、望ましい効果を達成するためのより良い方法はありますか?そうでない場合は、その理由を説明していただけますか?

4

1 に答える 1

4

あなたは本当に近いです...

代わりにこのようなものを試してください。

SwingWorker worker=new SwingWorker()
{
    protected Object doInBackground()
    {
        try{
            Thread.sleep(3000);
        }catch (InterruptedException ex){}
        return null;
    }

    // This is executed within the context of the EDT AFTER the worker has completed...    
    public void done() {
        jLabel1.setText(jLabel1.getText()+".");
    }
};
worker.execute();

を使用して、EDTで実行されているかどうかを確認できます。EventQueue.isDispatchingThread()

更新しました

また、より簡単かもしれないを使用することができjavax.swing.Timerます...

Timer timer = new Timer(3000, new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        jLabel1.setText(jLabel1.getText()+".");
    }
});
timer.setRepeats(false);
timer.start();
于 2013-02-27T01:07:09.730 に答える