atimectl.pas

来自「delphi编程控件」· PAS 代码 · 共 747 行 · 第 1/2 页

PAS
747
字号
            Pixels[Left, Bottom] := clBtnFace;
            Pixels[Right, Top] := clBtnFace;
          end;
        end;
      end;
    end;
  end;

  procedure DrawArrows;
  var
    Hour, Min, Sec, MSec: Word;
    X, Y: Longint;
    Alpha: Extended;

    procedure DrawArrow(Alpha, Radius, Thickness: Extended;
      IsShadow: Boolean; Altitude: Integer);
    const
      Colors: array[Boolean] of TColor = (clTeal, clBtnHighlight);
    var
      FirstPart: Boolean;
      P: array[1..4] of TPoint;
      I: Byte;
    begin
      FirstPart := (Alpha <= -5/4 * Pi) or (Alpha >= -1/4 * Pi);
      with Bitmap.Canvas do
      begin
        FromPolarToCartesian(Alpha + Pi, 0.2 * Radius, P[1].X, P[1].Y);
        FromPolarToCartesian(Alpha + Pi/2, Thickness / 2 * Radius, P[2].X, P[2].Y);
        FromPolarToCartesian(Alpha, 0.8 * Radius, P[3].X, P[3].Y);
        P[4] := Point(CX, CY - 2);
        if IsShadow then
        begin
          for I := 1 to 3 do
          begin
            Inc(P[I].X, Altitude);
            Inc(P[I].Y, Altitude);
          end;
          Brush.Color := clBtnShadow;
        end
        else Brush.Color := Colors[FirstPart];
        Pen.Color := Brush.Color;
        Polygon(P);
        FromPolarToCartesian(Alpha - Pi/2, Thickness / 2 * Radius, P[2].X, P[2].Y);
        if IsShadow then
        begin
          Inc(P[2].X, Altitude);
          Inc(P[2].Y, Altitude);
        end;
        if not IsShadow then Brush.Color := Colors[not FirstPart];
        Pen.Color := Brush.Color;
        Polygon(P);
      end;
    end;

  begin
    DecodeTime(Time, Hour, Min, Sec, MSec);
    with Bitmap.Canvas do
    begin
      { second arrow }
      Alpha := Pi/2 - Sec / 30 * Pi;
      FromPolarToCartesian(Alpha, 0.85 * Radius, X, Y);
      Pen.Color := clBlack;
      MoveTo(CX, CY);
      LineTo(X, Y);
      { minute arrow }
      Alpha := Pi/2 - (Min + Sec / 60) / 30 * Pi;
      DrawArrow(Alpha, Radius, 0.1, True, 2);
      DrawArrow(Alpha, Radius, 0.1, False, 2);
      { hour arrow }
      Alpha := Pi/2 - (Hour + Min / 60 + Sec / SecondsPerHour) / 6 * Pi;
      if Alpha <= -2 * Pi then Alpha := Alpha + 2 * Pi;
      DrawArrow(Alpha, 0.8 * Radius, 0.18, True, 3);
      DrawArrow(Alpha, 0.8 * Radius, 0.18, False, 3);
    end;
  end;

  procedure DrawElectronClock;
  var
    TimeStr: string;
    Extent: TSize;
    R: TRect;
  begin
    TimeStr := TimeToStr(Time);
    if TimeStr[2] = TimeSeparator then TimeStr := '0' + TimeStr;
    with Bitmap.Canvas do
    begin
      GetTextExtentPoint(Handle, PChar(TimeStr), Length(TimeStr), Extent);
      SetRect(R, 0, 0, Extent.cX, Extent.cY);
      OffsetRect(R, (ClientWidth - Extent.cX) div 2,
        CY + (CY - Extent.cY) div 2);
      InflateRect(R, 3, 1);
      Brush.Color := clWindow;
      Font.Color := clWindowText;
      FillRect(R);
      DrawText(Handle, PChar(TimeStr), Length(TimeStr), R,
        DT_CENTER or DT_SINGLELINE or DT_VCENTER);
      InflateRect(R, 2, 2);
      DrawEdge(Handle, R, EDGE_SUNKEN, BF_RECT);
    end;
  end;

begin
  inherited Paint;
  CX := ClientWidth div 2;
  CY := CX;
  Radius := Round(0.8 * CX);
  Bitmap := TBitmap.Create;
  Bitmap.Width := ClientWidth;
  Bitmap.Height := ClientHeight;
  with Bitmap.Canvas do
  begin
    Font := Self.Font;
    Brush.Color := clBtnFace;
    FillRect(ClientRect);
  end;
  DrawFace;
  DrawElectronClock;
  DrawArrows;
  Canvas.Draw(0, 0, Bitmap);
  Bitmap.Free;
end;

procedure TCustomAutoTimeControl.SetParent(AParent: TWinControl);
begin
  inherited SetParent(AParent);
  SetSize;
end;

procedure TCustomAutoTimeControl.SetSize;
begin
  if (not IsPopup and (Parent = nil)) or
    (csDestroying in ComponentState) then Exit;
  Height := GetHeight;
  RecreateWnd;
end;

procedure TCustomAutoTimeControl.Hide;
begin
  if IsPopup then DestroyHandle
  else inherited Hide;
  if Assigned(FOnHide) then FOnHide(Self);
end;

procedure TCustomAutoTimeControl.Show;
begin
  SetSize;
  if IsPopup then
  begin
    ShowWindow(Handle, SW_SHOW);
    SendMessage(TForm(Owner).Handle, WM_NCACTIVATE, Longint(True), 0);
    Windows.SetFocus(FTrackBar.Handle);
    ShowWindow(FTrackBar.Handle, SW_SHOW);
  end
  else inherited Show;
end;

{ TDropDownButton }

type
  TDropDownButton = class(TSpeedButton)
  private
    IsShowingPopup: Boolean;
    procedure HidePopup(Sender: TObject);
    procedure TimeChange(Sender: TObject);
    procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Click; override;
  end;

constructor TDropDownButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Align := alRight;
  Cursor := crArrow;
  Width := GetSystemMetrics(SM_CXVSCROLL);
end;

procedure TDropDownButton.HidePopup(Sender: TObject);
var
  P: TPoint;
begin
  GetCursorPos(P);
  P := ScreenToClient(P);
  if (GetAsyncKeyState(VK_LBUTTON) shr 15 = 0) or
    not PtInRect(ClientRect, P) then
    IsShowingPopup := False;
end;

procedure TDropDownButton.TimeChange(Sender: TObject);
begin
  TCustomAutoTimeEdit(Parent).Time := TCustomAutoTimeControl(Sender).Time;
end;

procedure TDropDownButton.WMLButtonDown(var Message: TWMLButtonDown);
begin
  if IsShowingPopup then IsShowingPopup := False
  else inherited;
end;

procedure TDropDownButton.Paint;
const
  EnabledStyles: array[Boolean] of Integer = (DFCS_INACTIVE, 0);
  DownStyles: array[Boolean] of Integer = (0, DFCS_PUSHED);
begin
  inherited Paint;
  with Canvas do
    DrawFrameControl(Handle, ClientRect, DFC_SCROLL, DFCS_SCROLLCOMBOBOX or
      EnabledStyles[Parent.Enabled] or DownStyles[FState = bsDown]);
end;

procedure TDropDownButton.Click;
var
  P: TPoint;
  R: TRect;
begin
  if TCustomAutoTimeEdit(Parent).ReadOnly then Exit;
  inherited Click;
  Parent.SetFocus;
  with Parent do
    P := Parent.ClientToScreen(Point(Left, Top + Height));
  with TCustomAutoTimeControl.Create(GetParentForm(Self)) do
  begin
    IsPopup := True;
    Left := P.X;
    Top := P.Y;
    Width := TCustomAutoTimeEdit(Self.Parent).DropDownWidth;
    Time := TCustomAutoTimeEdit(Self.Parent).Time;
    OnHide := HidePopup;
    OnTimeChange := TimeChange;
    SetSize;
    SystemParametersInfo(SPI_GETWORKAREA, 0, @R, 0);
    if Left < R.Left then Left := R.Left;
    if Left + Width > R.Right then
      Left := R.Right - Width;
    if Top + Height > R.Bottom then
      Top := Top - (Self.Parent.Height + Height);
    IsShowingPopup := True;
    Show;
  end;
end;

{ TCustomAutoTimeEdit }

constructor TCustomAutoTimeEdit.Create(AOwner: TComponent);
var
  OldDefaultBlank: Char;
begin
  inherited Create(AOwner);
  OldDefaultBlank := DefaultBlank;
  DefaultBlank := '0';
  EditMask := '00:00:00';
  MaxLength := 8;
  DefaultBlank := OldDefaultBlank;
  FDropDownWidth := 165;
  DropDownButton := TDropDownButton.Create(Self);
  DropDownButton.Parent := Self;
  Time := SysUtils.Time;
end;

function TCustomAutoTimeEdit.GetTime: TDateTime;
begin
  Result := StrToTime(EditText);
end;

procedure TCustomAutoTimeEdit.SetTime(Value: TDateTime);
begin
  if Value <> Time then
  begin
    EditText := FormatDateTime(TimeFormat, Value);
    Update;
    DoTimeChange;
  end;
end;

procedure TCustomAutoTimeEdit.WMEraseBkgnd(var Message: TWMEraseBkgnd);
var
  R: TRect;
begin
  R := ClientRect;
  Dec(R.Right, GetSystemMetrics(SM_CXVSCROLL));
  FillRect(Message.DC, R, Brush.Handle);
  Message.Result := 1;
end;

procedure TCustomAutoTimeEdit.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do Style := Style or ES_MULTILINE;
end;

procedure TCustomAutoTimeEdit.DoTimeChange;
begin
  if Assigned(FOnTimeChange) then FOnTimeChange(Self);
end;

function TCustomAutoTimeEdit.EditingPlace: TEditingPlace;
var
  S: string;
  Pos: Integer;
begin
  S := UpperCase(TimeFormat);
  Pos := SelStart + 1;
  if Pos > MaxLength then Pos := MaxLength;
  case S[Pos] of
    'H': Result := epHour;
    'N': Result := epMin;
    'S': Result := epSec;
  else Result := epError;
  end;
end;

procedure TCustomAutoTimeEdit.KeyDown(var Key: Word; Shift: TShiftState);

  procedure ChangeValue(Delta: Integer);
  var
    OldSelStart, OldSelStop: Integer;
    Hour, Min, Sec, MSec: Word;
    Seconds: Integer;
  begin
    GetSel(OldSelStart, OldSelStop);
    DecodeTime(Time, Hour, Min, Sec, MSec);
    Seconds := EncodeSeconds(Hour, Min, Sec);
    case EditingPlace of
      epHour: Inc(Seconds, SecondsPerHour * Delta);
      epMin: Inc(Seconds, 60 * Delta);
      epSec: Inc(Seconds, Delta);
      else Exit;
    end;
    if (Seconds < 0) or (Seconds >= SecondsPerDay) then Exit;
    DecodeSeconds(Seconds, Hour, Min, Sec);
    Time := EncodeTime(Hour, Min, Sec, 0);
    SetSel(OldSelStart, OldSelStop);
  end;

begin
  if not ReadOnly then
    case Key of
      VK_DOWN:
        if Shift = [ssAlt] then DropDownButton.Click
        else ChangeValue(-1);
      VK_UP: ChangeValue(1);
      VK_F4: if Shift = [] then DropDownButton.Click;
    end;
  inherited KeyDown(Key, Shift);
end;

procedure TCustomAutoTimeEdit.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
var
  R: TRect;
  W: Integer;
begin
  inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  if HandleAllocated then
  begin
    Perform(EM_GETRECT, 0, Longint(@R));
    W := GetSystemMetrics(SM_CXVSCROLL);
    if BorderStyle = bsSingle then Dec(W);
    if (R.Right - R.Left <= ClientWidth - W) or
      (Width = 0) or (Height = 0) then Exit;
    Dec(R.Right, W);
    Perform(EM_SETRECT, 0, Longint(@R));
    DropDownButton.Height := ClientHeight;
  end;
end;

initialization
  TimeFormat := 'hh:nn:ss';

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?