home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 April / Chip_2002-04_cd1.bin / zkuste / delphi / kolekce / d3456 / PBEDIT.ZIP / PBNumEdit.pas < prev    next >
Pascal/Delphi Source File  |  2002-01-19  |  21KB  |  690 lines

  1. {Author:    Poul Bak}
  2. {}
  3. {Copyright ⌐ 1999 - 2002 : BakSoft-Denmark (Poul Bak). All rights reserved.}
  4. {}
  5. {http://home11.inet.tele.dk/BakSoft/}
  6. {Mailto: baksoft-denmark@dk2net.dk}
  7. {}
  8. {Component Version: 6.00.00.00}
  9. {}
  10. {PBNumEdit is a Delphi Edit component with Alignment and mouse-AutoSelect-all.}
  11. {PBNumEdit is a special Edit component for numeric values - supporting
  12.  WYSIWYG editing, floating and fixed decimalpoint.}
  13. {NumberFormat sets the display- and editformat (Standard, Thousands,
  14. Scientific and Engineering). You can set max- and minValue.}
  15. { Note: To prevent conversion errors, the display is limited to 15 significant
  16.  numbers though the Value (and AsFloat) property is of type Extended.}
  17. {Supports Windows 95, 98 and NT.}
  18. {Supports Default-Button click.}
  19. {Supports Cancel-button click.}
  20.  
  21. unit PBNumEdit;
  22.  
  23. interface
  24.  
  25. uses
  26.     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  27.     StdCtrls;
  28.  
  29. type
  30. {Default: Normal format.}
  31. {Thousands: Showing Thousand-separators.}
  32. {Scientific: Exponential - 1 number left of decimalseparator and a 10-exponent (ex: 1.23E8).}
  33. {Engineering: Same as Scientific except the 10-exponent is always a multiplum
  34. of 3 (like milli, kilo, Mega etc.) and there are 1 to 3 numbers
  35. left of the decimalseparator.}
  36.     TNumberFormat = (Standard, Thousands, Scientific, Engineering);
  37.  
  38. {Author:    Poul Bak}
  39. {}
  40. {Copyright ⌐ 1999 - 2002 : BakSoft-Denmark (Poul Bak). All rights reserved.}
  41. {}
  42. {http://home11.inet.tele.dk/BakSoft/}
  43. {Mailto: baksoft-denmark@dk2net.dk}
  44. {}
  45. {Component Version: 6.00.00.00}
  46. {}
  47. {PBNumEdit is a Delphi Edit component with Alignment and mouse-AutoSelect-all.}
  48. {PBNumEdit is a special Edit component for numeric values - supporting
  49.  WYSIWYG editing, floating and fixed decimalpoint.}
  50. {NumberFormat sets the display- and editformat (Standard, Thousands,
  51. Scientific and Engineering). You can set max- and minValue.}
  52. { Note: To prevent conversion errors, the display is limited to 15 significant
  53.  numbers though the Value (and AsFloat) property is of type Extended.}
  54. {Supports Windows 95, 98 and NT.}
  55. {Supports Default-Button click.}
  56. {Supports Cancel-button click.}
  57.     TPBNumEdit = class(TCustomEdit)
  58.     private
  59.         FAlignment: TAlignment;
  60.         FDecimals: ShortInt;
  61.         FEnter : Boolean;
  62.         FInvalidEntry: TNotifyEvent;
  63.         FMaxValue: Extended;
  64.         FMinValue: Extended;
  65.         FNumberFormat : TNumberFormat;
  66.         FVersion: String;
  67.         function FormatText(Value: Extended): string;
  68.         function GetAsCurrency: Currency;
  69.         function GetAsFloat: Extended;
  70.         function GetAsInteger: Integer;
  71.         function GetValue: Extended;
  72.         function Remove1000(Num : string): string;
  73.         procedure DeleteKey(Key: Word);
  74.         procedure DeleteSelection;
  75.         procedure SetAlignment(Value: TAlignment);
  76.         procedure SetAsCurrency(Value: Currency);
  77.         procedure SetAsFloat(Value: Extended);
  78.         procedure SetAsInteger(Value: Integer);
  79.         procedure SetDecimals(Value: ShortInt);
  80.         procedure SetMaxValue(Value: Extended);
  81.         procedure SetMinValue(Value: Extended);
  82.         procedure SetNumberFormat(Value: TNumberFormat);
  83.         procedure SetValue(Value: Extended);
  84.         procedure SetVersion(Value: String);
  85.         procedure WMCut(var Message: TMessage); message WM_CUT;
  86.         procedure WMCopy(var Message: TMessage); message WM_COPY;
  87.         procedure WMGetDlgCode(var Msg : TWMGetDlgCode); message WM_GETDLGCODE;
  88.         procedure WMPaste(var Message: TMessage); message WM_PASTE;
  89.     protected
  90.         procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  91.         procedure DoEnter; override;
  92.         procedure DoExit; override;
  93.         procedure InvalidEntry;
  94.         procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  95.         procedure KeyPress(var Key: Char); override;
  96.         procedure Keyup(var Key: Word; Shift: TShiftState); override;
  97.     public
  98.         constructor Create(AOwner: TComponent); override;
  99.         procedure CreateParams(var Params: TCreateParams); override;
  100. {Set or access the value as a currency type.}
  101.         property AsCurrency: Currency read GetAsCurrency write SetAsCurrency;
  102. {Set or access the value as an extended type.}
  103. { Note: To prevent conversion errors, the display is limited to 15 significant
  104. numbers though the Value and AsFloat property are of type Extended and
  105. internally calculates with up to 20 significant numbers.}
  106.         property AsFloat: Extended read GetAsFloat write SetAsFloat;
  107. {Set or access the value as an integer type.}
  108.         property AsInteger: Integer read GetAsInteger write SetAsInteger;
  109.     published
  110. {Set Alignment to: taLeftJustify, taCenter or taRightJustify.}
  111. {Default : taLeftJustify.}
  112. {Supports Windows 95, 98 and NT.}
  113.         property Alignment: TAlignment read FAlignment write SetAlignment;
  114. {Default: True.}
  115. {Set AutoSelect to True to select all text when you set focus:}
  116. {Notice that when you set focus using the mouse, all text is also selected -
  117. unlike standard Delphi components that only selects all when setting focus with <tab>.}
  118. {When a form has a defaultbutton and you press <enter>, the click event
  119. triggers and focus is returned to the edit control which autoselect all.}
  120.         property AutoSelect;
  121.         property AutoSize;
  122.         property BorderStyle;
  123.         property Color;
  124.         property Ctl3D;
  125. {Set Decimals to -1 if you want a floating decimalpoint with 0 - 14
  126. decimals.}
  127. {Set Decimals to 0 or a value up to 14 to get fixed decimals.}
  128. { Note: To prevent conversion errors, the display is limited to 15 significant
  129. numbers though the Value (and AsFloat) property is of type Extended and
  130. internally calculates with up to 20 significant numbers.}
  131.         property Decimals: ShortInt read FDecimals write SetDecimals;
  132.         property DragCursor;
  133.         property DragMode;
  134.         property Enabled;
  135.         property Font;
  136.         property HideSelection;
  137.         property MaxLength;
  138. {Set MaxValue to prevent users from entering values greater than MaxValue.}
  139. {OnInvalidEntry triggers when the edit component looses focus.}
  140. {When MaxValue and MinValue are both zero, they have no effect.}
  141.         property MaxValue: Extended read FMaxValue write SetMaxValue;
  142. {Set MinValue to prevent users from entering values less than MinValue.}
  143. {OnInvalidEntry triggers when the edit component looses focus.}
  144. {When MaxValue and MinValue are both zero, they have no effect.}
  145.         property MinValue: Extended read FMinValue write SetMinValue;
  146. {Sets the display- and editformat.}
  147. {Standard: Normal format.}
  148. {Thousands: Showing Thousand-separators.}
  149. {Scientific: Exponential - 1 number left of decimalseparator and a 10-exponent
  150. (ex: 1.23E8).}
  151. {Engineering: Same as Scientific except the 10-exponent is always a multiplum
  152. of 3 (like milli, kilo, Mega etc.) and there are 1 to 3 numbers
  153. left of the decimalseparator.}
  154.         property NumberFormat: TNumberFormat read FNumberFormat write SetNumberFormat;
  155.         property OnChange;
  156.         property OnClick;
  157.         property OnDblClick;
  158.         property OnDragDrop;
  159.         property OnDragOver;
  160.         property OnEndDrag;
  161.         property OnEnter;
  162.         property OnExit;
  163. {Is called when the user enters a value greater than MaxValue or smaller
  164. than MinValue. If no procedure is assigned to this event Value will simply be set to MaxValue if Value is greater than MaxValue and MinValue if Value is less than MinValue.}
  165.         property OnInvalidEntry: TNotifyEvent read FInvalidEntry write FInvalidEntry;
  166.         property OnKeyDown;
  167.         property OnKeyPress;
  168.         property OnKeyUp;
  169.         property OnMouseDown;
  170.         property OnMouseMove;
  171.         property OnMouseUp;
  172.         property OnStartDrag;
  173.         property ParentColor;
  174.         property ParentCtl3D;
  175.         property ParentFont;
  176.         property ParentShowHint;
  177.         property PopupMenu;
  178.         property ReadOnly;
  179.         property ShowHint;
  180.         property TabOrder;
  181.         property TabStop;
  182. {The value of the text. Set or access the displayed text through
  183. this property.}
  184. { Note: To prevent conversion errors, the display is limited to 15 significant
  185. numbers though the Value (and AsFloat) property is of type Extended and
  186. internally calculates with up to 20 significant numbers.}
  187.         property Value: Extended read GetValue write SetValue;
  188. {Read only}
  189.         property Version: String read FVersion write SetVersion stored False;
  190.         property Visible;
  191.     end;
  192.  
  193. procedure Register;
  194.  
  195. implementation
  196.  
  197. uses Clipbrd;
  198.  
  199. constructor TPBNumEdit.Create(AOwner: TComponent);
  200. begin
  201.     inherited Create(AOwner);
  202.     Width := 100;
  203.     FAlignment := taRightJustify;
  204.     FDecimals := -1;
  205.     FEnter := False;
  206.     FMaxValue := 0;
  207.     FMinValue := 0;
  208.     FNumberFormat := Standard;
  209.     FVersion := '6.00.00.00';
  210.     Value := 0;
  211.     Text := FormatText(Value);
  212. end;
  213.  
  214. procedure TPBNumEdit.CreateParams(var Params: TCreateParams);
  215. const
  216.     Alignments: array[TAlignment] of Word = (ES_LEFT, ES_RIGHT, ES_CENTER);
  217. begin
  218.     inherited CreateParams(Params);
  219.     Params.Style := Params.Style or ES_MULTILINE or Alignments[FAlignment];
  220. end;
  221.  
  222. procedure TPBNumEdit.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  223. begin
  224.     if (Button = mbLeft) or (ssLeft in Shift) then
  225.     begin
  226.         if FEnter = True then
  227.         begin
  228.             FEnter := False;
  229.             if AutoSelect then SelectAll;
  230.         end;
  231.     end;
  232.     inherited MouseDown(Button, Shift, X, Y);
  233. end;
  234.  
  235. procedure TPBNumEdit.DoEnter;
  236. begin
  237.     inherited DoEnter;
  238.     if csLButtonDown in ControlState then FEnter := True;
  239.     if AutoSelect then SelectAll;
  240. end;
  241.  
  242. procedure TPBNumEdit.DoExit;
  243. begin
  244.     Text := FormatText(Value);
  245.     if ((FMinValue <> 0) or (FMaxValue <> 0))
  246.         and ((Value < FMinValue) or (Value > FMaxValue)) then InvalidEntry
  247.     else inherited DoExit;
  248. end;
  249.  
  250. procedure TPBNumEdit.KeyDown(var Key: Word; Shift: TShiftState);
  251. begin
  252.     inherited KeyDown(Key, Shift);
  253.     FEnter := False;
  254.     if not ReadOnly then
  255.     begin
  256.         if Key in [VK_DELETE, VK_BACK] then
  257.         begin
  258.             if SelLength > 0 then DeleteSelection
  259.             else DeleteKey(Key);
  260.             Key := 0;
  261.         end;
  262.     end;
  263. end;
  264.  
  265. procedure TPBNumEdit.KeyPress(var Key: Char);
  266. var
  267.     P, D, E : Integer;
  268.     N, NE : Boolean;
  269. begin
  270.     inherited KeyPress(Key);
  271.     if ReadOnly or (Key in [#3, #22, #24]) then exit;
  272.     if not (Key in ['0'..'9', DecimalSeparator, '-', 'e', 'E'])
  273.         or ((Key = DecimalSeparator) and (FDecimals = 0)) then
  274.     begin
  275.         MessageBeep(0);
  276.         Key := #0;
  277.         Exit;
  278.     end;
  279.     P := SelStart;
  280.     D := pos(DecimalSeparator, Text);
  281.     E := pos('E', Text);
  282.     if Key = 'e' then Key := 'E';
  283.     if Key in [DecimalSeparator, 'E'] then SelLength := 0
  284.     else DeleteSelection;
  285.     N := (Text[1] = '-');
  286.     NE := (pos('-', copy(Text, E + 1, length(Text) - E)) <> 0) and (E <> 0);
  287.     if N and (SelStart = 0) then SelStart := 1;
  288.     if NE and (Selstart = E + 1) then SelStart := SelStart + 1;
  289.     if Key = '-' then
  290.     begin
  291.         if (P < E) or (E = 0) then
  292.         begin
  293.             if not N then
  294.             begin
  295.                 Text := '-' + Text;
  296.                 SelStart := P + 1;
  297.             end
  298.             else
  299.             begin
  300.                 Text := Copy(Text, 2, Length(Text) - 1);
  301.                 SelStart := P - 1;
  302.             end;
  303.         end
  304.         else
  305.         begin
  306.             if not NE then
  307.             begin
  308.                 Text := copy(Text, 1, E) + '-' + copy(Text, E + 1, Length(Text) - E);
  309.                 SelStart := P + 1;
  310.             end
  311.             else
  312.             begin
  313.                 Text := copy(Text, 1, E) + copy(Text, E + 2, Length(Text) - E - 1);
  314.                 SelStart := P - 1;
  315.             end;
  316.         end;
  317.         Key := #0;
  318.         exit;
  319.     end;
  320.     if Key = DecimalSeparator then
  321.     begin
  322.         if D <> 0 then
  323.         begin
  324.             Selstart := D;
  325.             Key := #0;
  326.         end
  327.         else if FDecimals < 0 then
  328.         begin
  329.             if E <> 0 then Selstart := E - 1
  330.             else Selstart := Length(Text);
  331.         end;
  332.         exit;
  333.     end
  334.     else if Key = 'E' then
  335.     begin
  336.         if E = 0 then SelStart := Length(Text)
  337.         else
  338.         begin
  339.             SelStart := E;
  340.             Key := #0;
  341.         end;
  342.         Exit;
  343.     end;
  344.     if (SelStart <= 2) and (Copy(Text, 2, 1) = '0') and N then
  345.     begin
  346.         SelStart := 1;
  347.         SelLength := 1;
  348.     end
  349.     else if (SelStart <= 1) and (Copy(Text, 1, 1) = '0') then
  350.     begin
  351.         SelStart := 0;
  352.         SelLength := 1;
  353.     end
  354.     else if (SelStart = E) and (E <> 0) and (copy(Text,E + 1, 1) = '0')
  355.         then SelLength := 1
  356.     else if (SelStart >= E) and (E <> 0) then
  357.     begin
  358.         if  Abs(StrToInt(Copy(Text, E + 1, SelStart - E) + Key + Copy(Text, SelStart + 1, 99))) > 4932 then
  359.         begin
  360.             MessageBeep(0);
  361.             Key := #0;
  362.         end;
  363.     end
  364.     else if FDecimals > 0 then
  365.     begin
  366.         if (SelStart = D + FDecimals) then
  367.         begin
  368.             MessageBeep(0);
  369.             Key := #0;
  370.         end
  371.         else if SelStart >= D then SelLength := 1
  372.         else if SelStart < D - 1 then SelLength := 0;
  373.     end;
  374. end;
  375.  
  376. procedure TPBNumEdit.Keyup(var Key: Word; Shift: TShiftState);
  377. var
  378.     Numsep, NumSep0, SelStart0, X, D, N, N0 : integer;
  379.     Text0 : string;
  380. begin
  381.     inherited KeyUp(Key, Shift);
  382.     if (SelLength > 0) then exit;
  383.     if NumberFormat <> Thousands then exit;
  384.     D := pos(DecimalSeparator, Text);
  385.     SelStart0 := SelStart;
  386.     NumSep := 0;
  387.     NumSep0 := 0;
  388.     Text0 := FormatText(AsFloat);
  389.     for X := 1 to length(Text0) do
  390.         if Text0[X] = ThousandSeparator then inc(NumSep0);
  391.     for X := 1 to length(Text) do
  392.         if Text[X] = ThousandSeparator then inc(NumSep);
  393.     N := pos(ThousandSeparator, Text);
  394.     N0 := pos(ThousandSeparator, Text0);
  395.     if (NumSep <> NumSep0) or (N <> N0) or (Key in [32, 13]) then
  396.     begin
  397.         Text := Text0;
  398.         Selstart := SelStart0 + NumSep0 - NumSep;
  399.         if (pos(DecimalSeparator, Text) <> 0) and (D = 0) then Selstart := Selstart + 1
  400.         else if (D <> 0) and (pos(DecimalSeparator, Text) = 0) then Selstart := Selstart - 1;
  401.         if Copy(Text, Selstart + 1, 1) = ThousandSeparator then Selstart := Selstart + 1;
  402.     end;
  403. end;
  404.  
  405. function TPBNumEdit.GetAsCurrency: Currency;
  406. begin
  407.     Result := StrToCurr(Remove1000(Text));
  408. end;
  409.  
  410. function TPBNumEdit.GetAsFloat: Extended;
  411. begin
  412.     Result := StrToFloat(Remove1000(Text));
  413. end;
  414.  
  415. function TPBNumEdit.GetAsInteger: Integer;
  416. begin
  417.     Result := Trunc(StrToFloat(Remove1000(Text)));
  418. end;
  419.  
  420. function TPBNumEdit.GetValue: Extended;
  421. begin
  422.     Result := StrToFloat(Remove1000(Text));
  423. end;
  424.  
  425. procedure TPBNumEdit.SetAsCurrency(Value: Currency);
  426. begin
  427.     if Text <> FormatText(Value) then Text := FormatText(Value);
  428. end;
  429.  
  430. procedure TPBNumEdit.SetAsFloat(Value: Extended);
  431. begin
  432.     if Text <> FormatText(Value) then Text := FormatText(Value);
  433. end;
  434.  
  435. procedure TPBNumEdit.SetAsInteger(Value: Integer);
  436. begin
  437.     if Text <> FormatText(Value) then Text := FormatText(Value);
  438. end;
  439.  
  440. procedure TPBNumEdit.SetAlignment(Value: TAlignment);
  441. var
  442.     SelSt, SelLe : integer;
  443. begin
  444.     if FAlignment <> Value then
  445.     begin
  446.         SelSt := SelStart;
  447.         SelLe := SelLength;
  448.         FAlignment := Value;
  449.         RecreateWnd;
  450.         SelStart := SelSt;
  451.         SelLength := SelLe;
  452.     end;
  453. end;
  454.  
  455. procedure TPBNumEdit.SetDecimals(Value: ShortInt);
  456. var Value0 : ShortInt;
  457. begin
  458.     Value0 := Value;
  459.     if FDecimals <> Value0 then
  460.     begin
  461.         if Value0 < 0 then Value0 := -1
  462.         else if Value0 > 14 then Value0 := 14;
  463.         if (Value0 > MaxLength - 2) and (MaxLength > 0) then Value0 := maxlength - 2;
  464.         FDecimals := Value0;
  465.         Text := FormatText(AsFloat);
  466.     end;
  467. end;
  468.  
  469. procedure TPBNumEdit.SetMaxValue(Value: Extended);
  470. begin
  471.     if (FMaxValue <> Value) and (Value >= FminValue) then
  472.     begin
  473.         FMaxValue := Value;
  474.     end;
  475. end;
  476.  
  477. procedure TPBNumEdit.SetMinValue(Value: Extended);
  478. begin
  479.     if (FMinValue <> Value) and (Value <= FmaxValue) then
  480.     begin
  481.         FMinValue := Value;
  482.     end;
  483. end;
  484.  
  485. procedure TPBNumEdit.SetValue(Value: Extended);
  486. begin
  487.     if csDesigning in ComponentState then
  488.     begin
  489.         if (Value > FMaxValue) and ((FMaxValue <> 0) or (FMinValue <> 0)) then InvalidEntry;
  490.         if (Value < FMinValue) and ((FMaxValue <> 0) or (FMinValue <> 0)) then InvalidEntry;
  491.     end;
  492.     if Text <> FormatText(Value) then Text := FormatText(Value);
  493. end;
  494.  
  495. procedure TPBNumEdit.DeleteKey(Key: Word);
  496. var
  497.     P, D, E: Integer;
  498.     N: Boolean;
  499.     str0 : string;
  500. begin
  501.     D := pos(DecimalSeparator, Text);
  502.     E := pos('E', Text);
  503.     if E = 0 then E := length(Text) + 1;
  504.     if Key = VK_DELETE then
  505.     begin
  506.         P := SelStart + 1;
  507.         if P > Length(Text) then Exit;
  508.         if Text[P] in [ThousandSeparator, DecimalSeparator, 'E'] then inc(P);
  509.     end
  510.     else
  511.     begin
  512.         P := SelStart;
  513.         if P = 0 then Exit;
  514.         if Text[P] in [ThousandSeparator, DecimalSeparator, 'E'] then dec(P);
  515.     end;
  516.     N := (Pos('-', Text) > 0);
  517.     if (P = 0) or (P > Length(Text)) then exit;
  518.     str0 := '';
  519.     if (P > D) and (D <> 0) and ((P < E) or (E = 0)) then
  520.     begin
  521.         if FDecimals > 0 then str0 := '0';
  522.         Text := Copy(Text, 1, P - 1) + Copy(Text, P + 1,E - P - 1)
  523.             + str0 + Copy(Text, E, length(Text) - E + 1);
  524.         SelStart := P - 1;
  525.     end
  526.     else if (P = 1) and N then
  527.     begin
  528.         Text := Copy(Text, 2, Length(Text) - 1);
  529.         if Text = '' then Text := '0';
  530.     end
  531.     else if (P = 1) and ((P = D - 1) or (P = E - 1) or (P = length(Text))) then
  532.     begin
  533.         Text := '0' + Copy(Text, 2, Length(Text) - 1);
  534.         SelStart := 1;
  535.         if N then Text := '-' + Text;
  536.     end
  537.     else if P > 0 then
  538.     begin
  539.         Text := Copy(Text, 1, P - 1) + Copy(Text, P + 1, Length(Text) - P);
  540.         SelStart := P - 1;
  541.         if ((FNumberFormat = Scientific) or (FNumberFormat = Engineering))
  542.             and (Text[length(Text)] = 'E') then Text := Text + '0';
  543.     end;
  544. end;
  545.  
  546. procedure TPBNumEdit.DeleteSelection;
  547. var
  548.     X, Y, Z: Integer;
  549. begin
  550.     if SelLength = 0 then exit;
  551.     if SelText = Text then
  552.     begin
  553.         Text := FormatText(0);
  554.         exit;
  555.     end;
  556.     Y := Length(Remove1000(SelText));
  557.     if pos(DecimalSeparator, SelText) <> 0 then dec(Y);
  558.     Z := Length(SelText);
  559.     SelStart := SelStart + Z;
  560.     for X:= 1 to Y do
  561.     begin
  562.         DeleteKey(VK_BACK);
  563.     end;
  564. end;
  565.  
  566. procedure TPBNumEdit.InvalidEntry;
  567. begin
  568.     if Assigned(FInvalidEntry) then FInvalidEntry(Self)
  569.     else
  570.     begin
  571.         if Value < FMinValue then Value := FMinValue
  572.         else if Value > FMaxValue then Value := FMaxValue;
  573.         MessageBeep(0);
  574.         Self.SetFocus;
  575.     end;
  576. end;
  577.  
  578. procedure TPBNumEdit.SetVersion(Value: String);
  579. begin
  580.     { Read only! }
  581. end;
  582.  
  583. procedure TPBNumEdit.WMCopy(var Message: TMessage);
  584. begin
  585.     ClipBoard.AsText := Remove1000(Seltext);
  586. end;
  587.  
  588. procedure TPBNumEdit.WMCut(var Message: TMessage);
  589. begin
  590.     ClipBoard.AsText := Remove1000(Seltext);
  591.     DeleteSelection;
  592. end;
  593.  
  594. procedure TPBNumEdit.WMPaste(var Message: TMessage);
  595. var
  596.     X: integer;
  597.     S: String;
  598.     W: Word;
  599. begin
  600.     DeleteSelection;
  601.     S := Clipboard.AsText;
  602.     for X := 1 to Length(S) do
  603.     begin
  604.         W := Ord(S[X]);
  605.         Perform(WM_CHAR, W, 0);
  606.     end;
  607. end;
  608.  
  609. procedure TPBNumEdit.SetNumberFormat(Value: TNumberFormat);
  610. begin
  611.     if FNumberFormat <> Value then FNumberFormat := Value;
  612.     Text := FormatText(AsFloat);
  613. end;
  614.  
  615. function TPBNumEdit.Remove1000(Num : string): string;
  616. var
  617.     t : integer;
  618. begin
  619.     Result := '';
  620.     for t :=1 to length(Num) do
  621.     begin
  622.         if Num[t] <> ThousandSeparator then Result := Result + Num[t];
  623.     end;
  624.     if Result = '' then Result := '0';
  625.     if Result = '-' then Result := '-0';
  626. end;
  627.  
  628. function TPBNumEdit.FormatText(Value: Extended) : string;
  629. var
  630.     e0, E, D, NN, t, FD : integer;
  631.     a : extended;
  632.     Formatmask : string;
  633. begin
  634.     if (FNumberFormat = Engineering) and (Value <> 0) then
  635.     begin
  636.         e0 := trunc(ln(abs(Value)) / ln(10) / 3) * 3;
  637.         Result := 'E' + inttostr(e0);
  638.         a := Value / StrToFloat('1' + Result);
  639.         FD := 14;
  640.         if a > 9 then dec(FD);
  641.         if a > 99 then dec(FD);
  642.         if (FD > FDecimals) and (FDecimals <> -1) then FD := FDecimals;
  643.         if FDecimals < 0 then Result := formatfloat('0.' + StringOfChar('#',FD), a) + Result
  644.         else if FDecimals = 0 then Result := formatfloat('0', a) + Result
  645.         else Result := formatfloat('0.' + StringOfChar('0',FD), a) + Result;
  646.     end
  647.     else
  648.     begin
  649.         FormatMask := '0';
  650.         if FNumberFormat = Thousands then FormatMask := ',' + FormatMask;
  651.         if FDecimals > 0 then FormatMask := FormatMask + '.' + StringOfChar('0', FDecimals)
  652.         else if FDecimals < 0 then FormatMask := FormatMask + '.' + StringOfChar('#', 14);
  653.         if FNumberFormat > Thousands then FormatMask := FormatMask + 'E-';
  654.         Result := FormatFloat(FormatMask, Value);
  655.         E := pos('E',Result);
  656.         if E = 0 then
  657.         begin
  658.             D := pos(DecimalSeparator, Result);
  659.             if (D <> 0) then
  660.             begin
  661.                 NN := 0;
  662.                 for t := 1 to D do if (Result[t] in ['0'..'9'] = True) then inc(NN);
  663.                 if (FDecimals = -1) then
  664.                 begin
  665.                     if FNumberFormat = Thousands then Result := FormatFloat(',0.' + StringOfChar('#',15 - NN),Value)
  666.                     else if FDecimals <> -1 then Result := FormatFloat('0.' + StringOfChar('#',15 - NN),Value);
  667.                 end
  668.                 else if (FDecimals > 15 - NN) then
  669.                 begin
  670.                     if FNumberFormat = Thousands then Result := FormatFloat(',0.' + StringOfChar('0',15 - NN),Value)
  671.                     else if FDecimals <> -1 then Result := FormatFloat('0.' + StringOfChar('0',15 - NN),Value);
  672.                     Result := Result + StringOfChar('0', Fdecimals -15 + NN);
  673.                 end;
  674.             end;
  675.         end;
  676.     end;
  677. end;
  678.  
  679. procedure TPBNumEdit.WMGetDlgCode(var Msg: TWMGetDlgCode);
  680. begin
  681.     Msg.Result := DLGC_WANTCHARS or DLGC_WANTARROWS;
  682. end;
  683.  
  684. procedure Register;
  685. begin
  686.     RegisterComponents('PB', [TPBNumEdit]);
  687. end;
  688.  
  689. end.
  690.