winform 复合组件

    技术2024-02-22  105

    HTML5显然是软件开发中的下一件大事。 HTML5最初被称为Web应用程序,最终将桌面应用程序的功能(包括拖放,画布,视频和音频等功能)带给浏览器。 HTML5是技术(特别是规范)的集合,这些技术形成了功能强大的API,涵盖了HTML,JavaScript和级联样式表(CSS)。 以下是HTML5的亮点:

    关于本系列

    JSF 2 fu系列是David Geary同名文章的三篇文章的后续文章 ,将帮助您像功夫高手一样发展和磨练JSF 2框架技能。 本系列文章深入探讨了框架及其周围的生态系统。 通过展示一些Java EE技术(例如上下文和依赖注入)如何与JSF集成,可以一窥框外。

    帆布 拖放 地理位置* 内联编辑 网络工作者* 网络存储* 讯息传递 离线应用 视频和音频* 网络插座*

    注意前瞻性功能,例如地理位置和离线应用程序。 (功能我用星号标记不是HTML5规范的技术部分,但这个词HTML5用于口语涵盖所有我已经列出的。请参阅相关主题以获取更多信息。)

    在某些方面,HTML5是下一个Java。 在1990年代后期,Java语言变得非常流行,这在很大程度上要归功于它的一次写入,可在任何地方运行的功能,使开发人员不必在Windows®,Mac或Linux®中进行选择(或移植)。 HTML5允许您编写一次,并在任何(现代)浏览器中运行 ,因此您不必在iOS,Android和Chrome中进行选择。

    到处写一次?

    Java技术使您可以为多个操作系统编写一个应用程序,但是这样做并不完美。 HTML5也没有。 HTML5没有提供本机OS提供的某些便利,例如与加速度计进行交互。 (虽然有工具箱-如PhoneGap的[见相关主题 ] -桥接的间隙)。 这些不完善之处总是会导致某些开发人员避开HTML5,而转而使用本机应用程序。 但是对于许多应用程序,HTML5提供了更好的投资回报率。

    进入Java技术

    HTML5可能是下一个Java,但不会替代它。 Java技术为服务器端编程提供了丰富的生态系统。 而且,JSF最初是基于HTML的,它使您可以像迄今为止使用JSFHTML4一样轻松地使用HTML5。 除了HTML5之外,您还可以获得所有强大的JSF功能,例如facelets模板,复合组件和内置的Ajax。

    在本文中,您将学习如何使用JSF2创建HTML5复合组件。 在下一篇JSF 2 fu文章中,我将向您展示如何创建HTML5组件库。

    HTML5入门

    实际上,使用HTML5涉及JavaScript比HTML多得多。 这意味着您需要一个好JavaScript调试器。 我建议使用Google Chrome内置的开发人员工具随附的工具(请参阅参考资料 ),如图1所示:

    图1.使用Chrome Developer Tools调试JavaScript

    在图1所示的Chrome调试器中,包含JavaScript代码的面板出现在显示的画布组件下方。

    现在您已经有了一个不错JavaScript调试器,您只需要一个具有HTML5功能的浏览器即可。 较流行的浏览器的大多数最新版本都很好地支持HTML5。 (Microsoft在即将发布的Internet Explorer 9中似乎具有良好HTML5支持。)

    使用HTML5画布

    HTML5画布是成熟的2D绘图表面,其功能足以支持诸如植物大战僵尸和雷神之锤II之类的游戏 。 我对HTML5画布的使用(如图2所示)可能不那么引人注目,但足以满足指导目的:

    图2.一个简单HTML5 canvas示例

    我已经在HTML5画布中添加了一些JavaScript,以实现图2所示的简单绘画应用程序。 移动鼠标时,画布左上角的读数将显示鼠标坐标。 在画布上拖动鼠标时,将使用蓝色画笔进行绘制。

    图2中显示的应用程序是一个JSF应用程序。 图3显示了其目录结构:

    图3. canvas示例的目录结构

    该应用程序的单独方面在web / WEB-INF / index.xhtml中定义,而该应用程序JavaScript在web / resources / application / paintingCanvas.js中。 清单1显示了index.xhtml:

    清单1.使用<canvas>标记(WEB-INF / index.xhtml)
    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <title>#{msgs.windowTitle}</title> </h:head> <h:body style="background: #fefeef"> <h:outputScript library="application" name="paintingCanvas.js" target="head" /> <h3>#{msgs.heading}</h3> <canvas width="400px" height="400px" id="paintingCanvas"> Canvas not supported. </canvas> </h:body> </html>

    清单1中的index.xhtml文件被称为HTML5 多语言文档 (请参阅参考资料 ),因为它具有HTML5 doctype / namespace和格式良好的XHTML语法—正是我所设计的facelets和HTML5所需要的。

    我使用<h:outputScript>标记导入相应JavaScript。 最后,我深入探讨并使用HTML5 canvas元素。 如果浏览器不理解<canvas>标记,它将显示不支持Canvas的消息。 <canvas>标签没有用。 所有有趣的代码都在相应JavaScript中,如清单2所示:

    清单2.绘画画布JavaScript(resources / application / paintingCanvas.js)
    window.addEventListener("load", function() { var canvas, context, painting; function init() { canvas = document.getElementById("paintingCanvas"); if (canvas == null) return; context = canvas.getContext("2d"); if (context == null) return; painting = false; context.strokeStyle = "#00f"; context.lineWidth = 3; context.font = "15px Helvetica"; } init(); canvas.addEventListener("mousedown", function(ev) { painting = true; context.beginPath(); context.moveTo(ev.offsetX, ev.offsetY); }, false); canvas.addEventListener("mousemove", function(ev) { updateReadout(ev.offsetX, ev.offsetY); if (painting) { paint(ev.offsetX, ev.offsetY); } function updateReadout(x, y) { context.clearRect(0, 0, 100, 20); context.fillText("x: " + x + ", y: " + y, 5, 15); } function paint(x, y) { context.lineTo(ev.offsetX, ev.offsetY); context.stroke(); } }, false); canvas.addEventListener("mouseup", function() { painting = false; context.closePath(); }, false); }, false);
    运行示例代码

    该系列的代码基于在企业容器(例如GlassFish或Resin)中运行的JSF 2。 有关使用GlassFish安装和运行该系列代码的分步教程,请参阅第一个系列文章“ JSF 2 fu :Ajax组件 ”。 请参阅下载以获取本文的示例代码。

    清单2通过鼠标光标读数实现了简单绘制, 如图2所示。 页面加载时,我使用document.getElementById()获得了对画布的引用。 从画布上,可以得到对画布上下文的引用。 我在随后的事件处理程序中使用该上下文,该事件处理程序是使用JavaScript闭包实现的,或者是Java开发人员将其称为匿名内部类的实现。

    如果您使用了Abstract Window Toolkit(AWT),则画布的上下文将立即让人联想到AWT的图形上下文。 毕竟,只有两种方法可以在二维上绘制形状,图像和文本。 在清单2中 ,我使用蓝色的笔触样式初始化上下文,并设置线宽和字体。 从那时起,仅当鼠标分别向下,拖动和向上移动时,才需要移动,抚摸,重复。

    现在您已经掌握了HTML5画布的基础知识,我将向您展示如何创建JSF 2 HTML5复合组件。

    JSF 2 HTML5 canvas组件

    接下来,我将实现一个使用HTML5画布的JSF 2复合组件。 我需要复合组件来满足以下要求:

    具有可配置的(通过标签属性)宽度,高度,笔颜色,线宽和CSS样式 将component标签的主体用作画布不受支持的消息 自动包含画布JavaScript 在单个页面中支持多个画布组件

    图4显示了使用canvas复合组件的应用程序:

    图4.运行中的canvas复合组件

    图4所示的应用程序具有三个画布组件,每个组件具有不同的配置。 从左开始,前两个是绘画画布,类似于图2所示。 最右边的画布只是画一个笑脸。

    清单3显示了图4所示页面的标记:

    清单3.使用画布组合组件(WEB-INF / index.xhtml)
    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:h5="http://java.sun.com/jsf/composite/html5"> <h:head> <meta charset="UTF-8" /> <title>#{msgs.windowTitle}</title> </h:head> <h:body style="background: #fefeef"> <h3>#{msgs.heading}</h3> <h5:canvas id="paintingCanvas" width="300px" height="300px" penColor="#7F7" lineWidth="7"> #{msgs.canvasUnsupported} </h5:canvas> <h5:canvas id="secondPaintingCanvas" width="300px" height="300px" style="border: thick solid red"> #{msgs.canvasUnsupported} </h5:canvas> <h5:canvas id="smileyCanvas" library="application" script="smiley.js" width="300px" height="300px" style="border: thin solid red"> #{msgs.canvasUnsupported} </h5:canvas> </h:body> </html>

    在清单3中 ,canvas组件导入了适当JavaScript —与清单1不同,在清单1中 ,我手工使用HTML5,并且必须显式导入关联JavaScript。 页面作者可以使用画布组件的可选library和script属性来指定画布JavaScript,也可以依赖默认JavaScript。 在清单3中 ,我为笑脸画布使用script属性。 我在示例中最左边的两个画布使用了默认JavaScript(resources / html5 / canvasDefault.js,它实现了绘画画布)。

    清单4显示了canvas复合组件的实现:

    清单4. canvas复合组件(resources / html5 / canvas.xhtml)
    <?xml version="1.0" encoding="UTF-8"?> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:composite="http://java.sun.com/jsf/composite"> <composite:interface> <composite:attribute name="id"/> <composite:attribute name="width"/> <composite:attribute name="height"/> <composite:attribute name="library" default="html5"/> <composite:attribute name="script" default="canvasDefault.js"/> <composite:attribute name="style" default="border: thin solid blue"/> <composite:attribute name="penColor" default="#7777FF"/> <composite:attribute name="lineWidth" default="2"/> </composite:interface> <composite:implementation> <canvas id="#{cc.id}" width="#{cc.attrs.width}" height="#{cc.attrs.height}" style="#{cc.attrs.style}"> <composite:insertChildren/> </canvas> <h:outputScript library="#{cc.attrs.library}" name="#{cc.attrs.script}"/> <script> #{cc.attrs.script}.init('#{cc.id}', '#{cc.attrs.penColor}', '#{cc.attrs.lineWidth}') </script> </composite:implementation> </html>

    在清单4中 ,我为canvas复合组件声明了八个属性,其中五个具有默认值。 组件的实现包含一个HTML5画布,其ID,宽度,高度和样式是从组件的相关属性配置的。 这就满足了我对画布组件的第一个要求(可配置属性)。

    canvas复合组件将其子级 (即<h5:canvas>标记正文中的所有内容)插入HTML5 canvas标记( <canvas> )。 这意味着,如果浏览器不支持HTML5画布,则将显示标签正文中的所有文本。 这就满足了第二个要求(使用画布不受支持的消息的组件标签的主体)。

    画布组件包含一个<h:outputScript>标记,该标记导入画布JavaScript,该JavaScript是通过画布组件的library和script属性指定的。 请注意, library和script属性分别默认为html5和canvasDefault.js 。 这就满足了第三个要求(自动导入画布JavaScript)。

    最后,画布组件调用一个名为init()JavaScript方法,并传递画布的ID,笔颜色和线宽。 init()方法获取并初始化画布的上下文。 注意,我说的是method而不是function ,因为init()方法属于一个对象。 该对象的名称是从canvas组件的script属性派生的。 例如,对于清单3中的笑脸画布,我指定了script值smiley.js ,因此笑脸画布组件将调用smiley.js.init() -名为js的对象的init()方法,该对象包含在对象名为smiley 。 如果未明确指定script值,则默认为canvasDefault.js ,因此JavaScript方法为canvasDefault.js.init() 。 调用这些方法而不是全局函数可以满足我的第四个要求:在单个页面中支持多个画布。

    清单5显示了canvas组件的默认JavaScript:

    清单5.默认的画布JavaScript(resources / html5 / canvasDefault.js)
    if (!canvasDefault) var canvasDefault = {} if (!canvasDefault.js) { canvasDefault.js = { init : function(canvasId, penColor, lineWidth) { var canvas, context, painting; canvas = document.getElementById(canvasId); if (canvas == null) { alert("Canvas " + canvasId + " not found") } context = canvas.getContext("2d") if (context == null) return; painting = false; context.strokeStyle = penColor context.lineWidth = lineWidth context.font = "15px Helvetica" canvas.addEventListener("mousedown", function(ev) { painting = true context.beginPath() context.moveTo(ev.offsetX, ev.offsetY) }, false) canvas.addEventListener("mousemove", function(ev) { updateReadout(ev.offsetX, ev.offsetY) if (painting) { paint(ev.offsetX, ev.offsetY) } function updateReadout(x, y) { context.clearRect(0, 0, 100, 20) context.fillText("x: " + x + ", y: " + y, 5, 15) } function paint(x, y) { context.lineTo(ev.offsetX, ev.offsetY) context.stroke() } }, false) canvas.addEventListener("mouseup", function() { painting = false context.closePath() }, false) } } }

    在清单5中 ,我创建了一个名为canvasDefault的对象,其中包含一个名为js的对象,该对象包含一个init()方法。 我这样做是为了给init()方法命名空间 ,因此它不会被另一个全局init()函数覆盖。 这样,我可以在单个页面中拥有多个画布,所有画布都有自己的init()函数实现。

    清单6显示了笑脸画布JavaScript:

    清单6.笑脸画布JavaScript(resources / application / smiley.js)
    if (!smiley) var smiley = {} if (!smiley.js) { smiley.js = { init : function(canvasId, penColor, lineWidth) { var canvas, context canvas = document.getElementById(canvasId); if (canvas == null) { alert("Canvas " + canvasId + " not found") } context = canvas.getContext("2d"); if (context == null) return // smiley face code originally downloaded // from thinkvitamin.com // Create the face context.strokeStyle = "#000000"; context.fillStyle = "#AAAAFF"; context.beginPath(); context.arc(100,100,50,0,Math.PI*2,true); context.closePath(); context.stroke(); context.fill(); // eyes context.strokeStyle = "#000000"; context.fillStyle = "#FFFFFF"; context.beginPath(); context.arc(80,80,8,0,Math.PI*2,true); context.closePath(); context.stroke(); context.fill(); context.fillStyle = "#0000FF"; context.beginPath(); context.arc(80,80,5,0,Math.PI*2,true); context.closePath(); context.fill(); context.strokeStyle = "#000000"; context.fillStyle = "#FFFFFF"; context.beginPath(); context.arc(120,80,8,0,Math.PI*2,true); context.closePath(); context.stroke(); context.fill(); context.fillStyle = "#0000FF"; context.beginPath(); context.arc(120,80,5,0,Math.PI*2,true); context.closePath(); context.fill(); // nose context.fillStyle = "#000000"; context.beginPath(); context.moveTo(93,100); context.lineTo(100,93); context.lineTo(107,100); context.closePath(); context.fill(); // smile context.strokeStyle = "#000000"; context.beginPath(); context.moveTo(70,110); context.quadraticCurveTo(100,150,130,110); context.closePath(); context.stroke(); } } }

    清单6遵循与清单5中相同的命名间隔约定。 其他类型的画布的后续JavaScript必须遵循相同的约定。

    结论

    在本文中,我向您介绍了HTML5,并向您展示了如何实现JSF 2 HTML5 canvas复合组件,该组件使JSF开发人员和页面作者可以轻松使用HTML5 canvas。 我向您展示了如何将从JSF表达式语言获得的信息传递给与复合组件关联JavaScript,以及如何对JavaScript函数进行命名空间,以使名称相同的函数不会相互干扰。 在下一期JSF 2 fu中 ,我将向您展示如何实现另一个HTML5组件,以及如何将多个HTML5组件放入可重用的库中,然后可在JAR文件中分发给其他开发人员。


    翻译自: https://www.ibm.com/developerworks/java/library/j-jsf2fu-1010/index.html

    相关资源:Winform开发全套31个UI组件开源共享
    Processed: 0.125, SQL: 10