如何将Data类方法数据发送至GUITest类JTextArea或重定向System.out
两种方案实现DataOut数据更新时同步到JTextArea
我来给你两个靠谱的方案,都是在DataOut方法产生新数据时主动触发UI更新,完全不需要轮询:
方案一:使用回调接口(观察者模式,推荐)
这种方式更符合面向对象设计,直接让Data类在有新数据时通知UI组件,不需要依赖System.out的输出。
步骤说明:
- 定义一个回调接口,用来传递数据更新事件;
- 修改
Data类,让它持有这个接口的实例,在DataOut计算完数据后主动调用接口方法传递数据; - 让
GUITest实现这个接口,在回调方法里安全更新JTextArea(注意Swing组件必须在事件线程更新)。
修改后的完整代码:
1. 定义回调接口
// 定义数据更新的回调接口 interface DataListener { void onDataUpdated(int data); }
2. 修改Data类
import java.io.IOException; public class Data { private DataListener listener; // 设置数据监听器 public void setDataListener(DataListener listener) { this.listener = listener; } public void DataOut() throws IOException { int S = 0; for(int i = 0; i < 20; i++) { S++; } // 数据计算完成后,主动通知监听器 if(listener != null) { listener.onDataUpdated(S); } // 如果你还需要保留控制台输出,可以保留这句 // System.out.println(S); } }
3. 修改GUITest类
import javax.swing.*; import java.awt.*; import java.io.IOException; public class GUITest implements DataListener { private JFrame frame; JTextArea textArea_1 = new JTextArea(); public static void main(String[] args) throws InterruptedException, IOException { System.out.println("Thread Name 0 " + Thread.currentThread().getName()); GUITest window = new GUITest(); EventQueue.invokeLater(new Runnable() { public void run() { try { window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); Data data = new Data(); data.setDataListener(window); for(int i = 0; i < 100; i++) { Thread.sleep(20); data.DataOut(); } } public GUITest() throws IOException { initialize(); } public void initialize() throws IOException { frame = new JFrame(); frame.setBounds(1200, 100, 450, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout(null); textArea_1.setBounds(120, 45, 100, 23); textArea_1.setText(""); frame.getContentPane().add(textArea_1); } // 实现回调接口,处理数据更新 @Override public void onDataUpdated(int data) { // 必须在Swing事件线程更新UI,避免线程安全问题 SwingUtilities.invokeLater(() -> { textArea_1.append(data + "\n"); // 追加数据,也可以用setText覆盖,看需求 }); } }
方案二:重定向System.out到JTextArea
如果你不想修改Data类的逻辑,只想把System.out的输出直接转到JTextArea,可以自定义一个OutputStream来实现。
步骤说明:
- 自定义一个
OutputStream子类,把写入的字节转换成字符串,追加到JTextArea; - 在
GUITest初始化时,把System.out重定向到这个自定义流; - 这样
DataOut里的System.out.println(S)就会直接输出到JTextArea了。
修改后的完整代码:
1. 自定义OutputStream
import javax.swing.*; import java.io.IOException; import java.io.OutputStream; class TextAreaOutputStream extends OutputStream { private JTextArea textArea; public TextAreaOutputStream(JTextArea textArea) { this.textArea = textArea; } @Override public void write(int b) throws IOException { // 把字节转成字符,追加到文本域,注意要在事件线程操作 SwingUtilities.invokeLater(() -> { textArea.append(String.valueOf((char) b)); }); } }
2. 修改GUITest类
import javax.swing.*; import java.awt.*; import java.io.IOException; import java.io.PrintStream; public class GUITest { private JFrame frame; JTextArea textArea_1 = new JTextArea(); public static void main(String[] args) throws InterruptedException, IOException { System.out.println("Thread Name 0 " + Thread.currentThread().getName()); GUITest window = new GUITest(); EventQueue.invokeLater(new Runnable() { public void run() { try { window.frame.setVisible(true); // 重定向System.out到JTextArea System.setOut(new PrintStream(new TextAreaOutputStream(window.textArea_1))); } catch (Exception e) { e.printStackTrace(); } } }); Data data = new Data(); for(int i = 0; i < 100; i++) { Thread.sleep(20); data.DataOut(); } } public GUITest() throws IOException { initialize(); } public void initialize() throws IOException { frame = new JFrame(); frame.setBounds(1200, 100, 450, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout(null); textArea_1.setBounds(120, 45, 100, 23); textArea_1.setText(""); frame.getContentPane().add(textArea_1); } }
3. Data类保持不变
import java.io.IOException; public class Data { public void DataOut() throws IOException { int S = 0; for(int i = 0; i < 20; i++) { S++; } System.out.println(S); // 现在这句会输出到JTextArea } }
注意事项:
- 不管用哪种方案,**更新Swing组件必须在事件调度线程(EDT)**里执行,所以我们用了
SwingUtilities.invokeLater来包裹UI更新代码,避免线程安全问题; - 方案一更灵活,你可以传递任意类型的数据,而不只是字符串;方案二更适合不想修改原有
Data类逻辑的场景。
内容的提问来源于stack exchange,提问作者R.J.M
相关产品推荐
相关产品推荐

