2

我有这个JList用作System.out. 我正在创建一个 IRC 客户端,它JList位于JFrame. 似乎每当JLists ListModel同时添加 2 个或更多元素时,整体JList变成白色且非交互的,直到单独添加一个元素。同时添加多个元素的一个示例是异常打印堆栈跟踪时。

这是OutputStream我设置为System.out...的课程

public class LogOutputStream extends OutputStream {
    String sentence = "";
    boolean writing = false;
    private DefaultListModel subject;

    public LogOutputStream(DefaultListModel logListModel) {
        this.subject = logListModel;
    }

    public void write(final int b) {
        try {
            sentence = sentence + (char) b;

            if (sentence.endsWith("\n") && !sentence.isEmpty() && !sentence.equals("\t") && !sentence.equals("\r\n") && !sentence.equals("\n")) {
                if (writing == false) {
                    writing = true;
                    subject.addElement(sentence.replaceAll("\n", "").replaceAll("\r", "").trim());
                }

                sentence = "";
                writing = false;
            }
        } 
        catch (Exception e) {
            e.printStackTrace(Boot.stdErr);
        }
    }
}

有谁知道这里发生了什么,以及如何解决?

4

1 回答 1

2

这可能是一个 Swing 并发问题,因为您将项目添加到事件线程之外的 JList 模型中。这会阻塞线程并阻止它执行绘制 GUI 或允许用户交互有效地冻结您的 Swing GUI 的必要操作。

尝试确保只写入 EDT(Swing 事件调度线程)上的 JList。像这样的东西会将addElement(...)Swing 事件线程上的调用排队:

public void write(final int b) {
    try {
        sentence = sentence + (char) b;
        if (sentence.endsWith("\n") && !sentence.isEmpty()
                && !sentence.equals("\t") && !sentence.equals("\r\n")
                && !sentence.equals("\n")) {
            if (writing == false) {
                writing = true;
                final String text = sentence.replaceAll("\n", "")
                                .replaceAll("\r", "").trim();
                javax.swing.SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        subject.addElement(text);
                    }
                });

            }
            sentence = "";
            writing = false;
        }
    } catch (Exception e) {
        e.printStackTrace(Boot.stdErr);
    }
}

编辑 1
这更接近我过去使用 StringBuilder 所做的事情:

import java.io.IOException;
import java.io.OutputStream;

import javax.swing.DefaultListModel;
import javax.swing.SwingUtilities;

public class JListOutputStream extends OutputStream {
   private DefaultListModel logListModel;
   private StringBuilder sb = new StringBuilder();   

   public JListOutputStream(DefaultListModel logListModel) {
      this.logListModel = logListModel;
   }

   @Override
   public void write(int b) throws IOException {
      if (b == '\r')
         return;

      if (b == '\n') {
         final String text = sb.toString().trim();
         sb.setLength(0);
         if (text.isEmpty()) {
            return;
         }
         SwingUtilities.invokeLater(new Runnable() {
            public void run() {
               logListModel.addElement(text);
            }
         });

         return;
      }

      sb.append((char) b);
   }

}

编辑 2
根据这篇题为“编写您自己的 Java I/O 流类”的文章,如果您正在扩展 OutputStream,请不要忘记为flush()close()方法提供自定义实现。

于 2012-06-25T00:22:30.347 回答