Einzelnen Beitrag anzeigen

e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#1

Eigene Komponente für unvollständige Datumsangaben

  Alt 15. Mai 2017, 08:54
Hallo zusammen,

da ich immer wieder in die Situation komme, unvollständige Datumsangaben in eine Form eingeben zu müssen, habe ich mich nun am Wochenende mal hingesetzt und meine erste eigene Komponente geschrieben (siehe unten). Dafür, finde ich, ist sie nicht schlecht.

Allerdings stieß ich dabei auf einige Probleme, bei denen Ihr mir bestimmt weiterhelfen könnt:
1. In der Entwurfsansicht erhält das Panel immer automatisch eine Caption, obwohl ich diese im Constructor leere. Wieso kann ich das nicht unterbinden?
2. In der Entwurfsansicht lassen sich die drei Edit-Felder auf dem Panel verschieben. Wie kann man sowas verhindern?
3. Wenn ich die Komponente auf eine leere Form ziehe und dann das Projekt starte, kommt eine Fehlermelung 'Klasse TEdit nicht gefunden', obwohl im uses-Sektor der Komponete doch StdCtrls steht. Weiß jemand warum?
4. Wie sorge ich dafür, dass es trotz mehrere Komponenten mit jeweils eigenem Hint nur einmal ein Hinweis erscheint?

Viele Grüße
e-gon

Delphi-Quellcode:
unit DateEdit;

interface

  uses
    ExtCtrls, StdCtrls, Classes, DateUtils, SysUtils;

  type
    TDateFormatStyle = (fsDDMMYYYY, fsYYYYMMDD, fsMMDDYYYY);
    TFormatStyle = fsDDMMYYYY..fsMMDDYYYY;

    TCustomDateEdit = class(TCustomPanel)
    private
      FDate: Integer;
      FMinDate: Integer;
      FMaxDate: Integer;
      FFormatStyle: TFormatStyle;
      FFourDigit: Boolean;
      FAutoExpansionYear: Boolean;
      FEnabled: Boolean;
      dIndex: Byte;
      mIndex: Byte;
      yIndex: Byte;
      FEdit: Array [0..2] of TEdit;
      function CheckDate(const y,m,d: Word): Boolean;
      procedure SetDate(Value: Integer);
      procedure SetMinDate(Value: Integer);
      procedure SetMaxDate(Value: Integer);
      procedure SetFormatStyle(Value: TFormatStyle);
      procedure SetFourDigit(Value: Boolean);
      procedure SetAutoExpansionYear(Value: Boolean);
    protected
      procedure SetEnabled(Value: Boolean); override;
      procedure PanelExit(Sender: TObject);
      procedure FEditKeyPress(Sender: TObject; var Key: Char);
      procedure FEditExit(Sender: TObject);
      property Date: Integer read FDate write SetDate default 0;
      property MinDate: Integer read FMinDate write SetMinDate default 0;
      property MaxDate: Integer read FMaxDate write SetMaxDate default 0;
      property FormatStyle: TFormatStyle read FFormatStyle write SetFormatStyle default fsDDMMYYYY;
      property FourDigit: Boolean read FFourDigit write SetFourDigit default True;
      property AutoExpansionYear: Boolean read FAutoExpansionYear write SetAutoExpansionYear default False;
      property Enabled: Boolean read FEnabled write SetEnabled default True;
// property Hint: Integer read FHint write SetHint default 0;
    public
      constructor Create(AOwner: TComponent); override;
      destructor Destroy; override;
    end;

    TDateEdit = class(TCustomDateEdit)
    published
      property AutoExpansionYear;
      property Caption;
      property Color;
      property Date;
      property Enabled;
      property FormatStyle;
      property FourDigit;
      property Hint;
      property MinDate;
      property MaxDate;
      property ShowHint;
      property Visible;
    end;

  procedure Register;

implementation

  uses
    Dialogs, Graphics, Controls, UUtils;

  procedure Register;
  begin
    RegisterComponents('Beispiele', [TDateEdit]);
  end;


  function TCustomDateEdit.CheckDate(const y,m,d: Word): Boolean;
  var dAllow: Integer;
  begin
    Result:= True;

    if Result and (m>12) then begin
      MessageDLG('Ungültige Monatsangabe!',mtError,[mbOk],0);
      FEdit[mIndex].SetFocus;
      Result:= False;
    end;

    if Result then begin
      if m=0 then dAllow:= 31
      else dAllow:= DaysInAMonth(y,m);

      if d>dAllow then begin
        MessageDLG('Ungültiger Tag im Monat!',mtError,[mbOk],0);
        FEdit[dIndex].SetFocus;
        Result:= False;
      end;
    end;

    if Result and (y>0) and FFourDigit and (y<1000) then begin
      MessageDLG('Ungültige Jahresangabe! Da FourDigit gesetzt wurde, muss die Jahreszahl 4 Zeichen lang sein.',mtError,[mbOk],0);
      FEdit[yIndex].SetFocus;
      Result:= False;
    end;

    if Result and (y>0) and (y*10000+m*100+d<FMinDate) then begin
      MessageDLG('Das Datum ist kleiner als das angegebene Mindestdatum!',mtError,[mbOk],0);
      FEdit[yIndex].SetFocus;
      Result:= False;
    end;

    if Result and (FMaxDate>0) and (y*10000+m*100+d>FMaxDate) then begin
      MessageDLG('Das Datum ist größer als das angegebene Höchstdatum!',mtError,[mbOk],0);
      FEdit[yIndex].SetFocus;
      Result:= False;
    end;
  end;


  constructor TCustomDateEdit.Create(AOwner: TComponent);
  var x: Integer;
  begin
    inherited Create(AOwner);
    Color:= clBtnFace;
    BevelOuter:= bvNone;
    Height:= 25;
    Constraints.MaxWidth:= Width;
    Constraints.MinWidth:= Width;
    Width:= 85;
    Constraints.MaxHeight:= Height;
    Constraints.MinHeight:= Height;
    UseDockManager:= True;
    OnExit:= PanelExit;

    for x:= 0 to Length(FEdit)-1 do begin
      FEdit[x]:= TEdit.Create(AOwner);
      FEdit[x].Parent:= Self;
      FEdit[x].Tag:= x;
      FEdit[x].Top:= 2;
      FEdit[x].Left:= 2+(x*24);
      FEdit[x].Width:= 21+(Trunc(x/2)*12);
      FEdit[x].MaxLength:= 2+(Trunc(x/2)*2);
      FEdit[x].OnKeyPress:= FEditKeyPress;
      FEdit[x].OnExit:= FEditExit;
    end;

    dIndex:= 0;
    mIndex:= 1;
    yIndex:= 2;
    Caption:= '';
  end;


  destructor TCustomDateEdit.Destroy;
  var x: Integer;
  begin
    for x:= 0 to Length(FEdit)-1 do FEdit[x].Free;
    inherited Destroy;
  end;


  procedure TCustomDateEdit.FEditKeyPress(Sender: TObject; var Key: Char);
  var w: Word;
  begin
    w:= (Sender as TEdit).Tag;
    case Key of
      '0'..'9':
        begin
          if (Length(FEdit[w].Text)-FEdit[w].SelLength=FEdit[w].MaxLength-1) and (w<2) then
            FEdit[w+1].SetFocus;
        end;
      '.':
        begin
          if (FFormatStyle=fsDDMMYYYY) and (w<2) and (FEdit[w].Text<>'') then
            FEdit[w+1].SetFocus;
          Key:= #0;
        end;
      '-':
        begin
          if (FFormatStyle=fsYYYYMMDD) and (w<2) and (FEdit[w].Text<>'') then
            FEdit[w+1].SetFocus;
          Key:= #0;
        end;
      '/':
        begin
          if (FFormatStyle=fsMMDDYYYY) and (w<2) and (FEdit[w].Text<>'') then
            FEdit[w+1].SetFocus;
          Key:= #0;
        end;
      #8:
        begin
          if (FEdit[w].Text='') and (w>0) then begin
            FEdit[w-1].Text:= Copy(FEdit[w-1].Text,1,Length(FEdit[w-1].Text)-1);
            FEdit[w-1].SetFocus;
            FEdit[w-1].SelStart:= -1;
            Key:= #0;
          end;
        end;
      else Key:= #0;
    end;
  end;


  procedure TCustomDateEdit.FEditExit(Sender: TObject);
  var E: TEdit;
       i: Integer;
  begin
    E:= (Sender as TEdit);
    i:= StrToInt(E.Text);

    if FAutoExpansionYear and (E.Tag=yIndex) and (i>0) and (Length(E.Text)<3) then begin
      if i<50 then Inc(i,2000)
      else Inc(i,1900);
      E.Text:= IntToStr(i);
    end;
  end;


  procedure TCustomDateEdit.PanelExit(Sender: TObject);
  var d,m,y: Word;
  begin
    d:= StrToInt(FEdit[dIndex].Text);
    m:= StrToInt(FEdit[mIndex].Text);
    y:= StrToInt(FEdit[yIndex].Text);
    
    if CheckDate(y,m,d) then FDate:= d+m*100+y*10000;
  end;


  procedure TCustomDateEdit.SetDate(Value: Integer);
  var d,m,y: Word;
       i: Integer;
  begin
    y:= Value div 10000;
    i:= Value mod 10000;
    m:= i div 100;
    d:= i mod 100;

    FEdit[dIndex].Text:= FormatFloat('00',d);
    FEdit[mIndex].Text:= FormatFloat('00',m);
    FEdit[yIndex].Text:= IntToStr(y);

    if CheckDate(y,m,d) then FDate:= Value;
  end;


  procedure TCustomDateEdit.SetMinDate(Value: Integer);
  begin
    FMinDate:= Value;
  end;


  procedure TCustomDateEdit.SetMaxDate(Value: Integer);
  begin
    FMaxDate:= Value;
  end;


  procedure TCustomDateEdit.SetFormatStyle(Value: TFormatStyle);
  var y,m,d: string;
       i,Pix: Integer;
       IsYear: Boolean;
  begin
    if FFormatStyle<>Value then begin
      FFormatStyle:= Value;
      d:= FEdit[dIndex].Text;
      m:= FEdit[mIndex].Text;
      y:= FEdit[yIndex].Text;

      if FFormatStyle=fsDDMMYYYY then begin
        dIndex:= 0;
        mIndex:= 1;
        yIndex:= 2;
      end
      else if FFormatStyle=fsMMDDYYYY then begin
        dIndex:= 1;
        mIndex:= 0;
        yIndex:= 2;
      end
      else begin
        dIndex:= 2;
        mIndex:= 1;
        yIndex:= 0;
      end;

      Pix:= 2;
      for i:= 0 to 2 do begin
        IsYear:= i=yIndex;
        FEdit[i].Left:= Pix;
        FEdit[i].Width:= 21+(BoolToInt(IsYear)*12);
        FEdit[i].MaxLength:= 2+(BoolToInt(IsYear)*2);
        Inc(Pix,FEdit[i].Width+3);

        if i=dIndex then FEdit[i].Text:= d
        else if i=mIndex then FEdit[i].Text:= m
        else FEdit[i].Text:= y;
      end;
    end;
  end;


  procedure TCustomDateEdit.SetFourDigit(Value: Boolean);
  begin
    FFourDigit:= Value;
  end;


  procedure TCustomDateEdit.SetAutoExpansionYear(Value: Boolean);
  begin
    FAutoExpansionYear:= Value;
  end;

  procedure TCustomDateEdit.SetEnabled(Value: Boolean);
  var i: Integer;
  begin
    FEnabled:= Value;
    for i:= 0 to 2 do FEdit[i].Enabled:= Value;
  end;

end.
  Mit Zitat antworten Zitat