adobe air 工程师
The Adobe Integrated Runtime (AIR) platform changes the game for web developers, taking standard web technologies such as HTML, CSS, and JavaScript, and bringing them into a desktop application environment. In this tutorial, I’ll show you how to build a personal notes database with Adobe AIR.
Adobe Integrated Runtime(AIR)平台为Web开发人员改变了游戏规则,采用了HTML,CSS和JavaScript等标准Web技术,并将其引入了桌面应用程序环境。 在本教程中,我将向您展示如何使用Adobe AIR构建个人注释数据库。
In this article, we’re going to explore the client-side capabilities of Adobe AIR by building a simple, local notes database – think of it as your own personal paste bin. We’ll walk through the process of setting up an AIR development workflow, putting together a basic interface, and then enabling it with many of AIR’s front-end and back-end features.
在本文中,我们将通过构建一个简单的本地便笺数据库来探索Adobe AIR的客户端功能-将其视为您自己的个人粘贴容器 。 我们将逐步完成设置AIR开发工作流的过程,将基本界面放在一起,然后使用AIR的许多前端和后端功能启用它。
If you’re new to Adobe AIR, have a read through my previous article, Walk on AIR: Create a To-do List in Five Minutes – it will give you a good head start. For the application we’re about to build, I’ll assume you’ve at least dabbled with the Adobe AIR platform, and you’re comfortable with HTML and object oriented programming in JavaScript too.
如果您是Adobe AIR的新手,请通读我的上一篇文章,“ 在AIR上漫步:在五分钟内创建待办事项列表”,它将为您提供一个良好的起点。 对于我们将要构建的应用程序,我假设您至少已经涉足Adobe AIR平台,并且对HTML和JavaScript中的面向对象编程也感到满意。
Also, if you’re planning on playing along at home, you’ll want to grab the code archive for this article. I’ve made available the skeleton files from which to start, the completed application, and the final packaged AIR app.
另外,如果您打算在家中玩游戏,则需要获取本文的代码档案。 我已经提供了从其开始的框架文件 , 完整的应用程序以及最终打包的AIR应用程序 。
用于构建AIR应用程序的强大工具 (A Powerful Tool for Building AIR Apps)
We’ll use Aptana Studio to build our application – if you haven’t installed this tool yet, download and install Aptana Studio before reading any further.
我们将使用Aptana Studio来构建我们的应用程序-如果尚未安装此工具, 请先下载并安装Aptana Studio,然后再阅读其他内容。
We’ll also install the AIR plugin for Aptana. When you first launch Aptana, you’ll be asked to choose a workspace. Create a new folder to store your AIR projects (it can always be changed later, should you need to). You’ll see the welcome screen when Aptana loads, as displayed below.
我们还将为Aptana安装AIR插件。 首次启动Aptana时,系统会要求您选择一个工作区。 创建一个新文件夹来存储您的AIR项目(以后可以随时更改它,如果需要的话)。 加载Aptana时,您会看到欢迎屏幕,如下所示。
![Figure 1. The download page for the Aptana Studio AIR plugin](https://i-blog.csdnimg.cn/blog_migrate/401644e64d8e5e41faecdc8cff84dd4f.jpeg)
Select Download and install to install the AIR plugin, and select the Adobe AIR Support check box, as I’ve done below.
选择“ 下载并安装”以安装AIR插件,然后选择“ Adobe AIR支持”复选框,如下所示。
![Figure 2. Installing the AIR plugin for Aptana Studio](https://i-blog.csdnimg.cn/blog_migrate/93243a6bb2e5594476c6165cfcc9e90f.jpeg)
You’ll need to restart Aptana for the plugin to take effect.
您需要重新启动Aptana才能使插件生效。
其他工具 (Additional Tools)
In my previous article, I introduced the command line tools that Adobe make available as part of the AIR Software Development Kit (SDK). To refresh your memory, there are two main tools:
在上一篇文章中,我介绍了Adobe作为AIR软件开发工具包(SDK)的一部分提供的命令行工具。 要刷新内存,有两个主要工具:
The AIR Debug Launcher (ADL), which allows us to run AIR applications on-the-fly, and monitor debug output.
AIR Debug Launcher(ADL) ,它使我们能够即时运行AIR应用程序,并监视调试输出。
The AIR Developer Tool (ADT), which provides a set of tools to package applications for distribution.
AIR开发人员工具(ADT ),它提供了一组工具来打包应用程序以进行分发。
If you’re not sold on using Aptana, feel free to explore these alternatives. The official Adobe AIR documentation contains more details.
如果您不喜欢使用Aptana,请随时探索这些替代方案。 官方Adobe AIR文档包含更多详细信息 。
Aptana conveniently abstracts the ADL and ADT tools for us. There are some additional utilities in the SDK that we’ll also take advantage of – the AIR Introspector and the AIR Source Viewer. When we start a new AIR project, Aptana includes the JavaScript references for these tools in our <head>
section of the HTML:
Aptana为我们方便地抽象了ADL和ADT工具。 SDK中还有一些其他实用程序,我们还将利用AIR Introspector和AIR Source Viewer。 当我们开始一个新的AIR项目时,Aptana在HTML的<head>
部分中包含了这些工具JavaScript引用:
<!-- Uncomment the following line to add introspection. When running the application hit F12 to bring up the introspector -->
<script type="text/javascript" src="AIRIntrospector.js"></script>
<!-- Uncomment the following line to use the AIR source viewer -->
<script type="text/javascript" src="AIRSourceViewer.js"></script>
With the AIRIntrospector.js
reference in place, you can display the Adobe AIR HTML/JS Application Introspector by pressing F12 while running an AIR application, shown below:
有了AIRIntrospector.js
参考,您可以在运行AIR应用程序时按F12来显示Adobe AIR HTML / JS Application Introspector,如下所示:
![Figure 3. The HTML view of the Adobe AIR HTML/JavaScript Introspector](https://i-blog.csdnimg.cn/blog_migrate/5de2a333a96ea6fc3080f7a6843e14ed.jpeg)
Look familiar? Think of it as Firebug for Adobe AIR – it has a JavaScript console, a page inspector with point-and-click element selection, a DOM Inspector, and all the usual tools you’d expect. If you’ve used Firebug, you’ll pick up this tool up in no time; if not, you might want to check out the Introspector documentation.
看起来熟悉? 可以将其视为Adobe AIR的Firebug –它具有JavaScript控制台,具有点击元素选择功能的页面检查器,DOM检查器以及所有您期望的常用工具。 如果您使用过Firebug,则可以立即使用该工具。 如果不是,则可能要查看Introspector文档 。
Here’s a demonstration of the tool in action – check out the source viewer by using the JS Console in the Introspector – just call air.SourceViewer.getDefault().viewSource():
这是使用该工具的演示–使用Introspector中的JS控制台检出源代码查看器–只需调用air.SourceViewer.getDefault().viewSource():
![Figure 4. The Adobe AIR Introspector in action](https://i-blog.csdnimg.cn/blog_migrate/52a8528459f0a94a5c7b99864b90f5b8.jpeg)
This tool is highly configurable using JavaScript – check out the official documentation page for more details.
该工具可使用JavaScript进行高度配置-请查看官方文档页面以获取更多详细信息。
使用数据库 (Working with a Database)
We’ll use an SQLite database in our sample application, and fortunately AIR comes with a built-in SQLite driver. While we can construct our database on-the-fly, it’s more practical (and more efficient) to distribute a pre-populated database. I recommend using the open source SQLite Database Browser to get up and running quickly (also available as a Firefox extension). It runs on Windows, OS X, and GNU/Linux, and the binary packages work straight out of the box. Grab a copy from the SourceForge download page.
我们将在示例应用程序中使用SQLite数据库,幸运的是AIR带有内置SQLite驱动程序。 尽管我们可以即时构建数据库,但是分发预先填充的数据库更为实用(且效率更高)。 我建议使用开源SQLite数据库浏览器来快速启动和运行(也可以作为Firefox扩展 )。 它可以在Windows,OS X和GNU / Linux上运行,二进制程序包可以直接使用。 从SourceForge下载页面获取副本。
If you haven’t used SQLite before, it functions similarly to most relational databases – with a few exceptions; in particular, it applies data types to values (cells), rather than containers (columns) – read more about SQLite and data types on the SQLite web site.
如果您以前从未使用过SQLite,则它的功能与大多数关系数据库类似-例外。 特别是,它将数据类型应用于值(单元格),而不是容器(列)– 在SQLite网站上详细了解SQLite和数据类型。
构建个人注释数据库应用程序 (Building a Personal Notes Database Application)
OK, let’s begin! For a personal notes database, we need to be able to view our notes, create new ones, and delete existing ones. While we build this application, we’ll make use of the many client-side features for powerful UI functionality in AIR. We’ll use the jQuery library for some basic interface work, but we could just as well have used Prototype, MooTools, or even Adobe Spry. Most JavaScript frameworks can be used reliably inside AIR.
好的,让我们开始吧! 对于个人笔记数据库,我们需要能够查看笔记,创建新笔记和删除现有笔记。 在构建此应用程序时,我们将利用许多客户端功能来实现AIR中强大的UI功能。 我们将使用jQuery库进行一些基本的界面工作,但是我们也可以使用Prototype,MooTools甚至Adobe Spry 。 大多数JavaScript框架都可以在AIR中可靠地使用 。
In terms of our app’s functionality, we’ll be touching on each of the following areas:
在我们应用程序的功能方面,我们将涉及以下各个方面:
- native menus 本机菜单
- file system management 文件系统管理
- local SQLite databases 本地SQLite数据库
- clipboard operations, native copy-and-paste 剪贴板操作,本机复制和粘贴
- user interface niceties 用户界面细节
We’ll start by creating a template for our user interface, and then we’ll add each of the above features progressively.
我们将从为用户界面创建模板开始,然后逐步添加上述每个功能。
定义用户界面 (Defining the User Interface)
AIR’s built-in browser uses the WebKit rendering engine, which does a fantastic job of adhering to web standards. I find it practical to build the prototype of my interface in HTML, then test it in Firefox. Doing so means I can rely on the eternally useful Firebug tool to iron out any kinks. I’ve mocked up a basic interface for our Notes application in HTML, which is shown below. It includes a New note form, which we’ll hide when it’s not needed.
AIR的内置浏览器使用WebKit渲染引擎,该引擎在遵守Web标准方面做得非常好。 我发现用HTML构建我的界面原型,然后在Firefox中测试它是可行的。 这样做意味着我可以依靠永恒有用的Firebug工具来消除任何问题。 我为HTML中的Notes应用程序模拟了一个基本界面,如下所示。 它包括一个新便笺形式,我们将在不需要它时将其隐藏。
![Figure 5. A prototype of our Notes application, built in HTML](https://i-blog.csdnimg.cn/blog_migrate/c9bd2129ebd6eb7f97ab0e2000d4eecc.jpeg)
As you can see, it’s a fairly simple layout; each note contains:
如您所见,这是一个相当简单的布局。 每个注释包含:
- a title 标题
- a listing in a box 盒子里的清单
- a timestamp of when it was created 创建时间的时间戳
a red Delete button showing a minus sign (courtesy of the Silk icon set)
红色的“ 删除”按钮显示减号(由“ 丝绸”图标集提供 )
For us developers who write lots of code, the ability to store monospaced text notes would be really handy, so we’ll surround our actual note contents with <pre>
tags.
对于编写大量代码的开发人员而言,存储等宽文本注释的功能非常方便,因此我们将使用<pre>
标签将实际注释内容包围起来。
I’ve prototyped this in Firefox, but I’ve taken the actual screenshot in an AIR window itself. Notice how AIR adds some default chrome to some of the elements (that grey area around the edge) This is optional (see the AIR documentation for more details). We’re also displaying containers with rounded corners in our app; since we know that our app will always run within an AIR window, we don’t have the same cross-browser compatibility woes that we experience on the Web. We can therefore make use of WebKit’s many special CSS properties – in this case, the –webkit-border-radius
property.
我已经在Firefox中为其制作了原型,但是我已经在AIR窗口中获取了实际的屏幕截图。 请注意,AIR是如何向某些元素(边缘周围的灰色区域)添加一些默认镶边的。这是可选的(有关详细信息,请参阅AIR文档 )。 我们还在应用程序中显示带有圆角的容器; 因为我们知道我们的应用程序将始终在AIR窗口中运行,所以我们没有在Web上遇到的跨浏览器兼容性问题。 因此,我们可以利用WebKit的许多特殊CSS属性–在这种情况下,就是–webkit-border-radius
属性。
创建数据库 (Creating the Database)
We’ll use a simple, single-table SQLite database to store our notes. We need four fields in our table:
我们将使用一个简单的单表SQLite数据库来存储我们的注释。 我们的表中需要四个字段:
id
id
title
title
created
created
data
data
The created
field refers to when the note was created, and is stored in seconds (in UNIX time, which is the number of seconds that have elapsed since Jan 1, 1970). The data
field will be a BLOB (Binary Large Object), so that we can fit in just about anything. We’ll make our id
field an INTEGER PRIMARY KEY, our title
will be a TEXT, and the created
field will be an INTEGER (“NUMERIC” in SQLite Database Browser).
created
字段是指注释的创建时间 ,以秒为单位存储(在UNIX time中 ,这是自1970年1月1日以来经过的秒数)。 data
字段将是BLOB(二进制大对象) ,因此我们几乎可以容纳任何东西。 我们将id
字段设置为INTEGER PRIMARY KEY, title
将是TEXT, created
字段将是INTEGER(在SQLite数据库浏览器中为“ NUMERIC”)。
The theory behind using SQL databases in AIR applications is beyond the scope of this article, but Adobe provides some good documentation on strategies for working with SQL databases, which is definitely worth a read.
在AIR应用程序中使用SQL数据库的理论基础超出了本文的范围,但是Adobe提供了一些有关使用SQL数据库的策略的良好文档,这绝对值得一读。
在AIR上运行 (Running on AIR)
Once we’ve got a base interface and a database, we’re ready to start adding actual functionality to our application.
一旦有了基本接口和数据库,就可以开始向应用程序中添加实际功能了。
If you haven’t done so yet, download, and unzip the code archive containing the skeleton files for this article (air1-notesdb-base.zip).
如果尚未执行此操作,请下载并解压缩包含本文的框架文件的代码存档( air1-notesdb-base.zip )。
In the .zip file you’ll see the following files:
在.zip文件中,您将看到以下文件:
notes.html
notes.html
notes_base.db
notes_base.db
styles.css
styles.css
icons/delete.png
icons / delete.png
lib/notes.js
lib / notes.js
Next, create a new AIR project in Aptana, and name it NotesTest. Specify the folder to which you extracted the files from the code archive as a Location. When you click Next, you’ll be presented with a dialog to enter the Application Descriptor properties. Choose an appropriate ID (I’ve used com.sitepoint.example.NotesTest), click Next again, then set your default window size to 800 x 600 pixels. Click Next again, and from the Import JavaScript Library dialog, select jQuery, and finally click Finish.
接下来,在Aptana中创建一个新的AIR项目,并将其命名为NotesTest 。 将您从代码档案库中提取文件的文件夹指定为Location 。 当您单击Next时 ,将显示一个对话框,以输入Application Descriptor属性。 选择一个适当的ID(我使用了com.sitepoint.example.NotesTest),再次单击“ 下一步” ,然后将默认窗口大小设置为800 x 600像素。 再次单击Next ,然后从Import JavaScript Library对话框中,选择jQuery,最后单击Finish 。
Aptana will create a few sample files for you to try out your environment; you can safely delete some of them though, including NotesTest.html, sample.css, LocalFile.txt, jquery_sample.html, and jquery_sample.js. We do need to tell Aptana that the root of our AIR application should be our new notes.html file. Open up the application.xml file and locate the following (it should be on or around line 36):
Aptana将创建一些示例文件供您尝试环境。 您可以安全地删除其中的一些,包括NotesTest.html , sample.css , LocalFile.txt , jquery_sample.html和jquery_sample.js 。 我们确实需要告诉Aptana,AIR应用程序的根应该是我们的新notes.html文件。 打开application.xml文件并找到以下文件(该文件应位于第36行或附近):
<!-- The main HTML file of the application. Required. -->
<content>NotesTest.html</content>
Change NotesTest.html to notes.html and save the file. From the Run menu, select Run…. Select your NotesTest project in the left pane, and hit the Run button:
更改NotesTest.html到notes.html并保存文件。 从运行菜单中,选择运行… 。 在左窗格中选择您的NotesTest项目,然后单击“ 运行”按钮:
![Figure 6. Running our Note Storage project for the first time](https://i-blog.csdnimg.cn/blog_migrate/eaf50a9ead99daed80915b9209d080ac.jpeg)
Your AIR application will display in its own window, complete with the prototype HTML that we created earlier. It should look something like this:
您的AIR应用程序将显示在其自己的窗口中,并带有我们之前创建HTML原型。 它看起来应该像这样:
![Figure 7. The first iteration of our Note Storage application](https://i-blog.csdnimg.cn/blog_migrate/4c7dd2524259695abea416c5ffb98082.jpeg)
It’s a good start! Let’s make this application a bit more useful.
这是一个好的开始! 让我们使该应用程序更有用。
选单 (Menus)
We’ll first put the interface in place. We’ll store our JavaScript code in lib/notes.js. Here’s what our template looks like at the moment:
我们首先将接口放置到位。 我们将JavaScript代码存储在lib / notes.js中 。 这是我们当前模板的样子:
// Bootstrap
$(document).ready(function(){
BindEvents();
});
function BindEvents() {
$("#new_note_form").hide();
$("a.notes_list").click(HideNewNote);
}
function HideNewNote() {
$("#new_note_form").hide();
}
function ShowNewNote() {
$("#new_note_form").show();
}
This jQuery snippet waits until the DOM is ready to be manipulated, then hides the note creation form, and binds to the click event of the Cancel link inside that same form. If you need a primer on jQuery, check out the “jQuery 101” section of this article.
这个jQuery代码段等待直到DOM准备就绪,然后隐藏注释创建表单,并绑定到该表单内部的Cancel链接的click事件。 如果您需要在jQuery的底漆,检查出的“jQuery的101”部分这篇文章 。
AIR provides an extensive API for generating menus from intricate data structures. All we really want, however, is a basic menu that fires JavaScript events when certain menu items are selected. With AIR 1.1, we can make use of the AIR Menu Builder framework, which allows us to define menus in XML and just load them into the menu builder for them to be magically generated. Create a new file called notes_menus.xml inside your NotesTest project that looks like this:
AIR提供了广泛的API,可用于从复杂的数据结构中生成菜单。 但是,我们真正想要的是一个基本菜单,当选择某些菜单项时会触发JavaScript事件。 使用AIR 1.1,我们可以利用AIR菜单构建器框架,该框架允许我们以XML定义菜单并将其仅加载到菜单构建器中以神奇地生成它们。 在NotesTest项目中创建一个名为notes_menus.xml的新文件,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<root>
<menuitem label="File">
<menuitem label="_New Note" onSelect="ShowNewNote" />
</menuitem>
</root>
Using XML, we can define each menu item as a menuitem
node. If a node contains children (additional menuitems
), then the parent node becomes a submenu.
使用XML,我们可以将每个菜单项定义为一个menuitem
节点。 如果节点包含子节点(其他menuitems
),那么父节点将成为子菜单。
Save notes_menus.xml and open up the file lib/notes.js. Let’s create a new function, CreateMenus
, that contains the following code:
保存notes_menus.xml并打开文件lib / notes.js 。 让我们创建一个新函数CreateMenus
,其中包含以下代码:
// UI
function CreateMenus() {
var menu = air.ui.Menu.createFromXML("notes_menus.xml");
air.ui.Menu.setAsMenu(menu);
}
Place this function right after our $(document)
.ready function. We’ll then make a call to it at the end of that function, as I’ve done here:
将此函数放在$(document)
.ready函数之后。 然后,我们将在该函数的末尾对其进行调用,就像我在这里所做的那样:
// Bootstrap
$(document).ready(function(){
BindEvents();
CreateMenus();
});
Now when we run our AIR application again, our menus appear in the application’s window (or in the OS X menu bar on a Mac).
现在,当我们再次运行AIR应用程序时,菜单将显示在应用程序的窗口中(或在Mac上的OS X菜单栏中)。
Note: Aptana’s Time-saving Keyboard Shortcuts
注意:Aptana的省时键盘快捷键
Press Ctrl+F11 (Cmd-Shift-F11 on the Mac) to run your AIR application using the same configuration as the last time it ran.
按Ctrl + F11(在Mac上为Cmd-Shift-F11)以与上次运行相同的配置运行AIR应用程序。
![Figure 8. An example menu item created by the AIR Menu Builder](https://i-blog.csdnimg.cn/blog_migrate/41dca232abcd5e344ba67aba3936b50a.jpeg)
There are a number of possible attributes that each of our menu nodes can take, but the only one we’re concerned with is onSelect
. When a menu item is selected, this property defines which JavaScript function should be fired:
每个菜单节点都可以采用许多可能的属性,但我们关心的唯一属性是onSelect
。 选择菜单项时,此属性定义应触发JavaScript函数:
<menuitem label="_New Note" onSelect="ShowNewNote" />
function ShowNewNote() { ...
The XML snippet above defines that, when New Note is selected (either from a mouse click or via keyboard input), the ShowNewNote
JavaScript function should be invoked.
上面的XML代码段定义,当选择“ 新建注释” (通过单击鼠标或通过键盘输入)时,应调用ShowNewNote
JavaScript函数。
We can also add accessibility features to our menus – for example, we can add keyboard shortcuts, Keyboard shortcuts are specified using the underscore character, as I’ve done in the label property:
我们还可以在菜单中添加可访问性功能-例如,我们可以添加键盘快捷键,使用下划线字符指定键盘快捷键,就像我在label属性中所做的那样:
<menuitem label="_New Note" onSelect="ShowNewNote" />
探索文件系统 (Exploring the File System)
Now let’s look at storing and manipulating our data. We’re going to look at databases and file system APIs together, as AIR’s implementation of local SQL databases relies heavily on both. SQLite databases are independent files, and instead of being accessed through a database server, they are manipulated directly by the application. In this case, AIR plays the role of database server for us. However, to get started, we first need to tell AIR where to find the database file by specifying a .db file.
现在,让我们来看一下存储和操作数据。 我们将一起查看数据库和文件系统API,因为AIR的本地SQL数据库实现很大程度上依赖于两者。 SQLite数据库是独立的文件,而不是通过数据库服务器访问,而由应用程序直接操作。 在这种情况下,AIR为我们扮演了数据库服务器的角色。 但是,首先,我们首先需要通过指定.db文件来告诉AIR在哪里找到数据库文件。
All of the file system APIs live under the air.File
namespace. There are two important predefined paths for our AIR application: the application directory and application storage directory.
所有文件系统API都位于air.File
命名空间下。 AIR应用程序有两个重要的预定义路径:应用程序目录和应用程序存储目录。
- The application directory is the folder in which the application itself is stored. 应用程序目录是存储应用程序本身的文件夹。
- The application storage directory is a folder created by AIR for this particular application (and this application only) to store data. 应用程序存储目录是AIR为该特定应用程序(仅此应用程序)创建的文件夹,用于存储数据。
The application directory is actually read-only, so if we want to edit our database, we’ll need to place the database file in the storage directory. As we’re distributing our skeleton database as part of the application, we’ll need to copy our database template (notes_base.db) to the storage directory on-the-fly.
应用程序目录实际上是只读的,因此,如果要编辑数据库,则需要将数据库文件放置在存储目录中。 在将骨架数据库作为应用程序的一部分进行分发时,我们需要将数据库模板( notes_base.db )动态复制到存储目录中。
连接到数据库 (Connecting to the Database)
To open a connection to the database, we use the following code:
要打开与数据库的连接,我们使用以下代码:
var db = new air.SQLConnection();
try
{
db.open(air.File.applicationStorageDirectory.resolvePath("notes.db"));
}
catch (error)
{
air.trace("DB error:", error.message);
air.trace("Details:", error.details);
}
Note: Printing Trace Statements in AIR
注意:在AIR中打印跟踪语句
To print to the AIR debug console, or to the console view in Aptana, use the function air.trace().
若要打印到AIR调试控制台或Aptana中的控制台视图,请使用函数air.trace()。
In the code above, we use the resolvePath
function to open a file called notes.db in the application storage directory. However, before we can access this file, we first need to make a copy of our template SQLite database, contained in the notes_base.db file in our application directory. The following code achieves this:
在上面的代码中,我们使用resolvePath
函数在应用程序存储目录中打开一个名为notes.db的文件。 但是,在访问此文件之前,我们首先需要复制模板SQLite数据库,该副本包含在应用程序目录中的notes_base.db文件中。 以下代码实现了这一点:
var dbFile = air.File.applicationStorageDirectory.resolvePath("notes.db");
//In production, uncomment the if block to maintain the database.
//if (!dbFile.exists) {
var dbTemplate =
air.File.applicationDirectory.resolvePath("notes_base.db");
dbTemplate.copyTo(dbFile, true);
//}
When using resolvePath
to resolve a path on the file system, it’s not necessary to first check whether the file exists – the exists
property will indicate whether or not the file can be found. As you can see above, we check this property in the production-ready version of our app. It’s useful in testing mode to revert to our database template each time the application is launched – but we certainly wouldn’t want to replace the database with a blank template when dealing with real data!
使用resolvePath
解析文件系统上的路径时,无需首先检查文件是否存在exists
属性将指示是否可以找到该文件。 如您在上方所见,我们在应用的正式生产版本中检查了此属性。 每次启动应用程序时,在测试模式下恢复到我们的数据库模板都是有用的-但我们当然不希望在处理真实数据时用空白模板替换数据库!
Let’s pull all of these pieces together into a single function called SetupDB
, which looks like this:
让我们将所有这些片段放到一个名为SetupDB
函数中,该函数如下所示:
var db = new air.SQLConnection();
function SetupDB() {
var dbFile = air.File.applicationStorageDirectory.resolvePath("notes.db");
//In production, uncomment the if block to maintain the database.
//if (!dbFile.exists) {
var dbTemplate = air.File.applicationDirectory.resolvePath("notes_base.db");
dbTemplate.copyTo(dbFile, true);
//}
try
{
db.open(dbFile);
}
catch (error)
{
air.trace("DB error:", error.message);
air.trace("Details:", error.details);
}
}
Place this function at the end of your notes.js file, and while you’re there, add a call to this new method from within our $(document).ready()
function (which lives at the top of the file).
将此函数放在notes.js文件的末尾,然后在其中,从我们的$(document).ready()
函数(位于文件顶部$(document).ready()
添加对该新方法的调用。
使用数据库 (Working with Databases)
Now that we’ve set up a database, we’re ready to start pulling existing notes from the database.
既然我们已经建立了数据库,我们就可以开始从数据库中提取现有的注释了。
Just as an SQLConnection
object maintains a connection to a database, an SQLStatement
maintains a particular query to the database. These SQLStatement
instances are linked to a particular connection through their SQLConnection
property. SQLStatement
objects support prepared statements, and a few different methods for retrieving the result of each query; they can also be reused. Check out the reference page for SQLStatement for further details.
就像SQLConnection
对象维护与数据库的连接一样, SQLStatement
维护对数据库的特定查询。 这些SQLStatement
实例通过其SQLConnection
属性链接到特定连接。 SQLStatement
对象支持准备好的语句,以及几种不同的方法来检索每个查询的结果。 它们也可以重复使用。 请查看SQLStatement的参考页面以获取更多详细信息。
Let’s create a GetNotes
function to fetch our notes. Here’s the code, which should be added to the end of your notes.js file.
让我们创建一个GetNotes
函数来获取我们的笔记。 这是代码,应将其添加到notes.js文件的末尾。
function GetNotes() {
dbQuery = new air.SQLStatement();
dbQuery.sqlConnection = db;
dbQuery.text = "SELECT id,title,created,data FROM notes";
try {
dbQuery.execute();
} catch (error) {
air.trace("Error retrieving notes from DB:", error);
air.trace(error.message);
return;
}
return dbQuery.getResult();
}
This code is reasonably straightforward; we first create a new SQL statement and assign its SQLConnection
property to our existing database connection. We then set the actual query text and run the query, catching any potential errors along the way. Finally, we return the result as a SQLResult object.
该代码相当简单。 我们首先创建一个新SQL语句,并将其SQLConnection
属性分配给我们现有的数据库连接。 然后,我们设置实际的查询文本并运行查询,并在此过程中捕获任何潜在的错误。 最后,我们将结果作为SQLResult对象返回。
Let’s use the Introspector to examine the data type that this function returns. Run your AIR application (Run > Run…), then hit F12 to launch the Introspector, and execute “GetNotes()” from the JavaScript console. Here’s the output:
让我们使用Introspector来检查此函数返回的数据类型。 运行AIR应用程序(运行>运行…),然后按F12键启动Introspector,然后从JavaScript控制台执行“ GetNotes()”。 这是输出:
![Figure 9. Running the GetNotes function in the Introspector console](https://i-blog.csdnimg.cn/blog_migrate/37e683ba6e4fabd40dd13ec177158944.jpeg)
The number that’s important to us here is the value “0” that I’ve highlighted in the figure above – it represents the first item in our database table. The data
property, in fact, contains all of the rows returned by a database query, beginning at index number 0. Each query also provides us with a length
property, which tells us how many rows were returned. Knowing this information, we can now construct a simple routine to retrieve each note from the database, and print it to the page:
对我们来说重要的数字是我在上图中突出显示的值“ 0”,它代表数据库表中的第一项。 实际上, data
属性包含数据库查询返回的所有行,从索引号0开始。每个查询还为我们提供了length
属性,该属性告诉我们返回了多少行。 知道了这些信息,我们现在可以构造一个简单的例程,以从数据库中检索每个注释,并将其打印到页面上:
var notes = GetNotes();
$("#notes").empty();
var numRecords = notes.data.length;
for (i=0;i<numRecords;i++) {
dateObj = new Date(notes.data[i].created);
time = dateObj.getFullYear()+"-"+
String("0"+dateObj.getMonth()).slice(-2)+"-"+
String("0"+dateObj.getDate()).slice(-2)+" "+
String("0"+dateObj.getHours()).slice(-2)+":"+
String("0"+dateObj.getMinutes()).slice(-2);
$("<li/>").append('<span class="note_time">'+time+
'<a href="#del/'+notes.data[i].id+'">'+
'<img src="icons/delete.png"/></a></span>')
.append('<span class="note_title">'+notes.data[i].title)
.append('<pre>'+notes.data[i].data.'</pre>')
.appendTo("#notes");
}
This routine inspects each record, checking when the note was created and performing some basic formatting in preparation for displaying the note. We create a new list item for each record, and place each note at the end of the list. We’re achieving all this by relying fairly heavily on jQuery here, but this could well have been achieved using standard DOM calls.
此例程检查每条记录,检查创建注释的时间,并执行一些基本格式以准备显示注释。 我们为每个记录创建一个新的列表项,并将每个注释放在列表的末尾。 我们通过在这里相当依赖jQuery来实现所有这一切,但是使用标准DOM调用很可能已经实现了。
删除笔记 (Deleting Notes)
OK, so we can display our notes, but we’re still missing some functionality – namely, adding and deleting notes. Let’s enable that pretty, red Delete button!
好的,因此我们可以显示便笺,但仍然缺少一些功能-即添加和删除便笺。 让我们启用那个漂亮的红色“ 删除”按钮!
We need to bind a new function to each of the Delete buttons. Note that the actual Delete images will be surrounded by links, each of which has its own unique identifier. We can leverage this fact to determine which note we want to delete. Once we’ve written the code to do this, the code is almost identical to our GetNotes
Function.
我们需要将新功能绑定到每个“ 删除”按钮。 请注意,实际的删除图像将被链接包围,每个链接都有其自己的唯一标识符。 我们可以利用这一事实来确定我们要删除的笔记。 一旦编写了执行此操作的代码,该代码几乎与我们的GetNotes
函数相同。
It’s time to add a new method, ListNotes
, to the bottom of your notes.js file:
现在是时候将新方法ListNotes
添加到notes.js文件的底部:
function ListNotes() {
var notes = GetNotes();
$("#notes").empty();
var numRecords = notes.data.length;
for (i=0;i<numRecords;i++) {
dateObj = new Date(notes.data[i].created);
time = dateObj.getFullYear()+"-"+
String("0"+dateObj.getMonth()).slice(-2)+"-"+
String("0"+dateObj.getDate()).slice(-2)+" "+
String("0"+dateObj.getHours()).slice(-2)+":"+
String("0"+dateObj.getMinutes()).slice(-2);
$("<li/>").append('<span class="note_time">'+time+
'<a href="#del/'+notes.data[i].id+'">'+
'<img src="icons/delete.png"/></a></span>')
.append('<span class="note_title">'+unescape(notes.data[i].title))
.append('<pre>'+unescape(notes.data[i].data)+'</pre>')
.appendTo("#notes");
}
$(".note_time a").click(function(){
var currHash = $(this).attr("href").split('/');
var id = currHash[1];
var dbQuery = new air.SQLStatement();
dbQuery.sqlConnection = db;
dbQuery.text = "DELETE FROM notes WHERE id=" + id;
try {
dbQuery.execute();
} catch (error) {
air.trace("Error deleting note from DB:", error);
air.trace(error.message);
return;
}
ListNotes();
});
}
We also need to call ListNotes
from our $(document).ready
method at the start of our notes.js file.
我们还需要调用ListNotes
从我们$(document).ready
我们notes.js文件的启动方法。
添加新笔记 (Adding New Notes)
We have just one more database operation to flesh out: allowing our users to add new notes. This functionality is quite similar to both of the previous database operations, with two exceptions:
我们还有一个数据库操作可以充实:允许我们的用户添加新注释。 此功能与之前的两个数据库操作都非常相似,但有两个例外:
We need to fetch the values from the New Note form (and work out the current time in UNIX time), and
我们需要从New Note表单中获取值(并计算出UNIX时间中的当前时间),并且
- We need to regenerate the list of notes, once we’re done. 完成后,我们需要重新生成笔记列表。
Here’s the code, ready to copy into the end of our notes.js file:
这是代码,准备复制到我们的notes.js文件的末尾:
function AddNote() {
var title = escape($("#title").val());
var now = new Date();
var created = Date.parse(now.toString());
var data = escape($("#data").val());
dbQuery = new air.SQLStatement();
dbQuery.sqlConnection = db;
dbQuery.text = "INSERT INTO notes (title,created,data)";
dbQuery.text += "VALUES ('"+title+"',"+created+",'"+data+"')";
try {
dbQuery.execute();
} catch (error) {
air.trace("Error inserting new record into database:", error);
air.trace(error.message);
}
HideNewNote();
ListNotes();
}
The first few lines of this code fetch the values from each field. Date.parse
(a static date function) will convert a date string into a UNIX time value. When we construct our database query, we add the user data from these form fields. There’s just one minor limitation – we need to escape our string. Failing to do so could potentially result in a malformed query string, hence the escape
calls that you see there.
该代码的前几行从每个字段中获取值。 Date.parse
(静态日期函数)会将日期字符串转换为UNIX时间值。 在构造数据库查询时,我们从这些表单字段中添加用户数据。 只有一个小限制–我们需要转义字符串。 否则,可能会导致查询字符串格式错误,因此您在此处看到的escape
调用。
We also need to bind this new function to the Create Note button. This is very easy using jQuery – just add the following line, shown in bold, to your BindEvents
function:
我们还需要将此新功能绑定到“ 创建注释”按钮。 使用jQuery,这非常容易–只需将以下以粗体显示的行添加到BindEvents
函数中即可:
function BindEvents() {
$("#new_note_form").hide();
$("a.notes_list").click(HideNewNote); $("#new_note_btn").click(AddNote);
}
使用剪贴板 (Working with the Clipboard)
When creating notes, a user may have content stored in their operating system’s clipboard that they want to insert into our application as a note. AIR provides access to the clipboard quite easily, so let’s check it when we display the New Note form. Replace your ShowNewNote
function with the following lines:
创建便笺时,用户可能将要存储的内容作为便笺存储在其操作系统的剪贴板中。 AIR可以很容易地访问剪贴板,因此在显示“ 新笔记”表单时请对其进行检查。 用以下行替换ShowNewNote
函数:
function ShowNewNote() {
if (air.Clipboard.generalClipboard.hasFormat(
air.ClipboardFormats.TEXT_FORMAT)){
$("#data").val(air.Clipboard.generalClipboard.getData(
air.ClipboardFormats.TEXT_FORMAT));
}
$("#new_note_form").show();
}
In the above code snippet, lines 2–4, check whether there is any plaintext data on the clipboard. If there is, we copy that data into the main content area of our New Note form. It would be possible to extend this functionality to include other data formats as well, including rich text and HTML – check out the clipboard data formats in the AIR documentation if you’d like to experiment some more.
在上面的代码段的第2至4行中,检查剪贴板上是否有任何明文数据。 如果有的话,我们将该数据复制到“ 新注释”表单的主要内容区域。 可以扩展此功能以包括其他数据格式,包括RTF和HTML –如果您想尝试更多内容,请查阅AIR文档中的剪贴板数据格式 。
If we wanted to take this application even further, we could offer a simple “copy” function for each individual note. This functionality is already supported by most major browsers, but AIR goes one step further by allowing us to directly manipulate the contents of the general clipboard. If you’re interested in exploring this functionality, the official AIR documentation does a good job of explaining how to read from and write to the system clipboard, and includes some great code examples.
如果我们想进一步推广该应用程序,可以为每个单独的音符提供一个简单的“复制”功能。 大多数主要的浏览器都已支持此功能,但是AIR通过允许我们直接操纵常规剪贴板的内容而迈了一大步。 如果您有兴趣探索此功能,则AIR官方文档会很好地解释如何读写系统剪贴板 ,并提供了一些出色的代码示例。
关闭申请 (Closing an Application )
Chances are we’ll want to let our user close our note storage application easily. Let’s create a File > Exit menu item, to give our application a touch of desktop familiarity. First, open up notes_menus.xml and add the line in bold below:
我们可能希望让我们的用户轻松关闭便笺存储应用程序。 让我们创建一个File> Exit菜单项,使我们的应用程序对桌面有所了解。 首先,打开notes_menus.xml并在下面加粗的行:
<?xml version="1.0" encoding="utf-8"?>
<root>
<menuitem label="File">
<menuitem label="_New Note" onSelect="ShowNewNote" /> <menuitem label="E_xit" onSelect="QuitNotes" />
</menuitem>
</root>
We’ve set the mnemonic on the x of “Exit” – common practice in Windows desktop apps.
我们将助记符设置为“ Exit”(x)-Windows桌面应用程序中的常见做法。
We can close the application by calling the method air.NativeApplication.nativeApplication.exit
. However, AIR provides a sophisticated event system designed to deal with more complex operations that applications may need to perform. One of these operations is to prevent default actions. Given that we may want to temporarily disable the capacity of our user to exit the application – for example, during an asynchronous delete-all-notes database operation – we’ll use this approach instead.
我们可以通过调用方法air.NativeApplication.nativeApplication.exit
关闭应用程序。 但是,AIR提供了复杂的事件系统,旨在处理应用程序可能需要执行的更复杂的操作。 这些操作之一是防止发生默认操作。 鉴于我们可能要暂时禁用用户退出应用程序的能力(例如,在异步删除所有注释数据库操作期间),我们将改用这种方法。
There’s a preventDefault
method in air.Event
that will, not surprisingly, prevent AIR from executing an event’s default action. In our case, this event is called air.Event.EXITING
, and the routines throughout our application should all take this approach. We can check if the default exit action is being prevented by another area of the application using a simple procedure:
air.Event
, air.Event
中有一个preventDefault
方法,它将阻止AIR执行事件的默认操作。 在我们的例子中,此事件称为air.Event.EXITING
,整个应用程序中的例程都应采用这种方法。 我们可以使用一个简单的过程来检查默认退出动作是否被应用程序的另一个区域阻止:
function QuitNotes() {
var event = new air.Event(air.Event.EXITING, false, true);
air.NativeApplication.nativeApplication.dispatchEvent(event);
if (!event.isDefaultPrevented()) {
air.NativeApplication.nativeApplication.exit();
}
}
Place this function at the end of your notes.js file, and your user will no longer be able to terminate the application when it’s in the middle of something important. The AIR docs provide more information about handling application termination.
将此功能放在notes.js文件的末尾, 当用户将应用程序置于重要位置时,它将不再能够终止该应用程序。 AIR文档提供了有关处理应用程序终止的更多信息 。
整理起来 (Finishing up)
That’s it for our note storage application! If you hit any hurdles along the way, you can download the final project files to compare with your own. To use these files, simply import them into a new AIR project in Aptana (select File > Import > Archive File). Aptana also allows you to easily package the application as an AIR file for deployment. Click the air button on your Aptana toolbar. In the Adobe AIR Package Exporter dialog that appears, just confirm that the right project is selected, and that the application descriptor is called application.xml. To minimize file size, feel free to remove the AIR localizer and the excess jQuery files, then click Finish and an AIR package will be created for you. Here’s what your completed package should look like.
这就是我们的便笺存储应用程序! 如果您在此过程中遇到任何障碍,则可以下载最终项目文件以与自己的文件进行比较。 要使用这些文件,只需将它们导入Aptana中的新AIR项目中(选择File> Import> Archive File )。 Aptana还使您可以轻松地将应用程序打包为AIR文件进行部署。 单击Aptana工具栏上的空气按钮。 在出现的“ Adobe AIR包导出器”对话框中,只需确认选择了正确的项目,并且应用程序描述符称为application.xml 。 为了最大程度地减小文件大小,请随时删除AIR本地化程序和多余的jQuery文件,然后单击“ 完成” ,然后将为您创建AIR包。 这是您完整的软件包的外观。
进一步阅读 (Further reading)
AIR is a very powerful platform, and by using familiar web technologies, it has an extremely low barrier of entry. In this tutorial, we used our existing JavaScript skills and the powerful jQuery library to create a practical AIR application. Along the way, we looked at how AIR implements menu items, writes to a database, manages events, and more.
AIR是一个非常强大的平台,通过使用熟悉的Web技术,它的进入门槛极低。 在本教程中,我们使用了现有JavaScript技能和强大的jQuery库来创建实用的AIR应用程序。 在此过程中,我们研究了AIR如何实现菜单项,写入数据库,管理事件等等。
If this article has excited you enough to develop more with Adobe AIR, you’re in luck – next week we’ll be publishing a follow-up article, which builds on the principles we learned here.. If you can’t wait, however, be sure to visit the official AIR guide on adobe.com, Developing HTML/AJAX applications on Adobe AIR. This resource contains a number of comprehensive guides covering all the major areas of AIR development, as well as links to other great tutorials. And once you’ve exhausted the documentation, head to the Adobe AIR Developer Center for HTML and Ajax for some terrific, focused tutorials. So what are you waiting for? Get running on AIR!
如果本文使您兴奋到足以使用Adobe AIR进行更多开发,那么您很幸运–下周我们将发布后续文章,该文章以我们在这里学到的原理为基础。.如果您等不及,但是,请确保访问adobe.com上的官方AIR指南,即在Adobe AIR上开发HTML / AJAX应用程序 。 该资源包含许多涵盖AIR开发的所有主要领域的综合指南,以及指向其他出色教程的链接。 一旦您用完了文档,请访问Adobe AIR开发人员中心HTML和Ajax,以获取一些出色的,重点突出的教程。 那你还在等什么? 开始在AIR上运行!
adobe air 工程师