0

単純な Ping によって生成された新しい文字列ごとに JLabel を動的に変更したいのですが、Ping の実行中に入ってくる新しい文字列ごとに JLabel の既存の文字列を置き換える方法がわかりません。以下は私がこれまでに持っているものです。これまでのところ、JLabel のテキストを置き換えますが、Ping の実行が終了した後でのみです。

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.io.*;

public class Ping extends JFrame implements ActionListener{

private JButton runButton = new JButton("Run");
private JLabel pingResult = new JLabel("Result"); 
private String results;

public Ping(){
    runButton.addActionListener(this);

    add(pingResult, BorderLayout.CENTER);
    add(runButton, BorderLayout.NORTH);

}

//Action Listener
public void actionPerformed(ActionEvent e)
{
    String buttonString = e.getActionCommand( );

    if (buttonString.equals("Run"))
    {
        //Execute Ping
        try {
            String line;
            Process p = Runtime.getRuntime().exec("/sbin/ping -c 4 www.google.com");
            BufferedReader input = new BufferedReader(
                new InputStreamReader(p.getInputStream()));

            while ((line = input.readLine()) != null) {
                results += line + "\n";
                pingResult.setText(results);
                //System.out.println(line);
            }

            input.close();
        }catch (Exception err){
            err.printStackTrace();
        }

    }else{
        System.exit(0);
    }
}

public static void main(String[] args) {
    Ping sp = new Ping();
    sp.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    sp.setSize(400, 400);
    sp.setVisible(true);
    sp.setLayout(new BorderLayout());
}

}
4

3 に答える 3

3

イベント ディスパッチ スレッドで setText を呼び出します。そのために SwingUtils.invokeLater を使用します。EDT から長時間の操作を実行しないでください。経験しているように、これによりアプリがフリーズします。

于 2012-12-30T08:40:32.690 に答える
1

コードが EDT (イベント ディスパッチ スレッド) をフリーズします。そのため、ping の終了後に JLabel テキストが更新されます。それを避けるべきです。別のスレッドで長時間持続する操作を実行し、SwingUtils.invokeLater を使用して更新することは、1 つの解決策です。もう一つは SwingWorker クラスの使い方です。ここでチュートリアルを見つけることができます。

以下は、最初のオプションの例です。JLabel の代わりに JTextArea を使用しました。

もう 1 つ、Runtime.exec() の代わりに ProcessBuilder を使用する必要があります

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class PingExample {
  private static final Logger logger = Logger.getLogger(PingExample.class.getName());

  public static void main(String[] args) {
    PingExample p = new PingExample();
    p.run();
  }

  private void run() {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        JFrame frame = new PingFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
      }
    });
  }

  private class PingFrame extends JFrame {
    private static final long serialVersionUID = 1L;

    private JTextArea textArea;

    private PingFrame() {
      super.setName("Ping Frame");
      this.addComponents();
      super.setSize(400, 240);
    }

    private void addComponents() {
      super.setLayout(new BorderLayout());

      this.textArea = new JTextArea(10, 0);
      JScrollPane scrollPane = new JScrollPane(this.textArea);
      super.add(scrollPane, BorderLayout.NORTH);

      JButton button = new JButton("Run");
      button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
          new Thread(new Ping(PingFrame.this.textArea)).start();
        }
      });
      super.add(button, BorderLayout.SOUTH);
    }

    private class Ping implements Runnable {
      private JTextArea textArea;

      private Ping(JTextArea textArea) {
        this.textArea = textArea;
      }

      @Override
      public void run() {
        try {
          List<String> commands = new ArrayList<>(10);
          commands.add("ping");
          commands.add("www.google.com");

          ProcessBuilder builder = new ProcessBuilder();
          builder.command(commands);
          Process process = builder.start();

          try (
              BufferedReader br = new BufferedReader(
              new InputStreamReader(process.getInputStream(), Charset.defaultCharset()))) {
            String line = br.readLine();
            while (null != line) {
              final String text = line;
              SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                  Ping.this.textArea.append(text);
                  Ping.this.textArea.append("\n");
                }
              });
              line = br.readLine();
            }
          }

          process.waitFor();
          process.destroy();
        } catch (IOException | InterruptedException x) {
          logger.log(Level.SEVERE, "Error", x);
        }
      }
    }
  }

}

于 2012-12-30T10:53:43.517 に答える
0

正確には、ping が終了した後にのみ更新されます。完了する前に実行したい場合は、別のスレッドを使用する必要があります。

于 2012-12-30T08:38:50.250 に答える