4D v18 R5 ではマクロが導入されました。フォームエディター上で繰り返しおこなうタスクを自動化するのに、マクロは非常に便利です。このブログ記事ではいくつかの基本的な例とともに、マクロがどう機能するのか、なにが可能なのかを紹介します。 詳細については、オンラインマニュアルも参照ください。
マクロを使って次のことをおこなえます:
など
いくつかの例を実際に見てみましょう。 例1ではマクロの作り方・実行の仕方も説明します。
選択されているフォームオブジェクトのフォントカラーを赤に設定するマクロです。
まず、JSONマクロファイル (FormMacros.json) 内で、次のようにマクロを宣言します:
{ { "macros": { "赤に設定する": { "class": "SetRedColor" } }
次に4D内で、マクロによって呼び出される “SetRedColor” クラスを作成します。
このクラスの関数として、呼び出し時に実行される onInvoke 関数を設定します。
実行時にこの関数に渡される引数には、フォームエディターの情報が含まれています。
引数内の “currentSelection” プロパティから、選択されているフォームオブジェクトのコレクションが取得できます。
コレクションに格納されている各フォームオブジェクトの属性を変更します。
最後に、戻り値として “currentPage” 属性を返すことで、4Dに変更内容を通知します。
コードは次のようになります:
Function onInvoke($editor : Object) : Object
var $name : Text
If ($editor.editor.currentSelection.length>0)
// 選択オブジェクトのstroke属性を "red" に設定します
For each ($name;$editor.editor.currentSelection)
$editor.editor.currentPage.objects[$name].stroke:="red"
End for each
Else
ALERT("フォームオブジェクトを選択してください。")
End if
// 4D に変更内容を通知します
$0:=New object("currentPage";$editor.editor.currentPage)
マクロが実行するには、フォームエディター上でコンテキストメニューを開き、「マクロ > 赤に設定する」 を選択します。
マクロのコードを格納している “SetRedColor” クラスを HDI内で確認してください。
赤だけでなく、緑のフォントカラーも利用したい場合、2つのマクロと、それぞれに専用のクラスを作成することもできますが、2つのマクロにそれぞれパラメーターを設定して、それらを1つのクラスで処理することも可能です。
JSONマクロファイル (FormMacros.json) 内で、同じ “SetFontColor” クラスと、異なる “color” パラメーターが設定された 2つのマクロを宣言します:
{ "macros": { "フォントカラーを赤に設定する": { "class": "SetFontColor", "color": "red" }, "フォントカラーを緑に設定する": { "class": "SetFontColor", "color": "green" }, }
この “color” パラメーターはクラスのコンストラクターで取得します:
Class constructor
var $1 : Object
This.color:=$1.color
“SetFontColor” クラスの onInvoke 関数には例1と同じコードが再利用できます。異なる点は “red” という文字列で色を指定する代わりに、変数 This.color を使うことです。
マクロを使って、メソッドの付いたフォームオブジェクトをフォームに追加することができます。メソッドを紐づける方法は複数あります。オンラインマニュアルにて、それらの方法を説明しています。
このHDIの例では、メソッドのコードをオブジェクトに格納して4Dに渡します。当該メソッドファイルは実行時に 4D によって作成されます。
Function onInvoke($editor : Object)->$result : Object
var $btnHello : Object
// "Hello" ボタンを作成します
$btnHello:=New object("type";"button";\
"text";"Hello World!";\
"method";New object("source";"ALERT(\"coucou\")");\
"events";New collection("onClick");\
"width";120;\
"height";20;\
"top";0;\
"left";0)
// 現在のページにボタンを追加します
$editor.editor.currentPage.objects.btnHello:=$btnHello
// フォームエディター上で新規作成したボタンを選択します
$editor.editor.currentSelection.clear()
$editor.editor.currentSelection.push("btnHello")
// 4D に変更内容を通知します
$result:=New object
$result.currentSelection:=$editor.editor.currentSelection
$result.currentPage:=$editor.editor.currentPage
作成したばかりのフォームオブジェクトを編集しやすいよう、”currentSelection” を対象に clear() および push() を使用することで、このフォームオブジェクトを選択します。
最後に、戻り値として ”currentPage” 属性とともに “currentSelection” 属性も返し、4Dに変更内容を通知します。
フォームを編集するだけでなく、フォームの情報、属性、プロパティを検証するマクロも作れます。たとえば、複数のページを持つフォーム内で使用されているピクチャーパスを検証することができます。
マクロはモーダルウィンドウを開いてダイアログを表示することができます。 たとえば、現在のページ上にあるオブジェクトの一覧を、それらのオブジェクト名、タイプ、クラスなど任意のプロパティとともに表示することができます。一覧からオブジェクトを選択して、ダイアログ内の “選択” ボタンをクリックすると、フォームエディター上でも選択されるようにできます。
このマクロのコードを格納している “ObjectList” クラスを HDI内で確認してください。
4Dでオブジェクトを整列するには “整列” ダイアログも使用できますが、いくつかのオブジェクトを選択して、ターゲットオブジェクト (マクロ呼び出し時にマウスカーソルが置かれているオブジェクト) を基準に位置を揃えることもできます。
コードを書く際には:
このように、整列も均等配置も任意に実行するマクロを作成することができます。 “AlignOnTarget” クラスでは、左揃え・右揃え・上揃え・下揃えの例を確認することができます。
ORDAで作成したエンティティセレクションには固有のORDAコンテキストが関連づけられます。ORDAのコンテキストを作成するコマンドは,下記のとおりです。
dataClass.query()
entitySelection.query()
dataClass.fromCollection()
dataClass.all()
Create entity selection
Use ORDA to boost performance in Client/Server mode
ORDAのコンテキストは,クライアント/サーバーのパフォーマンスを最適化するために使用されます。具体的には,REST APIでサーバーから転送されるデータクラス属性のリストを内部的に管理し,リクエストされた属性だけを追加してゆくことにより,クエリの特性を自動的に「学習」するために使用されます。通常,コンテキストを意識してコーディングする必要はありませんが,条件分岐を含むエンティティセレクションの一括処理などでアクセスする可能性のあるすべての属性が事前にわかっているのであれば,最初に必要な属性名すべてにアクセスしてコンテキストを最適化することにより,一括処理の途中で不足した属性を補うためのネットワークリクエストが発生することを防ぐこともできます。コンテキストはフォームの描画にも使用されており,リストボックスのカラム内で使用されている属性(非表示カラムを含む)が初期コンテキストとなります。
ORDAコンテキストは,クエリの用途に対して特化されたものであるべきです。コンテキストから属性を除外することはできないので,コンテキストを汎用的に使用した場合,属性のリストが肥大化してパフォーマンスが低下する恐れがあります。リレーション属性にアクセスする場合は特にそうです。たとえば,下記のコードはマルチレベルのリレーション属性にアクセスしているため,指数的にコンテキストが肥大化し,一括処理の後は非常に処理が重くなります。ORDAリクエストログをみれば,一括処理の後,レベルのリレーション属性がそれぞれ最大80
件ずつ返されていることがわかります。
$logFile:=Folder(fk logs folder).file("ORDARequests.txt")
ds.startRequestLog($logFile)
$entitySelection:=$anEntity.relatedEntities
For each ($entity; $entitySelection)
$relatedData:=$entity.link.link.link.link.toCollection()
End for each
$result:=$entitySelection.orderBy() //重い処理
コンテキストが肥大化してしまった場合,dataClass.get()
で新しいコンテキストを作成することができます。
$logFile:=Folder(fk logs folder).file("ORDARequests.txt")
ds.startRequestLog($logFile)
$entitySelection:=$anEntity.relatedEntities
For each ($entity; $entitySelection)
$relatedData:=$entity.link.link.link.link.toCollection()
End for each
$key:=$anEntity.getKey() //プライマリーキー
$entitySelection:=ds[$anEntity.getDataClass().getInfo().name].get($key) //新しいコンテキスト
$result:=$entitySelection.orderBy() //軽い処理
v14でACI0084254が修正されたことにより,環境設定の「アプリケーションモードに移動する時にデザインモードを終了する」が有効にされていない場合,カスタムモードでは常にスプラッシュスクリーンが表示されるようになりました。その場合,データベース設定の「インターフェース」ページで「スプラッシュスクリーン」をオフにしても,スプラッシュスクリーンが強制的に表示されます。これは仕様です。
カスタムモードでメニューバーを表示するためには,メインプロセスが最前面でなければならず,プロセスが最前面であるためには,ウィンドウを表示していなければなりません。ACI0084254の修正前,環境設定の「アプリケーションモードに移動する時にデザインモードを終了する」が有効にされておらず,データベース設定の「スプラッシュスクリーン」もオフに設定されている場合,カスタムモードからデザインモードに切り替えた後,カスタムモードに復帰することができませんでした。修正により,環境設定の「アプリケーションモードに移動する時にデザインモードを終了する」が有効にされていない場合,強制的にスプラッシュスクリーンが表示されるようになりました。
Apple Silicon版の:macOS Big SurでGet application info
を実行した場合,cpuUsage
プロパティに-1
が返されます。これは仕様です。コマンドは内部的にthread_infoを使用していますが,Rosettaで動作しているIntelアプリケーションには,CPUの情報が返されないようです。
HTTP SET OPTION
で設定できるHTTP timeout
は,接続タイムアウトではありません。v18/19の初期リリースは,実装が間違っており,サーバー接続タイムアウト(サーバーがダウンしている場合,いつまでもレスポンスを待ち続けるようなことを避けるためのタイムアウト)にこのオプションが適用されていました。正しい動作は,HTTPレスポンスのタイムアウト(サーバーとの接続が確立された後,HTTPレスポンスが返されるまで待機する時間の上限)です。
更新:
下記の不具合修正も参照
HTTP SET OPTION
のHTTP timeout
オプションがHTTP Get
の動作に反映されませんでした。つまり,サーバー接続に成功し,なかなか応答が返されず,切断もされない場合,いつまでもレスポンスを待ちました。HTTP Request
を続けて何度も実行した場合,#17
(未実装の制御命令)エラーが返されることがありました。実際にはタイムアウトエラーが発生しています。HTTP SET OPTION
で設定した秒数以内にレスポンスを読むことができなかった場合にエラーが返されます。