2012年12月15日

クラスヘルパーでTCustomEdit以下のMaxLengthをバイト数での制限に一括変更!

[この記事は"Delphi Advent Calendar"参加記事です]

さて、現在の会社に入社して8年...長いことDelphi7を使い続けていましたが、この度XE3が導入されました〜(^^)

#ちと個人では手が出ない...(^^; どうせならEnterpriseとかが欲しいから...(^^;

その間にUNICODE化、Generics、などなど色んな変化があった模様です。

#すっかり浦島太郎状態...(^^;

そんな中、UNICODE化した事で、TCustomEdit以下のMaxLengthの挙動がバイト数から文字数の判断に変わっているじゃあ〜〜〜りませんか!

#勿論UNICODE化している以上、当然の動きなんですが(^^;

でも現実問題として、XE3でもMaxLengthはバイト数判断で使いたい!(しかもコンポ側には触らずに、自動的に)
そこで、クラスヘルパーに目を付けて試行錯誤してみました。

手法)
 ・フォーム生成時にTCustomEdit継承インスタンスのOnKeyPressイベントを自前のものに差し替える
   →元のイベントは別途記録。
 ・自前のOnKeyPressの中で、入力済みのテキストとキー入力をバイト数で判断、オーバー時はKey := #0で無効化する

...と書くとこれだけでも、ここに至るまでは、なかなか一筋縄では行かなかった(^^;
色々と悩んだものの、VCLの途中に介入できるのは有難いなぁと思いました。


-----------------------------------------------------------------------------
unit VCLHelper;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Generics.Collections,
KEdit;

type
// フォーム生成時に細工をする
TApplicationHelper = class helper for TApplication
procedure CreateForm(InstanceClass: TComponentClass; var Reference);
end;

TCustomEditHelper = class helper for TCustomEdit
// OnKeyPress差し替えの実行箇所
procedure SetKeyPress();
// 差し替えられる側のOnKeyPressイベント
procedure AOnKeyPress(Sender: TObject; var Key: Char);
end;

implementation

var
// 差し替え前のOnKeyPressイベントを記録
// ※クラスヘルパーでフィールドを定義できれば不要なんだけどね...
lstWinCtrlOnKeyPress: TDictionary;

{ TApplicationHelper }

procedure TApplicationHelper.CreateForm(InstanceClass: TComponentClass;
var Reference);
var
i: integer;
begin
inherited CreateForm(InstanceClass, Reference);

// 生成したフォームのTCustomEdit継承インスタンスのOnKeyPressイベントを差し替える
// ※SetKeyPress()もクラスヘルパーで実装
for i := 0 to TForm(Reference).ComponentCount - 1 do begin
if TForm(Reference).Components[i] is TCustomEdit then begin
TCustomEdit(TForm(Reference).Components[i]).SetKeyPress();
end;
end;
end;

{ TCustomEditHelper }

procedure TCustomEditHelper.SetKeyPress();
begin
// 元々のOnKeyPressイベントを記録
lstWinCtrlOnKeyPress.Add(Self, Self.OnKeyPress);
// 差し替え
Self.OnKeyPress := AOnKeyPress;
end;

// 差し替えられる方のOnKeyPressイベント
procedure TCustomEditHelper.AOnKeyPress(Sender: TObject; var Key: Char);
var
orgKeyPress: TKeyPressEvent;
sNew: string;
sAnsiNew: AnsiString;
begin
// 差し替え前のOnKeyPressイベントを召還
orgKeyPress := lstWinCtrlOnKeyPress.Items[TCustomEdit(Sender)];

if Assigned(orgKeyPress) then begin
// 差し替え前のOnKeyPressイベントが実装されている場合、実行
orgKeyPress(Sender, Key);
end;

// これ以下ぐらいがコントロールコードだろうという雑な判断
// ※必要なら厳密に
if Key < #20 then begin
// チェック対象外
exit;
end;

// MaxLengthの設定が存在する場合、バイト数でチェック
if Maxlength > 0 then begin
// 設定あり、チェック
// ※ここも、SelText分を引いたりなど、もっと使い勝手を良くできる部分
sNew := Text + Key;
sAnsiNew := sNew;
if Length(sAnsiNew) > MaxLength then begin
// 含めるとオーバーするので、この入力をキャンセル
Key := #0;
end;
end;
end;

initialization
lstWinCtrlOnKeyPress := TDictionary.Create;

finalization
lstWinCtrlOnKeyPress.Free;

end.
-----------------------------------------------------------------------------


#後は必要に応じて元のOnKeyPressイベントを返す関数を足したり...

これをメインフォームなどでusesすれば、後は勝手に動いてくれます...くれるはずです(^^;
...実は他にもっと良い手があるのかもしれませんが(^^;


posted by ありい at 01:44| Comment(0) | TrackBack(0) | Delphi | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。