java - 调整包含 JSVGCanvas 的 JComponent 大小时出现 Batik IllegalStateException

标签 java dom dynamic illegalstateexception batik

我的程序似乎工作得很好,但当我尝试调整组件大小时,我时不时地收到“IllegalStateExceptions:RunnableQueue 未启动或已退出”。我已将 documentState 设置为 ALWAYS_DYNAMIC,并且我读到您应该使用 JSVGCanvas 的 UpdateManager 并调用 invokelater()。据我了解,第一次使用后即可使用

gvtBuildCompleted(GVTTreeBuilderEvent e)

被调用,所以我在使用它之前检查它是否正在运行,但我仍然得到异常。 以下方法被线程重复调用,似乎会导致异常:

private void updateDomTree(final SVGComponent component, final Document doc)
{
if(component.getSvgCanvas().getUpdateManager() != null && component.getSvgCanvas().getUpdateManager().isRunning())
{
    component.getSvgCanvas().getUpdateManager().getUpdateRunnableQueue().invokeLater(new Runnable() 
    {
        public void run() 
        {
            final Node newNode = doc.getChildNodes().item(0).getFirstChild();
            //could be easier to get this value, but ... it works.
            String newNodeId = newNode.getAttributes().getNamedItem("id").getFirstChild().getNodeValue();

            NodeList nodes = component.getSvgDocument().getDocumentElement().getChildNodes();
            Node updateNode = findElementById(nodes, newNodeId);
            resizeComponent(component, doc);
            component.getSvgCanvas().getSVGDocument().adoptNode(newNode);
            component.getSvgCanvas().getSVGDocument().getDocumentElement().replaceChild(newNode, updateNode);
            component.refreshSVGCanvas();
        }
    });
}
}

实际的大小调整是在这里完成的:

protected void resizeComponent(SVGComponent component, Document doc)
{
    Element svgRoot = doc.getDocumentElement();
    final int svgWidth = Integer.parseInt(svgRoot.getAttribute("width"));
    final int svgHeight = Integer.parseInt(svgRoot.getAttribute("height"));
    String[] viewBox = svgRoot.getAttribute("viewBox").split(" ");
    int viewBoxLeft = Integer.parseInt(viewBox[0]);
    int viewBoxTop = Integer.parseInt(viewBox[1]);
    final float factor = component.getScaleFactor();
    String[] viewBoxOld = component.getSvgDocument().getDocumentElement().getAttribute("viewBox").split(" ");
    int viewBoxLeftOld = Integer.parseInt(viewBoxOld[0]);
    int viewBoxTopOld = Integer.parseInt(viewBoxOld[1]);
    int xDiff = (int) ((viewBoxLeftOld - viewBoxLeft)*factor);
    int yDiff = (int) ((viewBoxTopOld - viewBoxTop)*factor);

    if ( viewBoxLeftOld != viewBoxLeft ) //If there is additional content left
    {
        component.setLocation(component.getLocation().x - xDiff, component.getLocation().y);
    }
    if ( viewBoxTopOld != viewBoxTop ) //If there is additional content right)
    {
        component.setLocation(component.getLocation().x, component.getLocation().y - yDiff);
    }

    component.getSvgDocument().getDocumentElement().setAttribute("width",""+svgWidth);
    component.getSvgDocument().getDocumentElement().setAttribute("height",""+svgHeight);
    component.getSvgDocument().getDocumentElement().setAttribute("viewBox", ""+viewBoxLeft+" "+viewBoxTop+" "+svgWidth+" "+svgHeight);
    component.setSize((int)(svgWidth*factor),(int)(svgHeight*factor));
}

方法

refreshJSVGCanvas()

通话

JSVGCanvas.setDocument(Document);
JSVGCanvas.setSize(int, int);

这是完整的堆栈跟踪:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: RunnableQueue not started or has exited
at org.apache.batik.util.RunnableQueue.invokeLater(RunnableQueue.java:277)
at org.apache.batik.swing.svg.AbstractJSVGComponent.updateRenderingTransform(AbstractJSVGComponent.java:1057)
at org.apache.batik.swing.gvt.AbstractJGVTComponent$1.componentResized(AbstractJGVTComponent.java:237)
at java.awt.AWTEventMulticaster.componentResized(Unknown Source)
at java.awt.Component.processComponentEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(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$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.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)

先谢谢了,我到处搜索并尝试了很多,但找不到解决方案。

编辑: 这是 Batik 的 invokeLater-Method,实际上抛出了异常:

public void invokeLater(Runnable r) {
    if (runnableQueueThread == null) {
        throw new IllegalStateException
            ("RunnableQueue not started or has exited");
    }
    synchronized (list) {
        list.push(new Link(r));
        list.notify();
    }
}

runnableQueueThrad 在该类的 run()-Method 内部设置,并在最后设置为 null。 所以我想我必须进行某种同步。

最佳答案

大胆猜测,“public void run()”代码不应该位于另一个方法内,并且实际上是一个线程类/接口(interface)对象,因此称为构造函数(实际上是接口(interface)版本)。

将其删除到自己的类中(例如,嵌套子类以保留范围)并在该类上实现“线程可运行”接口(interface),以在其中放置“run()”方法以供使用。

堆栈跟踪表示 run 方法不可用,因为它实际上没有这样的方法(或者至少没有正确声明),因此它处于“非法状态”。

关于java - 调整包含 JSVGCanvas 的 JComponent 大小时出现 Batik IllegalStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14601027/

相关文章:

java - 如何查看 Eclipse Java SDK 示例的源代码

java - 如何在 AppEngine 上安装崩溃处理程序?

javascript - 合并或批处理 HTML 解析

javascript - 计算样式作为 JavaScript 对象

sql-server - 在触发器内执行动态sql "alter database"

java - 为什么 ArrayList 有 "implements List"?

java - 带有 Javassist 3.18.2-GA 的 Powermock 1.6.3 产生 NoSuchMethodError

javascript - JQuery 不过滤 DOM 更改

c++ - 在 C++ 中,类函数放在内存的哪个位置?

具有循环内容的 CSS 单页导航菜单