Skip to content


敏捷宣言遵循的原则

我们遵循以下原则:

我们最重要的目标,是通过持续不断地
及早交付有价值的软件使客户满意。

欣然面对需求变化,即使在开发后期也一样。
为了客户的竞争优势,敏捷过程掌控变化。

经常地交付可工作的软件,
相隔几星期或一两个月,倾向于采取较短的周期。

业务人员和开发人员必须相互合作,
项目中的每一天都不例外。

激发个体的斗志,以他们为核心搭建项目。
提供所需的环境和支援,辅以信任,从而达成目标。

不论团队内外,传递信息效果最好效率也最高的方式是
面对面的交谈。

可工作的软件是进度的首要度量标准。

敏捷过程倡导可持续开发。
责任人、开发人员和用户要能够共同维持其步调稳定延续。

坚持不懈地追求技术卓越和良好设计,敏捷能力由此增强。

以简洁为本,它是极力减少不必要工作量的艺术。

最好的架构、需求和设计出自自组织团队。

团队定期地反思如何能提高成效,
并依此调整自身的举止表现。

来源:http://agilemanifesto.org/iso/zhchs/principles.html

Posted in 其他.


敏捷软件开发宣言

我们一直在实践中探寻更好的软件开发方法,
身体力行的同时也帮助他人。由此我们建立了如下价值观:

个体和互动 高于 流程和工具
工作的软件 高于 详尽的文档
客户合作 高于 合同谈判
响应变化 高于 遵循计划

也就是说,尽管右项有其价值,
我们更重视左项的价值。

来源:http://agilemanifesto.org/iso/zhchs/

Posted in 其他.


不可见的 Flash

Michael Galpin, 软件架构师, eBay

简介: 您是否想过让 Cookies 容量更大以便在客户端存储更多数据,或者能实现跨域的 Asynchronous JavaScript and XML (Ajax) 调用?如果是,那么您很幸运。这两项技术都可以通过使用不可见的 Flash 实现。那么,什么是不可见的 Flash?它不是真正的不可见,而是它只有 1 × 1 个像素大,因此肉眼很难辨别。而且,它可以利用 Flash Player 的功能。在本文中,您将学习如何创建不可见 Flash 文件,以便能在客户端存储多达 100 KB 的数据,以及实现跨域 Ajax 调用 — 并且您的用户甚至不知道使用了 Flash。

让我们开始吧

如前所述,您将在本文中学习如何使用 Flash 为 Web 应用程序增添额外的功能。熟悉 JavaScript 是必需的技能,有 ActionScript 使用经验将会很方便。有很多方法编译 ActionScript,其中一些依赖于 Adobe 的商业工具。然而,也可以使用 Adobe 的开源 Flex SDK。本文使用的是 Flex SDK 4.0.0.10485 (Beta 2)。为了运行示例程序,需要 Flash Player 的第 10 版或更高版本。本文中使用的是 10.0.42.34 版本。参考资料 中有下载链接。

Flash 本地存储

许多 Web 应用程序需要在客户端存储状态。有时候这仅仅是某种类型的会话 ID,它可以用来从内存或数据库检索服务器端状态。然而,很多 Web 应用程序出于可伸缩性的考虑故意避免服务器端状态。因此,所有的状态都要存储在客户端。另外,通常希望状态在当前回话结束后仍然保持。

长期以来都使用 HTTP cookies 作为默认的处理方式。然而,HTTP cookies 存在缺陷。在开发人员看来,它难以运用,因为它实际是只是一个 HTTP 头部。更重要的是,存在安全隐患。对于每个请求,HTTP cookies 都会在客户端和服务器端来回传递,因此其中的所有数据都可能被截取。还有,跨站点脚本/伪造会利用这一特定 “窃取 cookie”。如果 cookies 被窃取了,您的相应账号很可能被破坏甚至被他人利用。

但是,HTTP cookies 最常见的缺陷就是大小限制。不同浏览器为每个域分配的 HTTP cookies 的最大容量是不同的。HTTP 规范将其限制为 4 KB,这就是您所能利用的所有空间。如果想在客户端存储大于 4 KB 的数据怎么办呢?如果您考虑过这些问题,您只好无奈地用 Java™Script 编写一个 gip 式的压缩算法,这是一种方法。或者,可以使用其他替代方法,例如,Flash。

本地共享对象

Flash Player 为 Flash 应用程序提供了本地存储空间。默认情况下,每个域有 100 KB 的限制。这样很好:可获得是 HTTP cookies 的 25 倍的空间。还有其他一些重要的差异。其一,Flash 中存储的客户端数据不会发送给服务器,因为它与 HTTP 没有任何关系。当然,如果您愿意,也可以将这些数据发送给服务器。这样做不会有任何障碍。然而,您必须选择发送哪些数据以及以什么方式发送。如果您真的希望客户端和服务器都包含这些数据,这就有点复杂了。但是,这通常更加安全,因为您必须在网络中显式 “公开” 这些数据。

用于存储和检索本地数据的 Flash API 是 SharedObject。其实,Flash 的 SharedObject 概念也可以是远程的,因此,仅存在于客户端的变体也称为本地 SharedObject。该 API 非常简单,它允许使用键-值范式存储和检索任意复杂的对象。清单 1 是存储和检索SharedObjects 的简单代码。
清单 1. 存储和检索 SharedObjects

package{

    import flash.display.Sprite;
    import flash.net.SharedObject;

    public class JsHelper extends Sprite{
        private const SO_NAME:String = "helperSo";

        private function saveLocal(name:String, value:Object):void{
            var so:SharedObject = SharedObject.getLocal(SO_NAME);
            so.data[name] = value;
            so.flush();
        }

        private function readLocal(name:String):Object{
            var so:SharedObject = SharedObject.getLocal(SO_NAME);
            return so.data[name];
        }
    }
}

如果您不熟悉 ActionScript,清单 1 的代码可能看上去有点奇怪。ActionScript 很像 JavaScript;实际上,它来自于 ECMAScript 标准。尽管如此,它具有很多 C++ 和 Java 中常见的特性。变量都是强类型的,还有基于类的继承。清单 1 中的代码是一个扩展了Sprite 类的类。该类将会编译进 Shockwave Flash (SWF) 文件,此文件会嵌入 Web 页面中。该类有两个方法。其中一个叫saveLocal。它需要一个名称(只是一个字符串)和一个值(任何类型的对象)。然后它使用 getLocal 工厂方法取得特定的SharedObject

每个 SharedObject 实例都有一个数据属性,可以看作存储数据的哈希表。这就是 saveLocal 函数的第二行的作用。 最后一行 “清除”SharedObject,或将其保存到磁盘上。这些就是本地存储所要做的一切。如果大量使用 SharedObjects 并接近了 100 KB 的限制,那么您可能需要添加事件监听器。这将能够对 “清除完成” 或 “清除失败” 之类的事件做出响应。

从本地存储中回读同样也很简单,这是通过清单 1 的 readLocal 函数完成的。本例中,已搜索到 SharedObject,并且 name 参数已用于从数据哈希表中搜索已存储的对象。如果哈希表中没有与键值对应的名称,将返回 null。既然已学会如何访问 SharedObjects,现在只需要在 Web 页面上获取 Flash(不可见)— 以及使用 JavaScript 访问它。

回页首

使其不可见

默认情况下,清单 1 中的任何函数都无法在 JsHelper 类以外访问。然而,Flash 能够很容易地将函数公开给 JavaScript。需要做的就是使用 Flash 的 ExternalInterface API,如清单 2 所示。
清单 2. 将 JsHelper 函数公开给 JavaScript

package{

    import flash.external.ExternalInterface;
    import flash.net.SharedObject;

    public class JsHelper extends Sprite{
        private const SO_NAME:String = "helperSo";
        private const SAVE_LOCAL:String = "saveLocal";
        private const READ_LOCAL:String = "readLocal";

        public function JsHelper(){
            ExternalInterface.addCallback(SAVE_LOCAL, saveLocal);
            ExternalInterface.addCallback(READ_LOCAL, readLocal);
        }
        // functions omitted for brevity
    }
}

清单 2 简单演示了向清单 1 中的 JsHelper 类添加的内容。主要的注意点是添加了一个显式构造函数。正如您所料,这个构造函数将在创建类的一个实例时得到调用。其中,使用 ExternalInterface API 将两个函数 saveLocal 和 readLocal 公开给 SWF 所嵌入的所有 Web 页面上的 JavaScript。addCallback 函数的第一个参数是字符串。JavaScript 客户端使用它作为名称识别函数。它与类中的函数名可能不同,但在该例中是相同的。第二个参数是一个函数闭包。与 JavaScript 一样,ActionScript 是函数语言,因此函数是一阶的,可以传递。这就是公开两个函数所需要做的。现在看看用于嵌入和访问 SWF 的 JavaScript。详见清单 3。
清单 3. 嵌入不可见 Flash

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Flash Helper for JavaScript</title>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
    function writeFlash(){
        var attrs = {id : "JsHelper"};
        swfobject.embedSWF("JsHelper.swf", "flashContainer", "1", "1", "10.0.0",
            "playerProductInstall.swf", null, null, attrs);
    }
    function save(name, value){
        var helper = document.getElementById("JsHelper");
        helper.saveLocal(name, value);
    }
    function load(name){
        var helper = document.getElementById("JsHelper");
        return helper.readLocal(name);
    }
</script>
</head>
<body onload="writeFlash()">
    <div id="flashContainer"></div>
</body>
</html>

这段代码中首先要注意的是使用了第三方 JavaScript 库 swfobject。这实际上是嵌入 SWF 的标准库。它是开源的,虽然最初不是由 Adobe 开发的,但是现在由他们维护。它的 embedSWF 函数用于嵌入由清单 2 编译的 SWF。第一个参数是指向 SWF 的 URL。本例中,SWF 来自和 HTML 文件相同的服务器和路径,因此可以使用一个相对 URL。第二个参数是在其中嵌入 SWF 的页面的 HTML 元素的 ID。本例中是 "flashContainer" — 同时您将注意到 HTML 文档的主体部分有一个 HTML div 使用该 ID。

接下来的两个 embedSWF 参数是 SWF 的高度和宽度。在本例中,两者的值都是 1。这意味着 SWF 的高度和宽度都为一个像素。这就是不可见的 SWF!下一个参数是 Flash 的最低版本,您的 JavaScript 将检查该参数。如果 Flash 已安装在浏览器上,但其版本号比传递给 embedSWF 的版本号更低,那么 embedSWF 将使用下一个参数 "playerProductInstall.swf"。这是指向另一个 SWF 的 URL,它提示用户安装最新版本的 Flash。对于不可见 Flash,这其实没什么影响 — “您需要安装最新版本 Flash” 的 SWF 其实也不可见(当然,也是 1×1 像素)。传给 embedSWF 的最后一个参数很重要。这是一个包含各种可选参数的属性对象。其中一个可选参数是 SWF 的 ID。对于和本文类似的用例,该参数是不可选的 — 这至关重要!它将会提供给 SWF 一个 HTML ID,而这将会在使用 JavaScript 进行编程访问时用到。

现在看看 清单 3 中的两个 JavaScript 函数。二者很相似。都使用熟悉的 getElementById 函数获取 SWF 的引用。请注意它们使用的是 writeFlash 函数中的 attrs 对象指定的 ID。取得 SWF 引用后,可以直接调用 清单 2 中公开的 ActionScript 函数。此处的关键是,JavaScript 中使用的函数名必须匹配 ExternalInterface.addCallback 函数中公开的名称或者是传给 addCallback 的第一个参数。

对于 save 方法,传递了一个 JavaScript 对象作为 value 参数。这可以是任意对象,甚至可以具有一个深度嵌套的结构。然而,只会传递对象的数据。如果该对象包含函数,那么将不会被传递。请注意 load 方法将返回所有来自 SWF 的内容。是什么内容?答案很简单:您发送的任何内容。如果您存储的是数字或字符串等标量值,那么将返回这些内容。如果存储的是复杂的对象,那么将返回该 JavaScript 对象 — 不需要解析或其它操作。一个例外是假如对象包含函数,那么肯定不会被序列化并保存。因此只会返回对象中的数据,而不是其他内容。以上总结了使用 Flash 进行本地存储所需掌握的全部内容。在学习使用 Flash 操作跨域 Ajax 之前,了解一些可作为替代选择的本地存储方法。

回页首

其他的本地存储选择

我提到 Flash 是面向客户端存储的一个有吸引力的选择,可以代替 HTTP cookies。尽管如此,还有两项 Web 技术采用了与 FlashSharedObjects 一样的范式。事实上,长期以来各种浏览器都提供相似的 API。但各浏览器的 API 不尽相同。因此您可以先了解一下各个浏览器,然后使用特定的 API。Flash 提供了一致的替代方案。本文中开发的代码几乎可以运行于所有浏览器:Internet Explorer 6 和 Firefox 2,以及这些浏览器的最新版本。更新的版本提供一致的解决方案。HTML 5 规范包含一个 localStorage API。主流浏览器的最新版本都实现了这个 API,包括 IE 8 和 Firefox 3.5。因此如果只担心浏览器的话,localStorage 将是一个可用的选项。如果担心旧的浏览器(IE 6、IE 7 等等),那么使用 Flash 可能会更容易。现在,看看 Flash 能够实现的新功能,跨域 Ajax。

回页首

跨域 Ajax

Ajax 目前在 Web 应用程序中无所不在;它是任何 Web 应用程序中都假设会有的部分。Ajax 的一个主要不足就是为人诟病的同源策略。如果 Web 页面由 a.com 提供,您只能向 a.com 调用 Ajax(更精确地说是 XMLHttpRequest)。例如,您无法调用 b.com。如果您的公司拥有 a.com 和 b.com,那就没有影响;浏览器不会关心这些。但是对 Flash 应用程序却不是这样。

Flash 应用程序可以获得许可,并对提供服务的域以外的域进行调用。这可以用跨域策略文件完成。默认情况下,Flash 运行时将在服务器的文档根目录搜索策略文件:http://<your domain>/crossdomain.xml。例如,清单 4 是 Twitter 搜索域的策略文件,http://search.twitter.com/crossdomain.xml。
清单 4. Twitter 搜索域的策略文件

<!DOCTYPE cross-domain-policy
SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">

<cross-domain-policy>
    <allow-access-from domain="*" />
</cross-domain-policy>

这是个相当好的策略文件。它允许所有(如 “*” 通配符所示)域对 SWF 进行访问。因此所有 Flash 应用程序都可以调用 Twitter 的搜索 API。在大多数具有公共 API 的 Web 网站上像这样的策略文件很常见。尽管如此,有些网站使用更加严格的策略,只允许自己所有的其他域或合作伙伴的域进行访问。有了策略文件,就可以细粒度地精确控制谁能够调用服务器,谁不能。看看如何将同样的功能扩展到 Ajax 应用程序中。

回页首

跨域

如果您的应用程序只需要调用特定的域,可以编写 ActionScript 代码调用该域,然后在应用程序中使用 ExternalInterface 将其公开给 JavaScript。然而,我将采取一种更好的方法,并试图用更一般化的方式进行公开。因此,清单 5 中,将使用一个实用类从 ActionScript 中调用任意域。
清单 5. 跨域工具 SWF

package{

    import flash.display.Sprite;
    import flash.events.Event;
    import flash.external.ExternalInterface;
    import flash.net.URLLoader;
    import flash.net.URLRequest;

    public class JsHelper extends Sprite{
        private const SEND_REQUEST:String = "sendRequest";

        public function JsHelper(){
            ExternalInterface.addCallback(SEND_REQUEST, sendRequest);
        }

        public function sendRequest(url:String, handlerName:String,
                method:String="GET", content:Object=null,
                headers:Object=null):void{
            var loader:URLLoader = new URLLoader();
            var request:URLRequest = new URLRequest(url);
            if (method){
                request.method = method;
            }
            if (headers){
                for each (var name:String in headers){
                    request.requestHeaders[name] = headers[name];
                }
            }
            if (content){
                request.data = content;
            }
            loader.addEventListener(Event.COMPLETE,
                function(e:Event):void{
                    ExternalInterface.call(handlerName, loader.data);
            });
            loader.load(request);
        }
    }
}

该类使用 ExternalInterface 将 sendRequest 函数公开给 JavaScript。这在对象的构造函数中完成,和之前 清单 2 中的例子一样。sendRequest 函数有点复杂:它有两个必需的参数。第一个参数是需要调用的 URL。这是一个完整的 URL 字符串,包含所有请求参数。下一个是 JavaScript 函数名,此函数在获得服务器响应后由 Flash 调用。和典型的 Ajax 一样,Flash 对远程服务器进行异步调用,主 UI 线程在等待远程服务器响应时不会停止。因此,与 Ajax 一样,需要编写 callback 函数,它将在接收到服务器响应后被调用。将其作为字符串传递给 Flash,但它必须与函数名完全相同。

sendRequest 函数也有三个可选参数。ActionScript 允许有可选参数,但必须有可用的缺省值。第一个是使用 HTTP 方法,通常是 GET或 POST。本文中,我将它默认为 GET,但是可以很容易地用 POST 将其替换,这取决于远程服务器的需要。下一个可选参数叫做content。这是一个一般数据对象,包含有需要发送给远程服务器的任意名称-值对。向远程服务器发送数据时需要用到。最后一个可选参数是另一个用于头部的一般数据对象。它用于将定制 HTTP 头部设置为作为远程服务器调用的一部分发送。

然后代码获取所有这些参数,使用 Flash URLRequest 对象构造 HTTP 请求,然后使用 Flash URLLoader 类发送请求。事件监听器会绑定到 URLLoader 以便能处理返回的响应。这里创建一个闭包,如同在 JavaScript 中一样,创建一个匿名内联函数,将在 COMPLETE 事件被加载程序触发后调用。该闭包将只使用 ExternalInterface 来调用名称被传递给 sendRequest 的函数。它将来自远程服务器的所有数据传递给该函数。这显然比使用本地存储复杂一点。看看清单 6 中调用 Twitter 搜索的例子。
清单 6. 调用 Twitter 搜索

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Calling Twitter from the client</title>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
    function writeFlash(){
        var attrs = {id : "JsHelper"};
        swfobject.embedSWF("JsHelper.swf", "flashContainer", "1", "1", "10.0.0",
            "playerProductInstall.swf", null, null, attrs);
    }
    function search(){
        var keyword = document.getElementById("keyword").value;
        var helper = document.getElementById("JsHelper");
        helper.sendRequest("http://search.twitter.com/search.json?q=" + keyword,
"showResults");
    }
    function showResults(responseStr){
        var response = eval("(" + responseStr +")");
        var results = response.results;
        alert("#Results = " + results.length);
    }
</script>
</head>
<body onload="writeFlash()">
    <div id="flashContainer"></div>
    <div id="inputDiv">
        <label for="id">Search Twitter</label>
        <input type="text" id="keyword" name="keyword"/>
        <input type="button" value="Search Twitter" onclick="search()"/>
    </div>
</body>
</html>

此处的代码与 清单 3 中的 HTML/JS 类似。再次使用了 swfobject 库将 SWF 嵌入页面中。代码中有个简单的表单,提示用户输入在 Twitter 中搜索的关键词。单击 Search 按钮后调用搜索函数。它从输入字段取得关键词并用于创建需要调用的 URL。然后传递给 JsHelper SWF,就像在 清单 3 中那样,通过使用 ID 取得 SWF 的引用,然后使用 ExternalInterface 直接调用公开的函数。传递一个 URL 和命名回调函数的字符串。数据从 Twitter 返回后,传递到 showResults 函数。这是一个 JSON 字符串,因为它是从 Twitter 返回的,因此可以简单地用 JavaScript 的 eval 函数将其转换为一个对象。本例中,只是简单显示了从 Twitter 中返回的结果数。尽管如此,可以方便地在页面中创建 HTML 来列举每个结果;只是些样板 DOM 代码。就是这样,您学习了借助 Flash 的跨域 Ajax 调用的方法。与使用 Flash 进行本地储存一样,还有其他一些替代方法。

跨域替代方案

Flash 长期以来被用于实现跨域调用,就像它可以实现本地存储一样。与本地存储的用例一样,一些 Web 浏览器实现了自己的方式,后来也出现了一些标准化工作。与本地存储相比,进展并不顺利。尽管目前已有跨域 Ajax 标准,却未被 IE 8 采用。相反,IE 8 以一种特有的方式处理跨域 Ajax。这种特有方式的实现在 IE 8 中是全新的,在旧版本 IE 中没有。Flash 再一次展示了一个可以跨所有浏览器工作的模型。

加入 My developerWorks 中的 Web 开发组

在 My developerWorks Web 开发组 中与其他开发人员讨论话题、分享资源。

还不是 My developerWorks 的成员?现在就加入!

最后,如果您研究过跨域 Ajax,您肯定会发现其他方法,而不需要 Flash 或任何其他浏览器特性。这项技术,通常称为 JSONP(含有 Padding 的 JSON )或者是 “动态脚本标记”,它利用了浏览器不对 JavaScript 源文件强制执行同源策略的特性。因此创建了一个脚本标记,它的源指向要调用的 URL,并插入到 DOM 中。该 URL 通常包含一个 “回调” 参数,它是您想要调用的回调函数的名称。服务器然后将数据与函数名封装,以便函数得到调用,且来自服务器的数据被传递给它。这项技术在 Internet 上广泛运用(例如,前面展示的 Twitter 搜索 API 就支持该技术),但有相应的安全风险 — 因此,标准的、安全的做法,就应该像 Flash 那样。

结束语

本文介绍了如何使用 Flash 扩展 Web 应用程序的功能。您可以极大地增加应用程序所能访问的本地存储容量。这使您能够在客户端缓存大量数据。您还可以使用 Flash 从 Web 应用程序进行跨域 Ajax 调用。这里只是粗略体验一下 Flash 的功能。如果您觉得其他功能对您也有所帮助,可以使用同样的技术:使 Flash 不可见并用 ExternalInterface 公开其函数。

下载

描述 名字 大小 下载方法
文章源代码 JsHelper.zip 12KB HTTP

参考资料

学习

获得产品和技术

  • 下载 Flex SDK
  • 使用 IBM 试用软件 改进您的下一个开源开发项目,可通过下载或 DVD 获得。

Posted in web技术.

Tagged with , .


DELPHI字符串分割函数

dephi中没有象PHP中的explode函数 ,但是使用TStringList类的 Delimter 和 DelimtedText 两个属性可以很容易的把字符串分割,然后放入 TStrings里面.
例:
s:=’aa,bb,cc,dd’
ts := TStringList.Create
ts.Delimter := ‘,’
ts.DelimtedText := s
//这时 ts里面就存放了 aa bb cc dd 这四个strings了. 你只要通过 ts[0]就可以取第一个数据
function SplitString(Source, Deli: string ): TStringList;stdcall;
var
EndOfCurrentString: byte;
StringList:TStringList;
begin
StringList:=TStringList.Create;
while Pos(Deli, Source)>0 do
begin
EndOfCurrentString := Pos(Deli, Source);
StringList.add(Copy(Source, 1, EndOfCurrentString – 1));
Source := Copy(Source, EndOfCurrentString + length(Deli), length(Source) – EndOfCurrentString);
end;
Result := StringList;
StringList.Add(source);
end;
procedure StrToStrs(str:string;strs:tstrings);
var temp:string;
i:integer;
label B,E;
begin
B:
i:= ansipos(‘|’,str);
if i=0 THEN GOTO E;
strs.Add(ansileftstr(str,i-1));
str:=ansirightstr(str,length(str)-i);
GOTO B;
E:
end;
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=590744
TStringList的用法
TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的。
常规的用法大家都知道,现在来讨论它的一些高级的用法。
先把要讨论的几个属性列出来:
1、CommaText
2、Delimiter & DelimitedText
3、Names & Values & ValueFromIndex
先看第一个:CommaText。怎么用呢?用代码说话:
const
constr :String = ‘aaa,bbb,ccc,ddd’;
var
strs :TStrings;
i :Integer;
begin
strs := TStringList.Create;
strs.CommaText := constr;
for i := 0 to Strs.Count-1 do
ShowMessage(Strs[i]);
end;
执行了这段代码后,可以看到ShowMessage显示出来的分别是:aaa bbb ccc ddd。
也就是说,strs.CommaText := constr这一句的作用,就是把一个字符串以’,'为分割符,分段添加到TStrings中。
那么如果不是以’,'来分割,又该怎么做呢?现在看第二个例子。使用Delimiter和DelimitedText。
const
constr :String = ‘aaa\bbb\ccc\ddd’;
var
strs :TStrings;
i :Integer;
begin
strs := TStringList.Create;
strs.Delimiter := ‘\’;
strs.DelimitedText := constr;
for i := 0 to Strs.Count-1 do
ShowMessage(Strs[i]);
end;
可以看到, 显示的效果和第一个例子是一模一样的。解释一下:
Delimiter为分隔符,默认为:’,'。DelimitedText就是按Delimiter为分隔符的一个串,得到赋值后回把这个字符串按Delimiter的字符添加到TStrings中。
说到这里,有想起一个属性,QuoteChar。其默认值为:’”‘(不包括单引号)
有何用呢?看例子:
const
constr :String = ‘”aaa”\”bbb”\”ccc”\”ddd”‘;
var
strs :TStrings;
i :Integer;
begin
strs := TStringList.Create;
strs.Delimiter := ‘\’;
strs.DelimitedText := constr;
for i := 0 to Strs.Count-1 do
ShowMessage(Strs[i]);
end;
显示出来的仍然是aaa bbb ccc ddd。为什么不是:”aaa” “bbb” “ccc” “ddd”呢?
再来看一个例子:
const
constr :String = ‘|aaa|\|bbb|\|ccc|\|ddd|’;
var
strs :TStrings;
i :Integer;
begin
strs := TStringList.Create;
strs.Delimiter := ‘\’;
strs.QuoteChar := ‘|’;
strs.DelimitedText := constr;
for i := 0 to Strs.Count-1 do
ShowMessage(Strs[i]);
end;
显示出来的又是aaa bbb ccc ddd。对比一下,应该不难明白吧?这个就不多说了,用得也不多。
但是还要多说一句,当Delimiter为:’,'而QuoteChar为:’”‘时,DelimitedText和CommaText是同等的。
最后要说的三个是:Names & Values & ValueFromIndex。
看看下面的代码:
const
constr :String = ‘0=aaa,1=bbb,2=ccc,3=ddd’;
var
strs :TStrings;
i :Integer;
begin
strs := TStringList.Create;
strs.CommaText := constr;
for i := 0 to strs.Count-1 do
begin
ShowMessage(strs.Names[i]);
ShowMessage(strs.Values[strs.Names[i]]);
ShowMessage(strs.ValueFromIndex[i]);
end;
end;
通过这个例子不难看出:
这个时候strs中的内容是:
0=aaa
1=bbb
2=ccc
3=ddd
而Names中则是:
0
1
2
3
在Values中则是:
aaa
bbb
ccc
ddd

Posted in DELPHI文档.

Tagged with .


delphi运算符列表

分类 运算符 操作 操作数 结果类型 范例
算术运算符 + 整数,实数 整数,实数 X + Y
- 整数,实数 整数,实数 Result – 1
* 整数,实数 整数,实数 P * InterestRate
/ 实数除 整数,实数 实数 X / 2
div 整数除 整数 整数 Total div UnitSize
mod 取模 整数 整数 Y mod 6
+(一元) 符号等同 整数,实数 整数,实数 +7
-(一元) 符号相反 整数,实数 整数,实数 -X
布尔运算符 not 否定 布尔型 Boolean not (C in MySet)
and 布尔型 Boolean Done and (Total > 0)
or 布尔型 Boolean A or B
xor 异或 布尔型 Boolean A xor B
逻辑(按位)运算符 not 按位否定 整数 整数 not X
and 按位与 整数 整数 X and Y
or 按位或 整数 整数 X or Y
xor 按位异或 整数 整数 X xor Y
shl 按位左移 整数 整数 X shl 2
shr 按位右移 整数 整数 Y shr I
字符串运算符 + 连接 字符串、压缩串、字符 字符串 S + ‘.’
指针运算符 + 指针加 字符指针,整数 字符指针 P + I
- 指针减 字符指针,整数 字符指针,整数 P – Q
^ 指针解除参照 指针 指针的基类型 P^
= 相等 指针 Boolean P = Q
<> 不等 指针 Boolean P <> Q
集合运算符 + 并集 集合 集合 Set1 + Set2
- 差集 集合 集合 S – T
* 交集 集合 集合 S * T
<= 子集 集合 Boolean Q <= MySet
>= 超集 集合 Boolean S1 >= S2
= 相等 集合 Boolean S2 = MySet
<> 不等 集合 Boolean MySet <> S1
in 成员 序数,集合 Boolean A in Set1
关系运算符 = 相等 简单类型、类、类引用、接口、串、压缩串 Boolean I = Max
<> 不等 简单类型、类、类引用、接口、串、压缩串 Boolean X <> Y
< 小于 简单类型、串、压缩串、PChar Boolean X < Y
> 大于 简单类型、串、压缩串、PChar Boolean Len > 0
<= 小于或等于 简单类型、串、压缩串、PChar Boolean Cnt <= 1
>= 大于或等于 简单类型、串、压缩串、PChar Boolean I >= 1
类运算符 as 转换 类和类的实例
is 判断
= 关系运算符 = 和 <> 也作用于类
<>
地址(@)运算符 @X 如果X是一个变量,那么@X返回X的地址。当编译指示 {$T-} 有效时,@X是Pointer类型; 而在编译指示 {$T+} 状态下时,@X是 ^T 类型,这里的T是X的类型。
@F 如果 F 是一个例程(函数或过程),那么@F返回 F 的入口点,@F的类型总是Pointer。
@类中方法 当 @ 适用于定义在类中的方法时,方法标识符必需被类的名称限定。例如: @TMyClass.DoSomething

Posted in DELPHI文档.

Tagged with , .


Delphi2010组件/控件安装方法

delphi 有很多组件可以用,下面介绍一下 在delphi2010中 添加组件的方法。

在D2010IDE,初学者大都能够安装.Net控件,但VCL控件如何安装?大都茫然!下面就来力求详尽地回答这一问题。
首先注意到Delphi2010的组件/控件安装,只支持BPL文件。所以,不管是pas文件、dpk文件或ocx文件类的组件或控件,都需要将其;变成bpl包文件。
1. BPL类,直接安装:确认你的BPL所丰文件夹后,点击“Cpmponent-Install Packages-Add……”即可完成安装;
2. 源码类:即Pas文件:需要新建BPL文件,再按步骤1进行安装。方法如下:点击“File-New-Package-Delphi”新建一个Package文件,并起名保存(别忘记保存在哪里哈!),点击“Project-Add to Project…”,将组件源码添加进来,然后在“project manager”里选择包文件,并点击右键选择“install”就行了。别忘记“Close All”退出时一定要保存包文件,否则下次启动时会找不到包了。
3. ActiveX类控件:通常为OCX文件,如“并行口访问控件”(http://bbs.2ccc.com/topic.asp?topicid=344133″> ),安装原则是,先将其编译成pas文件,再按照方法2安装。方法:点击“Cpmponent-Import Component…”,在对话框中选择“Import ActiveX Control”,点击Next,弹出对话框,此时有两种可能,若控件未注册,请选择Add;若控件已注册(通常在“运行…”处用“RegSvr32”命令来注册控件),则直接从列表中选择你要安装的控件(如上述的hwiInterface ActiveX Control module),然后点击Next;在弹出对话框中,要记住其中“Unit Dir Name”里面的路径名,它表示你在此保存的了pas文件;再点击Next,选中“Create Unit”即可生成pas文件,然后按照步骤2完成控件安装。
4. dpk类: 在IDE的file-open打开DPK文件;在project manager窗口点击右键,并选择“Build”,可生成BPL;然后按照步骤1完成控件安装;或者选择“Install”直接安装控件。

在D2010IDE,初学者大都能够安装.Net控件,但VCL控件如何安装?大都茫然!下面就来力求详尽地回答这一问题。
首先注意到Delphi2010的组件/控件安装,只支持BPL文件。所以,不管是pas文件、dpk文件或ocx文件类的组件或控件,都需要将其;变成bpl包文件。
1. BPL类,直接安装:确认你的BPL所丰文件夹后,点击“Cpmponent-Install Packages-Add……”即可完成安装;
2. 源码类:即Pas文件:需要新建BPL文件,再按步骤1进行安装。方法如下:点击“File-New-Package-Delphi”新建一个Package文件,并起名保存(别忘记保存在哪里哈!),点击“Project-Add to Project…”,将组件源码添加进来,然后在“project manager”里选择包文件,并点击右键选择“install”就行了。别忘记“Close All”退出时一定要保存包文件,否则下次启动时会找不到包了。
3. ActiveX类控件:通常为OCX文件,如“并行口访问控件”(http://bbs.2ccc.com/topic.asp?topicid=344133″><span ),安装原则是,先将其编译成pas文件,再按照方法2安装。方法:点击“Cpmponent-Import Component…”,在对话框中选择“Import ActiveX Control”,点击Next,弹出对话框,此时有两种可能,若控件未注册,请选择Add;若控件已注册(通常在“运行…”处用“RegSvr32”命令来注册控件),则直接从列表中选择你要安装的控件(如上述的hwiInterface ActiveX Control module),然后点击Next;在弹出对话框中,要记住其中“Unit Dir Name”里面的路径名,它表示你在此保存的了pas文件;再点击Next,选中“Create Unit”即可生成pas文件,然后按照步骤2完成控件安装。
4. dpk类: 在IDE的file-open打开DPK文件;在project manager窗口点击右键,并选择“Build”,可生成BPL;然后按照步骤1完成控件安装;或者选择“Install”直接安装控件。

文章来源:http://www.51xuewen.com/group/2035/topic_17525.htm

Posted in DELPHI文档.

Tagged with , , .


系统托盘的实现

主要代码

const

IconMessage = WM_USER+1;

ICON_ID=0;

type

PNewNotifyIconData = ^TNewNotifyIconData;

TDUMMYUNIONNAME = Record

case Integer of

0: (uTimeout: UINT);

1: (uVersion: UINT);

end;

TNewNotifyIconData = Record

cbSize: DWORD;

Wnd: HWND;

uID: UINT;

uFlags: UINT;

uCallbackMessage: UINT;

hIcon: HICON;

szTip: array [0..127] of Char;    //Version 5.0为128个,以前为64个

dwState: DWORD;    //Version 5.0

dwStateMask: DWORD;    //Version 5.0

szInfo: array [0..255] of Char;   //Version 5.0

DUMMYUNIONNAME: TDUMMYUNIONNAME;

szInfoTitle: array [0..63] of Char;   //Version 5.0

dwInfoFlags: DWORD;   //Version 5.0

end;

Var
IconData: TNewNotifyIconData;

// 添加图标

begin
IconData.cbSize:=sizeof(IconData);
IconData.Wnd:=self.Handle;
IconData.uID:= ICON_ID;
IconData.hIcon:=Application.Icon.Handle;
IconData.uCallbackMessage:=IconMessage;
IconData.uFlags:= NIF_MESSAGE   or   NIF_ICON   or   NIF_TIP or NIF_INFO;
IconData.szTip:=’托盘图标’;
IconData.cbSize:=sizeof(IconData);    IconData.Wnd:=self.Handle;    IconData.uID:= ICON_ID;    IconData.hIcon:=Application.Icon.Handle;    IconData.uCallbackMessage:=IconMessage;
IconData.uFlags:= NIF_MESSAGE   or   NIF_ICON   or   NIF_TIP or NIF_INFO;    IconData.szTip:=’托盘图标’;
//显示气球提示
strPLCopy(IconData.szInfo,’托盘图标已经启动’, sizeof(IconData.szInfo) – 1);
IconData.DUMMYUNIONNAME.uTimeout := 3000;
strPLCopy(IconData.szInfoTitle, 托盘图标, sizeof(IconData.szInfoTitle) – 1);
IconData.dwInfoFlags := NIIF_INFO;
Shell_NotifyIcon(NIM_MODIFY, @IconData);
Shell_notifyIcon(NIM_ADD,@IconData);//添加托盘图标
end
//删除图标
IconData.cbSize:=SizeOf(IconData);
IconData.Wnd:=winHandle;
IconData.uID:=ICON_ID;
Shell_NotifyIcon(NIM_DELETE,@IconData);

Posted in DELPHI文档.

Tagged with .


delphi之如何快速开发原生ActiveX控件

ActiveX技术虽然是一项古老的技术,但是却有着广泛的应用,支付宝
的密码输入控件,各大银行的密码输入控件,网页聊天室中的截屏功能,网页播放器中的p2p播放…甚至Flash ,Silverlight等等,在IE中都表现为ActiveX。虽然c#也能开发”用于网页的com应用”,能达到类似ActiveX的效果,但是有一个要命的问题是必须得安装几百M的.net framework框架,如果仅仅为了安全的输入一个密码,而要用户下载几百M的安装程序,这是很多人不能接受的,delphi做为win32下的原生开发工具,能很好的支持微软各种”古老”的经典技术。(再做点小广告:delphi的kyrix版本还能编译跨平台的应用哦!)
ok,开工吧:
开发工具:推荐用delphi 2010(d7也可以,不过添加属性,方法等过程要手动,稍微麻烦点)
1.启用delphi2010–>File->New->Other–>Active Library

2.项目命名为MyActiveX


3.File–>Save All 全部保存



实际上这样就能编译了,不过只是空的dll

4.File–>New–>Other–>Active Form

改名为MyForm


将对应的单元文件,保存为UMyForm.pas

5.打开MyAcitveX.ridl文件,切换到design视图,选中IMyForm接口,右击New–>Property 添加一个属性Msg


将Msg属性的Type改为BSTR 即WideString类型



完了之后,点击工具栏中的Refresh Implementation(即上图中工具栏中圈起来的部分)–这一步很重要,点击之后,它将自动生成属性Msg对应的声明和实现代码模板

6.打开UMyForm.pas–即ActiveForm对应的单元,找到Set_Msg以及Get_Msg的实现部分,补充代码如下:

function TMyForm.Get_Msg: WideString;
begin
result:=_msg;
end;
procedure TMyForm.Set_Msg(const Value: WideString);
begin
_msg := value;
end;

当然TMyForm的private部分,得先加一个私有成员

type
TMyForm = class(TActiveForm, IMyForm)
private
{ Private declarations }
_msg:WideString;
...

这样我们就为即将生成的ActiveX控件,添加了一个字符串类型的属性Msg,下面来测试一下:

7.编译项目,会生成一个MyActiveX.ocx,在运行栏里输入

regsvr32 C:\Users\jimmy.yang\Desktop\delphi_activex\MyActiveX\MyActiveX.ocx

注:这里ocx的路径,请各位根据自己的实际路径修改

这样就完成了ocx的注册。

8.放到html里测试一下:

<OBJECT ID='x' name='x' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<script type='text/javascript'>
var x = document.getElementById("x");
alert(x.Msg);
</script>

关于CLSID在哪里查看,打开:MyActiveX_TLB.pas文件,定位到下面这里:

const
// TypeLibrary Major and minor versions
MyActiveXMajorVersion = 1;
MyActiveXMinorVersion = 0;
LIBID_MyActiveX: TGUID = '{49138437-8265-4B1A-9EAE-D0F615D68464}';
IID_IMyForm: TGUID = '{54A20855-29A3-4C92-85DE-A419DA457C7A}';
DIID_IMyFormEvents: TGUID = '{60BBC967-E1E6-4E98-BAE5-776BFD06E9CC}';
CLASS_MyForm: TGUID = '{52D17094-0687-4A2F-B2DB-30F3189AC659}';


其中 CLASS_MyForm: TGUID对应的就是ClassID

运行后,除了弹出一个空白的警告框,暂时看不到其它:)(可不就是这样么?Msg属性没给任何初始值,当然是空字符串,所以弹出一个空的警告框是正常的)

9.我们再来添加一些控件和方法,以验证刚才设置的属性确实有效

在MyForm上添加一个文件框,一个按钮


按钮的事件如下:

procedure TMyForm.Button1Click(Sender: TObject);
begin
_msg:= self.Edit1.Text;
end;

即把文本框的值赋给属性Msg

再继续定位到Set_Msg,略做修改

procedure TMyForm.Set_Msg(const Value: WideString);
begin
_msg := value;
self.Edit1.Text := _msg;
end;

即设置Msg属性时,同时也把值显示在文本框里,以便等会儿我们好测试在js中给activeX属性赋值的效果

ok了,再来测试一下,编译一下,如果通不过,请先运行

regsvr32 C:\Users\jimmy.yang\Desktop\delphi_activex\MyActiveX\MyActiveX.ocx /u

将刚才注册的ocx反注册,同时关掉浏览器,不然该ocx文件一直被占用,无法更新.

修改一下html的代码:

<OBJECT ID='x' name='x' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<hr />
<input type='button' value='显示Msg属性的值' onclick='ShowMsg()'/>
<input type='button' value='设置Msg属性的值' onclick='SetMsg()'/>
<script type='text/javascript'>
var x = document.getElementById("x");
var ShowMsg = function(){
alert(x.Msg);
}
var SetMsg = function(){
x.Msg = 'js传过来的值';
}
</script>

运行效果:


10.添加Method

我们已经知道了如何给ActiveX添加对外公开的属性,但是光有属性显然不够,我们再添加一个Method,参考第5步中的截图,选择new–>Method,添加

一个方法,命名为ShowMsg,Return参数项用默认值HRESULT,然后Parameters添加一个参数,如下图:


同样不要忘记了点击工具栏中的更新按钮,再打开UMyForm.pas,会发现自动添加了一个过程的定义:

procedure ShowMsg(const p: WideString); safecall;

转到它的实现部分,写几行测试代码:

procedure TMyForm.ShowMsg(const p: WideString);
begin
showmessage('Msg属性的值为:' + _msg + #13 + '传入的参数为:' + p);
end;

再编译,html代码中添加一些代码:

<OBJECT ID='x' name='x' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<hr />
<input type='button' value='显示Msg属性的值' onclick='ShowMsg()'/>
<input type='button' value='设置Msg属性的值' onclick='SetMsg()'/>
<input type='button' value='调用ShowMsg方法' onclick='CallShowMsg()'/>
<script type='text/javascript'>
var x = document.getElementById("x");
var ShowMsg = function(){
alert(x.Msg);
}
var SetMsg = function(){
x.Msg = 'js传过来的值';
}
var CallShowMsg = function(){
x.ShowMsg('这是js传过来的参数');
}
</script>


运行看下:


类似的,我们还可以为ActiveX添加带返回值的function,而非过程procedure,但是比较郁闷的是,我试了半天,delphi中编译正常后,但是在javascript中就是无法取得返回值,估计是delphi的变量类型与javascript的变量类型不匹配引起的,哪位 delphi高人如果知道原因,还请指点一二,在此先谢过.

11.深入看下ActiveX中到底有哪些玩意儿?

既然ActiveX能加载到网页中,肯定也是dom树的一份子了,想知道ActiveX到底提供了哪些其它属性或方法吗?以下的js代码可以测试出来:

<div id="info"></div>
<script type="text/javascript">
var _info="";
for(var p in x){
_info += p + ":" + x[p] + "<br/>";
}
document.getElementById("info").innerHTML = _info;
</script>

当然如果你用IE8的js调试功能,也能看到刚才定义的那些方法和属性:


注意一下这里还有其它很多属性,比如Caption,所以你在js中用alert(x.Caption)也能弹出ActiveForm的标题,这是我们通过IE/JS从外部来看ActiveX的,其实也能换个角度从delphi内部看下activex的结构,com技术号称就是一组通用的接口规范,所以我们在delphi内部确实也能发现不少接口:

MyActiveX.ridl中可以看到

library MyActiveX
{
...
interface IMyForm;
...
...

表明IMyForm就是一个接口,再定位到MyActiveX_TLB.pas可以发现:

type
...
IMyForm = interface;
...
MyForm = IMyForm;
IMyForm = interface(IDispatch)
...

说明MyForm就是从IDispatch继承下来的一个接口

最后再到UMyForm.pas中可以看到

type
TMyForm = class(TActiveForm, IMyForm)
Edit1: TEdit;
...

说明最终的运行窗口,就是继承自TActiveForm并实现了IMyForm的一个类

12.事件支持

打开MyActiveX.ridl,查看IMyFormEvents部分,可以看到delphi生成的ActiveX控件中已经预置了很多事件

dispinterface IMyFormEvents
{
properties:
methods:
[id(0x000000C9)]
void OnActivate(void);
[id(0x000000CA)]
void OnClick(void);
[id(0x000000CB)]
void OnCreate(void);
[id(0x000000CC)]
void OnDblClick(void);
[id(0x000000CD)]
void OnDestroy(void);
[id(0x000000CE)]
void OnDeactivate(void);
[id(0x000000CF)]
void OnKeyPress([in, out] short* Key);
[id(0x000000D0)]
void OnMouseEnter(void);
[id(0x000000D1)]
void OnMouseLeave(void);
[id(0x000000D2)]
void OnPaint(void);
};

我们可以用javascript来响应这些事件,比如就拿我们最熟悉的OnClick事件,js中要这么处理:

<OBJECT ID='x' name='a' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<script type="text/javascript" event="OnClick" for="a">
alert('你点击了ActiveX控件');
</script>

运行后,鼠标在ActiveX的空白处点击,会弹出一个警告框:”你点击了ActiveX控件”

13.其它问题

前面提到了带返回值的function不好弄,其实这个不是什么大问题,完全可以迂回用procedure与属性解决

比如我们可以定义一个带参数的procedure,js调用时传入参数,然后在procedure内部,对参数进行处理后,将其赋值为 ActiveX的任何一个类型匹配的属性,比如前面提到的Caption属性,然后js获取Caption属性,相当于就是ActiveX处理后的返回值了

Posted in DELPHI文档.

Tagged with .


开始整理一些delphi的东西

听说delphi用的人很少了,不过前阵子 要做一个网页启动截屏程序的activex ,找了一些资料,发现用 delphi很容易构建,看了一下,很容易上手,很快就做完了,然后一发不可收拾的用delphi做了几个小玩意,发现delphi开发东西很快,很适合做一些简单桌面需求的快速实现。期间学习了一些文档,在此处整理一下,以备不时之需。

Posted in DELPHI文档.

Tagged with .


最困难的事

有人问古希腊哲学家泰勒斯:“你认为人活在这个世界上,什么事情是最困难的?”泰勒斯回答说:“认识你自己。”

———————-认识自己难,认识自己的不足更难。

Posted in 分享.