IP编辑控件(因为封装的是系统自带控件,所以也使用了CreateSubClass,不过为啥要封装CN_COMMAND和CN_NOTIFY不是很明白)

最近需要用一个IP输入控件,网上找了几个,都不符合效果,有些还有一些奇怪的Bug。后来发现原来系统已经提供了IP地址编辑控件,只是系统提供的控件不能设置只读效果。网上找了下资料,封装了一下,自己迂回一下实现了只读效果。

源码下载

[delphi] view plain copy
 
 print?IP编辑控件(因为封装的是系统自带控件,所以也使用了CreateSubClass,不过为啥要封装CN_COMMAND和CN_NOTIFY不是很明白)IP编辑控件(因为封装的是系统自带控件,所以也使用了CreateSubClass,不过为啥要封装CN_COMMAND和CN_NOTIFY不是很明白)
  1. unit ueIPEdit;  
  2.   
  3. interface  
  4.   
  5. uses  
  6.   System.SysUtils, System.Classes, Vcl.Controls, Winapi.Windows, Winapi.Messages,  
  7.   Vcl.ComCtrls, Winapi.CommCtrl;  
  8.   
  9. type  
  10.   TFieldChangeEvent = procedure(Sender: TObject; OldField, OldValue: Byte) of object;  
  11.   
  12.   TUeIPEdit = class(TWinControl)  
  13.   private  
  14.     FState: Integer; //Internal use  
  15.     FBakIP: Longint; //Internal use  
  16.     FMinIP: Longint;  
  17.     FMaxIP: Longint;  
  18.     FOnChange: TNotifyEvent;  
  19.     FOnFieldChange: TFieldChangeEvent;  
  20.     procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;  
  21.     procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;  
  22.   protected  
  23.     procedure CreateParams(var Params: TCreateParams); override;  
  24.     function  GetMinIP: String;  
  25.     function  GetMaxIP: String;  
  26.     procedure SetMinIP(const Value: String);  
  27.     procedure SetMaxIP(const Value: String);  
  28.     procedure UpdateRange;  
  29.     function  GetIP: String;  
  30.     procedure SetIP(const Value: String);  
  31.     function  GetEmpty: Boolean;  
  32.     function GetReadOnly: Boolean;  
  33.     procedure SetReadOnly(Value: Boolean);  
  34.     function IPToString(const AIp: Longint): String;  
  35.     function StringToIP(const Value: String): Longint;  
  36.   public  
  37.     constructor Create(AOwner: TComponent); override;  
  38.     procedure Clear;  
  39.     procedure SetActiveField(const Value: Integer);  
  40.     property Empty: Boolean read GetEmpty;  
  41.     property ReadOnly: Boolean read GetReadOnly write SetReadOnly;  
  42.     property IP: String read GetIP write SetIP;  
  43.     property MinIP: String read GetMinIP write SetMinIP;  
  44.     property MaxIP: String read GetMaxIP write SetMaxIP;  
  45.     property OnChange: TNotifyEvent read FOnChange write FOnChange;  
  46.     property OnIPFieldChange: TFieldChangeEvent read FOnFieldChange write FOnFieldChange;  
  47.   
  48.     property Font;  
  49.     property ParentColor;  
  50.     property ParentFont;  
  51.     property ParentShowHint;  
  52.     property PopupMenu;  
  53.     property ShowHint;  
  54.     property TabOrder;  
  55.     property TabStop;  
  56.     property Tag;  
  57.     property DragCursor;  
  58.     property DragMode;  
  59.     property HelpContext;  
  60.   end;  
  61.   
  62. implementation  
  63.   
  64. uses Vcl.Graphics;  
  65.   
  66. constructor TUeIPEdit.Create(AOwner: TComponent);  
  67. const  
  68.   EditStyle = [csClickEvents, csSetCaption, csDoubleClicks, csFixedHeight, csPannable];  
  69. begin  
  70.   inherited Create(AOwner);  
  71.   if NewStyleControls then  
  72.     ControlStyle := EditStyle else  
  73.     ControlStyle := EditStyle + [csFramed];  
  74.   ParentColor := False;  
  75.   Color := clWindow;  
  76.   Width:= 130;  
  77.   Height:= 20;  
  78.   TabStop:= True;  
  79.   FState := 0;  
  80.   FBakIP := -1;  
  81.   FMinIP:= 0;  
  82.   FMaxIP:= $0FFFFFFFF;  
  83.   FOnChange:= nil;  
  84.   FOnFieldChange:= nil;  
  85. end;  
  86.   
  87. procedure TUeIPEdit.CreateParams(var Params: TCreateParams);  
  88. begin  
  89.   InitCommonControl(ICC_INTERNET_CLASSES);  
  90.   inherited CreateParams(Params);  
  91.   CreateSubClass(Params, WC_IPADDRESS);  
  92.   with Params do  
  93.   begin  
  94.     Style := WS_VISIBLE or WS_BORDER or WS_CHILD;  
  95.     if NewStyleControls and Ctl3D then  
  96.     begin  
  97.       Style := Style and not WS_BORDER;  
  98.       ExStyle := ExStyle or WS_EX_CLIENTEDGE;  
  99.     end;  
  100.   end;  
  101. end;  
  102.   
  103. procedure TUeIPEdit.CNNotify(var Message: TWMNotify);  
  104. begin  
  105.   if (FState=0) and Assigned(FOnFieldChange) and  
  106.     (Message.NMHdr^.code=IPN_FIELDCHANGED) then  
  107.     FOnFieldChange(Self, PNMIPAddress(Message.NMHdr)^.iField,  
  108.         PNMIPAddress(Message.NMHdr)^.iValue);  
  109. end;  
  110.   
  111. procedure TUeIPEdit.CNCommand(var Message: TWMCommand);  
  112. begin  
  113.   if (Message.NotifyCode = EN_CHANGE) then  
  114.   begin  
  115.     case FState of  
  116.       0: if Assigned(FOnChange) then FOnChange(Self);  
  117.       1: begin  
  118.            FState := 2;  
  119.            PostMessage(Handle, IPM_SETADDRESS, 0, FBakIP);  
  120.          end;  
  121.       2: FState := 1;  
  122.     end;  
  123.   end;  
  124. end;  
  125.   
  126. function TUeIPEdit.IPToString(const AIp: Longint): String;  
  127. begin  
  128.   Result:= Format('%d.%d.%d.%d',[FIRST_IPADDRESS(AIp),SECOND_IPADDRESS(AIp),  
  129.     THIRD_IPADDRESS(AIp),FOURTH_IPADDRESS(AIp)]);  
  130. end;  
  131.   
  132. function TUeIPEdit.StringToIp(const Value: String): Longint;  
  133. var  
  134.   B: array[0..3] of Byte;  
  135.   Strs: TArray<string>;  
  136.   i, Cnt : Integer;  
  137. begin  
  138.   B[0]:= 0;  
  139.   B[1]:= 0;  
  140.   B[2]:= 0;  
  141.   B[3]:= 0;  
  142.   if Value<>'' then  
  143.   begin  
  144.     Strs := Value.Split(['.'],TStringSplitOptions.ExcludeEmpty);  
  145.     try  
  146.       Cnt := Length(Strs);  
  147.       if Cnt>then Cnt := 4;  
  148.       for i := to Cnt-do  
  149.         B[i] := StrToInt(Strs[i]);  
  150.     finally  
  151.       Strs := nil;  
  152.     end;  
  153.   end;  
  154.   Result:= MakeIPAddress(b[0], b[1], b[2], b[3]);  
  155. end;  
  156.   
  157. function TUeIPEdit.GetIP: String;  
  158. var  
  159.   AIp: Longint;  
  160. begin  
  161.   SendMessage(Handle, IPM_GETADDRESS, 0, Longint(@AIp));  
  162.   Result:= IPToString(AIp);  
  163. end;  
  164.   
  165. procedure TUeIPEdit.SetIP(const Value: String);  
  166. begin  
  167.   SendMessage(Handle, IPM_SETADDRESS, 0, StringToIp(Value));  
  168. end;  
  169.   
  170. function TUeIPEdit.GetMinIP: String;  
  171. begin  
  172.   Result:= IPToString(FMinIP);  
  173. end;  
  174.   
  175. procedure TUeIPEdit.SetMinIP(const Value: String);  
  176. var  
  177.   AMin: LongInt;  
  178. begin  
  179.   AMin := StringToIp(Value);  
  180.   if FMinIP<>AMin then  
  181.   begin  
  182.     FMinIP := AMin;  
  183.     UpdateRange;  
  184.   end;  
  185. end;  
  186.   
  187. procedure TUeIPEdit.UpdateRange;  
  188. begin  
  189.   SendMessage(Handle, IPM_SETRANGE, 0, MAKEIPRANGE(FIRST_IPADDRESS(FMinIP), FIRST_IPADDRESS(FMaxIP)));  
  190.   SendMessage(Handle, IPM_SETRANGE, 1, MAKEIPRANGE(SECOND_IPADDRESS(FMinIP), SECOND_IPADDRESS(FMaxIP)));  
  191.   SendMessage(Handle, IPM_SETRANGE, 2, MAKEIPRANGE(THIRD_IPADDRESS(FMinIP), THIRD_IPADDRESS(FMaxIP)));  
  192.   SendMessage(Handle, IPM_SETRANGE, 3, MAKEIPRANGE(FOURTH_IPADDRESS(FMinIP), FOURTH_IPADDRESS(FMaxIP)));  
  193. end;  
  194.   
  195. procedure TUeIPEdit.SetMaxIP(const Value: String);  
  196. var  
  197.   AMax: LongInt;  
  198. begin  
  199.   AMax := StringToIp(Value);  
  200.   if FMaxIP<>AMax then  
  201.   begin  
  202.     FMaxIP := AMax;  
  203.     UpdateRange;  
  204.   end;  
  205. end;  
  206.   
  207. function TUeIPEdit.GetMaxIP: String;  
  208. begin  
  209.   Result:= IPToString(FMaxIP);  
  210. end;  
  211.   
  212. function TUeIPEdit.GetReadOnly: Boolean;  
  213. begin  
  214.   Result := FState<>0;  
  215. end;  
  216.   
  217. procedure TUeIPEdit.SetReadOnly(Value: Boolean);  
  218. begin  
  219.   if Value <> GetReadOnly then  
  220.   begin  
  221.     if Value then  
  222.     begin  
  223.       SendMessage(Handle, IPM_GETADDRESS, 0, Longint(@FBakIP));  
  224.       FState := 1;  
  225.     end else begin  
  226.       FState := 0;  
  227.     end;  
  228.   end;  
  229. end;  
  230.   
  231. function TUeIPEdit.GetEmpty: Boolean;  
  232. begin  
  233.   Result:= Boolean(SendMessage(Handle, IPM_ISBLANK, 0, 0));  
  234. end;  
  235.   
  236. procedure TUeIPEdit.Clear;  
  237. begin  
  238.   SendMessage(Handle, IPM_CLEARADDRESS, 0, 0);  
  239. end;  
  240.   
  241. procedure TUeIPEdit.SetActiveField(const Value: Integer);  
  242. begin  
  243.   if (Value < 4) then  
  244.   begin  
  245.     SendMessage(Handle, IPM_SETFOCUS, wParam(Value), 0);  
  246.   end;  
  247. end;  
  248.   
  249. end.  

http://blog.csdn.net/tht2009/article/details/50623816