📄 wwmask.pas
字号:
{*******************************************************}
{ }
{ Borland Delphi Visual Component Library }
{ }
{ Copyright (c) 1995-2001 Borland Software Corporation }
{ }
{*******************************************************}
unit wwmask;
{$R-,T-,H+,X+}
interface
uses Windows, SysUtils, Classes, StdCtrls, Controls, Messages,
Forms, Graphics, Menus, MaskUtils;
type
{ TCustomMaskEdit }
EDBEditError = class(Exception);
TwwMaskedState = set of (wwmsMasked, wwmsReEnter, wwmsDBSetText);
TwwSpecialMaskEdit = class(TCustomEdit)
private
FEditMask: TEditMask;
FMaskBlank: Char;
FMaxChars: Integer;
FMaskSave: Boolean;
FMaskState: TwwMaskedState;
FCaretPos: Integer;
FBtnDownX: Integer;
FOldValue: string;
FSettingCursor: Boolean;
function DoInputChar(var NewChar: Char; MaskOffset: Integer): Boolean;
function InputChar(var NewChar: Char; Offset: Integer): Boolean;
function DeleteSelection(var Value: string; Offset: Integer;
Len: Integer): Boolean;
function InputString(var Value: string; const NewValue: string;
Offset: Integer): Integer;
function AddEditFormat(const Value: string; Active: Boolean): string;
function RemoveEditFormat(const Value: string): string;
function FindLiteralChar (MaskOffset: Integer; InChar: Char): Integer;
function GetEditText: string;
function GetMasked: Boolean;
function GetText: TMaskedText;
function GetMaxLength: Integer;
function CharKeys(var CharCode: Char): Boolean;
procedure SetEditText(const Value: string);
procedure SetEditMask(const Value: TEditMask);
procedure SetMaxLength(Value: Integer);
procedure SetText(const Value: TMaskedText);
procedure DeleteKeys(CharCode: Word);
procedure HomeEndKeys(CharCode: Word; Shift: TShiftState);
procedure CursorInc(CursorPos: Integer; Incr: Integer);
procedure CursorDec(CursorPos: Integer);
procedure ArrowKeys(CharCode: Word; Shift: TShiftState);
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
procedure WMCut(var Message: TMessage); message WM_CUT;
procedure WMPaste(var Message: TMessage); message WM_PASTE;
procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
procedure CMExit(var Message: TCMExit); message CM_EXIT;
procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
procedure CMWantSpecialKey(var Message: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
protected
procedure ReformatText(const NewMask: string);
procedure GetSel(var SelStart: Integer; var SelStop: Integer);
procedure SetSel(SelStart: Integer; SelStop: Integer);
procedure SetCursor(Pos: Integer);
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
procedure KeyPress(var Key: Char); override;
function EditCanModify: Boolean; virtual;
procedure Reset; virtual;
function GetFirstEditChar: Integer;
function GetLastEditChar: Integer;
function GetNextEditChar(Offset: Integer): Integer;
function GetPriorEditChar(Offset: Integer): Integer;
function GetMaxChars: Integer;
function Validate(const Value: string; var Pos: Integer): Boolean; virtual;
procedure ValidateError; virtual;
procedure CheckCursor;
property EditMask: TEditMask read FEditMask write SetEditMask;
property MaskState: TwwMaskedState read FMaskState write FMaskState;
property MaxLength: Integer read GetMaxLength write SetMaxLength default 0;
Property SettingCursor read FSettingCursor;
public
constructor Create(AOwner: TComponent); override;
procedure ValidateEdit; virtual;
procedure Clear; override;
function GetTextLen: Integer;
property IsMasked: Boolean read GetMasked;
property EditText: string read GetEditText write SetEditText;
property Text: TMaskedText read GetText write SetText;
end;
implementation
uses Clipbrd, Consts;
{ TCustomMaskEdit }
constructor TwwSpecialMaskEdit.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMaskState := [];
FMaskBlank := DefaultBlank;
end;
procedure TwwSpecialMaskEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
if not FSettingCursor then inherited KeyDown(Key, Shift);
if IsMasked and (Key <> 0) and not (ssAlt in Shift) then
begin
if (Key = VK_LEFT) or(Key = VK_RIGHT) then
begin
ArrowKeys(Key, Shift);
if not ((ssShift in Shift) or (ssCtrl in Shift)) then
Key := 0;
Exit;
end
else if (Key = VK_UP) or(Key = VK_DOWN) then
begin
Key := 0;
Exit;
end
else if (Key = VK_HOME) or(Key = VK_END) then
begin
HomeEndKeys(Key, Shift);
Key := 0;
Exit;
end
else if ((Key = VK_DELETE) and not (ssShift in Shift)) or
(Key = VK_BACK) then
begin
if EditCanModify then
DeleteKeys(Key);
Key := 0;
Exit;
end;
CheckCursor;
end;
end;
procedure TwwSpecialMaskEdit.KeyUp(var Key: Word; Shift: TShiftState);
begin
if not FSettingCursor then inherited KeyUp(Key, Shift);
if IsMasked and (Key <> 0) then
begin
if ((Key = VK_LEFT) or(Key = VK_RIGHT)) and (ssCtrl in Shift) then
CheckCursor;
end;
end;
procedure TwwSpecialMaskEdit.KeyPress(var Key: Char);
begin
inherited KeyPress(Key);
if IsMasked and (Key <> #0) and not (Char(Key) in [^V, ^X, ^C]) then
begin
CharKeys(Key);
Key := #0;
end;
end;
procedure TwwSpecialMaskEdit.WMLButtonDown(var Message: TWMLButtonDown);
begin
inherited;
FBtnDownX := Message.XPos;
end;
procedure TwwSpecialMaskEdit.WMLButtonUp(var Message: TWMLButtonUp);
var
SelStart, SelStop : Integer;
begin
inherited;
if (IsMasked) then
begin
GetSel(SelStart, SelStop);
FCaretPos := SelStart;
if (SelStart <> SelStop) and (Message.XPos > FBtnDownX) then
FCaretPos := SelStop;
CheckCursor;
end;
end;
procedure TwwSpecialMaskEdit.WMSetFocus(var Message: TWMSetFocus);
begin
inherited;
if (IsMasked) then
CheckCursor;
end;
procedure TwwSpecialMaskEdit.SetEditText(const Value: string);
begin
if GetEditText <> Value then
begin
SetTextBuf(PChar(Value));
CheckCursor;
end;
end;
function TwwSpecialMaskEdit.GetEditText: string;
begin
Result := inherited Text;
end;
function TwwSpecialMaskEdit.GetTextLen: Integer;
begin
Result := Length(Text);
end;
function TwwSpecialMaskEdit.GetText: TMaskedText;
begin
if not IsMasked then
Result := inherited Text
else
begin
Result := RemoveEditFormat(EditText);
if FMaskSave then
Result := AddEditFormat(Result, False);
end;
end;
procedure TwwSpecialMaskEdit.SetText(const Value: TMaskedText);
var
OldText: string;
Pos: Integer;
begin
if not IsMasked then
inherited Text := Value
else
begin
OldText := Value;
if FMaskSave then
OldText := PadInputLiterals(EditMask, OldText, FMaskBlank)
else
OldText := AddEditFormat(OldText, True);
if not (wwmsDBSetText in FMaskState) and
(csDesigning in ComponentState) and
not (csLoading in ComponentState) and
not Validate(OldText, Pos) then
raise EDBEditError.CreateRes(@SMaskErr);
EditText := OldText;
end;
end;
procedure TwwSpecialMaskEdit.WMCut(var Message: TMessage);
begin
if not (IsMasked) then
inherited
else
begin
CopyToClipboard;
DeleteKeys(VK_DELETE);
end;
end;
procedure TwwSpecialMaskEdit.WMPaste(var Message: TMessage);
var
Value: string;
Str: string;
SelStart, SelStop : Integer;
begin
if not (IsMasked) or ReadOnly then
inherited
else
begin
Clipboard.Open;
Value := Clipboard.AsText;
Clipboard.Close;
GetSel(SelStart, SelStop);
Str := EditText;
DeleteSelection(Str, SelStart, SelStop - SelStart);
EditText := Str;
SelStart := InputString(Str, Value, SelStart);
EditText := Str;
SetCursor(SelStart);
end;
end;
function TwwSpecialMaskEdit.GetMasked: Boolean;
begin
Result := EditMask <> '';
end;
function TwwSpecialMaskEdit.GetMaxChars: Integer;
begin
if IsMasked then
Result := FMaxChars
else
Result := inherited GetTextLen;
end;
procedure TwwSpecialMaskEdit.ReformatText(const NewMask: string);
var
OldText: string;
begin
OldText := RemoveEditFormat(EditText);
FEditMask := NewMask;
FMaxChars := MaskOffsetToOffset(EditMask, Length(NewMask));
FMaskSave := MaskGetMaskSave(NewMask);
FMaskBlank := MaskGetMaskBlank(NewMask);
OldText := AddEditFormat(OldText, True);
EditText := OldText;
end;
procedure TwwSpecialMaskEdit.SetEditMask(const Value: TEditMask);
var
SelStart, SelStop: Integer;
begin
if Value <> EditMask then
begin
if (csDesigning in ComponentState) and (Value <> '') and
not (csLoading in ComponentState) then
EditText := '';
if HandleAllocated then GetSel(SelStart, SelStop);
ReformatText(Value);
Exclude(FMaskState, wwmsMasked);
if EditMask <> '' then Include(FMaskState, wwmsMasked);
inherited MaxLength := 0;
if IsMasked and (FMaxChars > 0) then
inherited MaxLength := FMaxChars;
if HandleAllocated and (GetFocus = Handle) and
not (csDesigning in ComponentState) then
SetCursor(SelStart);
end;
end;
function TwwSpecialMaskEdit.GetMaxLength: Integer;
begin
Result := inherited MaxLength;
end;
procedure TwwSpecialMaskEdit.SetMaxLength(Value: Integer);
begin
if not IsMasked then
inherited MaxLength := Value
else
inherited MaxLength := FMaxChars;
end;
procedure TwwSpecialMaskEdit.GetSel(var SelStart: Integer; var SelStop: Integer);
begin
SendMessage(Handle, EM_GETSEL, Integer(@SelStart), Integer(@SelStop));
end;
procedure TwwSpecialMaskEdit.SetSel(SelStart: Integer; SelStop: Integer);
begin
SendMessage(Handle, EM_SETSEL, SelStart, SelStop);
end;
procedure TwwSpecialMaskEdit.SetCursor(Pos: Integer);
const
ArrowKey: array[Boolean] of Word = (VK_LEFT, VK_RIGHT);
var
SelStart, SelStop: Integer;
KeyState: TKeyboardState;
NewKeyState: TKeyboardState;
I: Integer;
begin
if (Pos >= 1) and (ByteType(EditText, Pos) = mbLeadByte) then Dec(Pos);
SelStart := Pos;
if (IsMasked) then
begin
if SelStart < 0 then
SelStart := 0;
SelStop := SelStart + 1;
if (Length(EditText) > SelStop) and (EditText[SelStop] in LeadBytes) then
Inc(SelStop);
if SelStart >= FMaxChars then
begin
SelStart := FMaxChars;
SelStop := SelStart;
end;
SetSel(SelStop, SelStop);
if SelStart <> SelStop then
begin
GetKeyboardState(KeyState);
for I := Low(NewKeyState) to High(NewKeyState) do
NewKeyState[I] := 0;
NewKeyState [VK_SHIFT] := $81;
NewKeyState [ArrowKey[UseRightToLeftAlignment]] := $81;
SetKeyboardState(NewKeyState);
FSettingCursor := True;
try
SendMessage(Handle, WM_KEYDOWN, ArrowKey[UseRightToLeftAlignment], 1);
SendMessage(Handle, WM_KEYUP, ArrowKey[UseRightToLeftAlignment], 1);
finally
FSettingCursor := False;
end;
SetKeyboardState(KeyState);
end;
FCaretPos := SelStart;
end
else
begin
if SelStart < 0 then
SelStart := 0;
if SelStart >= Length(EditText) then
SelStart := Length(EditText);
SetSel(SelStart, SelStart);
end;
end;
procedure TwwSpecialMaskEdit.CheckCursor;
var
SelStart, SelStop: Integer;
begin
if not HandleAllocated then Exit;
if (IsMasked) then
begin
GetSel(SelStart, SelStop);
if SelStart = SelStop then
SetCursor(SelStart);
end;
end;
procedure TwwSpecialMaskEdit.Clear;
begin
Text := '';
end;
function TwwSpecialMaskEdit.EditCanModify: Boolean;
begin
Result := True;
end;
procedure TwwSpecialMaskEdit.Reset;
begin
if Modified then
begin
EditText := FOldValue;
Modified := False;
end;
end;
function TwwSpecialMaskEdit.CharKeys(var CharCode: Char): Boolean;
var
SelStart, SelStop : Integer;
Txt: string;
CharMsg: TMsg;
begin
Result := False;
if Word(CharCode) = VK_ESCAPE then
begin
Reset;
Exit;
end;
if not EditCanModify or ReadOnly then Exit;
if (Word(CharCode) = VK_BACK) then Exit;
if (Word(CharCode) = VK_RETURN) then
begin
ValidateEdit;
Exit;
end;
GetSel(SelStart, SelStop);
if (SelStop - SelStart) > 1 then
begin
DeleteKeys(VK_DELETE);
SelStart := GetNextEditChar(SelStart);
SetCursor(SelStart);
end;
if (CharCode in LeadBytes) then
if PeekMessage(CharMsg, Handle, WM_CHAR, WM_CHAR, PM_REMOVE) then
if CharMsg.Message = WM_Quit then
PostQuitMessage(CharMsg.wparam);
Result := InputChar(CharCode, SelStart);
if Result then
begin
if (CharCode in LeadBytes) then
begin
Txt := CharCode + Char(CharMsg.wParam);
SetSel(SelStart, SelStart + 2);
end
else
Txt := CharCode;
SendMessage(Handle, EM_REPLACESEL, 0, LongInt(PChar(Txt)));
GetSel(SelStart, SelStop);
CursorInc(SelStart, 0);
end;
end;
procedure TwwSpecialMaskEdit.ArrowKeys(CharCode: Word; Shift: TShiftState);
var
SelStart, SelStop : Integer;
begin
if (ssCtrl in Shift) then Exit;
GetSel(SelStart, SelStop);
if (ssShift in Shift) then
begin
if (CharCode = VK_RIGHT) then
begin
Inc(FCaretPos);
if (SelStop = SelStart + 1) then
begin
SetSel(SelStart, SelStop); {reset caret to end of string}
Inc(FCaretPos);
end;
if FCaretPos > FMaxChars then FCaretPos := FMaxChars;
end
else {if (CharCode = VK_LEFT) then}
begin
Dec(FCaretPos);
if (SelStop = SelStart + 2) and
(FCaretPos > SelStart) then
begin
SetSel(SelStart + 1, SelStart + 1); {reset caret to show up at start}
Dec(FCaretPos);
end;
if FCaretPos < 0 then FCaretPos := 0;
end;
end
else
begin
if (SelStop - SelStart) > 1 then
begin
if ((SelStop - SelStart) = 2) and (EditText[SelStart+1] in LeadBytes) then
begin
if (CharCode = VK_LEFT) then
CursorDec(SelStart)
else
CursorInc(SelStart, 2);
Exit;
end;
if SelStop = FCaretPos then
Dec(FCaretPos);
SetCursor(FCaretPos);
end
else if (CharCode = VK_LEFT) then
CursorDec(SelStart)
else { if (CharCode = VK_RIGHT) then }
begin
if SelStop = SelStart then
SetCursor(SelStart)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -