【问题标题】:Scrollbars not visible for JTextPane when appending text into JTextPane将文本附加到 JTextPane 时,JTextPane 的滚动条不可见
【发布时间】:2019-10-25 18:25:19
【问题描述】:

我在 JScrollPane 中有一个 JTextPane(水平策略 NEVER 和垂直策略 ALWAYS)。我已经编写了一种在此 JTextPane 中附加文本的方法。现在有一个按钮,单击该按钮,动作侦听器正在运行,执行一些数据操作并更新 JTextPane 上的数据。我正在使用 JScrollPane.update() 方法来刷新附加的文本。文本正确更新,直到达到 JTextPane 的高度。随着更多文本的添加,它应该显示垂直滚动条并更新文本。但这并没有发生。相反,整个文本显示为从动作侦听器方法流出的流。

我已尝试更新 JTextPane 和 JScrollPane。但它似乎不起作用。

JTextPane txt_message = new JTextPane();
txt_message.setPreferredSize(new Dimension(300,300));
JScrollPane sPane = new JScrollPane(txt_message);
sPane.setHorizontalScrollBarPolicy
           (JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
sPane.setVerticalScrollBarPolicy
           (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
sPane.setPreferredSize(new Dimension(320,320));
pnl_messagePane.add(sPane);
txt_message.setEditable(false);
DefaultCaret caret = (DefaultCaret) txt_message.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

//some other GUI elements
..... 

btn_Run.addActionListener(e->{
  for(int i=1; i<100; i++){
       appendToPanel(this.txt_message, "dummy text "+i, TextType.SUCCESS);
  }

//TextType is an enum defined in code whose value can be SUCCESS, ERROR

});



// Method for appending JTextPanel Text
private void appendToPane(JTextPane tp, String msg, TextType type)
   {
       Color c = null;
       switch(type) {
       case ERROR:
           c = Color.RED;
           break;

       case SUCCESS:
           c=Color.GREEN;
           break;
       default:
           c = Color.BLACK;
       }


       StyledDocument doc = tp.getStyledDocument();

       SimpleAttributeSet keyWord = new SimpleAttributeSet();
       StyleConstants.setForeground(keyWord, c);
       StyleConstants.setBold(keyWord, true);

       try
       {
           doc.insertString(doc.getLength(), "\n"+msg, keyWord );
       }

       catch(Exception e) { 
           System.out.println(e); 
       }

       tp.update(tp.getGraphics());

       this.sPane.update(this.sPane.getGraphics());
   }


当循环运行时,它应该将 JTextPane 中的文本更新为
虚拟文本 1
虚拟文本 2
虚拟文本 3
. . .

假设在虚拟文本 10 之后,它达到了 JScrollPane 高度。
现在预期的行为是 --
它应该继续更新新文本,例如
虚拟文本 11
虚拟文本 12
.. 应该会出现垂直滚动条。

但实际行为是 --
在虚拟文本 10 之前它可以正常工作(假设 JScrollPane 的高度可以容纳 10 行)。之后 JTextPane 闪烁,但没有任何反应,循环完成后,它立即显示剩余的 90 行,并带有垂直滚动条。

虚拟文本 11
虚拟文本 12
.
.
.

我想当我添加越来越多的行时,问题出在 JScrollBar 的可见性上。

任何帮助将不胜感激。

【问题讨论】:

  • 在您的情况下,以下改进可能会有所帮助:SwingUtilities.invokeLater(() -&gt; appendToPanel(this.txt_message, "dummy text "+i, TextType.SUCCESS))。但最好阅读concurrency in Swing
  • 上述方法试过了,还是不行。
  • 在这种情况下,您必须阅读Concurrency in Swing 并按照该页面中的示例进行操作。

标签: java swing


【解决方案1】:

相反,整个文本显示为从动作侦听器方法流出的流。

从侦听器调用的代码在 Event Dispatch Thread (EDT) 上执行。

因此,正如已经提到的,您的循环代码正在EDT 上执行。 EDT 负责重新绘制 GUI,但在主循环完成执行之前它不能这样做。

在虚拟文本 10 之前它工作正常(假设 JScrollPane 的高度可以容纳 10 行)。之后 JTextPane 闪烁,但没有任何反应

它似乎只是因为您错误地使用了 Swing:

tp.update(tp.getGraphics());
this.sPane.update(this.sPane.getGraphics());

您不应该直接调用 update(...) 方法。当组件需要重新绘制时,Swing 将在内部调用此方法。强制更新会导致闪烁。不要这样做!

要更新文本区域,您需要在单独的 Thread 上执行代码,这样您就不会阻止 EDT

一种方法是使用SwingWorker。它为您创建了线程,并允许您根据需要将结果publish() 到您的文本窗格,以便随后在 EDT 上正确更新文本窗格。

您在 cmets 部分中获得的 Concurrency 链接有一个关于 How to Use a SwingWorker 的部分,其中包含帮助您入门的工作示例。本教程还解释了EDT 的工作原理。

【讨论】:

    猜你喜欢
    • 2012-11-03
    • 2013-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多