2017-08-11 137 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

控件不提供一種機制來更新其創建後的佈局。是的,你可以破解內部編輯控件,但這是危險的。您將依賴可能會更改的未公開的實現細節。

總之,我會說重新創建窗口是最好的解決方案。