Archive for 5月, 2009
TextAreaにタブをキーボードから入力したいのであるが、これがまた何もしないとできないのだ。
プログラムやらを書いているとタブが入らず、結構ストレス。
このブログの記入もタブが記入できないのですが・・・・
というわけで今回はTextAreaにタブ(Tab、いわゆる”\t” ) を記入したいということです。
TextAreaのマニュアル見ましたよ。じーーくり。
そこで気になったイベントが3つ。
- KeyDown
- KeyFocusChange
- FocusOut
もちろんタブキーが押されたら、って考えたらKewDownが素直な考えですよね。
KeyCode == 9 なら、って考えましたよ。でも、タブを入れることができても、フォーカスがなくなってしまうのですよ!!
イベントをキャンセルしても関係がないですし・・・
結局、組み合わせなければいけないのかなーーーと。マニュアルと格闘。
そしたら、KeyFocusChange
「ユーザーがキーボード操作によってフォーカスを変更しようとすると送出されます。」
と書いてあります。
あれ!?、キーボード操作によってフォーカスが変わる時って、TAB以外にあるのかな?
つまり、タブが入力されたとき?
じゃ、これだけでいいんだ。あれ、思ったより簡単!?
後は、今いるカーソル(キャレット)にタブを差し込めばいい。
あとは、TextAreaのTextFieldを操作すればよい。
この辺は、ちょうどこの問題がRichTextEditorが不満なのでつくりかえていたところなので、
そのソースを解析中だったのでわかりました。
でも、RichTextEditorで textArea.getTextField()ってやっているのに、なぜできない?
mx_internal function getTextField():IUITextField
こういうことでした。
ここで、mx_internalのNamespaceを使ってしまってもいいのですが、
ここはTextAreaの継承クラスを作成することにしました。
できた、ソースはこんな感じ
public class CustomTextArea extends TextArea
{
public function CustomTextArea()
{
super();
this.addEventListener(FocusEvent.KEY_FOCUS_CHANGE,handleKeyFocusChange);
}
private function handleKeyFocusChange(e:FocusEvent):void{
e.preventDefault();
var str1:String = textField.text.substr(0,textField.selectionBeginIndex);
var str2:String = textField.text.substr(textField.selectionBeginIndex);
textField.text = str1 + "\t" + str2;
textField.setSelection(textField.selectionBeginIndex + 1,textField.selectionEndIndex + 1);
}
}
実際にタブが押された時には、半角スペースで埋めるなんてのも後でできるようにしよと、解決できて満足です。
今から書くことは決して、メールサーバ(Postfix)を運用するためのノウハウではないのであしからず。
ただし、開発者がメール関係の開発をするときにテストとして知っておいたほうがいいとは思います。
また、サーバ系のミドルウェアに全くタッチしない人も、このような内容をしっているとちょっとはいいかもと思うこともあるかも知れません。
さて、今回のお題は「社外にメールを配信しても、実際には飛ばないようにしたい」という話です。
メールアドレスを適当に作ってしまい、それをもとにテスト配信したいのですが、実際飛んでしまっても困りますし、
でも、そのメール捨てられても困るんですよね。
さらに、贅沢なことに、一部のメールはほんとに飛んでほしいですよ。
ってことで、Postfixを使って、docomo.ne.jpとかにメールを出しても、そのサーバで受取る。ということをしたいと思います。
余談ですが・・・
その前に、あなたのLinuxにはPostfixはもしかしたら入っていないかもしれません。
でも、Redhat系ならばRPMで入っているでしょうから、sendmail を削除し、postfixをインストールしてください。
あなたが既にsendmail使いならいいのですが、postfixのほうがプログラマには向いていると思いますよ。
また、高速配信ならqmailだー!って人もいますが、あなたの高速配信ってどのレベルですか?
秒間数百通送りたい!!って人ならいいのですが、通常、日本でそんな需要はないですよ。
ちなみに高速配信するには、サーバの並列稼働が必要なのでアプリケーションレベルのみで解決はほぼできません。
だって、受け取り側が受け取ってくれないのですから・・・・
したがって、使いやすいMTAが一番。
さて、話をもどして、postfixで指定したドメインの受信をするには、
/etc/postfix/main.cf
のファイルを修正します。
| mydestination |
The mydestination parameter specifies the list of domains that this machine considers itself the final destination for. |
って、設定ファイルには書いてあります。
要するに、このパラメータで指定したドメインは、このマシンが受け取るよ。ってことです。
なので、ここの設定に、
mydestination = $myhostname, localhost.$mydomain, localhost,
ezweb.ne.jp, softbank.ne.jp, docomo.ne.jp
こんな感じに記述してしまえば、このサーバからのezwebや、docomo、softbank向けのメールはぜーーーんぶ、このサーバが受け取ってしまうということ。
あとは、
/etc/init.d/postfix restart
を忘れないでください。
じゃないと、ほんとに飛んでしまいますよ。
念のために、自分の携帯アドレスで確認してから実行してくださいね。失敗しても責任は負えませんので・・・
どうにかして、Flexで日本語フォントのみを抽出するということができないのでしょうか?
調べたのですが、どうしてもわかりませんでした。
でも、やたらと使わないフォントの一覧があってもこまります。
(ちなみに、フォント一覧をみるにはこちらから)
んー、考えたあげく、フォント名が日本語のフォントという考え方にすることにしました。
まあ、日本語フォントが日本語名になっていないということはまれでしょう。多分。
さらに、たいていの人は、複数の言語のフォントなんてないでしょうということで、
さらに、マルチバイトのフォント名は、「日本語フォント」だー。という強引な結論にしました。
まあ、ほとんどこれで大丈夫でしょう。
だめになったときに、それはそれで考えるということで、マルチバイトのフォント名一覧を作成するという命題です。
var fontArray:Array = Font.enumerateFonts(true);
var janList:Array = new Array();
var ba:ByteArray = new ByteArray();
var cnt:Number = 0;
for(var i:Number = 0; i<fontarray .length; i++){
var ft:Font = fontArray[i] as Font;
ba.writeUTFBytes(ft.fontName);
if(ba.length > ft.fontName.length){
janList.push(ft);
}
ba.clear();
}
ba = null;
ちょっと注意点ですが、ここでbytearray.clear()を使っています。
これは、バージョンが10からですので、ご了承を。。。
私自身、なぜと思ってしまったので・・・
もっと、スマートなやり方を知っている方がいたら教えてください。
久々のflex mx:Treeのネタです。といっても、非常に基本的なことです。
Treeのアイテムを開いたり、閉じたりするには?
これ、開くには以前、flex:Treeで自動的にフォルダを展開させるには でTreeのアイテムにドラッグ&ドロップでドロップしようとしたときに、
自動的に開くようにするということで述べましたが、今回は閉じるには?を調べました。
久々のflex mx:Treeのネタです。といっても、非常に基本的なことです。
というのも、デフォルトで「閉じる」「開く」は矢印をクリックすればできるのですが、やっぱり、フォルダとして機能している場合、つまり、他のアイテムの親としてしか機能しないアイテムをクリックすると、開いたり、閉じたりしてほしいなーと思ったのがきっかけです。
だって、矢印が小さいんですもん。
最近、できるとはわかっているよりも、できるのか?できないのか?
のほうを優先してしまい、結構、基本的な部分がはて?どうやるんだ???のままでほったらかしなので。
さて、話は戻って、Treeで、「閉じる」、「開く」を実装するためには、
もちろん、「開く」、「閉じる」のメソッドが必要ですが、「今は開いているの?、閉じているの?」がわからないといけないですよね。
さて、それでは、クリックのイベントで処理をおこなうようにしましょう。
tree.addEventListener(ListEvent.ITEM_CLICK,_fireClickItem);
次に、クリックされた時の処理は
protected function _fireClickItem(e:ListEvent):void{
var tree:Tree = e.currentTarget as Tree;
var obj:Object = tree.selectedItem;
if(!tree.isItemOpen(item.selectedItem)){
tree.expandItem(obj,true,true);
}
else{
tree.expandChildrenOf(obj,false);
}
}
さて、閉じるときと、開くときでことなったメソッドを使っています。
expandChidrenOf(item,boolean)のドキュメントをみると
“指定したアイテムの配下にあるすべてのツリーを開くか、または閉じます。”
とあります。
すべて、開かれても困るので、開くときは、expandItemを使っていまし、
閉じるならすべて閉じたほうがいいかなと使い分けています。
この辺の動作は好みかもしれませんが、深ーいツリーで、やっぱり浅い階層のものを見るときに「閉じて」、「開く」ってことを私自身やってしまうので・・・
でも、ふつうは両方ともexpandItemでいいのでしょうね。
Windowsのエクスプローラもそうなっていることですし・・・・
AIRでアプリケーションを作成していると、アプリケーションのサイズを指定するわけだが、でも起動後にサイズを変更するわけだ。
私なんかは、ノートの場合、たいてい最大化してしまう。
しかし、大きなディスプレイのときにはそうでもなかったする。
要するにアプリケーションのサイズは前回閉じたときの大きさで再現できればより親切だろう。
こうなるとAIRのアプリケーションで閉じるときに値を保存しておかなければいけない。
保存しておくデータは、サイズと状態(最大?通常?)というデータだ。
理屈は、閉じるときに保存し、起動時に読み込み、そのサイズ、もしくは状態に変更させればいいわけだ。
さて、こうなると、サイズの取得と、状態の取得をする必要がある。
サイズの取得はWindowedApplicationのオブジェクトのwidthとheightをとればいいわけだが、状態を取るのはどうすればいいのだろうか?
実は、状態と記述しているところに訳がある。私ははじめ、「最大にした時」というのを探してしまった。こう考えてしまったために、たどり着くまでに時間がかかってしまったが、状態の変化は、以下のようにイベントでとれるのだ。
以下のように、状態が変わったときと、アプリケーションが閉じるときのイベントで処理をするようにする。
// thisはWindowedApplicationのインスタンス this.addEventListener(NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGE,windowStateChange); this.addEventListener(Event.CLOSING,windowClosing);
これで、状態が変わったときにその状態を変数に保存しておき、アプリケーションが閉じるときに保存すればいい。というわけだ。
具体的にはこんな感じだ。
private function windowStateChange(e:NativeWindowDisplayStateEvent):void{
this.windowState = e.afterDisplayState;
}
次にをアプリケーションが閉じるときのイベントだが、
private function windowClosing(e:Event):void{
props.saveValue("window.height",String(this.height));
props.saveValue("window.width",String(this.width));
props.saveValue("window.state",this.windowState);
}
上のprops.saveValueというメソッドは私が作ったもので、実際にはここでプロパティ情報を管理するDB(sqlite)に値を保存している。
ここでは、どのような方法を使ってもいいのでローカルに保存できればいいのだが、後で値が簡単に見えるのと、変更も可能なのでテストしやすいために私はそうしただけだ。
ここまでできれば、今度は次回の起動時にこれを再現するだけだ。
再現は、WindowedApplicationにcreationComplete=”createEnd()”のように関数を登録し、
private function createEnd():void{
this.windowState = props.getValue("window.state");
if(this.windowState == NativeWindowDisplayState.MAXIMIZED){
this.maximize();
}
else{
saveWidth = props.getNumberValue("window.width");
if(saveWidth > 0 ){
this.width = saveWidth;
}
saveHeight = props.getNumberValue("window.height");
if(saveHeight > 0 ){
this.height = saveHeight;
}
}
}
ここででも、props.getValueとprops.getNumberValueがあるが、これは保存した値を読むように私が作ったものなので、ここは各自にあった実装をしてほしい。
また、ここでは状態が最大しか考慮していないが、状態には、通常、最小、最大がある。
しかし、最小にしたいということはありえないと思うので、最大の場合だけ最大にし、それ以外は前回のサイズにしている。
これを応用すれば、それ以外にもアプリケーション特有の再現はできるとおもいますので、ますます、AIRとしての(クライアントアプリケーションとして)メリットが出せるのではないでしょうか?

