为什么我需要在JLabel中重置setText()才能防止错误? [英] Why do I need to reset setText() in a JLabel to prevent errors?

查看:61
本文介绍了为什么我需要在JLabel中重置setText()才能防止错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为我早些时候发布的这个问题,我想知道引起该问题的原因.

As a follow-up to this question that I posted earlier, I am wondering about the cause of the issue I had.

问题是,在更新带有大量HTML文本的JLabel时出现此错误.

The problem was that I was getting this error when updating a JLabel with a lot of HTML text.

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at javax.swing.text.html.StyleSheet$ListPainter.paint(Unknown Source)
    at javax.swing.text.html.ListView.paintChild(Unknown Source)
    at javax.swing.text.BoxView.paint(Unknown Source)
    at javax.swing.text.html.BlockView.paint(Unknown Source)
    at javax.swing.text.html.ListView.paint(Unknown Source)
    at javax.swing.text.BoxView.paintChild(Unknown Source)
    at javax.swing.text.BoxView.paint(Unknown Source)
    at javax.swing.text.html.BlockView.paint(Unknown Source)
    at javax.swing.text.BoxView.paintChild(Unknown Source)
    at javax.swing.text.BoxView.paint(Unknown Source)
    at javax.swing.text.html.BlockView.paint(Unknown Source)
    at javax.swing.text.BoxView.paintChild(Unknown Source)
    at javax.swing.text.BoxView.paint(Unknown Source)
    at javax.swing.text.html.BlockView.paint(Unknown Source)
    at javax.swing.plaf.basic.BasicHTML$Renderer.paint(Unknown Source)
    at javax.swing.plaf.basic.BasicLabelUI.paint(Unknown Source)
    at javax.swing.plaf.ComponentUI.update(Unknown Source)
    at javax.swing.JComponent.paintComponent(Unknown Source)
    at javax.swing.JComponent.paint(Unknown Source)
    at javax.swing.JComponent.paintToOffscreen(Unknown Source)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
    at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
    at javax.swing.RepaintManager.paint(Unknown Source)
    at javax.swing.JComponent._paintImmediately(Unknown Source)
    at javax.swing.JComponent.paintImmediately(Unknown Source)
    at javax.swing.RepaintManager$4.run(Unknown Source)
    at javax.swing.RepaintManager$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.access$1200(Unknown Source)
    at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

要设置的HTML由StringBuilder和转换后的.toString生成.像这样,但范围更广:

The HTML that's being set is generated by a StringBuilder and the converted .toString. Something like this, but more extensive:

public static String entityOverviewHTML() {
    StringBuilder sb = new StringBuilder();
    List<Entity> entities = Entity.getEntities();

    sb.append("<html><div style='padding: 12px;'>");

    sb.append("<h1>People: alive</h1>");

    // A lot of appending: also loop through getEntities (dynamic, can change)
    // and get contents from each entity in #getEntityInfo below
    if (entities.size() > 0) {
        sb.append("<ul>");
        for (Entity e: entities) {
            getEntityInfo(e);
        }
        sb.append("</ul>");
    }

    sb.append("</div></html>");
    return sb.toString();
}

private static StringBuilder getEntityInfo(Entity e) {
    StringBuilder sbInfo = new StringBuilder();
    // A lot of appending: append info of Entity e such as e.getFirstName()
    sbInfo.append("<li>");
    sbInfo.append(e.getFirstName())
    sbInfo.append("</li>");

    return sbInfo;
}

在发生一些事件之后,HTML会发生变化,之后我将调用自定义刷新方法:

After some events, the HTML will change after which I call a custom refresh method:

public static void bringToFront() {
    getInstance().setVisible(true);
    getInstance().setExtendedState(JFrame.ICONIFIED);
    getInstance().setExtendedState(JFrame.NORMAL);
}

public static void refresh() {
    // text is a JLabel
    text.setText(entityOverviewHTML());
    bringToFront();
}

然后是这篇文章顶部的错误发生了,但是并不总是!我还没有弄清楚为什么会发生这种情况,但是我确实发现,将文本重置为空字符串然后调用entityOverviewHTML可以解决此问题.

And it's then that the errors at the top of this post happen, however not always! I haven't figured out why this happens, but I did find that when resetting the text to an empty string and then calling entityOverviewHTML solves the issue.

public static void refresh() {
    text.setText(""); // Here we go
    text.setText(entityOverviewHTML());
    bringToFront();
}

文本被定义为Class变量:

text is defined as a Class variable:

private static JLabel text = new JLabel();

我想知道的是:为什么?这行看似过时的代码如何解决该问题?究竟是什么 问题?

What I like to know is: why? How can this single line of seemingly obsolete code solve the problem? Exactly what is the problem?

推荐答案

问题是您的refresh()方法未在Swing EDT上调用.

The problem is that your refresh() method is not called on the Swing EDT.

Swing不是线程安全的( https://docs.oracle.com /javase/tutorial/uiswing/concurrency/dispatch.html ),这意味着调用text.setText(entityOverviewHTML());破坏了JLabel实例用来显示文本的内部数据结构.

Swing is not threadsafe (https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html) which means that the call text.setText(entityOverviewHTML()); corrupts the internal data structures that your JLabel instance uses to display the text.

您的刷新方法需要这样重写:

Your refresh-method needs to be rewritten like this:

public static void refresh() {
    try {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                text.setText(entityOverviewHTML());
                bringToFront();
            }
        });
    } catch (InvocationTargetException | InterruptedException e) {
        e.printStackTrace();
    }
}

这篇关于为什么我需要在JLabel中重置setText()才能防止错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆