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 更新它是一种解决方案。另一个是 SwingWorker 类的用法。你可以在这里找到教程

下面是第一个选项的示例。我使用 JTextArea 而不是 JLabel。

还有一件事你应该使用 ProcessBuilder 而不是 Runtime.exec(),是一篇很好的文章为什么。

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 回答