月別アーカイブ: 2020年3月

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

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

4D プロジェクトフォームとテーブルフォーム、イベントプロパティが違う その1

4D プロジェクトフォームとテーブルフォーム、イベントプロパティが違う

DBを集計した結果を画面に表示して、それをそのまま印刷したいと考えた。結構複雑な集計表なので印刷用と2つ作って両方をメンテするのは面倒。複数のテーブルから情報収集しているので、この印刷フォームは特定のテーブルに帰属させたくない、ということでプロジェクトフォームを作った。

4Dのフォームにはテーブルフォームとプロジェクトフォームがあって、前者はテーブルに帰属している、テーブルが削除されると同時に削除される。後者はプロジェクトに帰属していて呼び出し方が異なる。4Dv17

テーブルフォームを開くときはテーブル名とフォーム名を与える:Open form window([Table1];”P01_Print”)

プロジェクトフォームを開くときはフォーム名だけ与える:Open form window(“P01_Print”)

集計結果を画面に表示したところまでは順調。画面表示用なので[印刷]ボタンと[キャンセル]ボタンがある。当然だ。でも印刷時にはこれらのボタンを隠したい。いつものようにフォームメソッドの「On Printing Detail」でObject set visibleしようかな、と。やろうとしたら、

◆ プロジェクトフォームのプロパティに「On Printing Detail」イベントがない!

テーブルフォームじゃないとこれらのイベントは取得できない、らしい。Object set visibleなどのコマンドはフォームオブジェクトがロードされた後でないとコマンドが無効になるので、フォームがロードされた後、印刷が始まる前までに実行したい。選択肢は次の2つ?

1)プロジェクトフォームのままで、「On Load」イベントでボタンを制御

2)テーブルフォームに変更して、「On Printing Detail」を使う

今回のケースでは、複数のテーブルからデータを集計するのだが、カレントセレクションは使わないためどちらのテーブルに帰属させても動きに問題はない。しかしどちらのテーブルにも帰属させたくない。あとでメンテするたびにどちらのテーブルか思い出す必要があったりするので。

とりあえず1)を試す。

◆ Print formコマンドで「On Load」イベントが来ない!

そうかもしれない、今回のケースでは自身のフォームが画面表示用としてすでにロードされているから。これが別のフォームを開く場合だったら[印刷]ボタンクリックのあとで別のフォームがロードされてOn Loadイベントが発生するのに。

ほかに方法もありそうだけど、このあたりで方針変更して、2)に宗旨替え。

で、どのテーブルに帰属させるか。昔プロジェクトフォームがなかった頃はすべてのがテーブルフォームだった。[Z_Dialog]とか[Z_UserInterfae]とかフォームを作るためだけのレコードのないテーブルを作ってた。これをやりたくなかったけど仕方がない。あとで探しやすいように印刷用フォーム専用の[Z_PrintForm]という名前のテーブルを作ることにした。フォームの名前はP01_のようにPで始めたり、PF01_のようにPFで始める。

以上が印刷用フォーム専用テーブル[Z_PrintForm]ができた背景。これは4Dv17の場合であり、将来の4Dでプロジェクトフォームでもテーブルフォームと同様に「On Printing Detail」がサポートされたら[Z_PrintForm]を廃止するか、というとそうでもない。印刷用フォームを1箇所に集めておく意味はありそうだし、これはこれで悪くないと思う、今のところは。

4D プロジェクトフォームとテーブルフォーム、イベントプロパティが違う その2

本棚追加

自力リフォームで本棚追加。上の棚が板厚24mmで重かったため、中段は板厚20mmでやってみた。材木店には「元の板厚が24mmだから薄くするとオガクズが多くなるだけ」と言われている。仕上がりのサイズは正確。

元の壁が杉、腰壁を自力で張って、ホワイトボードとディスプレイ(32inch)、時計をつけて、仕上げがこの本棚。

まだ材木が残っている。