ラベル ActionScript の投稿を表示しています。 すべての投稿を表示
ラベル ActionScript の投稿を表示しています。 すべての投稿を表示

2009年8月21日金曜日

2009年6月4日木曜日

ActionScriptでISO8601をDateに変換してみた

ちゃんとテストしてない。ていうか、ほとんどテストしてない。そのうえ作る時に考えてない。
parseIso8601
private static const ISO8601_RE:RegExp
= /^(\d{4})(-?(((\d{2})(-?(\d{2}))?)|(\d{3})|(W(\d{2})-?(\d)))([T ](\d{2})(:?(\d{2})(:?(\d{2})([,\.](\d+))?)?)?(Z|(([+-])(\d{2})(:?(\d{2}))?))?)?)?$/;
public static function parseIso8601(s:String):Date
{
var year:int = 1970;
var month:int = 0;
var date:int = 1;
var hour:int = 0;
var minute:int = 0;
var second:int = 0;
var millisec:int = 0;
var offset:int = 0;
var m:Array = s.match(ISO8601_RE);
if(!m) return null;
if(m[1]) year = int(m[1]);
if(m[3]) date = int(m[3]);
if(m[5]) month = int(m[5]) - 1;
if(m[7]) date = int(m[7]);
if(m[10] && m[11]){
var first:Date = new Date(year, 0, 1);
var w:int = (first.day == 0 ? 6 : first.day - 1);
date = 8 - w + (int(m[11]) - 1) + 7 * (int(m[10]) - 2);
}
if(m[13]) hour = int(m[13]) % 24;
if(m[15]) minute = int(m[15]);
if(m[17]) second = int(m[17]);
if(m[19]) millisec = int(m[19]);
if(m[20] && m[20] == 'Z')
return new Date(Date.UTC(year, month, date, hour, minute, second, millisec));

if(m[23]) offset = int(m[23]) * 60;
if(m[25]) offset += int(m[25]);
if(m[22] && m[22] == '-') offset = -offset;

offset *= 60 * 1000;
return new Date(Date.UTC(year, month, date, hour, minute, second, millisec) - offset);
}

列挙型がないAS3で列挙を使う


「ActionScript 3.0 は、C++ の enum キーワードや Java の Enumeration インターフェイスとは異なり、特定の列挙機能をサポートしません」

と書いてある。さらに、代替手段も記載されている。

一つ目の方法は「staticなパブリック定数(String型かint型かuint型)を定義する」というもの。

Flex3のイベント名が類似品だろう。
この方法だと、定義していない列挙をうっかり使ってしまったり、既に定義してある列挙値と同じ列挙値をうっかり違うものと思い込んで使ったりしてしまうという心配がある。

二つ目の方法は「staticなパブリック定数にクラスのインスタンスを入れる」というもの。

これを使ったコードはまだ見たことがなかったし、考えもしなかったのでなるほどと思った。
この方法だと、値のセットを任意の新しい型として作ることができる。
それでも、任意の列挙値を後から作れてしまう。
C++だとコンストラクタをprivateにしてインスタンスを作れないようにもできるのだが・・・。
day
public final class Day {
public static const MONDAY:Day = new Day();
public static const TUESDAY:Day = new Day();
...
}
nasty day
public final class NastyDay {
public static const GALACTICDAY:Day = new Day();
}

2009年6月3日水曜日

AIRでタスクバーに表示されないアプリケーションを作る


ウィジェットをAIRで作ってみたくなった。

ウィジェットがタスクバーに表示されていたら邪魔だから、タスクバーに表示されないようにしたい。
そのためにはウィンドウのtypeをlightweightにすればよい。

  1. ベースを<mx:Window>にしたカスタムコンポーネントを作りtype="lightweight"にする。
  2. (1)が閉じられたらアプリケーションを終了させるコードを書く
  3. アプリケーションファイルを<mx:Application>にして(1)を表示する

ウィンドウの位置を動かすためにnativeWindow.startMove()をmouseDownイベントのハンドラで呼び出す。このときmouseDownをカスタムコンポーネントで拾うと、イベントバブリングがあるので、全ての子コンポーネントのmouseDownを拾ってしまう。解決方法は、イベントバブリングを中断するという方法もあるのだろうけれど(...調べてないからやり方は分からない)、mouseDownを受け取るコンポーネントを配置する方法のほうが簡単だと思う(...知識は少なくても解決できたから^^)。

ちなみに、<mx:Application>を使う理由は、Flex Builder 3でAIRアプリのプロジェクトを作ると、アプリケーションファイルは<mx:WindowedApplication>になるのだが、このときウィンドウのtypeをlightweightにする方法を見つけられなかったから。

WidgetWindow.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Window xmlns:mx="http://www.adobe.com/2006/mxml"
maximizable="false"
minimizable="false"
resizable="false"
systemChrome="none"
showFlexChrome="false"
transparent="true"
type="lightweight"
layout="absolute"
width="100"
height="100"
close="exit()">
<mx:Script>
<![CDATA[
private function exit():void
{
NativeApplication.nativeApplication.exit(0);
}
]]>
</mx:Script>
<mx:Canvas width="100%" height="100%"
cornerRadius="8" borderStyle="solid" backgroundColor="#F3F3D1"
mouseDown="nativeWindow.startMove()" backgroundAlpha="0.7"/>
<mx:VBox horizontalCenter="0" verticalCenter="0" horizontalAlign="center">
<mx:Label text="Hello world"/>
<mx:Button label="close" click="exit()"/>
</mx:VBox>
</mx:Window>

Widget.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="init()">
<mx:Script>
<![CDATA[
private function init():void
{
new WidgetWindow().open();
}
]]>
</mx:Script>
</mx:Application>

2009年6月1日月曜日

2009年5月29日金曜日

ActionScriptでrubyのString#scanもどき

RubyのString#scan
scan.as
package com.blogspot.takumakei.utils
{
public function scan(str:String, re:RegExp):Array
{
if(!re.global){
var flags:String = 'g';

if(re.dotall)
flags += 's';
if(re.multiline)
flags += 'm';
if(re.ignoreCase)
flags += 'i';
if(re.extended)
flags += 'x';

re = new RegExp(re.source, flags);
}

var r:Array = [];
var m:Array = re.exec(str);
while(null != m){
if(1 == m.length)
r.push(m[0]);
else
r.push(m.slice(1, m.length));
m = re.exec(str);
}
return r;
}
}

サンプルスクリプト
p(scan('foobar', /./));
p(scan('foobar', /(.)/));
p(scan('foobarbazfoobarbaz', /ba./));
p(scan('foobarbazfoobarbaz', /(ba)(.)/));
実行結果
["f","o","o","b","a","r"]
[["f"],["o"],["o"],["b"],["a"],["r"]]
["bar","baz","bar","baz"]
[["ba","r"],["ba","z"],["ba","r"],["ba","z"]]

ActionScriptでrubyのObject#inspectとp

RubyのObject#inspectp
inspect.as
package com.blogspot.takumakei.utils
{
import flash.utils.getQualifiedClassName;

public function inspect(x:*):String
{
if(x == null)
return "null";

if(x is Boolean)
return (x ? 'true' : 'false');

if(x is int || x is uint || x is Number)
return x.toString();

if(x is String)
return '"' + x + '"';

if(x is Array){
var r:String = '[';
if(0 < x.length){
r += inspect(x[0]);
for(var i:int = 1; i < x.length; ++i){
r += ',';
r += inspect(x[i]);
}
}
r += ']';
return r;
}

return '#<' + flash.utils.getQualifiedClassName(x) + ':"' + x.toString() + '">';
}
}

p.as
package com.blogspot.takumakei.utils
{
public function p(x:*):void
{
trace(inspect(x));
}
}