4D」カテゴリーアーカイブ

4DのDrug and Drop

4D Drug & Drop

ひとつの画面に複数の画像を表示する仕組みを考えていた。画像は外部ファイルを想定、多くて10個くらいあるのだが、要望としては代表的な画像を2個登録したい、ということだった。例えば画像は2個と限定してピクチャー変数を2つ配置しておけば、ドラッグ&ドロップを2回やれば画像登録ができる。操作も実装も簡単だ。しかしプログラマーとしては、3個以上の画像がありうるのに2個に制限して良しとするのは敗北感がある。

そこで考えた。リストボックスがいいんじゃないか?リストボックスなら画像をいくら追加しても大丈夫。行が増えていけば勝手にスクロールしてくれる。画像の数を制限しなくて済む。画像は別テーブルに保存すれば良い。

いつものようにリストボックスの上に[+]と[ー]のボタンを置いて、[+]クリックで表示されたダイアログにピクチャー変数を配置してドラッグ&ドロップしてもらって、という仕様で実装した。

これだとダイアログボックスを開いて閉じるのが面倒。もともとの要望の通り、ピクチャー変数を2個、配置しておけば、ドラッグ&ドロップを2回やれば画像登録ができる。その方がユーザは簡単だ。同じように簡単な操作で複数の画像を登録する方法はないのだろうか?

リストボックスに画像をドロップすればいいのでは?

リストボックスに画像をドロップしたら行が増えていくようにすれば操作性は悪くない。ドロップのたびに行を追加、削除するときは[ー]ボタン。増やしたり減らしたり、縦スクロールなら実装も簡単そうだ。

ただリストボックスに画像をドロップしても標準的な機能では受け取ってくれない。リストボックスのOnDropイベントにコードを書くことになる。OnDropで配列要素を増やして、画像列に取得した画像を代入すればいい。と、ここまでわかったところで気がついた。一般に4DでDrug&Dropをい実装する場合は、フォームオブジェクトが勝手に処理してくれるからコードを書く必要がない。マニュアルサイトを見ても、イベントを取得したあと、ドロップされたコンテンツをどうやって受け取るか、よくわからない。

とりあえずリストボックスにイベントハンドラを書いて。

ドロップされた画像はドラッグ&ドロップ専用のペーストボードから取得するそうです。

GET PICTURE FROM PASTEBOARD($picture)

OnDropで呼ばれるコードはこれ。

リストボックスに行を追加したり、自動スクロールさせたり、ついでにドロップされたファイルのパスを取り出したり、している。

ドロップされた直後に行を選択して、自動スクロールさせていてる

4D macOSでプロジェクトのパッケージ化をやめる

いつも使っているのがMacBook Pro(13-inch 2018)なので、4DのプロジェクトもmacOSで開発している。Windowsで動かす場合もコーディングはmacOS。Windowsを使うのはたまにフォームを調整する時だけだ。最近わかったことだがメイリオフォントを使うとWindowsとほぼ同じレイアウトになる。例えばリストボックスの列幅にはソートマーク表示用に余裕を持たせるなど、少しのケアで調整はいらなくなる。要はmacOSとWindowsで同じフォントを使えば良いのだ。MSゴシックやMS明朝もあるけどこちらは試していない。

さて本題。4D macOS版でプロジェクトを作ると、ストラクチャファイル(「.4DB」ファイル)は「.4dbase」という拡張子がついたフォルダの中に生成される。この. 4dbaseフォルダがmacOSの「パッケージ」だ。パッケージは特殊なフォルダで、アイコンをつけたり、ダブルクリックで中の所定のファイルを開くことができる、macOSが提供してくれる便利?な機能だ。

プロジェクトフォルダはパッケージなので選択しただけでは中は見えない

例えばmacOSのアプリケーションフォルダに並んでいるアプリはダブルクリックすると起動する。アイコンもついてる。実行ファイルのように見えるが実態は「.app」という拡張子がついたパッケージ。多数のファイルで構成されているアプリでもパッケージでまとまっているためにスッキリしている。アプリを起動する時、アプリケーションフォルダを開いて、そこに並んでいるアプリのフォルダを開いて、その中のアプリ本体を見極めてダブルクリックするよりは、アイコンのついた.appをダブルクリックした方が楽だろう。1階層ほじらなくて済む。

4Dのパッケージに話を戻そう。この.4dbaseのアイコンをダブルクリックすると4Dが起動してプロジェクトが開く。4Dでアプリ開発の続きをやるだけなら1階層ほじって.4DBファイルをダブルクリックする必要はない。

リリース時にはストラクチャファイルやデータファイル(「.4DD」ファイル)を操作することになる。ストラクチャファイルを取り出して圧縮したり、開発用のデータファイルを本番データに入れ替えてから圧縮したりする。プロジェクトのパッケージを右クリックして「パッケージの内容を表示」を実行する。ウインドウに表示された.4DBファイルを選択して、ドラッグしたりして移動させてから圧縮する。

パッケージを右クリック

元のフォルダに戻るときはウインドウタイトルを右クリックしてプルダウンメニューを表示させて、階層が1つ上のフォルダを選択する。このようにmacOSで作業するときはパッケージの中に入ったり出たりしている。

ウインドウタイトルを右クリック

これってもしかして面倒臭い?

Windowsに持っていくとパッケージはフォルダとして認識されるし、そもそもパッケージ化が必要なのかを自問してみると、

1)パッケージをダブルクリックしてプロジェクトを開くことはしない
 → パッケージに中の「.4DB」ファイルをDockの4Dアイコンにドロップして開いている。ちなみに現在のDockにはv15からv18までの4Dと4D Serverが並んでいる。

2)「Resources」フォルダ、「WebFolder」フォルダ、「Components」フォルダの中身を操作することは多い

3)データファイルを操作する
 データが巨大なために「.4DD」ファイルを差し替えてから圧縮するプロジェクトもある。

4)いつものことだが頻繁にリリース作業を行っている
 ビルドしてリリースするものもあるが、「.4DB」ファイルと「.4Dindy」ファイルを圧縮して送ることが多い。パッケージの中に入ったり出たりすることになる。

長年付き合ってきて名残惜しい気もするがパッケージは邪魔でしかないという考えに到達した。やめるのは簡単だ。パッケージについている「. 4dbase」という拡張子を削除するだけ。4D的には何も問題はないらしい。現にWindowsではこの機能は使えないし。

やってみたら快適だった。クリックするだけでプロジェクトフォルダに出たり入ったりできる。当たり前だけど。

普通のフォルダ

少しだけ弊害があった。プロジェクトフォルダがわかりにくくなったのだ。今まではアイコンがついていたので識別しやすかったし、パッケージの中は4Dの管理下にあるファイルでその外側は自分で入れたファイル、という境界をはっきりと意識できていたのが薄れてしまった。なるほどパッケージにも一利あったのだ、と思いつつも面倒が減ったからこれでしばらくやってみよう。

4D v18のテキストベースプロジェクトでgit

4Dはv18から、プロジェクト全体をテキストファイルに書き出してgitで管理できるようになった(涙)。これまでは自力でメソッドを外部テキストファイルに書き出して共通ライブラリメソッドだけgitでバージョン管理していた。フォームはテキストに書き出すことができないし、データ構造は別の仕掛けで書き出していたり面倒だし、なんといっても自力で書き出した情報は一体として動くプロジェクトを保証するものではなかった。

早速やってみよう。今回の目的は、半年間の間に行われたあるプロジェクトの変更内容を調べるというものだ。ローカルリポジトリを使って半年前のプロジェクトと今のプロジェクトを比べる。リモートのリポジトリは不要だ。

ステップ1 プロジェクトに書き出し

20190530のソースv17をv18で開いて「ストラクチャーをプロジェクトに書き出し」を実行。パッケージの中に「Project」フォルダができている(A)。

「Sources」フォルダを見てみると感動。フォーム、メソッド、テーブルフォームとそれらやオブジェクトのメソッドが並んでいる。フォームには「.4DForm」メソッドには「.4dm」という拡張子がついているのですぐわかる。

20191217のソースv17をv18で開いて「ストラクチャーをプロジェクトに書き出し」を実行。同じように「Project」フォルダができている(B)。

ステップ2 gitリポジトリを作る

次にgitフォルダを作る。ここでは「git_work」というフォルダを作っておく。ここにgitのリポジトリを作るのだ。gitのコマンドラインツールを使う方法もあるけど、差分をグラフィカルに見たいので今回は「GitHub」アプリを使った。

File -> New Repositoryを実行。リポジトリ名「dcc_git」、git_workを選択する。

ステップ3 リポジトリに「Project」ファイルを保存してコミット

(A)を「dcc_git」フォルダにコピー。GitHubでリポジトリを開くとソースが並んでいる。

SummaryとDescriptionをタイプインして[Commit to master]をクリック。これで最初のテキストファイル群がgitリポジトリに書き込まれた。

ステップ4 比較対象の「Project」ファイルを保存

最初にコピーした(A)を(B)で上書きして(A)がなくなってしまうのだが、ご心配なく。すでに(A)の内容はgitのコミットコマンドによって.gitファイルにコピーされているのだ。.gitは隠しファイルなのでターミナルアプリを使って確認できる。さあ(A)を上書きして(B)を置き換えよう。

ステップ5 GitHubで変更箇所を確認

GtHubアプリを起動して、リポジトリ「dcc_git」を見ると...。48箇所変更されていると表示されている。4dFormをクリックすると...うう感動。フォームの修正箇所、この場合座標値が変更されているのがわかる。うれしい。

フォームの座標値が変更されたことがわかる。ピクセル単位。
メソッドはこんな風に

修正箇所がすべてリストアップされている。やってくれました4Dv18。これからの4Dライフが大きく変化しそうな瞬間でした。

思えば2014年のDeveloper Summitでフランスに行ったとき「フォームをプログラムで作成したり修正することができないの?」と質問、そのときはv15では予定なしと言われた。今回のテキストベースプロジェクトの仕組みを使えば、メソッドでフォームを生成したり、修正することができる。こんな形になって実装されてくるとは。


4D notarizeその2

2020年4月、4DでビルドしたmacOS Catalina配布アプリを作ったときのメモ。2019年からCatalina用にnotarizeして配布していたのだがそのときの手順どおりにうまくいかない。2020年2月、アップルの方針が変わったらしい。32bitコードが含まれているとnotarizeで承認されない、というのが本題なのだが、本題の前にいくつか障害があって手間取った。思えば2019年は「2ファクター認証」や「Catalinaのためのnotarize」でハマった。障害を乗り越えて安心しているとすぐにまた新たな障害が現れる、いつものことだ。次はハマりたくないと思ってこのメモを書いている。このメモも将来役に立つかどうかはわからないが、ないよりマシだろう。

4Dでビルドするアプリは、Xcodeでビルドするアプリと異なり、ターミナルからcodesign、xcrunを使う。今回のポイントは2段階あって、1段階目はxcrun altool ―notarize-appがエラーになる段階(レベル1)、2段階目はxcrunは成功してUploadedになるのだがnotarizeで承認されない段階(レベル2)。

(レベル1)

xcrun altool –notarize-appが失敗。

本当はここの話の方が長くなるけどさらっと

1)Apple Developer Connectionでライセンスを承認していなかった。 → パスワードとかやばかったけどクリア。承認はオーナーでログイン。

2)AppStore connectに署名サインが必要 You must first sign the relevant contracts online. (1048) → ログインして「有料アプリケーション契約」に署名

3)MojaveでXcode 11.2.1のxcrunが使えない? → MojaveでXcode 10.3をインストールして実行。自分のマシンをCatalinaにしたくないのだ。

4)App用パスワードが無効になっていた → 別のCatalinaマシンでビルドしようとした際にiCloudの同期でおかしくなった? → パスワード再作成

これもxcrunが失敗。「app-specific passwordでサインインしてね。パスワードはappleid.apple.comで作れるよ」と言っている
アップロードが成功した時のメッセージ


(レベル2)

5)notarizeコマンドにHardened Runtimeオプション → オプションをつけた

–options=runtime

6)32bitコードが承認されない

→ ここからの話は長い。

Uploadedになると、notarizeの結果がメールで送られてくる。すぐに結果が見れないのはnotarizeに時間がかかるからだが、実際には数分待たされるだけ。で、結果はログに出力される。not approvedの場合、ログに理由が書いてあるので簡単に対策が立てられるはずだ。レベル1とはハマり方が違って楽勝だろう。まずi386とかログに出てる。

32bitコードが含まれていると承認されない、という話を聞いて、さっそく4Dプロジェクトのデータベース設定で、マルチターゲットコンパイルのチェックをオフと思ったら、ここはチェックされてなかった。次はコンポーネントのプロジェクトをチェック。こちらはマルチターゲットコンパイルがチェックされていたのでオフに。それでも通らない。楽勝ではなさそうだ。

notarizeのlogは、たとえば次のように見る。最初はメールを待っていたのだが、ダメな時のメールにはログを見ろとしか書いてないし、メールを取るまでの手間もあるので、こちらのほうが早く結果を知ることができる。暗号のようなところがuuidで、Uploadedが成功した時のメッセージに出力されているのをコピーして使う。たとえば、

xcrun altool –notarization-info b7229996-bdb8-48d4-82d7-467d5317efdd -u “wataru@jirokichi.jp” –password “@keychain:AC_PASSWORD””

Upload成功後にすぐに実行すると初めは「in progres」、これが出ればUploadのuuidが正しくコピペできたことがわかる。5分後くらいにもう一度実行する。審査が終わっていれば次のような結果が表示される。

nortarize失敗。Package Invalid

反転箇所のURLをコピーしてブラウザで見ると、

      “architecture”: “i386”

のところが32bitコードが含まれている、という意味らしい。

ビルドしたコードに32bitコードが含まれている?もしかして4Dの4D Volume Desktop.appに含まれているのでは?と思ってnotarizeのlogをよく見てみると、そのようだ。まず引っかかったのが「php-fcgi-4d」。次に「InternetCommands」。4D v17.4 mac版には32bitコードが含まれていない、はずなのだが、なぜかビルドした結果の.appには含まれてしまっているようだ。サポートにVoumeDesktopには4D Internet Commands.bundleに含まれている。「Windows」フォルダがあってここにWin32用のコードが含まれている、と聞いてこれをappのパッケージから削除しても結果は変わらず、承認されない。

で、4D v18.1に移行した。コンパイルしてビルド。codesignしてnotarize、あっさり承認された。4D v18 + Catalinaではまた別の変更があって新たな障害となって立ちふさがってくれるのだが...その話はまた後ほど。

参考サイト:

https://miyako.github.io/2019/10/16/notarization.html


4D 文字列の最初の30バイトまでを切り出す方法は?

文字列を頭からバイト数で切り出す

4D v17

文字数ではなくてバイト数?

もともとコンピュータはバイトの世界、全角も半角も文字数を間違わずに計算してくれているので今は意識することが少なくなった。いまどきバイト数を気にするのはC言語使ってるプログラマが構造体のオフセットを考えている時だけかもしれない。

4D v17には文字列の長さを取得するコマンドはある。Lengthだ。文字数を返す。全角・半角混じりの場合はうまいこと文字数を返す。ただしその文字数が何バイトかわからない。文字列の長さをバイト数で取得したい、ということでコマンドを探してみたら、ない。

そこで文字列のバイト数を返すメソッド「zz_byte_Substring」を作ってみた。ので紹介する。全角半角が混じるので全角文字の途中で切ることをしないとすれば実際は30バイトちょうどにはならない、という仕様はご承知いただきたい。

実装のポイントはバイト数を返すだけのメソッド「zz_byte_GetLen」を別モジュールにしたこと。

//zz_byte_GetLen
//文字列のバイト数を返す
C_TEXT($1;$inStr)
$inStr:=$1
C_LONGINT($0;$sizeOfBlob)
$sizeOfBlob:=$0
C_BLOB($blob)

TEXT TO BLOB($inStr;$blob)
$sizeOfBlob:=BLOB size($blob)

$0:=$sizeOfBlob

このプログラムでバイト数を計算する。BLOB型の変数に代入してBLOB sizeを使った。

図2

zz_byte_GetLenは、(半角文字数 x 1) + (全角文字数 x 2) + 1を返すみたいだ。おそらく最後の1バイトは文字列の終端を示す区切り文字だと思われる。呼び元のメソッドzz_byte_Substringでは、この文字を含めて上限バイト数とする。上限バイト数は引数でもらうようにした。whileループで文字列を一文字ずつ少なくしていって、30byte以下になったところで止めれば良い。

次のようなコード。

//zz_byte_Substring
//20200317 wat
//指定されたバイト数で、文字化けしないように文字列を切る。

C_TEXT($1;$inStr)
$inStr:=$1
C_LONGINT($2;$inByteLen)
$inByteLen:=$2
C_TEXT($0;$outStr)
$outStr:=$inStr
C_LONGINT($byteLen)

//バイト数を取得
$byteLen:=zz_byte_GetLen ($outStr)
$outStr:=$inStr

While ($byteLen>$inByteLen)
//文字を一つ減らして、バイト数を取得
$outStr:=Substring($outStr;1;Length($outStr)-1)
$byteLen:=zz_byte_GetLen ($outStr)

End while
$0:=$outStr

これでバイト数で切り出すメソッド完成。