📄 jvdatepickeredit.pas
字号:
{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: JvDatePickerEdit, released on 2002-10-04.
The Initial Developer of the Original Code is Oliver Giesen [giesen att lucatec dott de]
Portions created by Oliver Giesen are Copyright (C) 2002 Lucatec GmbH.
All Rights Reserved.
Contributor(s): Peter Th鰎nqvist.
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net
Description:
A replacement for TDateTimePicker which is better suited for keyboard-input by
ultimately descending from TCustomMaskEdit.
Other notable features (especially in comparison to the native DATETIMEPICKER):
- The control is able to construct a suitable EditMask from a valid date format
string such as the global ShortDateFormat (the default) which should make it
adapt well to regional settings / individual requirements.
- It is possible to specify a NoDateText which will be displayed when no date
is selected. The original datetimepicker would display 1899-12-31 in such
cases. This feature could be further controlled by the AllowNoDate and
NoDateShortcut properties.
Known issues / not (yet) implemented features:
- there is no real support for DateFormats containing any literal characters
other than the defined DateSeparator, especially spaces. it /might/ work in
some cases but in the majority of cases it will not.
TODO: simply disallow such characters or implement proper handling?
- as the embedded MS-calendar does not support dates prior to 1752-09-14,
neither does this control. this is not yet handled gracefully in absolutely
all situations though.
- the Min/MaxYear contstraints are currently commented out as they are not
functional in the current state. They would still require some work to make
up for two-digit year entries.
- the control does (currently) not allow for time entry
- it really is a control for date entry only.
-----------------------------------------------------------------------------}
// $Id: JvDatePickerEdit.pas,v 1.60 2005/03/06 23:04:08 remkobonte Exp $
unit JvDatePickerEdit;
{$I jvcl.inc}
interface
uses
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
Windows, Messages, Classes, Controls, ImgList,
JvCalendar, JvDropDownForm, JvCheckedMaskEdit, JvToolEdit;
type
{Types used to handle and convert between date format strings and EditMasks:}
TJvDateFigure = (dfNone, dfYear, dfMonth, dfDay);
TJvDateFigureInfo = record
Figure: TJvDateFigure;
Start: Byte;
Length: Byte;
Index: Byte;
end;
TJvDateFigures = array[ 0..2] of TJvDateFigureInfo;
{A dropdown form with an embedded calendar control.}
TJvDropCalendar = class(TJvCustomDropDownForm)
private
FCal: TJvCustomMonthCalendar;
FWithBeep: Boolean;
FOnChange: TNotifyEvent;
FOnSelect: TNotifyEvent;
FOnCancel: TNotifyEvent;
procedure CalSelChange(Sender: TObject; StartDate, EndDate: TDateTime);
procedure CalSelect(Sender: TObject; StartDate, EndDate: TDateTime);
procedure CalKeyPress(Sender: TObject; var Key: Char);
procedure CalKillFocus(const ASender: TObject; const ANextControl: TWinControl);
protected
procedure DoCancel;
procedure DoChange;
procedure DoSelect;
procedure DoShow; override;
function GetSelDate: TDateTime;
procedure SetSelDate(const AValue: TDateTime);
public
constructor CreateWithAppearance(AOwner: TComponent;
const AAppearance: TJvMonthCalAppearance);
destructor Destroy; override;
procedure SetFocus; override;
property SelDate: TDateTime read GetSelDate write SetSelDate;
property WithBeep: Boolean read FWithBeep write FWithBeep;
property OnCancel: TNotifyEvent read FOnCancel write FOnCancel;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnSelect: TNotifyEvent read FOnSelect write FOnSelect;
end;
TJvCustomDatePickerEdit = class(TJvCustomCheckedMaskEdit)
private
FAllowNoDate: Boolean;
FCalAppearance: TJvMonthCalAppearance;
FDate: TDateTime;
FDateError: Boolean;
FDeleting: Boolean;
FDateFigures: TJvDateFigures;
FInternalDateFormat,
FDateFormat: string;
FEnableValidation: Boolean;
FMask: string;
FNoDateShortcut: TShortcut;
FNoDateText: string;
FStoreDate: Boolean;
FAlwaysReturnEditDate: Boolean;
FEmptyMaskText: string;
FStoreDateFormat: Boolean;
FDateSeparator: Char;
// FMinYear: Word;
// FMaxYear: Word;
procedure CalChange(Sender: TObject);
procedure CalDestroy(Sender: TObject);
procedure CalSelect(Sender: TObject);
procedure CalCloseQuery(Sender: TObject; var CanClose: Boolean);
function AttemptTextToDate(const AText: string; var ADate: TDateTime;
const AForce: Boolean = False; const ARaise: Boolean = False): Boolean;
function DateFormatToEditMask(var ADateFormat: string): string;
function DateToText(const ADate: TDateTime): string;
function DetermineDateSeparator(AFormat: string): Char;
procedure ResetDateFormat;
procedure FindSeparators(var AFigures: TJvDateFigures; const AText: string; const AGetLengths: Boolean = True);
procedure ParseFigures(var AFigures: TJvDateFigures; AFormat: string; const AMask: string);
procedure RaiseNoDate;
procedure SetAllowNoDate(const AValue: Boolean);
procedure SetCalAppearance(const AValue: TJvMonthCalAppearance);
function GetDate: TDateTime;
procedure SetDate(const AValue: TDateTime);
procedure SetDateFormat(const AValue: string);
function GetDropped: Boolean;
procedure SetNoDateText(const AValue: string);
procedure SetDateSeparator(const AValue: Char);
function GetEditMask: string;
procedure SetEditMask(const AValue: string);
function GetText: TCaption;
procedure SetText(const AValue: TCaption);
procedure WMPaste(var Msg: TMessage); message WM_PASTE;
protected
function IsNoDateShortcutStored: Boolean;
function IsNoDateTextStored: Boolean;
procedure Change; override;
procedure Loaded; override;
procedure CreateWnd; override;
procedure DoKillFocus(const ANextControl: TWinControl); override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyPress(var Key: Char); override;
procedure CreatePopup; override;
procedure HidePopup; override;
procedure ShowPopup(Origin: TPoint); override;
procedure DoCtl3DChanged; override;
procedure EnabledChanged; override;
function GetChecked: Boolean; override;
function GetPopupValue: Variant; override;
procedure SetChecked(const AValue: Boolean); override;
procedure SetPopupValue(const Value: Variant); override;
procedure SetShowCheckbox(const AValue: Boolean); override;
function GetEnableValidation: Boolean; virtual;
procedure UpdateDisplay; virtual;
function ValidateDate(const ADate: TDateTime): Boolean; virtual;
function ActiveFigure: TJvDateFigureInfo;
procedure ClearMask;
procedure RestoreMask;
function IsEmptyMaskText(const AText: string): Boolean;
property AllowNoDate: Boolean read FAllowNoDate write SetAllowNoDate;
property AlwaysReturnEditDate: Boolean read FAlwaysReturnEditDate write FAlwaysReturnEditDate default True;
property CalendarAppearance: TJvMonthCalAppearance read FCalAppearance write SetCalAppearance;
property Date: TDateTime read GetDate write SetDate stored FStoreDate;
property DateFormat: string read FDateFormat write SetDateFormat stored FStoreDateFormat;
property DateSeparator: Char read FDateSeparator write SetDateSeparator stored FStoreDateFormat;
property Dropped: Boolean read GetDropped;
property EnableValidation: Boolean read GetEnableValidation write FEnableValidation default True;
property ImageKind default ikDropDown;
// property MaxYear: Word read FMaxYear write FMaxYear;
// property MinYear: Word read FMinYear write FMinYear;
property NoDateShortcut: TShortcut read FNoDateShortcut write FNoDateShortcut stored IsNoDateShortcutStored;
property NoDateText: string read FNoDateText write SetNoDateText stored IsNoDateTextStored;
property ShowButton default True;
property StoreDate: Boolean read FStoreDate write FStoreDate default False;
property StoreDateFormat: Boolean read FStoreDateFormat write FStoreDateFormat default False;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
class function DefaultImageIndex: TImageIndex; override;
procedure Clear; override;
function IsEmpty: Boolean; virtual;
property EditMask: string read GetEditMask write SetEditMask;
property Text: TCaption read GetText write SetText;
end;
TJvDatePickerEdit = class(TJvCustomDatePickerEdit)
public
property Dropped;
published
property Action;
property Align;
property AllowNoDate;
property AlwaysReturnEditDate;
property Anchors;
property AutoSelect;
property AutoSize;
property BorderStyle;
property ButtonFlat;
property ButtonHint;
property ButtonWidth;
property CalendarAppearance;
property Caret;
property CharCase;
property Checked;
property ClickKey;
property ClipboardCommands;
property Color;
property Constraints;
property Date;
property DateFormat;
property DateSeparator;
{$IFDEF VCL}
{property BiDiMode;}
{property ParentBiDiMode;}
property Flat;
property ImeMode;
property ImeName;
property OEMConvert;
property ParentCtl3D;
property OnEndDock;
property OnStartDock;
{$ENDIF VCL}
property DirectInput;
property DisabledColor;
property DisabledTextColor;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property EnableValidation;
property Font;
property Glyph;
property GroupIndex;
property HideSelection;
property HintColor;
property HotTrack;
// property MaxYear default 2900;
// property MinYear default 1900;
property ImageIndex;
property ImageKind;
property Images;
property NoDateShortcut;
property NoDateText;
property NumGlyphs;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ReadOnly;
property ShowCheckBox;
property ShowHint;
property ShowButton;
property StoreDate;
property StoreDateFormat;
property TabOrder;
property TabStop;
property Visible;
property OnButtonClick;
property OnChange;
property OnClick;
property OnCheckClick;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEnabledChanged;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnKillFocus;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnParentColorChange;
property OnSetFocus;
property OnStartDrag;
end;
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$RCSfile: JvDatePickerEdit.pas,v $';
Revision: '$Revision: 1.60 $';
Date: '$Date: 2005/03/06 23:04:08 $';
LogPath: 'JVCL\run'
);
{$ENDIF UNITVERSIONING}
implementation
uses
{$IFDEF HAS_UNIT_VARIANTS}
Variants,
{$ENDIF HAS_UNIT_VARIANTS}
SysUtils, Menus,
JclStrings,
{$IFDEF COMPILER5}
JvJCLUtils, // StrToXxxDef
{$ENDIF COMPILER5}
JvConsts, JvTypes, JvResources;
const
DateMaskSuffix = '!;1;_';
//=== { TJvCustomDatePickerEdit } ============================================
function TJvCustomDatePickerEdit.ActiveFigure: TJvDateFigureInfo;
var
I: Integer;
begin
for I := 2 downto 0 do
{ SelStart is 0-based, FDateFigures[I].Start is 1-based }
if SelStart + 1 >= FDateFigures[I].Start then
begin
Result := FDateFigures[I];
Exit;
end;
Result.Figure := dfNone;
end;
function TJvCustomDatePickerEdit.AttemptTextToDate(const AText: string;
var ADate: TDateTime; const AForce: Boolean; const ARaise: Boolean): Boolean;
var
OldFormat: string;
OldSeparator: Char;
OldDate: TDateTime;
Dummy: Integer;
begin
{only attempt to convert, if at least the Mask is matched
- otherwise we'd be swamped by exceptions during input}
if AForce or Validate(AText, Dummy) then
begin
OldDate := ADate;
OldFormat := ShortDateFormat;
OldSeparator := SysUtils.DateSeparator;
try
SysUtils.DateSeparator := FDateSeparator;
ShortDateFormat := FInternalDateFormat;
try
if AllowNoDate and IsEmptyMaskText(AText) then
ADate := 0.0
else
ADate := StrToDate(StrRemoveChars(AText, [' ']));
Result := True;
except
Result := False;
if (ARaise) then
raise
else
ADate := OldDate;
end;
finally
SysUtils.DateSeparator := OldSeparator;
ShortDateFormat := OldFormat;
end;
end
else
Result := False;
end;
procedure TJvCustomDatePickerEdit.CalChange(Sender: TObject);
begin
if FPopup is TJvDropCalendar then
Text := DateToText(TJvDropCalendar(FPopup).SelDate);
end;
procedure TJvCustomDatePickerEdit.CalCloseQuery(Sender: TObject; var CanClose: Boolean);
var
P: TPoint;
begin
{If we would let the calendar close itself while clicking the button, the
DropButtonClick method would simply reopen it again as it would find the
calendar closed.}
GetCursorPos(P);
CanClose := not PtInRect(Button.BoundsRect, Button.ScreenToClient(P));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -