2012-06-24 25 views
2

我有这个JList,我用它作为System.out的显示。我在JFrame的底部创建了一个IRC客户端,它的这个JList。似乎每当将两个或更多个元素同时添加到JListsListModel时,整个JList变成白色并且是非交互式的,直到单独添加一个元素为止。当一个异常打印堆栈跟踪时,会同时添加多个元素的示例。JList空白[我认为OutputStream Buffering问题]

这里是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); 
     } 
    } 
} 

有谁知道是怎么回事,它如何能解决吗?

+0

使用[synchronized](http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html)而不是使用书写进行阻止。 –

+0

我不明白*任何事情。*请澄清。输出流缓冲如何在不使用输出流的方法中执行任何操作?一个字符串如何以换行符结尾并同时为空? – EJP

+0

@EJP这个类通过“System.setOut(new PrintStream(new LogOutputStream()));”代替System.out。目的是让我可以有一个自定义控制台进行日志记录。但是,当多行事件(如异常)打印其堆栈跟踪时,会阻塞它或导致JList停止显示当前任何元素。此外,它会检查字符串是否为空,然后检查它是否以换行符结束。 – injectv

回答

2

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

请确保您只写入EDT上的JList(Swing Event Dispatch Thread)。像这样将排队Swing事件线程上addElement(...)电话:

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
根据本文标题为Writing Your Own Java I/O Stream Classes,如果您要扩展OutputStream,请不要忘记为此提供自定义实现e flush()close()方法。

+0

非常感谢,我会试试这个 – injectv

+0

这确实有点更好,但有时它仍然隐藏当添加多个元素时 – injectv

+0

是的,我试了第二个(第一个没有工作)。现在你提到它有一个while循环,它使客户端连接到IRC服务器,但是它在一个单独的线程中,所以我不认为这很重要。 – injectv