programing」カテゴリーアーカイブ

VectorScriptのインクルード その2

VectorWorksプログラミング実行環境で使える言語「VectorScript」の話。インクルードしたいファイル名を絶対パスで指定するか、相対パスで指定するか、という話(VectorScriptのインクルード その1)の続きです。

普通C/C++などのコンパイル型言語では、コンパイル時にコンパイラーが理解できる相対パスでインクルードするのが一般的。ビルドしてしまえばあとは一体化しているのでプログラムを動かす時はインクルードパスを意識する必要はない。

VectorScriptでも、絶対パスでインクルードファイルを指定するのは無しだと思う。相対パスじゃないと別のマシンで読み込めない。ではインクルードファイルを参照可能な場所とはどこか。

ここではVectorWorksフォルダ(Vectorworksアプリのあるフォルダ)にしてみた。図面ファイルの横に置くと、図面を別の場所に保存するとき、VectorScriptのインクルードするソースファイルもコピーしなくてはならない。Vectorworksフォルダならすべての図面ファイルから参照可能。

メインとなるソースはたとえば次のようになる。

{$INCLUDE xxx}で4つのソースファイルをインクルード

{$INCLUDE xxx}で4つのソースファイルをインクルード。次の図のようにVectorWorksフォルダに「JCLVS」フォルダを置き、ソースファイルとテキストファイルを置いておく。

Vectorworks 2015フォルダに「JCLVS」フォルダ

たとえばダイアログを表示する「My_dlg_2Edit1Cbx.pas」の中身は次。

2つの入力フィールドと1つのチェックボックスを指定するためのダイアログボックスを表示するためのプログラムだ。メインのソースの、{$INCLUDE JCLVS\My_dlg_2Edit1Cbx.pas}のところに「My_dlg_2Edit1Cbx.pas」の中身(231行)が展開されて、構文チェックされる。メインプログラムは飛躍的に読みやすくなった。

メインプログラムの13行目、filenameに「JCLVS\default.txt」を代入してダイアログの関数に渡しいてる。外部ファイル「My_dlg_2Edit1Cbx.pas」のソースから引数でファイル名を渡された「JCLVS\default.txt」を読み込むことができていることにも注目してほしい。

このようにVectorWorksフォルダにソースファイルの一部を置いておくことでメインプログラムの可読性が高まる。メインプログラムを作っている時にうっかりサブプログラムに影響を与えることが減って生産性が高まる。変数のスコープ(有効範囲)を意識して、変数名・関数名にネーミングルールを設けた方がいい。これはソースを分割しない場合でも。

ソースが展開されるだけなので、サブプログラムからメインプログラムの変数は参照できるし、インクルードしているサブファイルが2つ以上あって、両方に同じ関数が定義されているとエラーになるので注意が必要だ。C言語の分割ソースとは異なる。

上記の場合で、たとえばMy_Lib.pasの中で共通ライブラリ「JCL_str.pas」の文字列操作関数を使いたいとする。My_Lib.pasに{$INCLUDE JCLVS\JCL_str.pas}を記述すれば、JCL_strを使えるようになる。が、メインプログラムでも{$INCLUDE JCLVS\JCL_str.pas}が記述されていて二重インクルードのエラーになる。この問題についてはまた次回。

4D リストボックスから開くフォームの次前ボタン

4Dのリストボックスから開いたフォームに、「次前(つぎまえ、と読む)」を実装する

リストボックスの選択行の詳細を表示した時、次のレコードに移動するには、一度フォームを閉じてリストボックスに戻り、次の行をダブルクリックなどでレコードを表示する。これではユーザは不便。それでフォームに[次][前]ボタンを配置して、リストボックスに戻らなくても隣のレコードを表示できるように、という要望にお応えするのだ。

実装方法

たとえばvKA01_lstKAというリストボックスがある。キー配列はvKA01_lstKA_IDとすると、次前はこのvKA01_lstKA_IDの配列中から隣のKA_IDを取得して、そのレコードをロードして表示する、ような実装をする。これでリストボックスに表示されているレコードを行ったり来たりする動きになる。

実装箇所

修正が必要なのは次の箇所。

1)フォームに◁▶︎のようなボタンと現在の位置を2/30のような形式で表示するテキストが必要

フォームにオブジェクトを配置、現在の位置はvKA02_varIndexに表示、メッセージはSetControlsValues_PrevNext(後述)で作成する。

2)呼び出し元、たぶんKA01_btnModのようなボタンメソッド

次前しなければ$ka_idは変更されない値だったが、次前を実装するとフォームが閉じた時に変化していることがある。選択されている行番号も同様だ。戻ってきた時、最後に選択されているはずの行の内容を保存したり、リストボックスでその行を選択したりするために、フォームで次前が行われた結果の$ka_idと行番号を返してもらう必要がある。よってこれらはポインタで渡す。引数は次の3つ。

  • $ka_idのポインタ
  • 配列vKA01_lstKA_IDのポインタ
  • 選択されている行番号のポインタ
KA01_btnModの例

3)呼び出される側、KA02_Input_Mod

KA02_Displayする前に、配列のポインタ、行番号、$ka_idをプロセス変数に保持、ゲッターセッターを用意。_DisplayでOKされたら、フォームを表示する前のKA_IDと閉じた時のKA_IDは次前で変化している可能性があるため、Acceptの際にゲッターでKA_IDを取得してからレコードを保存する。リストを再作成してから、変化した行番号をゲッターで取得してリストボックスの行を選択し直す。

KA02_Input_Modの例

4)一番前に来たら前ボタン、一番後ろに来たら次ボタンをディスエイブルにするために、SetControlsValuesにSetControlsValues_PrevNextを追加

SetControlsValuesの例

5)次前ボタン(KA02_brnNext)

次前の際に、レコードを保存するかどうかは設計が必要だ。次のようなケースがある。

  • A)問答無用で保存(いわゆる自動保存)
  • B)問答無用でキャンセル(保存しない、変更内容は失われる)
  • C)変更していたら自動保存、変更していなければ保存しない
  • D)変更していたらアラートでお知らせしてから保存、変更していなければアラートせずに保存しない

理想を言えばDだが、Aでも成立するケースは多い。ユーザからの強い要望でBというケースもあったので決めつけることのないように。次の実装はAの自動保存。

KA02_brnNextの例、KA02_brnPrevは24、26行目の「+1」を「-1」に変えるだけ。

ネーミングおよびJCL4Dについては「4Dアプリ開発ガイド」を参照。

VectorScriptのインクルード その1

知ってましたか?インクルード。VectorScriptの実行環境には、複数のソースファイルに分割して記述されたコードをまとめて実行する機能がある。あ、言い換える、ソースコードを複数のソースファイルに分けて書くことができる。

VectorScriptのスクリプトエディタには貼り付けることのできるコード量の上限があって。は、ひとつのプログラムがソースで32kbytesまで、字数にして32,000文字、全角なら16,000文字、A4に1行に50文字くらいだとして、1ページに60行入るとして、1ページに3,000文字、10ページちょっと。ソースだからステップ数(行数)でいうと600ステップ。えっ、そんなに少ないの?これだとすぐに限界がきちゃう。

VectorScriptでそんなに長いプログラムを書くことがあるのか?という疑問もおありでしょうが、いろいろなプログラムを作っているとすぐにぶつかりますね。特にダイアログ関係はアイテム数が多いとぐんぐんコードが増えていく。図面に色々な図形を自動描画させたりすれば、これもまたコードが増える。プログラマの欲望としてプログラムには1度に大量のことをやらせたいのだ。上限なんてとんでもねえ。

もう一つプログラムが長くなるのがライブラリ化。可読性を高めるために、たとえば文字列切り出しなどの小技なプログラムをfunction/procedureに書いておく。一度役に立ったものは、別のプログラムでも使えるかもしれない。どんどんたまっていく。使うところだけ切り離すのは手間。

そこでインクルード(INCLUDE)の登場。言語によってはimportって記述する。ソースコードを分割して記述できる機能で多くの言語に備わっている。VectorScriptでも実装されている。VectorScriptのスクリプトエディタに貼り付けたメインとなるソースの他に、どこかのフォルダにサブとなるソースファイル(テキスト形式)を置いておいて、コンパイル・実行時に読み込んでくれる。

ということは、メインとなるソースは図面ファイルの中にあって、プログラムの一部が外部のソースファイルにある。図面ファイルだけではプログラムが動かない。

外部にソースファイルを置く、ということはファイルのパス名(通り道の意味のpath)、ファイルパスとか呼ばれている。macOSでは「Macintosh HD:アプリケーション:…..」のようなもの、Windowsでは「C:\….」からはじまっている記述方法、が絶対パス、これに対して「../download」のような一つ上の「download」フォルダ、の意味を示す記述方法、相対パスがある。絶対パスで参照するか、相対パスで参照するか、いずれにしてもこのパス名をソースの中に記述することになる。自分のマシンだけでプログラムを動かすのなら絶対パスでもいいけど、別のマシンでもソースを修正することなく動いて欲しい。そう、マシンが変わったらパス名が違うし、フォルダが変わっても絶対パスは変わる。

VectorScriptのインクルード その2」に続く

4DアプリをNotarizeするぞ、Catalina対応

これまで4Dアプリは、署名つきビルドをすれば、macOS Mojaveまでは、control+クリックで「開く」を選択すれば、実行することができた。

macOS 10.15 Catalinaは厳しい。Appleのいうところの「notarize」をしていないアプリをダウンロードして実行しようとすると、Controlクリックだろうが環境設定のセキュリティでなんとかしようとしても開けない。異常終了させられる。同じアプリをビルドしたマシンで起動させれば正常に動くし、USBで持っていけば別のマシンでも正常に動くのに。つまりアプリそのものは実行可能であるにも拘わらず、ネットから落としてきたというだけで悪者アプリのレッテルを貼ってくれる。

で、notarize。参考資料はここ↓、さすがです。

https://www.rk-k.com/archives/3458

xcodeでビルドするアプリはxcodeがこの辺りを上手いことやってくれるので、実際に何が行われているかはわかりにくい。アールケーさんありがとうございます。ターミナルコマンドでやってくれているのが助かります。4Dアプリにとっては必須ですので。

ここからは4Dアプリの場合:

4D v17.3で署名つきでビルド。まず拡張属性を取り除こう。特にResourcesフォルダとかにネットで管理しているテキストファイルとか画像ファイルを置いている場合は要チェック。まず

xattr -rc 「パス名」

これで「パス名」の中のフォルダの中まで拡張属性を取り除いてくれる。次に4Dをアプリケーションビルド。

治郎吉商店では、できたアプリとデータファイルなどをバンドルして出荷するので、出荷前にアプリを起動してデータファイルを作成。できた出荷用アプリを複製してデータファイル作成用アプリを作って起動。データファイル作成後は複製したアプリを削除。

この出荷用アプリはまだ実行されていないものを使う

出荷フォルダには「お読みください」などのファイルを配置。できたフォルダが次。

これが出荷イメージ

これをディスクユーティリティの機能でdmg化する。ターミナルを起動して、次を実行。圧縮のオプションを使っている。

実行すると ・・・ と表示されて実行しているのがわかる。結構時間がかかる。

ここでも拡張属性に注意。「お読みください」などのファイルを誰かに編集を依頼して、ネットで落とした場合は拡張属性がついてしまうのだ。codesignに失敗することになる。

次はnotarize

このコマンドは成功する時が長い。dmgよりも長い。何も表示されずいきなり終わる。

これでできたのをzip圧縮する。なぜかWordPressのサイトにdmgがアップできないからね。しばらくすると(数分?)Appleからメールが来る。

このケースではビルドのタイムスタンプとメールのタイムスタンプの差はおよそ8分。

ShareDocにアップして、別のCatalinaマシンで試す。Catalinaで動いた!ちなみにアップしたマシンはMojaveでした。

4Dでバーコード

4Dアプリでバーコードを作成することになった。で、調べてみるとgithubにありました。プラグインとコンポーネントの両方があったので、まずコンポーネントを試すことに。プラグインよりもコンポーネントの方が4Dのバージョンとの互換性的がありそうなので。

https://github.com/miyako/4d-component-barcode

 //JANコード(SVGピクチャ)を作成

$bar:=Barcode_create ($code;”EAN13″)

確かにできた、けどEAN13とCode_39はできたけど、他の3つはできなかった。

バーコードスキャナー opticon C-41で試したところ、画面に表示されたEAN13には反応したが、Code_39には反応しなかった。

上から2つ目がEAN13、5つ目がCode_39