∵ なぜならば

映画とかネットとかパソコンとかコミックとか音楽とか……

覚え書き:UniCode 混じりの文字列長さ

2020-10-24 10:54:27 | Delphi

その昔日本語(Shift-JIS)は半角と全角しかなかったので「半角文字か2バイト文字」とか判別していた
「半角かな」も混じっていたし当時のコンパイラの長さを求める関数も「あいう」なら「6」と返していた
(秀丸マクロは互換性のためいまでも全角文字は2文字として数えます)
UniCode が広まってもうその考えもほぼほぼ不要になってきて全ての種類を判断して「文字」として数えてくれるようになった
ただ簡単で便利になった反面場合によってはそんな仕様がかえって困ることになる


今回の
┌―――┐
|あいう|
└―――┘
選択文字を罫線で囲むというだけの簡単なマクロでも罫線「―」は全角なので
┌―――┐
|aいう|
└―――┘
の様な場合に判別して後ろに半角スペースを追加しなければならない
このとき UniCode が混ざると昔ながらの方法で単純に「AnsiString」に変換して長さを測るとかは出来ない
┌―――┐
|আ¶£|
└―――┘
とかなるときにどう判断すればいいのかと考えた結果単純な方法でやっつけた



//半角英数字の長さなら何文字か返す
//KiriAge が True なら小数値は切り上げ False なら四捨五入
function ASCIILength(S:string;KiriAge:Boolean):integer;
var
  F:Extended;
begin
  F:=Canvas.TextWidth(S)/Canvas.TextWidth('q');//Canvas が等幅フォント前提
  if KiriAge then
  begin
    if  Frac(F)<>0 then Result:=Trunc(F)+1 else Result:=Trunc(F);
  end else
  begin
    if F>=0 then Result:=Trunc(F+0.5) else Result:=Trunc(F-0.5);
  end;
end;

それは半角英数字の何文字相当なのかという関数
中でやってることは「とりあえず書いたらどれだけの長さになるのか」だけ

多分これで解決したんだけれどもそんなことをやっているとき秀丸を見て気づいたんだけど
同じフォントにしても微妙に違うの笑う

バグ修正時の覚え書き

2020-10-18 22:09:48 | Delphi
『マルチモニタで使用時マイナス座標側で最大化のまま終了したとき次回起動時にメインモニタ側に最大化表示される』
という件の調査と修正を行ったんだけど

フォーム位置の再現はオリジナル(NanaTree)の頃から JEDI の TJvDockVSNetStyle 任せで
彼は本来メインフォームのサイズや位置とかを意識しているわけではなくて全ての窓のドッキング状態を管理するコンポーネントなので最大化なども「WindowState の変更」ではなく「Align := alClient」とかいうことをしているみたいとわかる

WindowState だとアクティブなところで最大化するんだけど
「Align」の方では Windows の仕様で常にプライマリモニタの作業領域が基準になる(https://groups.google.com/forum/#!topic/delphicbuilder-ml-archive/OJ1LBlNOMJU)のが原因だったようで

結局終了時に「現在のモニタナンバー」を記録しておいて
Ini.WriteInteger('MonitorNum',Monitor.MonitorNum);
起動時に「最大化していて」なおかつ「前回のモニタを違う」場合
if (IsZoomed(Self.Handle)) and(OldMonitorNum<>Monitor.MonitorNum) then
一端元のサイズに戻し
Self.WindowState:=wsNormal;
前回のモニタ位置に移動してから
Self.Left:=Left+Screen.Monitors[OldMonitorNum].Left;
Self.Top:=Left+Screen.Monitors[OldMonitorNum].Top;
再び最大化する
Self.WindowState:=wsMaximized;
ことで解決しました
(ここはもしかしたら一発で MonitorNum の移動が出来るのかも知れない)

しかしこうやって調べてたら TJvDockVSNetStyle って終了時に記録するとき最大化してたら元の位置を忘れちゃうのね
おいらは今まで TWindowPlacement で「最大化解除した時の位置とサイズを」きちんと保存する習慣があったから結構以外だったわ



余談
Delphi 関連をググってると結構自動翻訳された海外の掲示板とかがヒットするんだけど

モニターが変更された通知を受け取るとき自前で SendMessage で WM_WTSSESSION_CHANGE を送らなければならないと紹介されてて
他の人の発言で

私は古いバージョンDelphi5でこれをテストし、それだけに簡単に働いた:

Screen.Free;
Screen := TScreen.Create(Nil);

こんなアプローチがあって面白かった