使用Batik开发SVG应用程序(二)

使用Batik创建SVG应用程序

Batik工具集提供的JSVGCanvas模块是一个swing 组件,用于显示静态或动态SVG文档。通过JSVGCanvas模块,开发人员可以轻松显示SVG文档(通过URI地址或DOM树)并对其进行操作,例如旋转、缩放、摇动、选择文本或激活超级链接等。首先介绍如何创建JSVGCanvas并集成到一个swing应用程序中。接下来解释如何完成与SVG画布相关的常用功能,例如如何跟踪SVG文档渲染时发生的所有事件,以及如何通过JavaTM语言操作SVG文档。

创建JSVGCanvas

JSVGCanvas是一个swing 组件并遵循swing设计规则(Swing design rule[4])。这意味着组件不是线程安全的,而且所有操作应当参照swing教程描述使用。JSVGCanvas 也是一个JavaBean 组件,因此可以在可视化应用程序开发工具中使用。下例中演示了如何轻松创建和使用JSVGCanvas 组件(见图3)。

import java.awt.*;

import java.awt.event.*;

import java.io.*;

import javax.swing.*;

 

import org.apache.batik.swing.JSVGCanvas;

import org.apache.batik.swing.gvt.GVTTreeRendererAdapter;

import org.apache.batik.swing.gvt.GVTTreeRendererEvent;

import org.apache.batik.swing.svg.SVGDocumentLoaderAdapter;

import org.apache.batik.swing.svg.SVGDocumentLoaderEvent;

import org.apache.batik.swing.svg.GVTTreeBuilderAdapter;

import org.apache.batik.swing.svg.GVTTreeBuilderEvent;

 

public class SVGApplication {

 

    public static void main(String[] args) {

        JFrame f = new JFrame("Batik");

        SVGApplication app = new SVGApplication(f);

        f.getContentPane().add(app.createComponents());

        f.addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent e) {

                System.exit(0);

            }

        });

        f.setSize(400, 400);

        f.setVisible(true);

    }

   

    JFrame frame;

    JButton button = new JButton("Load...");

    JLabel label = new JLabel();

    JSVGCanvas svgCanvas = new JSVGCanvas();

 

    public SVGApplication(JFrame f) {

        frame = f;

    }

 

    public JComponent createComponents() {

        final JPanel panel = new JPanel(new BorderLayout());

        JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));

        p.add(button);

        p.add(label);

        panel.add(p, BorderLayout.NORTH);

        panel.add(svgCanvas, BorderLayout.CENTER);

 

        // Set the button action.

        button.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {

                JFileChooser fc = new JFileChooser(".");

                int choice = fc.showOpenDialog(panel);

                if (choice == JFileChooser.APPROVE_OPTION) {

                    File f = fc.getSelectedFile();

                    try {

                        svgCanvas.setURI(f.toURL().toString());

                    } catch (IOException ex) {

                        ex.printStackTrace();

                    }

                }

            }

        });

 

        // Set the JSVGCanvas listeners.

        svgCanvas.addSVGDocumentLoaderListener(new SVGDocumentLoaderAdapter() {

            public void documentLoadingStarted(SVGDocumentLoaderEvent e) {

                label.setText("Document Loading...");

            }

            public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {

                label.setText("Document Loaded.");

            }

        });

 

        svgCanvas.addGVTTreeBuilderListener(new GVTTreeBuilderAdapter() {

            public void gvtBuildStarted(GVTTreeBuilderEvent e) {

                label.setText("Build Started...");

            }

            public void gvtBuildCompleted(GVTTreeBuilderEvent e) {

                label.setText("Build Done.");

                frame.pack();

            }

        });

 

        svgCanvas.addGVTTreeRendererListener(new GVTTreeRendererAdapter() {

            public void gvtRenderingPrepare(GVTTreeRendererEvent e) {

                label.setText("Rendering Started...");

            }

            public void gvtRenderingCompleted(GVTTreeRendererEvent e) {

                label.setText("");

            }

        });

 

        return panel;

    }

}


3: 运行中的SVG应用程序

事件处理机制

如上例所示,每当设置JSVGCanvas URISVG DOM时(通过setURIsetSVGDocument方法),相关文档首先被解析(在URI的情况),然后创建、渲染和有选择的更新。为了接收这些不同的阶段的事件通知,正确的方法是实现一个侦听器并附加到该组件。有五种类型的侦听器:

  • SVGDocumentLoaderListener提供了用于跟踪SVGDocumentLoaderEvent 事件的一组方法。它描述了SVG装载阶段,即使用SVG文件创建SVG DOM树。
  • GVTTreeBuilderListener提供了用于跟踪GVTTreeBuilderEvent事件的一组方法。它描述了创建阶段,即通过SVG DOM树创建一个GVT(图形矢量工具集),然后GVT被用于渲染文档。
  • SVGLoadEventDispatcherListener提供了用于跟踪SVGLoadEventDispatcherEvent事件的一组方法。它描述了DOM 'SVGLoad'的事件派发阶段。该事件仅在动态类型文档中触发。
  • GVTTreeRendererListener提供了用于跟踪GVTTreeRendererEvent事件的一组方法。它描述了渲染阶段,即使用一个GVT树创建图像。在动态文档中该事件只在最初渲染时被触发一次。
  • UpdateManagerListener提供了用于跟踪UpdateManagerEvent事件的一组方法。它描述了运行阶段,即显示更新管理器启动,然后显示线程可能被挂起、恢复或停止。该侦听器可用于跟踪图像更新情况。只有动态文档触发该事件。

使用JavaTM脚本

Batik工具集提供了简便的,基于JavaTM 语言的SVG文档脚本。在前一节中,我们学习了如何显示一个SVG文档;本节描述如何操作当前在JSVGCanvas中显示的SVG文档。下面的例子中演示了如何操作SVG文档。注意开发人员不需要考虑图像的更新问题,在事件侦听器激活后画布根据需要进行自动更新。

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import javax.swing.JFrame;

import org.apache.batik.swing.JSVGCanvas;

import org.apache.batik.swing.svg.SVGLoadEventDispatcherAdapter;

import org.apache.batik.swing.svg.SVGLoadEventDispatcherEvent;

import org.apache.batik.script.Window;

import org.w 3c .dom.Document;

import org.w 3c .dom.Element;

import org.w 3c .dom.events.Event;

import org.w 3c .dom.events.EventListener;

import org.w 3c .dom.events.EventTarget;

 

public class SVGApplication {

    public static void main(String[] args) {

        new SVGApplication();

    }

 

    JFrame frame;

    JSVGCanvas canvas;

    Document document;

    Window window;

 

    public SVGApplication() {

        frame = new JFrame();

        canvas = new JSVGCanvas();

        // Forces the canvas to always be dynamic even if the current

        // document does not contain scripting or animation.

        canvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC);

        canvas.addSVGLoadEventDispatcherListener

            (new SVGLoadEventDispatcherAdapter() {

                    public void svgLoadEventDispatchStarted

                        (SVGLoadEventDispatcherEvent e) {

                        // At this time the document is available...

                        document = canvas.getSVGDocument();

                        // ...and the window object too.

                        window = canvas.getUpdateManager().

                            getScriptingEnvironment().createWindow();

                        // Registers the listeners on the document

                        // just before the SVGLoad event is dispatched.

                        registerListeners();

                        // It is time to pack the frame.

                        frame.pack();

                    }

                });

        frame.addWindowListener(new WindowAdapter() {

                public void windowOpened(WindowEvent e) {

                    // The canvas is ready to load the base document

                    // now, from the AWT thread.

                    canvas.setURI("doc.svg");

                }

            });

        frame.getContentPane().add(canvas);

        frame.setSize(800, 600);

        frame.show();

    }

 

    public void registerListeners() {

        // Gets an element from the loaded document.

        Element elt = document.getElementById("elt-id");

        EventTarget t = (EventTarget)elt;

        // Adds a 'onload' listener

        t.addEventListener("SVGLoad", new OnLoadAction(), false);

        // Adds a 'onclick' listener

        t.addEventListener("click", new OnClickAction(), false);

    }

 

    public class OnLoadAction implements EventListener {

        public void handleEvent(Event evt) {

            // Make some actions here...

            // ... for example start an animation loop:

            window.setInterval(new Animation(), 50);

        }

    }

 

    public class OnClickAction implements EventListener {

        public void handleEvent(Event evt) {

            // Make some actions here...

            // ... for example schedule an action for later:

            window.setTimeout(new DelayedTask(), 500);

        }

    }

 

    public class Animation implements Runnable {

        public void run() {

            // Insert animation code here...

        }

    }

 

    public class DelayedTask implements Runnable {

        public void run() {

            // Make some actions here...

            // ... for example displays an alert dialog:

            window.alert("Delayed Action invoked!");

        }

    }

}

SVG文档中注册的DOM侦听器在画布更新线程中被激活。为了避免冲突的情况,开发人员不应该在另一个线程中操作DOM树,而应当切换到画布更新线程进行更新操作。从外部线程切换到画布更新线程的方法如下:

// Returns immediately

canvas.getUpdateManager().getUpdateRunnableQueue().

    invokeLater(new Runnable() {

       // Insert some actions on the DOM here

    });

// Waits until the Runnable is invoked

canvas.getUpdateManager().getUpdateRunnableQueue().

    invokeAndWait(new Runnable() {

       // Insert some actions on the DOM here

    });

与常规的事件侦听器相似,当Runnable从更新线程激活时,图形被更新。

Batik同时提供了SVG<script>元素的扩展,以便在SVG文档中执行Java 程序。所有使用bridge模块的Batik应用程序都可以使用该功能(例如JSVGCanvas ImageTranscoder模块)。为了使用该扩展,<script>元素中的'type'属性必须设置为application/java-archive。另外,xlink:href属性应设置为执行程序所在的jar文档URI地址。该jar文件的表述文件(manifest)必须包括下表中的入口项:

Script-Handler: <classname>

<classname>必须是实现org.apache.batik.script.ScriptHandler接口的类的名称。该类可以直接放在jar文件中,也可以位于表述文件Class-Path入口项所包含的其它jar文件中。

总结

在本文中,我们了解到开发人员如何使用Batik工具集创建、操作和显示SVG内容。Batik的模块具有良好的扩展性而且易于使用,通过本文的学习,JavaTM 开发人员现在可以着手编写客户端或服务器端的SVG应用程序。另外,Batik项目是Apache 软件基金会 (ASF)倡导的开源志愿项目。这就意味着有很多方式对该项目贡献自己的力量,包括直接参与(编码、写文档、回答问题、提供想法、报告错误、错误修改建议等等),或资源捐献(公开代码、硬件、软件、出席会议、演讲等)。本项目特别关注使用Batik模块的应用程序,包括各种工具和扩展,因此请积极的通过Batik邮件列表为本项目作出贡献,邮件列表为batik-users@xml.apache.org

参考资料

[1] "The official SVG page at W 3C "

SVG工作组,网址 http://www.w3.org/Graphics/svg.

[2] "The Document Object Model"

DOM工作组,网址 http://www.w3.org/DOM.

[3] "The Batik SVG Generator Tutorial"

Batik小组,网址http://xml.apache.org/batik/svggen.html.

[4] "Creating a GUI with JFC/Swing"Swing小组(Sun Microsystems) ,网址http://java.sun.com/docs/books/tutorial/uiswing/overview/threads.html.


原文地址:

http://www.svgopen.org/2002/papers/kormann__developing_svg_apps_with_batik/

 
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值