unit Dates;
interfaceuses
SysUtils, Classes;
type
TDate = class (TComponent)
private
FMonth, FDay, FYear: Integer;
FOnChange: TNotifyEvent;
protectedfunction DaysInMonth: Integer;
procedure SetMonth (Value: Integer);
procedure SetYear (Value: Integer);
procedure SetDay (Value: Integer);
procedure DoChange; virtual;
publicconstructor Create (AOwner: TComponent); override;
constructor Init (m, d, y: Integer);
procedure SetValue (m, d, y: Integer);
function LeapYear: Boolean;
procedure Increase;
procedure Decrease;
procedure Add (NumberOfDays: Integer);
procedure Subtract (NumberOfDays: Integer);
function GetText: string;
// properties:property Text: stringread GetText;
publishedproperty Day: Integer read FDay write SetDay;
property Month: Integer read FMonth write SetMonth;
property Year: Integer read FYear write SetYear;
// event:property OnChange: TNotifyEvent
read FonChange write FOnChange;
end;
// dates exceptiontype
EDateOutOfRange = class (Exception);
procedureRegister;
implementationconstructor TDate.Create (AOwner: TComponent);
var
Y, D, M: Word;
begininherited Create (AOwner);
// today...
DecodeDate (Now, Y, M, D);
FYear := Y;
FMonth := M;
FDay := D;
end;
constructor TDate.Init (m, d, y: Integer);
begin
SetValue (m, d, y);
end;
procedure TDate.DoChange;
beginif Assigned (FOnChange) then
FOnChange (self);
end;
procedure TDate.SetValue (m, d, y: Integer);
var
OldY, OldM: Integer;
begin// store the old value
OldY := FYear;
OldM := FMonth;
// assing the new valuetry
FYear := y;
// check the ranges
SetMonth (m);
SetDay (d);
DoChange;
excepton EDateOutOfRange dobegin// reset the values
FYear := OldY;
FMonth := OldM;
// let the error show upraise;
end;
end;
end;
procedure TDate.SetMonth (Value: Integer);
beginif (Value >= 1) and (Value <= 12) thenbegin
FMonth := Value;
DoChange;
endelseraise EDateOutOfRange.Create ('Month out of range');
end;
procedure TDate.SetYear (Value: Integer);
begin
FYear := Value;
DoChange;
end;
procedure TDate.SetDay (Value: Integer);
beginif (Value >= 1) and (Value <= DaysInMonth) thenbegin
FDay := Value;
DoChange;
endelseraise EDateOutOfRange.Create ('Day out of range');
end;
function TDate.LeapYear: Boolean;
begin// compute leap years, considering "exceptions"if (FYear mod 4 <> 0) then
LeapYear := False
elseif (FYear mod 100 <> 0) then
LeapYear := True
elseif (FYear mod 400 <> 0) then
LeapYear := False
else
LeapYear := True;
end;
function TDate.DaysInMonth: Integer;
begincase FMonth of
1, 3, 5, 7, 8, 10, 12:
DaysInMonth := 31;
4, 6, 9, 11:
DaysInMonth := 30;
2:
if (LeapYear) then
DaysInMonth := 29
else
DaysInMonth := 28;
else// if the month is not correct
DaysInMonth := 0;
end;
end;
procedure TDate.Increase;
begin// if this day is not the last of the monthif FDay < DaysInMonth then
Inc (FDay) // increase the value by 1else// if it is not in Decemberif FMonth < 12 thenbegin// Day 1 of next month
Inc (FMonth);
FDay := 1;
endelsebegin// else it is next year New Year's Day
Inc (FYear);
FMonth := 1;
FDay := 1;
end;
DoChange;
end;
// exactly the reverse of the Increase methodprocedure TDate.Decrease;
beginif FDay > 1 then
Dec (FDay) // decrease the value by 1else// it is the first of a monthif FMonth > 1 thenbegin// assign last day of previous month
Dec (FMonth);
FDay := DaysInMOnth;
endelse// it is the first of Januarybegin// assign last day of previous year
Dec (FYear);
FMonth := 12;
FDay := DaysInMOnth;
end;
DoChange;
end;
function TDate.GetText: string;
begin
GetText := Format ('%s %d, %d',
[LongMonthNames[Month], Day, Year]);
end;
procedure TDate.Add (NumberOfDays: Integer);
var
N: Integer;
begin// increase the day n timesfor N := 1 to NumberOfDays do
Increase;
end;
procedure TDate.Subtract (NumberOfDays: Integer);
var
N: Integer;
begin// decrease the day n timesfor N := 1 to NumberOfDays do
Decrease;
end;
procedureRegister;
begin
RegisterComponents ('Md3', [TDate]);
end;
end.
unit SList;
interfaceuses
Classes;
type
TSafeList = classprivate
LType: TClass;
FList: TList;
function Get (Index: Integer): TObject;
procedure Put (Index: Integer; Item: TObject);
function GetCount: Integer;
publicconstructor Create (CType: TClass);
destructor Destroy; override;
function Add (Item: TObject): Integer;
function Equals(List: TSafeList): Boolean;
property Count: Integer read GetCount;
property Items [Index: Integer]: TObject
read Get write Put; default;
end;
implementationuses
SysUtils;
constructor TSafeList.Create (CType: TClass);
begin
FList := TList.Create;
LType := CType;
end;
destructor TSafeList.Destroy;
begin
FList.Free;
inherited Destroy;
end;
function TSafeList.Get(Index: Integer): TObject;
begin
Result := FList [Index];
end;
function TSafeList.Add (Item: TObject): Integer;
var
Test: Boolean;
begintry
Test := Item is LType;
excepton Exception doraise EInvalidCast.Create (Format (
'SafeList: Cannot add a non-object to a list of %s objects',
[LType.ClassName]));
end;
if Test then
Result := FList.Add (Item)
elseraise EInvalidCast.Create (Format (
'SafeList: Cannot add a %s object to a list of %s objects',
[Item.ClassName, LType.ClassName]));
end;
procedure TSafeList.Put(Index: Integer; Item: TObject);
var
Test: Boolean;
begintry
Test := Item is LType;
excepton Exception doraise EInvalidCast.Create (Format (
'SafeList: Cannot put a non-object into a list of %s objects',
[LType.ClassName]));
end;
if Test then
FList [Index] := Item
elseraise EInvalidCast.Create (Format (
'SafeList: Cannot put a %s object into a list of %s objects',
[TObject(Item).ClassName, LType.ClassName]));
end;
function TSafeList.GetCount: Integer;
begin
Result := FList.Count;
end;
function TSafeList.Equals(List: TSafeList): Boolean;
var
I: Integer;
begin
Result := False;
if List.Count <> FList.Count then
Exit;
for I := 0 to List.Count - 1 doif List[I] <> FList[I] then
Exit;
Result := True;
end;
end.
unit SafeForm;
interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, SList;
type
TForm1 = class(TForm)
ButtonAddDates: TButton;
ButtonAddButton: TButton;
ButtonAddPointer: TButton;
ButtonNewDate: TButton;
ListBox1: TListBox;
ButtonNewButton: TButton;
ButtonNewPointer: TButton;
procedure ButtonAddDatesClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ButtonAddButtonClick(Sender: TObject);
procedure ButtonAddPointerClick(Sender: TObject);
procedure ButtonNewDateClick(Sender: TObject);
procedure ButtonNewButtonClick(Sender: TObject);
procedure ButtonNewPointerClick(Sender: TObject);
private
List: TSafeList;
publicprocedure UpdateList;
end;
var
Form1: TForm1;
implementation{$R *.DFM}uses
Dates;
procedure TForm1.ButtonAddDatesClick(Sender: TObject);
var
I: Integer;
begin
Randomize;
tryfor I := 1 to 10 do
List.Add (TDate.Init (
1 + Random (12), 1 + Random (28),
1900 + Random (200)));
finally
UpdateList;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
List := TSafeList.Create (TDate);
end;
procedure TForm1.ButtonAddButtonClick(Sender: TObject);
begin
List.Add (Sender);
UpdateList;
end;
procedure TForm1.ButtonAddPointerClick(Sender: TObject);
var
P: Pointer;
begin
P := @Form1;
List.Add (P);
UpdateList;
end;
procedure TForm1.UpdateList;
var
I: Integer;
begin
ListBox1.Clear;
for I := 0 to List.Count - 1 do
Listbox1.Items.Add ((
TDate(List [I]).GetText));
end;
procedure TForm1.ButtonNewDateClick(Sender: TObject);
begin
List [1] := TDate.Create (self);
UpdateList;
end;
procedure TForm1.ButtonNewButtonClick(Sender: TObject);
begin
List [1] := Sender;
UpdateList;
end;
procedure TForm1.ButtonNewPointerClick(Sender: TObject);
var
S: String;
begin
S := 'Hi';
List [1] := Pointer(S);
UpdateList;
end;
end.
Программный проект на языке Delphi, состоящий из трех модулей: Dates, SList и SafeForm. Вот подробное описание каждого модуля:
Dates.pas
Этот модуль определяет класс TDate, который представляет собой дату. Класс имеет свойства для месяца, дня и года, а также методы для увеличения или уменьшения даты на один день, добавления или вычитания заданного количества дней и получения текстового представления даты.
Кроме того, класс TDate выбрасывает исключения при попытке установить недопустимую дату (например, 30 февраля).
SList.pas
Этот модуль определяет класс TSafeList, который является списком объектов, который может содержать только объекты определенного типа. Класс имеет методы для добавления и удаления элементов из списка, а также метод для проверки равенства двух списков.
Класс TSafeList использует underlying объект TList для хранения элементов, но добавляет дополнительный слой безопасности, проверяя каждый элемент на соответствие типу перед добавлением в список.
SafeForm.pas
Этот модуль определяет класс TForm1, который является формой с несколькими кнопками и списком. Форма имеет методы для обработки кликов по кнопкам и обновления списка.
Класс TSafeList используется для хранения дат в списке формы. Форма может добавлять даты в список с помощью кнопки "Добавить даты" или другие типы объектов (например, кнопки или указатели) с помощью кнопок "Добавить кнопку" и "Добавить указатель".
Форма также имеет методы для обновления списка при добавлении или удалении элемента из списка.
В целом, этот проект демонстрирует, как создать custom список класса, который может содержать только объекты определенного типа, и использовать его в приложении Delphi.
Сохранение типа списка объектов: в этом проекте создана система для хранения и обмена данными о датах, использованы классы TDate и TSafeList. Класс TDate отвечает за хранение и форматирование дат, а класс TSafeList - за безопасное хранение списка объектов
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.