Delphi 7
Delphi 7
.
.
:
.
. .
:
X : .
X .
X TrakBar ProgressBar .
X .
X .
X .
X .
DataSource DataSource .
DataSource Data link
TDataLink .
.
DataSource.DataField
DataSource DataLink .
)
( .
.
) .(One-to-many
)
( .
TDataLink
.DB
. " " .
.
:
TDataLink
)TDataLink = class(TPersistent
protected
;procedure ActiveChanged; virtual
;procedure CheckBrowseMode; virtual
;procedure DataSetChanged; virtual
;procedure DataSetScrolled(Distance: Integer); virtual
;procedure FocusControl(Field: TFieldRef); virtual
;procedure EditingChanged; virtual
;procedure LayoutChanged; virtual
;procedure RecordChanged(Field: TField); virtual
;procedure UpdateData; virtual
DataEvent
) .(TDataEvent
.
DataEvent .
NotifyDataLinks
OnDataChange OnUpdateData .
.17
TDataLink .
. TFieldDataLink
TDataLink
.
TFieldDataLink .
TDataLink . TFieldDataLink
.
.
:
;procedure TFieldDataLink.ActiveChanged
begin
;UpdateField
;)if Assigned(FOnActiveChange) then FOnActiveChange(Self
;end
.
ProgressBar .TrackBar ) (
. .
: MdDataPack
.
.
ProgressBar
ProgressBar
.
:
type
TMdDbProgress = class(TProgressBar)
private
FDataLink: TFieldDataLink;
function GetDataField: string;
procedure SetDataField (Value: string);
function GetDataSource: TDataSource;
procedure SetDataSource (Value: TDataSource);
function GetField: TField;
protected
// data link event handler
procedure DataChange (Sender: TObject);
// useless
{procedure Notification (AComponent: TComponent;
Operation: TOperation); override;}
public
constructor Create (AOwner: TComponent); override;
destructor Destroy; override;
property Field: TField read GetField;
published
property DataField: string read GetDataField write SetDataField;
property DataSource: TDataSource read GetDataSource write
SetDataSource;
end;
DataField DataSource
.
:
function TMdDbProgress.GetDataField: string;
begin
Result := FDataLink.FieldName;
end;
procedure TMdDbProgress.SetDataField (Value: string);
begin
FDataLink.FieldName := Value;
end;
function TMdDbProgress.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
procedure TMdDbProgress.SetDataSource (Value: TDataSource);
begin
.17
;FDataLink.DataSource := Value
;end
;function TMdDbProgress.GetField: TField
begin
;Result := FDataLink.Field
;end
:
;)constructor TMdDbProgress.Create (AOwner: TComponent
begin
;)inherited Create (AOwner
;FDataLink := TFieldDataLink.Create
;FDataLink.Control := self
;FDataLink.OnDataChange := DataChange
;end
;destructor TMdDbProgress.Destroy
begin
;FDataLink.Free
;FDataLink := nil
;inherited Destroy
;end
.
.
:
;)procedure TMdDbProgress.DataChange (Sender: TObject
begin
if FDataLink.Field is TNumericField then
Position := FDataLink.Field.AsInteger
else
;Position := Min
;end
VCL
.
SetDataField .
17-1 DbProgr
.
.
MdProgr .
.
DBCtrlGrid .
:17-1
ProgressBar .DbProgr
: Notification
.
.
Notification VCL
.
DBCtrlGrid .
MdRepPr MdDataPack
RepProgr HTML .
DBCtrlGrid : .
) (buffer
.
DBCtlGrid csReplicatable
.
cm_GeTDataLink .
Paint ) (Canvas
wm_Paint csPaintCopy ControlState .True
DBCtrlGrid
.
:
.17
TrackBar
.
.
FieldDataLink .
TrackBar
. .
) MdTrack :(MdDataPack
type
)TMdDbTrack = class(TTrackBar
private
;FDataLink: TFieldDataLink
;function GetDataField: string
;)procedure SetDataField (Value: string
;function GetDataSource: TDataSource
;)procedure SetDataSource (Value: TDataSource
;function GetField: TField
;procedure CNHScroll(var Message: TWMHScroll); message CN_HSCROLL
;procedure CNVScroll(var Message: TWMVScroll); message CN_VSCROLL
;procedure CMExit(var Message: TCMExit); message CM_EXIT
protected
// data link event handlers
: .
constructor TMdDbTrack.Create (AOwner: TComponent);
begin
inherited Create (AOwner);
FDataLink := TFieldDataLink.Create;
FDataLink.Control := self;
FDataLink.OnDataChange := DataChange;
FDataLink.OnUpdateData := UpdateData;
FDataLink.OnActiveChange := ActiveChange;
Enabled := False;
end;
TMdDbProgress DataChange
:
procedure TMdDbTrack.SetDataSource (Value: TDataSource);
begin
FDataLink.DataSource := Value;
Enabled := FDataLink.Active and (FDataLink.Field <> nil) and
not FDataLink.Field.ReadOnly;
end;
. :
.
: try/Finally
procedure TMdDbTrack.SetDataField (Value: string);
begin
try
FDataLink.FieldName := Value;
finally
.17
:
;)procedure TMdDbTrack.ActiveChange (Sender: TObject
begin
Enabled := FDataLink.Active and (FDataLink.Field <> nil) and
;not FDataLink.Field.ReadOnly
;end
.
) ( . :
;)procedure TMdDbTrack.CNHScroll(var Message: TWMHScroll
begin
// edit mode
;FDataLink.Edit
// update data
;inherited
// let the system know
;FDataLink.Modified
;end
;)procedure TMdDbTrack.CNVScroll(var Message: TWMVScroll
begin
// edit mode
;FDataLink.Edit
// update data
;inherited
// let the system know
;FDataLink.Modified
;end
(
) Post
OnUpdateData :TFieldDataLink
;)procedure TMdDbTrack.UpdateData (Sender: TObject
begin
if FDataLink.Field is TNumericField then
;FDataLink.Field.AsInteger := Position
;end
.
) (
. .
CMExit VCL :
;)procedure TMdDbTrack.CMExit(var Message: TCMExit
begin
try
;FDataLink.UpdateRecord
except
;SetFocus
;raise
;end
;inherited
;end
DBTrack . 17-2 .
TrackBar .
.TrackBar
:17-2
) (TrackBar DbTrack
. .
- -
TFieldDataLink .
" : " .record viewer
.17
.
.
. DBGrid DBCtrlGrid
.
:
.
.
implementation .
VCL . :
type
)TMdRecordLink = class (TDataLink
private
;RView: TMdRecordView
public
;)constructor Create (View: TMdRecordView
;procedure ActiveChanged; override
;procedure RecordChanged(Field: TField); override
;end
)
activation ) ( .
.TFieldDataLink
:
;)constructor TMdRecordLink.Create (View: TMdRecordView
begin
;inherited Create
;RView := View
;end
:
;procedure TMdRecordLink.ActiveChanged
var
;I: Integer
begin
// set number of rows
. .
TCustomGrid
.
( protected)
:( ) .
type
TMdRecordView = class(TCustomGrid)
private
// data-aware support
FDataLink: TDataLink;
function GetDataSource: TDataSource;
procedure SetDataSource (Value: TDataSource);
protected
// redefined TCustomGrid methods
procedure DrawCell(ACol, ARow: Longint; ARect: TRect;
AState: TGridDrawState); override;
procedure ColWidthsChanged; override;
procedure RowHeightsChanged; override;
public
constructor Create (AOwner: TComponent); override;
destructor Destroy; override;
procedure SetBounds (ALeft, ATop, AWidth, AHeight: Integer);
override;
// public parent properties (omitted...)
published
// data-aware properties
property DataSource: TDataSource read GetDataSource write
SetDataSource;
// published parent properties (omitted...)
end;
DataSource
.17
. DataField .
:
;)constructor TMdRecordView.Create (AOwner: TComponent
begin
;)FDataLink := TMdRecordLink.Create (self
;)inherited Create (AOwner
// set numbers of cells and fixed cells
RowCount := 2; // default
;ColCount := 2
;FixedCols := 1
;FixedRows := 0
{grid options -- choose among:
goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
goRangeSelect, goDrawFocusSelected, goRowSizing, goColSizing,
goRowMoving, goColMoving, goEditing, goTabs, goRowSelect,
}goAlwaysShowEditor, goThumbTracking
Options := [goFixedVertLine, goFixedHorzLine,
;]goVertLine, goHorzLine, goRowSizing, goColSizing
;DefaultDrawing := False
;ScrollBars := ssVertical
;FSaveCellExtents := False
;end
) (
.
.
: .DBGrid
. .
. )
( .
) ( :
procedure TMdRecordView.SetBounds (ALeft, ATop,
;)AWidth, AHeight: Integer
begin
;inherited
;]ColWidths [1] := ClientWidth - ColWidths[0
;end
.
- DefaultColWidth - .
DrawCell .
. . 17-1
)][( .
.
. DBGrid DisplayName
DisplayText
.(memo AsString )
RECORDVIEW DRAWCELL
:17-1
.17
begin
DrawText (Canvas.Handle,
PChar (Text), Length (Text),
)ARect, dt_WordBreak or dt_NoPrefix
end
else // draw single line vertically centered
DrawText (Canvas.Handle,
PChar (Text), Length (Text), ARect,
;)dt_vcenter or dt_SingleLine or dt_NoPrefix
if gdFocused in AState then
;)Canvas.DrawFocusRect (ARect
;end
memo .
TMemoField DrawText dt_SingleLine
dt_WorldBreak .
.
DefaultDrawing False
.DrawCell InflatRect
) (API . API
Windows DrawText .
) (17-3 .
.
. ) (TCustomGrid
.BLOB
BLOB .
.
ActiveChanged RowHeightsChanged
DefaultRowHeight :
;procedure TMdRecordLink.ActiveChanged
var
;I: Integer
begin
// set number of rows
:17-3
. TCustomGrid
DefineProperties RowHeights .ColHeights
) inherited (
FSaveCellExtents ) (.
DBGrid
DBGrid
. DBGrid
RecordView memo .
. 17-4 .
.17
:17-4
MDbGrid .memo
.
.
: DBGrid
.
DBGrid
.
.
.
:
type
)TMdDbGrid = class(TDbGrid
private
;FLinesPerRow: Integer
;)procedure SetLinesPerRow (Value: Integer
protected
;procedure DrawColumnCell(const Rect: TRect; DataCol: Integer
;Column: TColumn; State: TGridDrawState); override
;procedure LayoutChanged; override
public
: .FLinesPerRow
procedure TMdDbGrid.SetLinesPerRow(Value: Integer);
begin
if (Value <> FLinesPerRow) and (Value > 0) then
begin
FLinesPerRow := Value;
LayoutChanged;
end;
end;
LayoutChanged
.
.
. TCustomDBGrid
( ) Wg)
: .(
procedure TMdDbGrid.LayOutChanged;
var
PixelsPerRow, PixelsTitle, I: Integer;
begin
inherited LayOutChanged;
Canvas.Font := Font;
PixelsPerRow := Canvas.TextHeight('Wg') + 3;
if dgRowLines in Options then
Inc (PixelsPerRow, GridLineWidth);
Canvas.Font := TitleFont;
PixelsTitle := Canvas.TextHeight('Wg') + 4;
if dgRowLines in Options then
Inc (PixelsTitle, GridLineWidth);
// set number of rows
RowCount := 1 + (Height - PixelsTitle) div
(PixelsPerRow * FLinesPerRow);
// set the height of each row
DefaultRowHeight := PixelsPerRow * FLinesPerRow;
RowHeights [0] := PixelsTitle;
for I := 1 to RowCount - 1 do
RowHeights [I] := PixelsPerRow * FLinesPerRow;
.17
.
DefaultRowHeight
DefaultRowHeight
VisibleRowCount )
( ) .(
.
:
RecordView
procedure TMdDbGrid.DrawColumnCell(const Rect: TRect;
DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
Bmp: TBitmap;
OutRect: TRect;
begin
if FLinesPerRow = 1 then
inherited DrawColumnCell(Rect, DataCol, Column, State)
else
begin
// clear area
Canvas.FillRect (Rect);
// copy the rectangle
OutRect := Rect;
// restrict output
InflateRect (OutRect, -2, -2);
// output field data
if Column.Field is TGraphicField then
begin
Bmp := TBitmap.Create;
try
Bmp.Assign (Column.Field);
Canvas.StretchDraw (OutRect, Bmp);
finally
Bmp.Free;
end;
end
else if Column.Field is TMemoField then
begin
DrawText (Canvas.Handle,
PChar (Column.Field.AsString),
Length (Column.Field.AsString),
)OutRect, dt_WordBreak or dt_NoPrefix
end
else // draw single line vertically centered
DrawText (Canvas.Handle,
PChar (Column.Field.DisplayText),
Length (Column.Field.DisplayText),
;)OutRect, dt_vcenter or dt_SingleLine or dt_NoPrefix
;end
;end
memo . .
.GridDemo
.
.
TDataSet .
.
.
.
)
( . Borland
.
.
TDataSet )) (abstarct 23
5 ( . )
( . TDataSet .
) TDataSet
(record buffering .
) (buffers .
.
.17
) (buffers
.
.
.
. TDataSet
.
VCL .TDataSet
.
.TMdCustomDataSet
.
.
:
. 17-2
. ) (Virtual methods
) (Protected Fields
. record :
) .(buffers
:
:17-2
TMdCustomDataSet.TMdDataSetStream
// in unit MdDsCustom
type
;)EMdDataSetError = class (Exception
TMdRecInfo = record
;Bookmark: Longint
;BookmarkFlag: TBookmarkFlag
;end
;PMdRecInfo = ^TMdRecInfo
)TMdCustomDataSet = class(TDataSet
protected
// status
FIsTableOpen: Boolean;
// record data
FRecordSize, // the size of the actual data
FRecordBufferSize, // data + housekeeping (TRecInfo)
FCurrentRecord, // current record (0 to FRecordCount - 1)
BofCrack, // before the first record (crack)
EofCrack: Integer; // after the last record (crack)
// create, close, and so on
procedure InternalOpen; override;
procedure InternalClose; override;
function IsCursorOpen: Boolean; override;
// custom functions
function InternalRecordCount: Integer; virtual; abstract;
procedure InternalPreOpen; virtual;
procedure InternalAfterOpen; virtual;
procedure InternalLoadCurrentRecord(Buffer: PChar);
virtual; abstract;
// memory management
function AllocRecordBuffer: PChar; override;
procedure InternalInitRecord(Buffer: PChar); override;
procedure FreeRecordBuffer(var Buffer: PChar); override;
function GetRecordSize: Word; override;
// movement and optional navigation (used by grids)
function GetRecord(Buffer: PChar; GetMode: TGetMode;
DoCheck: Boolean): TGetResult; override;
procedure InternalFirst; override;
procedure InternalLast; override;
function GetRecNo: Longint; override;
function GetRecordCount: Longint; override;
procedure SetRecNo(Value: Integer); override;
// bookmarks
procedure InternalGotoBookmark(Bookmark: Pointer); override;
procedure InternalSetToRecord(Buffer: PChar); override;
procedure SetBookmarkData(Buffer: PChar; Data: Pointer);
override;
procedure GetBookmarkData(Buffer: PChar; Data: Pointer);
override;
procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
override;
function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
override;
// editing (dummy vesions)
procedure InternalDelete; override;
procedure InternalAddRecord(Buffer: Pointer; Append: Boolean);
override;
.17
) (
.
.
:I
.
. TFields
FieldsDef
:InternalOpen .TField
procedure TMdCustomDataSet.InternalOpen;
begin
InternalPreOpen; // custom method for subclasses
// initialize the field definitions
// (another virtual abstract method of TDataSet)
InternalInitFieldDefs;
// if there are no persistent field objects,
// create the fields dynamically
if DefaultFields then
CreateFields;
// connect the TField objects with the actual fields
.17
BindFields (True);
InternalAfterOpen; // custom method for subclasses
// sets cracks and record position and size
BofCrack := -1;
EofCrack := InternalRecordCount;
FCurrentRecord := BofCrack;
FRecordBufferSize := FRecordSize + sizeof (TMdRecInfo);
BookmarkSize := sizeOf (Integer);
// everything OK: table is now open
FIsTableOpen := True;
end;
BookmarkSize
InternalAfterOpen InternalPreOpen .TDataSet
InternalPreOpen .
.
.
.
:
const
HeaderVersion = 10;
// I: open the table/file
procedure TMdDataSetStream.InternalPreOpen;
begin
// the size of the header
FDataFileHeaderSize := sizeOf (TMdDataFileHeader);
// check if the file exists
if not FileExists (FTableName) then
raise EMdDataSetError.Create ('Open: Table file not found');
// create a stream for the file
FStream := TFileStream.Create (FTableName, fmOpenReadWrite);
// initialize local data (loading the header)
FStream.ReadBuffer (FDataFileHeader, FDataFileHeaderSize);
if FDataFileHeader.VersionNumber <> HeaderVersion then
raise EMdDataSetError.Create ('Illegal File Version');
// let's read this, double check later
FRecordCount := FDataFileHeader.RecordCount;
end;
procedure TMdDataSetStream.InternalAfterOpen;
begin
InternalAfterOpen
.InternalInitFieldDefs
. .
.
InternalOpen InternalInitFieldDefs
) ( .
) INI ( .
.String 17-3
Contrib .INI .
:17-3
Contrib.INI .
][Fields
Number=6
][Field1
Type=ftString
Name=Name
Size=30
][Field2
Type = ftInteger
Name = Level
][Field3
Type = ftDate
Name = BirthDate
][Field4
Type = ftCurrency
Name = Stipend
][Field5
Type = ftString
Name = Email
Size = 50
.17
[Field6]
Type = ftBoolean
Name = Editor
) (
(17-4 ) InternalInitFieldDefs .
.
TList . TList
. ( buffer)
. InternalInitFieldDefs
procedure TMdDataSetStream.InternalInitFieldDefs;
var
IniFileName, FieldName: string;
IniFile: TIniFile;
nFields, I, TmpFieldOffset, nSize: Integer;
FieldType: TFieldType;
begin
FFieldOffset := TList.Create;
FieldDefs.Clear;
TmpFieldOffset := 0;
IniFilename := ChangeFileExt(FTableName, '.ini');
Inifile := TIniFile.Create (IniFilename);
// protect ini file
try
nFields := IniFile.ReadInteger ('Fields', 'Number', 0);
if nFields = 0 then
raise EMdDataSetError.Create ('InitFieldsDefs: 0 fields?');
for I := 1 to nFields do
begin
// create the field
FieldType := TFieldType (GetEnumValue (
TypeInfo (TFieldType),
IniFile.ReadString (
'Field' + IntToStr (I), 'Type', '')));
FieldName := IniFile.ReadString (
'Field' + IntToStr (I), 'Name', '');
if FieldName = '' then
raise EMdDataSetError.Create (
'InitFieldsDefs: No name for field ' +
IntToStr (I));
nSize := IniFile.ReadInteger (
'Field' + IntToStr (I), 'Size', 0);
FieldDefs.Add (FieldName,
FieldType, nSize, False);
// save offset and compute size
FFieldOffset.Add (Pointer (TmpFieldOffset));
:17-4
case FieldType of
ftString:
Inc (TmpFieldOffset, nSize + 1);
ftBoolean, ftSmallInt, ftWord:
Inc (TmpFieldOffset, 2);
ftInteger, ftDate, ftTime:
Inc (TmpFieldOffset, 4);
ftFloat, ftCurrency, ftDateTime:
Inc (TmpFieldOffset, 8);
else
raise EMdDataSetError.Create (
'InitFieldsDefs: Unsupported field type');
end;
end; // for
finally
IniFile.Free;
end;
FRecordSize := TmpFieldOffset;
end;
.( )
:
Procedure TMCustomDataSet.InternalClose;
begin
// disconnect field objects
BindFields (False);
// destroy field object (if not persistent)
if DefaultFields then
DestroyFiels;
// close the file
FIsTableOpen := False;
end;
procedure TMdDataSetStream.InternalClose;
begin
// if required, save updated header
if (FDataFileHeader.RecordCount <> FRecordCount) or
(FDataFileHeader.RecordSize = 0) then
begin
FDataFileHeader.RecordSize := FRecordSize;
FDataFileHeader.RecordCount := FRecordCount;
if Assigned (FStream) then
begin
FStream.Seek (0, soFromBeginning);
FStream.WriteBuffer (
FDataFileHeader, FDataFileHeaderSize);
end;
end;
// free the internal list field offsets and the stream
.17
;FFieldOffset.Free
;FStream.Free
;inherited InternalClose
;end
.
. CreateTable
: )
( ) (:
;procedure TMdDataSetStream.CreateTable
begin
;CheckInactive
;InternalInitFieldDefs
// create the new file
if FileExists (FTableName) then
raise EMdDataSetError.Create ('File ' + FTableName +
;)'' already exists
FStream := TFileStream.Create (FTableName,
;)fmCreate or fmShareExclusive
try
// save the header
;FDataFileHeader.VersionNumber := HeaderVersion
FDataFileHeader.RecordSize := 0; // used later
FDataFileHeader.RecordCount := 0; // empty
( FStream.WriteBuffer
;)FDataFileHeader, FDataFileHeaderSize
finally
// close the file
;FStream.Free
;end
;end
:II
.
. .
) .(Pointers
.
.
TMdRecInfo .
) (buffer :
type
;)TBookmarkFlag = (bfCurrent, bfBOF, bfEOF, bfInserted
.
17-5 .
:17-5
) (buffer
.
PMdRecInfo TMdRecInfo
. :
( procedure TMdCustomDataSet.SetBookmarkData
;)Buffer: PChar; Data: Pointer
begin
=PMdRecInfo(Buffer + FRecordSize).Bookmark :
;)^Integer(Data
;end
;function TMdCustomDataSet.GetRecordCount: Longint
begin
;CheckActive
;Result := InternalRecordCount
;end
.Data
:integer
.17
procedure TMdCustomDataSet.GetBookmarkData (
Buffer: PChar; Data: Pointer);
begin
Integer(Data^) :=
PMdRecInfo(Buffer + FRecordSize).Bookmark;
end;
procedure TMdCustomDataSet.SetBookmarkData (
Buffer: PChar; Data: Pointer);
begin
PMdRecInfo(Buffer + FRecordSize).Bookmark :=
Integer(Data^);
end;
InternalGotoBookmark
- .
GetRecord ) -
) (
.( InternalLast InternalFirst
InternalGotoBookmark
InternalSetToRecord .( derference)
.InternalGotoBookmark InternalSetToRecord
:
procedure TMdCustomDataSet.InternalGotoBookmark (Bookmark: Pointer);
var
ReqBookmark: Integer;
begin
ReqBookmark := Integer (Bookmark^);
if (ReqBookmark >= BofCrack) and (ReqBookmark <=
InternalRecordCount) then
FCurrentRecord := ReqBookmark
else
raise EMdDataSetError.Create ('Bookmark ' +
IntToStr (ReqBookmark) + ' not found');
end;
procedure TMdCustomDataSet.InternalSetToRecord (Buffer: PChar);
var
ReqBookmark: Integer;
begin
ReqBookmark := PMdRecInfo(Buffer + FRecordSize).Bookmark;
InternalGotoBookmark (@ReqBookmark);
end;
.
. : Borland ) .(Cracks
BofCrack ) -1 (InternalOpen
. EofCrack
.FRecordCount-1 EofCrack BofCrack
:
;procedure TMdCustomDataSet.InternalFirst
begin
;FCurrentRecord := BofCrack
;end
// II: Go to a special position after the last record
;procedure TMdCustomDataSet.InternalLast
begin
;EofCrack := InternalRecordCount
;FCurrentRecord := EofCrack
;end
.17
;CheckBrowseMode
if (Value >= 1) and (Value <= InternalRecordCount) then
begin
;FCurrentRecord := Value - 1
;)][(Resync
;end
;end
.
stream .
:III
.
- ) stream( TField
.
.
;function TMdCustomDataSet.AllocRecordBuffer: PChar
begin
;)GetMem (Result, FRecordBufferSize
;end
;)procedure TMdCustomDataSet.FreeRecordBuffer (var Buffer: PChar
begin
;)FreeMem (Buffer
;end
.
AllocRecordBuffer
. :InternalOpen
;)FRecordBufferSize := FRecordSize + sizeof (TMdRecInfo
) (buffer
) (InternalInitRecord .
.
) RecordSize (
.VCL GetRecordSize FRecordSize
.
.
) ( .
. :
type
;)TGetResult = (grOK, grBOF, grEOF, grError
.
.
CurrentRecord >= InternalRecordCount gmCurrent
.Case .
.
DBGrid
GetRecord GetRecord .grEOF
GetRecord:
// III: Retrieve data for current, previous, or next record
// (eventually moving to it) and return the status
;function TMdCustomDataSet.GetRecord(Buffer: PChar
;GetMode: TGetMode; DoCheck: Boolean): TGetResult
begin
Result := grOK; // default
case GetMode of
gmNext: // move on
if FCurrentRecord < InternalRecordCount - 1 then
)Inc (FCurrentRecord
else
Result := grEOF; // end of file
gmPrior: // move back
if FCurrentRecord > 0 then
)Dec (FCurrentRecord
else
Result := grBOF; // begin of file
gmCurrent: // check if empty
if (FCurrentRecord >= InternalRecordCount) or
.17
AddRecord InternalAddRecord
.AppendRecord InsertRecord
. (Public)
. AppendRecord InsertRecord
:InternalPost
procedure TMdDataSetOne.InternalAddRecord(Buffer: Pointer;
Append: Boolean);
begin
// always append at the end
InternalLast;
FStream.Seek (0, soFromEnd);
FStream.WriteBuffer (ActiveBuffer^, FRecordSize);
Inc (FRecordCount);
end;
.
.
.
:IV
.
) .(buffer GetData :
SetData
.
.
FFieldOffset .TList
FieldDataSize .
Field .Buffer
Buffer
.
GetData SetData
) .(infinite recursion - - ActiveBuffer
. Buffer .
.
function TMdDataSetOne.GetFieldData (Field: TField; Buffer:
;Pointer): Boolean
var
;FieldOffset: Integer
;Ptr: PChar
begin
;Result := False
if not IsEmpty and (Field.FieldNo > 0) then
begin
;)]FieldOffset := Integer (FFieldOffset [Field.FieldNo - 1
;Ptr := ActiveBuffer
;)Inc (Ptr, FieldOffset
if Assigned (Buffer) then
.17
InternalHandleException
.
StreamDSDemo .17-6
DBGrid .
17-6
. INI )
( .
:17-6
StreamDSDemo
.
Fields Editor
. .
.
TableName
:
. TableName
.17
.
:Create New Table
;)procedure TForm1.Button1Click(Sender: TObject
begin
;MdDataSetStream1.CreateTable
;MdDataSetStream1.Open
;CheckBox1.Checked := MdDataSetStream1.Active
;end
CreateTable .
) TTable .(CreateTable
:
;)procedure TForm1.CheckBox1Click(Sender: TObject
begin
;MdDataSetStream1.Active := CheckBox1.Checked
;end
) (set
. SQL
XML.
.
) (TObjectList
.
.
:
dbn.borland.com/articale/0,1410,20587,00.html
TMdLisTDataSet
.
) (Buffer
. :
type
)TMdListDataSet = class (TMdCustomDataSet
protected
// the list holding the data
;FList: TObjectList
// dataset virtual methods
;procedure InternalPreOpen; override
;procedure InternalClose; override
// custom dataset virtual methods
;function InternalRecordCount: Integer; override
;procedure InternalLoadCurrentRecord (Buffer: PChar); override
;end
TDataSet
) ( .
):(Buffer
;procedure TMdListDataSet.InternalPreOpen
begin
FList := TObjectList.Create (True); // owns objects
FRecordSize := 4; // an integer, the list item id
;end
.
:
.ClientDataSet
.
) ( :
;function TMdListDataSet.InternalRecordCount: Integer
begin
;Result := fList.Count
;end
. )
(:
.17
.
:((C:\docs\*.txt ) )
type
TMdDirDataset = class(TMdListDataSet)
private
FDirectory: string;
procedure SetDirectory(const NewDirectory: string);
protected
// TDataSet virtual methods
procedure InternalInitFieldDefs; override;
procedure SetFieldData(Field: TField; Buffer: Pointer); override;
function GetCanModify: Boolean; override;
// custom dataset virtual methods
procedure InternalAfterOpen; override;
public
function GetFieldData(Field: TField; Buffer: Pointer):
Boolean; override;
published
property Directory: string read FDirectory write SetDirectory;
end;
TDataSet GetCanModify
.False .
.(abstract virtual) SetFieldData
.
:TFieldData TSearchRec
type
TFileData = class
public
ShortFileName: string;
Time: TDateTime;
Size: Integer;
Attr: Integer;
constructor Create (var FileInfo: TSearchRec);
end;
constructor TFileData.Create(var FileInfo: TSearchRec);
begin
ShortFileName := FileInfo.Name;
Time := FileDateToDateTime (FileInfo.Time);
Size := FileInfo.Size;
Attr := FileInfo.Attr;
end;
:
procedure TMdDirDataset.InternalAfterOpen;
var
Attr: Integer;
FileInfo: TSearchRec;
FileData: TFileData;
begin
// scan all files
Attr := faAnyFile;
FList.Clear;
if SysUtils.FindFirst(fDirectory, Attr, FileInfo) = 0 then
repeat
FileData := TFileData.Create (FileInfo);
FList.Add (FileData);
until SysUtils.FindNext(FileInfo) <> 0;
SysUtils.FindClose(FileInfo);
end;
:
procedure TMdDirDataset.InternalInitFieldDefs;
begin
if fDirectory = '' then
raise EMdDataSetError.Create ('Missing directory');
// field definitions
FieldDefs.Clear;
FieldDefs.Add ('FileName', ftString, 40, True);
FieldDefs.Add ('TimeStamp', ftDateTime);
FieldDefs.Add ('Size', ftInteger);
FieldDefs.Add ('Attributes', ftString, 3);
FieldDefs.Add ('Folder', ftBoolean);
end;
.GetFieldData ( ActiveBuffer )
StrCopy Move
( system S read-Only R hidden H)
: .
.17
function TMdDirDataset.GetFieldData (
Field: TField; Buffer: Pointer): Boolean;
var
FileData: TFileData;
Bool1: WordBool;
strAttr: string;
t: TDateTimeRec;
begin
FileData := fList [Integer(ActiveBuffer^)] as TFileData;
case Field.Index of
0: // filename
StrCopy (Buffer, pchar(FileData.ShortFileName));
1: // timestamp
begin
t := DateTimeToNative (ftdatetime, FileData.Time);
Move (t, Buffer^, sizeof (TDateTime));
end;
2: // size
Move (FileData.Size, Buffer^, sizeof (Integer));
3: begin // attributes
strAttr := '
';
if (FileData.Attr and SysUtils.faReadOnly) > 0 then
strAttr [1] := 'R';
if (FileData.Attr and SysUtils.faSysFile) > 0 then
strAttr [2] := 'S';
if (FileData.Attr and SysUtils.faHidden) > 0 then
strAttr [3] := 'H';
StrCopy (Buffer, pchar(strAttr));
end;
4: begin // folder
Bool1 := FileData.Attr and SysUtils.faDirectory > 0;
Move (Bool1, Buffer^, sizeof (WordBool));
end;
end; // case
Result := True;
end;
TDataTime ./
TTimeStamp
VCL .native date and time format
:/
function DateTimeToNative(DataType: TFieldType; Data: TDateTime):
TDateTimeRec;
var
TimeStamp: TTimeStamp;
begin
TimeStamp := DateTimeToTimeStamp(Data);
case DataType of
ftDate: Result.Date := TimeStamp.Date;
) ) (17-7 (
DBGrid )
.(ShellTreeView Root \.C:
OnChange ShellTreeView
:
;)procedure TForm1.ShellTreeView1Change(Sender: TObject; Node: TTreeNode
begin
;MdDirDataset1.Close
;'*MdDirDataset1.Directory := ShellTreeView1.Path + '\*.
;MdDirDataset1.Open
;end
:17-7
DirDemo .
: Windows Shell
DirDemoNoShell
.Windows 3.1
.
.TFieldData
RTTI .
.17
. TMdListDataSet
) ObjectClass :
:(17-5 TMdObjDataSet
:TMdObjDataSet
type
TMdObjDataSet = class(TMdListDataSet)
private
PropList: PPropList;
nProps: Integer;
FObjClass: TPersistentClass;
ObjClone: TPersistent;
FChangeToClone: Boolean;
procedure SetObjClass(const Value: TPersistentClass);
function GetObjects(I: Integer): TPersistent;
procedure SetChangeToClone(const Value: Boolean);
protected
procedure InternalInitFieldDefs; override;
procedure InternalClose; override;
procedure InternalInsert; override;
procedure InternalPost; override;
procedure InternalCancel; override;
procedure InternalEdit; override;
procedure SetFieldData(Field: TField; Buffer: Pointer); override;
function GetCanModify: Boolean; override;
procedure InternalPreOpen; override;
public
function GetFieldData(Field: TField; Buffer: Pointer):
Boolean; override;
property Objects [I: Integer]: TPersistent read GetObjects;
function Add: TPersistent;
published
property ObjClass: TPersistentClass read FObjClass write
SetObjClass;
property ChangesToClone: Boolean read FChangeToClone
write SetChangeToClone default False;
end;
InternalInitFieldDefs
:RTTI .( published)
procedure TMdObjDataSet.InternalInitFieldDefs;
var
i: Integer;
begin
if FObjClass = nil then
raise Exception.Create ('TMdObjDataSet: Unassigned class');
:17-5
// field definitions
FieldDefs.Clear;
nProps := GetTypeData(fObjClass.ClassInfo)^.PropCount;
GetMem(PropList, nProps * SizeOf(Pointer));
GetPropInfos (fObjClass.ClassInfo, PropList);
for i := 0 to nProps - 1 do
case PropList [i].PropType^.Kind of
tkInteger, tkEnumeration, tkSet:
FieldDefs.Add (PropList [i].Name, ftInteger, 0);
tkChar: FieldDefs.Add (PropList [i].Name, ftFixedChar, 0);
tkFloat: FieldDefs.Add (PropList [i].Name, ftFloat, 0);
tkString, tkLString:
FieldDefs.Add (PropList [i].Name, ftString, 50); // TODO:
fix size
tkWString: FieldDefs.Add (PropList [i].Name, ftWideString, 50);
// TODO: fix size
end;
end;
.17
tkFloat:
begin
;)]FlValue := GetFloatProp(Obj, PropList [Field.FieldNo-1
;))Move (FlValue, Buffer^, sizeof (Double
;end
tkString, tkLString, tkWString:
StrCopy (Buffer, pchar(GetStrProp(Obj, PropList
;)))][Field.FieldNo-1
;end
;Result := True
;end
) (Pointer
. )
( TypeInfo .
) ( .
ChangesToClone
. DoClone RTTI
) (.
ChangesToClone
Post
.Cancel :
;Procedure TobjDataSet.InternalEdit
begin
)DoClone (fList[FCurrentRecord] as TdbPers, ObjClone
;end
Procedure
begin
if FchangeToClone and Assigend (ObjClone) then
;))]DoClone (ObjClone, TdbPers (fLIst [fCurrentRecord
;end
;procedure TMdObjDataSet.InternalCancel
begin
if not FChangeToClone and Assigned (ObjClone) then
;))]DoClone (ObjClone, TPersistent(fList [fCurrentRecord
;end
SetFieldData .
GetFieldData
)
(.
17-5 Objects
OOP Add Add ) .(Collection
Add :
;function TMdObjDataSet.Add: TPersistent
begin
if not Active then
;Open
;Result := fObjClass.Create
;)fList.Add (Result
;end
ObjDataSetDemo .
.17-8
.
DBGrid TDemo
.
:17-8
ObjDataSetDemo .RTTI
TDataSet .
- -
.
.17
.
.7
Web
XML SOAP .