📄 jvcomctrls.pas
字号:
FRange := TJvIPAddressRange.Create(Self);
FAddressValues := TJvIPAddressValues.Create;
FAddressValues.OnChange := DoAddressChange;
FAddressValues.OnChanging := DoAddressChanging;
FTabThroughFields := True;
Color := clWindow;
ParentColor := False;
TabStop := True;
Width := 150;
AdjustHeight;
for I := 0 to High(FEditControls) do
FEditControls[I] := TJvIPEditControlHelper.Create(Self);
end;
destructor TJvIPAddress.Destroy;
var
I: Integer;
begin
FreeAndNil(FRange);
FreeAndNil(FAddressValues);
inherited Destroy;
// (ahuser) I don't know why but TWinControl.DestroyWindowHandle raises an AV
// when FEditControls are released before inherited Destroy.
for I := 0 to High(FEditControls) do
FEditControls[I].Free;
end;
procedure TJvIPAddress.CreateParams(var Params: TCreateParams);
begin
InitCommonControl(ICC_INTERNET_CLASSES);
inherited CreateParams(Params);
CreateSubClass(Params, WC_IPADDRESS);
with Params do
begin
Style := Style or WS_CHILD;
WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW);
end;
end;
procedure TJvIPAddress.CreateWnd;
var
EditHandle: HWND;
Msg: TWMParentNotify;
begin
ClearEditControls;
FChanging := True;
try
inherited CreateWnd;
FRange.Change(-1);
if FSaveBlank then
ClearAddress
else
begin
Perform(IPM_SETADDRESS, 0, FAddress);
FAddressValues.Address := FAddress;
end;
if (FEditControlCount = 0) and (csDesigning in ComponentState) then
begin
// WM_PARENTNOTIFY messages are captured by the IDE starting when
// CreateWnd is called the second time. So we must find the edit controls
// ourself and simulate a WM_PARENTNOTIFY by a direct function call.
EditHandle := 0;
repeat
EditHandle := FindWindowEx(Handle, EditHandle, 'EDIT', nil);
if EditHandle <> 0 then
begin
Msg.Msg := WM_PARENTNOTIFY;
Msg.Event := WM_CREATE;
Msg.ChildID := GetDlgCtrlID(EditHandle);
Msg.ChildWnd := EditHandle;
WMParentNotify(Msg); // IDE captures WM_PARENTNOTIFY
end;
until EditHandle = 0;
end;
finally
FChanging := False;
end;
end;
procedure TJvIPAddress.DestroyLocalFont;
begin
if FLocalFont <> 0 then
begin
OSCheck(DeleteObject(FLocalFont));
FLocalFont := 0;
end;
end;
procedure TJvIPAddress.DestroyWnd;
begin
FSaveBlank := IsBlank;
inherited DestroyWnd;
end;
type
TWinControlAccess = class(TWinControl);
procedure TJvIPAddress.SelectTabControl(Previous: Boolean);
var
Control: TWinControl;
begin
Control := TWinControlAccess(Parent).FindNextControl(Self, not Previous, True, True);
if Control <> nil then
Control.SetFocus;
end;
procedure TJvIPAddress.WMKeyDown(var Msg: TWMKeyDown);
var
I, FocusIndex: Integer;
begin
if Msg.CharCode = VK_TAB then
begin
FocusIndex := -1;
for I := 0 to FEditControlCount - 1 do
begin
if FEditControls[I].Focused then
begin
FocusIndex := I;
Break;
end;
end;
if GetKeyState(VK_SHIFT) < 0 then
Dec(FocusIndex)
else
Inc(FocusIndex);
if FocusIndex >= 0 then
begin
if FocusIndex < FEditControlCount then
FEditControls[FocusIndex].SetFocus
else
SelectTabControl(False);
end
else
if FocusIndex = -1 then
SelectTabControl(True);
end
else
inherited;
end;
procedure TJvIPAddress.WMKeyUp(var Msg: TWMKeyUp);
begin
if Msg.CharCode = VK_TAB then
Msg.Result := 0
else
inherited;
end;
function TJvIPAddress.DoEraseBackground(Canvas: TCanvas; Param: Integer): Boolean;
begin
Canvas.Brush.Color := Color;
Canvas.FillRect(ClientRect);
Result := True;
end;
procedure TJvIPAddress.Paint;
var
I: Integer;
R1, R2: TRect;
X, Y: Integer;
Pt: TPoint;
begin
{ We paint the '.' ourself so we can also paint the control's background in
DoEraseBackground what would be impossible without self-painting because
the IP-Control always paints a clWindow background in WM_PAINT. }
for I := 0 to (FEditControlCount - 1) - 1 do
begin
GetWindowRect(FEditControls[I].Handle, R1);
GetWindowRect(FEditControls[I + 1].Handle, R2);
X := R1.Right + (R2.Left - R1.Right) div 2;
Y := R1.Top;
Pt := ScreenToClient(Point(X, Y));
Canvas.Font.Color := Font.Color;
Canvas.Brush.Color := Color;
Canvas.TextOut(Pt.X, Pt.Y, '.');
end;
end;
procedure TJvIPAddress.AdjustHeight;
var
DC: HDC;
SaveFont: HFONT;
// I: Integer;
// R: TRect;
Metrics: TTextMetric;
begin
DC := GetDC(HWND_DESKTOP);
SaveFont := SelectObject(DC, Font.Handle);
GetTextMetrics(DC, Metrics);
SelectObject(DC, SaveFont);
ReleaseDC(HWND_DESKTOP, DC);
Height := Metrics.tmHeight + (GetSystemMetrics(SM_CYBORDER) * 8);
{ for I := 0 to FEditControlCount - 1 do
begin
GetWindowRect(FEditControls[I].Handle, R);
R.TopLeft := ScreenToClient(R.TopLeft);
R.BottomRight := ScreenToClient(R.BottomRight);
OffsetRect(R, -R.Left, -R.Top);
R.Bottom := ClientHeight;
SetWindowPos(FEditControls[I].Handle, 0, 0, 0, R.Right, R.Bottom,
SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE);
end;}
end;
procedure TJvIPAddress.AdjustSize;
begin
inherited AdjustSize;
RecreateWnd;
end;
procedure TJvIPAddress.ClearAddress;
begin
if HandleAllocated then
Perform(IPM_CLEARADDRESS, 0, 0);
FAddressValues.Address := 0;
end;
procedure TJvIPAddress.ClearEditControls;
var
I: Integer;
begin
for I := 0 to High(FEditControls) do
if FEditControls[I] <> nil then
FEditControls[I].Handle := 0;
FEditControlCount := 0;
end;
procedure TJvIPAddress.ColorChanged;
begin
inherited ColorChanged;
Invalidate;
end;
procedure TJvIPAddress.FontChanged;
begin
inherited FontChanged;
AdjustHeight;
Invalidate;
end;
procedure TJvIPAddress.EnabledChanged;
var
I: Integer;
begin
inherited EnabledChanged;
for I := 0 to High(FEditControls) do
if (FEditControls[I] <> nil) and (FEditControls[I].Handle <> 0) then
EnableWindow(FEditControls[I].Handle, Enabled and not (csDesigning in ComponentState));
end;
procedure TJvIPAddress.CNCommand(var Msg: TWMCommand);
begin
with Msg do
case NotifyCode of
EN_CHANGE:
begin
Perform(IPM_GETADDRESS, 0, Integer(@FAddress));
if not FChanging then
DoChange;
end;
EN_KILLFOCUS:
begin
FChanging := True;
try
if not IsBlank then
Perform(IPM_SETADDRESS, 0, FAddress);
finally
FChanging := False;
end;
end;
EN_SETFOCUS:
begin
FFocusFromField := True;
try
// Mantis 2599: Send a WM_SETFOCUS to self so that the
// OnEnter event (and the other control's OnExit) works.
// We simply take the precaution to indicate it comes
// from a field. See WMSetFocus for details
Perform(WM_SETFOCUS, 0, 0);
finally
FFocusFromField := False;
end;
end;
end;
inherited;
end;
procedure TJvIPAddress.WMSetFocus(var Msg: TWMSetFocus);
begin
// if we receive the focus from a field, then it's because
// of a mouse click. Thus we do nothing or it would prevent
// the focus from being directly set to the field. Note that
// doing this does not prevent OnFocus from running, which
// is what we want.
if not FFocusFromField then
inherited;
end;
procedure TJvIPAddress.CNNotify(var Msg: TWMNotify);
begin
with Msg, NMHdr^ do
if code = IPN_FIELDCHANGED then
with PNMIPAddress(NMHdr)^ do
DoFieldChange(iField, iValue);
inherited;
end;
procedure TJvIPAddress.DoAddressChange(Sender: TObject);
begin
Address := FAddressValues.Address;
end;
procedure TJvIPAddress.DoAddressChanging(Sender: TObject; Index: Integer; Value: Byte; var AllowChange: Boolean);
begin
AllowChange := (Index > -1) and (Index < 4) and
(Value >= FRange.FRange[Index].Min) and (Value <= FRange.FRange[Index].Max);
end;
procedure TJvIPAddress.DoChange;
begin
if Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TJvIPAddress.DoFieldChange(FieldIndex: Integer; var FieldValue: Integer);
begin
if Assigned(FOnFieldChange) then
FOnFieldChange(Self, FieldIndex, FRange.FRange[FieldIndex], FieldValue);
end;
function TJvIPAddress.IsBlank: Boolean;
begin
Result := False;
if HandleAllocated then
Result := SendMessage(Handle, IPM_ISBLANK, 0, 0) <> 0;
end;
procedure TJvIPAddress.SetAddress(const Value: LongWord);
begin
if FAddress <> Value then
begin
FAddress := Value;
if HandleAllocated then
Perform(IPM_SETADDRESS, 0, FAddress);
FAddressValues.Address := Value;
end;
end;
procedure TJvIPAddress.SetAddressValues(const Value: TJvIPAddressValues);
begin
// (p3) do nothing
end;
{ Added 03/05/2004 by Kai Gossens }
procedure TJvIPAddress.WMCtlColorEdit(var Msg: TWMCtlColorEdit);
var
DC: HDC;
begin
inherited;
DC := GetDC(Handle);
try
Brush.Color := ColorToRGB(Color);
Brush.Style := bsSolid;
SetTextColor(DC, ColorToRGB(Font.Color));
SetBkColor(DC, ColorToRGB(Brush.Color));
SetTextColor(Msg.ChildDC, ColorToRGB(Font.Color));
SetBkColor(Msg.ChildDC, ColorToRGB(Brush.Color));
SetBkMode(Msg.ChildDC, TRANSPARENT);
finally
ReleaseDC(Handle, DC);
end;
Msg.Result := Brush.Handle;
end;
procedure TJvIPAddress.WMDestroy(var Msg: TWMNCDestroy);
begin
DestroyLocalFont;
inherited;
end;
procedure TJvIPAddress.GetDlgCode(var Code: TDlgCodes);
begin
Include(Code, dcWantArrows);
if FTabThroughFields then
Include(Code, dcWantTab);
Exclude(Code, dcNative); // prevent inherited call
end;
procedure TJvIPAddress.WMSetText(var Msg: TWMSetText);
var
S: string;
begin
// really long values for the text crashes the program (try: 127.0.0.8787787878787878), so we limit it here before it is set
S := Msg.Text;
with AddressValues do
begin
Value1 := StrToIntDef(StrToken(S, '.'), 0);
Value2 := StrToIntDef(StrToken(S, '.'), 0);
Value3 := StrToIntDef(StrToken(S, '.'), 0);
Value4 := StrToIntDef(S, 0);
Msg.Text := PChar(Format('%d.%d.%d.%d', [Value1, Value2, Value3, Value4]));
end;
inherited;
end;
procedure TJvIPAddress.WMParentNotify(var Msg: TWMParentNotify);
begin
with Msg do
case Event of
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -