2

長時間実行されるいくつかの機能を実行するアプリケーションに取り組んでいます。処理が行われていることをユーザーに知らせるために、それを表すラベルを表示できるラベルが必要でした。そこで、そのようなラベル用の小さなウィジェットを作成しました。

以下のプログラムで find を実行すると、希望どおりの出力が得られます。

import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


/**
 * This is an extension to a JLabel that can be used to display an ongoing progress.
 * @author Ankit Gupta
 */
public class ProgressLabel extends JLabel {

    /**
     * The prefix label to which periods are added.
     */
    private String startLabel;
    /**
     * The label to display end of an operation.
     */
    private String endLabel;

    /**
     * Flag to indicate whether the animation is running or not.
     */
    private boolean running = false;
    //list to hold intermediate labels
    List<String> intermediateLabels;

    public ProgressLabel(String slbl, String elbl) {
        this.startLabel = slbl;
        this.endLabel = elbl;
        //initialize all the labels to be used once as creating them again and again is expensive
        intermediateLabels = new ArrayList<String>();
        intermediateLabels.add(startLabel+".");
        intermediateLabels.add(startLabel+"..");
        intermediateLabels.add(startLabel+"...");
        intermediateLabels.add(startLabel+"....");
    }

    public void done(){
        running = false;
    }

    public void start(){
        running = true;
        new LabelUpdateThread().start();
    }

    private class LabelUpdateThread extends Thread{
        int i;

        public LabelUpdateThread(){
            i=0;
        }

        @Override
        public void run(){
            while(running){
                SwingUtilities.invokeLater(new Runnable(){
                    @Override
                    public void run() {
                        setText(intermediateLabels.get((i++)%3));
                    }
                });

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {}
            }
            setText(endLabel);
        }
    }

    public static void main(String []args) throws InterruptedException{
        final JFrame frame = new JFrame("Testing ProgressLabel");
        JPanel panel = new JPanel();
        ProgressLabel progressLabel = new CZProgressLabel("Searching", "Done");
        panel.add(progressLabel);
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(500,500));
        frame.pack();
        progressLabel.start();
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                frame.setVisible(true);
            } 
        });
        Thread.sleep(5000);
        progressLabel.done();
    }
}

しかし、これをアプリケーションに含めようとすると、期待どおりに動作しませんでした。ボタン付きの小さなパネルを作成し、ボタンのactionPerfomed()コードで以前と同じようにProgressLabelstart( ) メソッドとdone()メソッドを使用しましたが、今回は長さのプロセスが完了するまでラベルがDoneに更新されませんでした。ProgressLabelwithを使用した別のコードを次に示しますactionPerformed()

public class SearchPanel extends JPanel {

    private JTextArea queryBox;
    private JButton searchBtn;
    private ProgressLabel progressLabel;
    private JSeparator queryAreaSeparator;

    public SearchPanel() {
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();

        //First Row
        gbc.gridy = 0;
        gbc.gridwidth = 2;
        gbc.gridx = 0;
        queryBox = new JTextArea();
        queryBox.setRows(25);
        queryBox.setColumns(25);
        this.add(queryBox, gbc);


        //Second Row
        gbc.gridy = 1;

        gbc.gridwidth = 1;
        progressLabel = new ProgressLabel("Searching", "Done");
        this.add(progressLabel, gbc);

        gbc.gridx = 1;
        searchBtn = new JButton("Search");
        this.add(searchBtn, gbc);
        searchBtn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                progressLabel.start();
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException ex) {
                    Exceptions.printStackTrace(ex);
                }
                //the above sleep() call will be replace by some time-consuming process. It is there just for testing now

                progressLabel.done();
            }
        });


        gbc.gridx = 0;
    }

    /**
     * function to test CZSemanticSearchLabel
     */
    public static void main(String[] args) throws InterruptedException {
        final JFrame frame = new JFrame();
        CZSemanticSearchPanel panel = new CZSemanticSearchPanel();
        frame.add(panel);
        frame.setPreferredSize(new Dimension(500, 500));
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        Thread.sleep(10000);
        frame.dispose();


        final JFrame frame1 = new JFrame("Testing ProgressLabel");
        JPanel panel1 = new JPanel();
        CZProgressLabel progressLabel = new CZProgressLabel("Searching", "Done");
        panel1.add(progressLabel);
        frame1.add(panel1);
        frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame1.setPreferredSize(new Dimension(500, 500));
        frame1.pack();
        progressLabel.start();
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                frame1.setVisible(true);
            }
        });
        Thread.sleep(5000);
        progressLabel.done();
    }
}

私は、Swing の Event ディスパッチ モデルで何かを台無しにしてしまったと思います。しかし、私は何を理解できませんか?このコードのどこが間違っているのか、どうすれば修正できるのか教えてもらえますか?

4

2 に答える 2

3

スレッドでこれを自分で実装する代わりに、SwingWorker: Simple Background Tasksを使用できます。これは、そのようなもののために作成されたもので、リンクされた例は問題に非常に似ています。

あなたはあなたstart()を実行しませんLabelUpdateThread().run()が、あなたのLabelUpdateThread().start().

于 2012-08-30T23:34:30.063 に答える
3

実際のコードについてはわかりませんが、サンプル コードには欠陥があります...

あなたActionListenerはこれをやっています...

progressLabel.start();
try {
    Thread.sleep(10000);
} catch (InterruptedException ex) {
    Exceptions.printStackTrace(ex);
}
//the above sleep() call will be replace by some time-consuming process. It is there just for testing now

progressLabel.done();

これにより、イベント ディスパッチ スレッドが停止し、10 秒間、再描画要求が処理されなくなります (つまり、画面の更新はありません)。これにより、アプリケーションが「ハング」したように見えます。

このように読むように更新しました(ラベルからメンバーを返すメソッドActionListenerを追加したことに注意してください)isRunningrunning

if (progressLabel.isRunning()) {
    progressLabel.done();
} else {
    progressLabel.start();
}

そして、それはうまくいきます。

他のアイデアについては、Swing の Currencyをお読みください。

また、すでに示唆されているように、SwingWorker はより良いアプローチかもしれません

于 2012-08-30T23:46:03.497 に答える