2017-08-11 117 views
3

我试图实现IP编辑。这是我的代码:更改宽度SysIPAddress32

unit Main; 

interface 

uses 
    System.SysUtils, System.Classes, 
    Winapi.Windows, Winapi.Messages, Winapi.CommCtrl, 
    Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, Vcl.ComCtrls; 

type 

    TIpEdit = class(TWinControl) 
    strict protected 
    procedure CreateParams(var Params: TCreateParams); override; 
    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE; 
    procedure WMSetFont(var Message: TWMSetFont); message WM_SETFONT;  
    end; 

    TMainForm = class(TForm) 
    Btn1: TButton; 
    procedure FormCreate(Sender: TObject); 
    procedure Btn1Click(Sender: TObject); 
    private 
    FIpEdit: TIpEdit; 
    public 
    { Public declarations } 
    end; 

var 
    MainForm: TMainForm; 

implementation 

{$R *.dfm} 

{ TIPEdit } 

procedure TIPEdit.CreateParams(var Params: TCreateParams); 
begin 
    InitCommonControl(ICC_INTERNET_CLASSES); 
    inherited CreateParams(Params); 
    CreateSubClass(Params, WC_IPADDRESS); 
    Params.Style := Params.Style or WS_TABSTOP or WS_CHILD; 
end; 

procedure TIPEdit.WMGetDlgCode(var Message: TWMGetDlgCode); 
begin 
    inherited; 
    Message.Result := Message.Result or DLGC_WANTARROWS; 
end; 

procedure TIPEdit.WMSetFont(var Message: TWMSetFont); 
var 
    LF: LOGFONT; 
begin 
    if GetObject(Message.Font, SizeOf(LF), @LF) <> 0 then 
    begin 
    Message.Font := CreateFontIndirect(LF); 
    inherited; 
    end; 
end; 

{ TMainForm } 

procedure TMainForm.Btn1Click(Sender: TObject); 
begin 
    FIpEdit.Width := FIpEdit.Width + 100; 
end; 

procedure TMainForm.FormCreate(Sender: TObject); 
begin 
    FIpEdit := TIpEdit.Create(Self); 
    FIpEdit.Parent := Self; 
    FIpEdit.SetBounds(10, 10, 120, 21); 
end; 

end. 

之前Btn1.Click

enter image description here

结果Btn1.Click

enter image description here

后:控制自己的改变宽度,但不会改变宽度内编辑。

我通过两种方式

  • 使用RecreateWnd尝试修复。这工作,但恕我直言,其丑陋的解决方案。
  • 修正了内部编辑宽度的问题。这工作,但很难 执行,由于控制的内部工作

也许我错过了什么,有一个更简单的解决方案?

编辑:

我测试RecreateWnd,但使用的DevExpress布局控制时,它不能使用。似乎布局控件使用绕过SetBounds方法的API直接调用。在这种情况下RecreateWnd不能使用。

最后的结论是:

  • RecreateWnd是一些ristrictions
  • RepeatUntil简单的解决方案answer比较困难,但总是工作
+0

VCL中的很多东西都使用'RecreateWnd'来应用窗口更改。它有时可能不是最佳解决方案,但它也不是一个难看的解决方案。 –

回答

0

你可以使用TPanel与子女TEdit控件来创建自己的IP编辑,这将让你更多的控制自己的财产。

该如何它的外观在运行时: enter image description here

我这段时间前,其未完成的工作写,但可能给我的意思的想法。

unit IPEdit; 

interface 

uses 
    System.SysUtils, System.Classes, Vcl.Controls, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Forms, 
    Vcl.Graphics, System.UITypes; 

type 
    TExitType = (etNone, etNext); 

type 
    TIPEdit = class(TCustomPanel) 
    private 
    FPart1  : TEdit; 
    FPart2  : TEdit; 
    FPart3  : TEdit; 
    FPart4  : TEdit; 
    FSplitter1 : TPanel; 
    FSplitter2 : TPanel; 
    FSplitter3 : TPanel; 
    FRiseErr : Boolean; 
    FErrMsg  : string; 
    FExitType : TExitType; 
    FBevelInner : TPanelBevel; 
    FLeadingzero: Boolean; 
    procedure SetExitType(Value : TExitType); 
    procedure SetBevelInner(Value: TPanelBevel); 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    protected 
    procedure EditOnKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 
    procedure EditOnChange(Sender: TObject); 
    procedure OnPanelResize(Sender: TObject); 
    procedure EditOnExit(Sender: TObject); 
    published 
    property ShowError: Boolean read FRiseErr write FRiseErr default False; 
    property Leadingzero: Boolean read FLeadingzero write FLeadingzero default False; 
    property ErrorText: string read FErrMsg write FErrMsg; 
    property ExitType: TExitType read FExitType write SetExitType default etNext; 
    property BevelInner: TPanelBevel read FBevelInner write SetBevelInner default bvNone; 
    end; 


implementation 

const 
    Msg_Err_Value_Exceeded = 'Value cannot be greater than 255'; 
    SplitterWidth = 5; 

{ TIPEdit } 

constructor TIPEdit.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
    if AOwner is TWinControl then 
    Parent   := TWinControl(AOwner); 
    { Main Panle Style } 
    ParentBackground := False; 
    BevelKind  := bkFlat; 
    BevelOuter  := bvNone; 
    Color   := clWindow; 
    Height   := 25; 
    Width   := 165; 
    Caption   := ''; 
    ///////////////////////////// 

    { Set Handlers} 
    OnResize := OnPanelResize; 

    { Create child controls } 
    FPart1   := TEdit.Create(Self); 
    FPart1.Name  := 'IPEditPart1'; 
    FPart1.Visible := False; 
    FSplitter1  := TPanel.Create(Self); 
    FSplitter1.Name := 'IPSplitter1'; 
    FSplitter1.Visible:= False; 
    FPart2   := TEdit.Create(Self); 
    FPart2.Name  := 'IPEditPart2'; 
    FPart2.Visible := False; 
    FSplitter2  := TPanel.Create(Self); 
    FSplitter2.Name := 'IPSplitter2'; 
    FSplitter2.Visible:= False; 
    FPart3   := TEdit.Create(Self); 
    FPart3.Name  := 'IPEditPart3'; 
    FPart3.Visible := False; 
    FSplitter3  := TPanel.Create(Self); 
    FSplitter3.Name := 'IPSplitter3'; 
    FSplitter3.Visible:= False; 
    FPart4   := TEdit.Create(Self); 
    FPart4.Name  := 'IPEditPart4'; 
    FPart4.Visible := False; 
    FPart1.Align  := alLeft; 
    FSplitter1.Align := alLeft; 
    FPart2.Align  := alLeft; 
    FSplitter2.Align := alLeft; 
    FPart3.Align  := alLeft; 
    FSplitter3.Align := alLeft; 
    FPart4.Align  := alLeft; 
    ///////////////////////////// 

    { Set Child Style } 
    // This order is very important // 
    FPart1.Parent   := TWinControl(Self); 
    FSplitter1.Parent  := TWinControl(Self); 
    FPart2.Parent   := TWinControl(Self); 
    FSplitter2.Parent  := TWinControl(Self); 
    FPart3.Parent   := TWinControl(Self); 
    FSplitter3.Parent  := TWinControl(Self); 
    FPart4.Parent   := TWinControl(Self); 
    FPart1.Visible   := True; 
    FSplitter1.Visible  := True; 
    FPart2.Visible   := True; 
    FSplitter2.Visible  := True; 
    FPart3.Visible   := True; 
    FSplitter3.Visible  := True; 
    FPart4.Visible   := True; 
    ////////////////////////////////// 


    FPart1.Alignment    := taCenter; 
    FPart2.Alignment    := taCenter; 
    FPart3.Alignment    := taCenter; 
    FPart4.Alignment    := taCenter; 



    FPart1.Margins.Left   := 0; 
    FPart2.Margins.Left   := 0; 
    FPart3.Margins.Left   := 0; 
    FPart4.Margins.Left   := 0; 
    FSplitter1.Margins.Left  := 0; 
    FSplitter2.Margins.Left  := 0; 
    FSplitter3.Margins.Left  := 0; 
    FPart1.Margins.Right   := 0; 
    FPart2.Margins.Right   := 0; 
    FPart3.Margins.Right   := 0; 
    FPart4.Margins.Right   := 0; 
    FSplitter1.Margins.Right  := 0; 
    FSplitter2.Margins.Right  := 0; 
    FSplitter3.Margins.Right  := 0; 


    FPart1.AlignWithMargins  := True; 
    FSplitter1.AlignWithMargins := True; 
    FPart2.AlignWithMargins  := True; 
    FSplitter2.AlignWithMargins := True; 
    FPart3.AlignWithMargins  := True; 
    FSplitter3.AlignWithMargins := True; 
    FPart4.AlignWithMargins  := True; 
    FPart1.AutoSize    := False; 
    FPart2.AutoSize    := False; 
    FPart3.AutoSize    := False; 
    FPart4.AutoSize    := False; 
    FPart1.BorderStyle   := bsNone; 
    FPart2.BorderStyle   := bsNone; 
    FPart3.BorderStyle   := bsNone; 
    FPart4.BorderStyle   := bsNone; 
    FPart1.NumbersOnly   := True; 
    FPart2.NumbersOnly   := True; 
    FPart3.NumbersOnly   := True; 
    FPart4.NumbersOnly   := True; 
    FPart1.MaxLength    := 3; 
    FPart2.MaxLength    := 3; 
    FPart3.MaxLength    := 3; 
    FPart4.MaxLength    := 3; 
    FPart1.Width     := 36; 
    FPart2.Width     := 36; 
    FPart3.Width     := 36; 
    FPart4.Width     := 36; 
    FSplitter1.Alignment   := taCenter; 
    FSplitter2.Alignment   := taCenter; 
    FSplitter3.Alignment   := taCenter; 
    FSplitter1.Caption   := '.'; 
    FSplitter2.Caption   := '.'; 
    FSplitter3.Caption   := '.'; 
    FSplitter1.BevelOuter  := bvNone; 
    FSplitter2.BevelOuter  := bvNone; 
    FSplitter3.BevelOuter  := bvNone; 
    FSplitter1.Color    := clWindow; 
    FSplitter2.Color    := clWindow; 
    FSplitter3.Color    := clWindow; 
    FSplitter1.ParentBackground := False; 
    FSplitter2.ParentBackground := False; 
    FSplitter3.ParentBackground := False; 
    FSplitter1.TabStop   := False; 
    FSplitter2.TabStop   := False; 
    FSplitter3.TabStop   := False; 
    FSplitter1.Width    := SplitterWidth; 
    FSplitter2.Width    := SplitterWidth; 
    FSplitter3.Width    := SplitterWidth; 
    FSplitter1.Font.Style  := FSplitter1.Font.Style + [fsBold]; 
    FSplitter2.Font.Style  := FSplitter2.Font.Style + [fsBold]; 
    FSplitter3.Font.Style  := FSplitter3.Font.Style + [fsBold]; 
    ////////////////////////////// 

    {Set Child handlers} 
    FPart1.OnChange := EditOnChange; 
    FPart2.OnChange := EditOnChange; 
    FPart3.OnChange := EditOnChange; 
    FPart4.OnChange := EditOnChange; 
    FPart1.OnKeyDown := EditOnKeyDown; 
    FPart2.OnKeyDown := EditOnKeyDown; 
    FPart3.OnKeyDown := EditOnKeyDown; 
    FPart4.OnKeyDown := EditOnKeyDown; 
    FPart1.OnExit := EditOnExit; 
    FPart2.OnExit := EditOnExit; 
    FPart3.OnExit := EditOnExit; 
    FPart4.OnExit := EditOnExit; 

    {Set Child control tab order for the handlers work} 
    FPart1.TabOrder := 0; 
    FPart2.TabOrder := 1; 
    FPart3.TabOrder := 2; 
    FPart4.TabOrder := 3; 

    FPart1.Text := '1'; 
    FPart2.Text := '2'; 
    FPart3.Text := '3'; 
    FPart4.Text := '4'; 

    FExitType := etNext; 
    FErrMsg := Msg_Err_Value_Exceeded; 
end; 

destructor TIPEdit.Destroy; 
begin 
    FPart1.Free; 
    FPart2.Free; 
    FPart3.Free; 
    FPart4.Free; 

    FSplitter1.Free; 
    FSplitter2.Free; 
    FSplitter3.Free; 
    inherited; 
end; 

procedure TIPEdit.EditOnChange(Sender: TObject); 
var 
    iValue  : Integer; 
    bValGrater : Boolean; 
    I: Integer; 
begin 
    if NOT (Sender is TEdit) then Exit; 
    bValGrater := False; 
    if TryStrToInt(TEdit(Sender).Text, iValue) then begin 
    if (iValue > 255) then begin 
     iValue  := 255; 
     bValGrater := True; 
     TEdit(Sender).Text := iValue.ToString; 
     if (FRiseErr and bValGrater) then 
     raise Exception.Create(FErrMsg); 
    end; 
    end; 
    if Length(TEdit(Sender).Text) = 3 then begin 
    case FExitType of 
     etNone: ; 
     etNext: FindNextControl(TEdit(Sender), True, False, False).SetFocus; 
    end; 
    end; 
end; 

procedure TIPEdit.EditOnKeyDown(Sender: TObject; var Key: Word; 
    Shift: TShiftState); 
const 
    vkReturn = $0D; 
begin 
    if not (Sender is TEdit) then Exit; 
    if Key = vkReturn then 
    FindNextControl(TEdit(Sender), True, False, False).SetFocus; 
end; 

procedure TIPEdit.OnPanelResize(Sender: TObject); 
const 
    EditCount  = 4; 
    SplitterCount = 3; 
var 
    EditWidth  : Integer; 
    FSplitterWidth : Integer; 
    EditMargin  : Integer; 
begin 
    EditWidth := Trunc(((Width)/EditCount) - (SplitterCount * (SplitterWidth))); 
    FPart1.Width := EditWidth; 
    FPart2.Width := EditWidth; 
    FPart3.Width := EditWidth; 
    FPart4.Width := EditWidth; 
    FSplitterWidth := Trunc(((Width) - (EditWidth * EditCount))/SplitterCount); 
    FSplitter1.Width := FSplitterWidth; 
    FSplitter2.Width := FSplitterWidth; 
    FSplitter3.Width := FSplitterWidth; 

    {Center edits text vertically == this is a temporary workaround} 
    FPart1.Margins.Top := 0; 
    FPart2.Margins.Top := 0; 
    FPart3.Margins.Top := 0; 
    FPart4.Margins.Top := 0; 
    EditMargin := Round(((Height/5))); 
    FPart1.Margins.Top := EditMargin; 
    FPart2.Margins.Top := EditMargin; 
    FPart3.Margins.Top := EditMargin; 
    FPart4.Margins.Top := EditMargin; 
    FSplitter1.Margins.Top  := EditMargin + SplitterWidth; { the +lblWidth to make it lower than the edits} 
    FSplitter2.Margins.Top  := EditMargin + SplitterWidth; 
    FSplitter3.Margins.Top  := EditMargin + SplitterWidth; 
end; 

procedure TIPEdit.SetBevelInner(Value: TPanelBevel); 
begin 
    TPanel(Self).BevelInner := Value; 
end; 

procedure TIPEdit.SetExitType(Value: TExitType); 
begin 
    FExitType := Value; 
end; 

procedure TIPEdit.EditOnExit(Sender: TObject); 
var 
    I: Integer; 
begin 
    if not (Sender IS TEdit) then Exit; 
    if FLeadingzero then begin 
    if Length(TEdit(Sender).Text) >= 1 then 
    for I := Length(TEdit(Sender).Text) to 2 do begin 
     TEdit(Sender).Text := '0' + TEdit(Sender).Text; 
    end; 
    end; 
end; 

end. 
2

控件不提供一种机制来更新其创建后的布局。是的,你可以破解内部编辑控件,但这是危险的。您将依赖可能会更改的未公开的实现细节。

总之,我会说重新创建窗口是最好的解决方案。