電卓
今回のテーマは、オブジェクト指向プログラミングによる「電卓」の作成です。電卓プログラムは簡単なわりに奥が深く、でプログラム入門には最適なネタです。作り方を覚えると多くの局面で応用出来るので、かなりお得感があります。
特にこの記事では、AfterEffects用として秒数計算が出来る電卓を解説していきたいと思います。
とりあえず、AEスクリプト版電卓でアルゴリズム・クラスによるオブジェクト指向プログラミングの解説を行い、
その後にC#版電卓(Windowsアプリ)を作成しながら、でカスタムコントール等のユーザーインターフェースの作成方法を説明していきます。
電卓のアルゴリズム
電卓はやってることは単純ですが、いろいろなファクターがあるので混乱しないように注意してください。一般的な電卓は以下の流れになっています。
- 数値1の入力(文字列)
- 数値1を画面に表示
- 計算命令の指定1。
- 数値1を数値化して計算結果へ
- 数値2の入力(文字列)
- 数値2を画面に表示
- 計算命令の指定2(もしくは計算実行=)
- 数値2を数値化して、計算命令1に応じた演算を計算結果に行う。
- 計算結果を画面に表示
- 計算命令1は破棄して計算命令2を保存
- 上記の繰り返し
いろいろ調べましたが、電卓はメーカーごとに操作方法・動作がかなり違いますね。一般的な操作方法を採用しようとして困りました。今回はCasioのWebにあった操作方法を参考にして作成します。
AEスクリプトで電卓
では、実際に作ってみましょう。今回作ったfxCalc.jsx電卓スクリプトと今回の記事用に作成したサンプルスクリプトです。
☆fxCalc_jsx.zip
fxCalc_jsx.zip
twitterで先日アップしたものと同じURLですが、中身は更新して新しいものになっています。
中身の一覧は以下のとおりです。
- fxCalc.jsx AE用電卓スクリプト
- fxCalc_jsx_ダイアログ作成.zip fxCalc.jsxのダイアログ作成の為のC#プロジェクト
- sampleScripts 今回の記事で作成したサンプルスクリプトが入ってます。
fxCalc.jsxを実行するとこんな感じになります。
僕の個人的な好みで、入力文字と計算結果が別に表示させるようになってますが、それ以外は普通の電卓です。
SS+FF形式のチェックがONなら秒+コマ表記で計算できます。
余談ですが、実はAfterEffectsで単純に計算させるだけなら簡単で、
の1行で出来ます。下の図のように計算式を書けばいいだけなので、実はこれが一番便利だったりします。
パネル・パレットのデザイン
ダウンロードしたアーカイブ内にあるスクリプトは、直接実行するとパレットウィンドウに、ScriptUI Panelsフォルダに入れてウィンドウメニューから表示させるとパネルウィンドウになります。
このような動作をするウィンドウの作り方は、Scripting GuideのThe Window menu and ScriptUI Panels folderの項目で説明されていますので、参照してください。
簡単に説明すると、オブジェクトの作成時にスクリプト自体のオブジェクトを参照して、それがパネルならそれ自身を、パネルではなかったらwindowオブジェクトを作成するように切り替えて実装しています。
上のコードはオブジェクトを作成時thisでスクリプトオブジェクト自身を引数にしています。
そのオブジェクトをinstanceofでPanelかどうか識別しています。
?条件演算子は良く見かけますが、僕自身は分かりづらいのであまり使いません。
普通にif文で書くと、以下のようになります。
この電卓のユーザーインターフェースは、プログラム入門その1で紹介したAEScriptDialogExport.csを使ってデザインしています。
今回のようにパネル・パレット動作が可能なようにこっそりAEScriptDialogExport.csをバージョンアップしてます。しかし、AEスクリプトユーザーにVisual C#をインストールさせようって目的で作ったコンポーネントですが、意外に便利ですなぁ(^o^)/
fxTimeクラス
まず、AfterEfefctsの時間(Duration)を扱うためのクラス「fxTime」を説明します。fxTimeクラスは、時間(time/Duration)を扱うために必要な変数・関数をまとめたクラスになります。
fxTimeクラスは、時間を通常の数(Number)としても、秒+コマ形式の文字列としても扱える事を目的にしたクラスで、通常の変数として使いながら表示を自由に切り替えることができます。ちょっと改造すればタイムコード(hh:mm:ss:ff)形式にも簡単に対応させる事ができます。
さて、なぜこのようにクラスにするかというとあとあと楽になるからです。
秒+コマの表示に対応させるためには他にframeRateも管理する必要があります。また、文字列から数値にといったデータ依存した関数も多数作成し、管理しなければいけません。
必要な変数・関数をまとめてパックしたものがクラスなので、管理が楽になります。機能拡張時のコーディング追加も省力化できます。
あと、使用する変数をクラス内だけで使用できる状態(private)に出来るので、たくさんのスクリプトを使っていて変数名が重複して動作が変になる事をふせぐことが出来ます。
小さなスクリプトの場合、LianさんのWeb無名関数で囲む話(前回の補足)で解説されている無名関数で囲む方法が変数の重複を避ける気軽な処理になります。ただ、今回のようにパネル化等無名関数で囲む方法が使えない場合や、スクリプト自体が生巨大な場合は、クラス化で処理した方が有効になります。
fxTimeクラス内部にはいろいろ変数・関数がありますが、外部に公開されているものは以下の関数だけです。
- setDuration関数 Durationを設定する。
- getDuration関数 Durationを獲得する。
- setDurationStr関数 数字文字列からDurationを設定する。
- setSecKoma関数 Sec+Koma形式の文字列で、Durationを設定する。
- getSecKoma関数 Sec+Koma形式の文字列で、Durationを獲得する。
- setFrameRate関数 frameRateを設定する。
- getFrameRate関数 frameRateを獲得する。
内部実装を忘れても、上記のpublic関数さえ使えれば特に問題なく使えます。
詳細はソースを参照してください。クラス化してあるだけで特に難しいことはしていません。
AEスクリプトでクラス作成
Javascriptは柔軟な言語でクラスの作成方法は複数有ります。C++やC#と違い継承を使わなくても動的にどんどんメンバ変数・関数を追加・削除出来ます。あまりにも柔軟で自由なのでよく初心者が混乱するのでここでは1種類しか説明しません(最初僕はめちゃ混乱した)
下のコードが簡単なクラス定義のサンプルになります。(mclass.jsx)
以上がクラス定義の基本です。よくみるとthisって単語が見慣れないだけで関数定義と全く同じです。
Javascriptの凄いところで関数もクラス(オブジェクト)の一つなので、実は全く区別が有りません。
僕自身実はあまりよくわかってないので、適当にやってます。
クラス内部で、varで宣言された変数はprivateで外部からアクセス出来ないローカル変数になります。
外部で同じ変数名があっても、内部で宣言されたものが優先されます。
クラスの外部に公開したい変数は、this.bという形で宣言を行えば出来ます。
関数も同様にfunctionでと定義したものはローカルのみで、thisで指定した変数に割り当てれば外部に公開されます。
クラスは定義しただけではダメで、newでオブジェクトとして作成して初めて使えます。
具体的には、以下のとおりです。
下のコメントアウトされた行を有効ににして実行すると、メンバ変数のスコープの挙動がなんとなくわかると思います。
余談ですが、定義だけの状態をクラス、newで実体化されたものがオブジェクトって呼ぶらしいです。
昔borland Delphiの言語Object Pascalではクラスとオブジェクトの意味がC++と全く逆だったのでよく混乱して失敗しました。最近の言語C#/Javaでは言語自体がオブジェクト志向で設計されているので、意識しなくても全然問題有りませんが。
動的にメンバを追加
上記はfunctionを使ってクラスを定義する方法ですが、Javascriptでは面倒な手続きなしにいきなりメンバを追加することが可能です。nObj.jsx
上の例では空のオブジェクトを作成して、単純にメンバ変数をオブジェクトに追加しています。
関数の戻り値を複数の値にしたい時に有効に使えます。
splitFn.jsx
また、AEスクリプトでは、キーフレームの情報を変数に獲得するときなんかに役に立ちます。
OpacityKeyShift.jsx
上の例では、不透明度のキーフレームの情報を配列に記録してさせています。
以上のように動的にメンバを追加した時は、しっかりとメンバ名を覚えておかないとundefinedを連発しますので注意です。
prototypeでクラス作成
他にもprototypeを使用してクラスを作成する方法もあり結構便利です。上の例では、NumberオブジェクトにgetSecKomaメンバ関数を追加しています。実はprototypeについてはあまり僕も分かっていません^^;ですが、既存のオブジェクトに関数を簡単に追加できるので、使い勝手が非常によいです。
fxCalcクラス
fxCalcクラスは、インターフェースのfxCalcPanelオブジェクトの作成等を行い、電卓そのものを実装したクラスです。特に変わったことはしてませんが、トリッキーなテクニックとしてボタン毎の動作切り替えを、ボタンの表示文字を獲得してそれで行っています。
setBtnExec関数でonClickにinputBtn/inputBtnSecKoma関数を割り当てています。
その関数内で
var c = this.text;
の行でボタンの表示文字の獲得を行っています。この関数単独では、this.textは全く意味を持ちませんが、ボタンオブジェクトのメンバ関数に割り当てた事によりthisはそのボタンオブジェクトそのものを意味するようになります。
その為ボタンごとに関数を作成する必要がなくしています。
文字列を数値に変える時の注意
文字列を数値に変える場合parseInt()、parseFloat()、Number()や、0との引き算がよく使われますが、僕はeval()を多用してます。eval()は、元々はJavascriptのコードを実行させるものですが、「2+3」とか「10+(2+3)/2」のような計算式を数値化してくれるので便利です。
あと、重要なのがエラーチェックです。文字列を数値へ変換させる時は必ずエラーチェックを行うべきです。
javascriptは柔軟な言語仕様のため変数の型が動的に変更される時があります。いきなりスクリプトが不安定になる原因がほとんどこれです。
具体的にはtry文を使い例外を捉える方法と、変換した結果をisNaN()関数で確認する方法があります。
ちょっと適当なサンプルですが、以下のようになります。
上記の関数はエラーが有った場合、Number.NaNを返すようになってます。
関数によっては違う実装も有りますが、値を必ずisNaN()関数でチェックする癖をつけるといいです。
isNaN()関数は、指定された変数がNaN(Not a Number)だった場合、trueを返します。つまりfalseなら数値になります。
ただ、数値に変換可能な文字列でもfalseを返してしまうので注意してください。
fxCalcクラスはさらに、数値に変換する前に文字列のチェックを行って不正な文字は削除し、変換時にエラーがでない用に工夫してあります。用心に越したことはないので、エラーチェックはこまめにコーディングしておくと幸せになります。
次回予告
C#版の電卓の説明は次回に持ち越します。個人的な都合ですが目の手術をうけたばかりで、あまり長時間PCの作業が出来ないのでT_T
15分書いたら1時間休憩ってペースなので。今回の記事は殆ど入院前に書き終わっていたので楽でしたが。
C#版電卓では、主にカスタムコントールによるユーザーインターフェースの作成がメインテーマになります。
新着記事 : After Effectsユーザーのための、プログラミング入門 その3 電卓 クラスを使ったプログラム http://bit.ly/gSNQcu
RT @AEUSERS: 新着記事 : After Effectsユーザーのための、プログラミング入門 その3 電卓 クラスを使ったプログラム http://bit.ly/gSNQcu
RT @AEUSERS: 新着記事 : After Effectsユーザーのための、プログラミング入門 その3 電卓 クラスを使ったプログラム http://bit.ly/gSNQcu
RT @AEUSERS: 新着記事 : After Effectsユーザーのための、プログラミング入門 その3 電卓 クラスを使ったプログラム http://bit.ly/gSNQcu
After Effectsユーザーのための、プログラミング入門 その3 電卓 クラスを使ったプログラム | AEP Project http://bit.ly/gAcm08
RT @AEUSERS: 新着記事 : After Effectsユーザーのための、プログラミング入門 その3 電卓 クラスを使ったプログラム http://bit.ly/gSNQcu
RT @AEUSERS: 新着記事 : After Effectsユーザーのための、プログラミング入門 その3 電卓 クラスを使ったプログラム http://bit.ly/gSNQcu
RT @AEUSERS After Effectsユーザーのための、プログラミング入門 その5 callSystem http://bit.ly/fmHdQwユーザーのための、プログラミング入門 そ-5/ #aejp
今更ですがコレすげー。夢が拡がる。。 RT @AEUSERS After Effectsユーザーのための、プログラミング入門 その5 callSystem http://bit.ly/e28fj8ユーザーのための、プログラミング入門 そ-5/ #aejp
o8CAJZ fvjjaifuobda, [url=http://otjtlwdmvdqw.com/]otjtlwdmvdqw[/url], [link=http://huhrqhqupzlz.com/]huhrqhqupzlz[/link], http://idmoamqdtcat.com/
「After Effectsユーザーのための、プログラミング入門 その3 電卓 クラスを使ったプログラム」AEP Project http://bit.ly/ae-users_110301 #CS5_jp
スクリプトは経験があるけれどその他の言語はさわったことがないユーザーを対象に、C#/AEのJavaScriptをメインにプログラム全般を解説する連載の第3回です。http://bit.ly/ae-users_110301 #CS5_jp
#Java RT @AdobeCS_jp: スクリプトは経験があるけれどその他の言語はさわったことがないユーザーを対象に、C#/AEのJavaScriptをメインにプログラム全般を解説する連載の第3回です。http://bit.ly/ae-users_110301 #CS5_jp
This article aceivehd exactly what I wanted it to achieve.