📄 flatgrids.pas
字号:
end;
Color := DrawEditBorder(Attrib,Clip);
end;
procedure TFlatDrawGrid.SetParentColor(Value: Boolean);
begin
if Value <> FParentColor then
begin
FParentColor := Value;
if FParentColor then
begin
if Parent <> nil then
FFlatColor := TForm(Parent).Color;
RedrawBorder;
end;
end;
end;
procedure TFlatDrawGrid.CMSysColorChange(var Message: TMessage);
begin
if (Parent <> nil)and(FParentColor) then
FFlatColor := TForm(Parent).Color;
RedrawBorder;
end;
procedure TFlatDrawGrid.CMParentColorChanged(var Message: TWMNoParams);
begin
if (Parent <> nil)and(FParentColor) then
FFlatColor := TForm(Parent).Color;
RedrawBorder;
end;
procedure TFlatDrawGrid.SetColors(Index: Integer; Value: TColor);
begin
case Index of
0: FFocusColor := Value;
1: FBorderColor := Value;
2: begin
FFlatColor := Value;
FParentColor := False;
end;
3: FLinesColor := Value;
end;
Repaint;
RedrawBorder;
end;
procedure TFlatDrawGrid.CMMouseEnter(var Message: TMessage);
begin
inherited;
if (GetActiveWindow <> 0) then
begin
FMouseIn := True;
RedrawBorder;
end;
end;
procedure TFlatDrawGrid.CMMouseLeave(var Message: TMessage);
begin
inherited;
FMouseIn := False;
RedrawBorder;
end;
procedure TFlatDrawGrid.CMEnabledChanged(var Message: TMessage);
const
EnableColors: array[Boolean] of TColor = (clBtnFace, clWindow);
begin
inherited;
Color := EnableColors[Enabled];
RedrawBorder;
end;
procedure TFlatDrawGrid.WMSetFocus(var Message: TWMSetFocus);
begin
inherited;
if not(csDesigning in ComponentState) then
RedrawBorder;
end;
procedure TFlatDrawGrid.WMKillFocus(var Message: TWMKillFocus);
begin
inherited;
if not(csDesigning in ComponentState) then
RedrawBorder;
end;
procedure TFlatDrawGrid.WMNCCalcSize(var Message: TWMNCCalcSize);
begin
inherited;
InflateRect(Message.CalcSize_Params^.rgrc[0], -3, -3);
end;
procedure TFlatDrawGrid.WMNCPaint(var Message: TMessage);
begin
inherited;
RedrawBorder(HRGN(Message.WParam));
end;
procedure TFlatDrawGrid.DrawCell(ACol, ARow: Integer; ARect: TRect;
AState: TGridDrawState);
var FRect:TRect;
begin
inherited;
//绘制数据区的表格边框
with ARect, Canvas do
begin
FRect := Rect(Left-2,Top-2,Right+2,Bottom+2);
//选择线型颜色。。。
Brush.Color:=FLinesColor;
//对表格进行绘制
InflateRect(FRect, -1, -1);
FrameRect(FRect);
end;
end;
{ TFlatStringGrid }
{ StrItem management for TStringSparseList }
type
PStrItem = ^TStrItem;
TStrItem = record
FObject: TObject;
FString: string;
end;
function NewStrItem(const AString: string; AObject: TObject): PStrItem;
begin
New(Result);
Result^.FObject := AObject;
Result^.FString := AString;
end;
procedure DisposeStrItem(P: PStrItem);
begin
Dispose(P);
end;
type
{ TSparsePointerArray class}
{ Used by TSparseList. Based on Sparse1Array, but has Pointer elements
and Integer index, just like TPointerList/TList, and less indirection }
{ Apply function for the applicator:
TheIndex Index of item in array
TheItem Value of item (i.e pointer element) in section
Returns: 0 if success, else error code. }
TSPAApply = function(TheIndex: Integer; TheItem: Pointer): Integer;
TSecDir = array[0..4095] of Pointer; { Enough for up to 12 bits of sec }
PSecDir = ^TSecDir;
TSPAQuantum = (SPASmall, SPALarge); { Section size }
TFlatSparseArray = class(TObject)
private
secDir: PSecDir;
slotsInDir: Word;
indexMask, secShift: Word;
FHighBound: Integer;
FSectionSize: Word;
cachedIndex: Integer;
cachedPointer: Pointer;
{ Return item[i], nil if slot outside defined section. }
function GetAt(Index: Integer): Pointer;
{ Return address of item[i], creating slot if necessary. }
function MakeAt(Index: Integer): PPointer;
{ Store item at item[i], creating slot if necessary. }
procedure PutAt(Index: Integer; Item: Pointer);
public
constructor Create(Quantum: TSPAQuantum);
destructor Destroy; override;
{ Traverse SPA, calling apply function for each defined non-nil
item. The traversal terminates if the apply function returns
a value other than 0. }
{ NOTE: must be static method so that we can take its address in
TSparseList.ForAll }
function ForAll(ApplyFunction: Pointer {TSPAApply}): Integer;
{ Ratchet down HighBound after a deletion }
procedure ResetHighBound;
property HighBound: Integer read FHighBound;
property SectionSize: Word read FSectionSize;
property Items[Index: Integer]: Pointer read GetAt write PutAt; default;
end;
{ TFlatSparseList class }
TFlatSparseList = class(TObject)
private
FList: TFlatSparseArray;
FCount: Integer; { 1 + HighBound, adjusted for Insert/Delete }
FQuantum: TSPAQuantum;
procedure NewList(Quantum: TSPAQuantum);
protected
function Get(Index: Integer): Pointer;
procedure Put(Index: Integer; Item: Pointer);
public
constructor Create(Quantum: TSPAQuantum);
destructor Destroy; override;
procedure Clear;
procedure Delete(Index: Integer);
procedure Exchange(Index1, Index2: Integer);
function ForAll(ApplyFunction: Pointer {TSPAApply}): Integer;
procedure Insert(Index: Integer; Item: Pointer);
procedure Move(CurIndex, NewIndex: Integer);
property Count: Integer read FCount;
property Items[Index: Integer]: Pointer read Get write Put; default;
end;
{ TFlatSparseLists class }
TFlatSparseLists = class(TStrings)
private
FList: TFlatSparseList; { of StrItems }
FOnChange: TNotifyEvent;
protected
function Get(Index: Integer): String; override;
function GetCount: Integer; override;
function GetObject(Index: Integer): TObject; override;
procedure Put(Index: Integer; const S: String); override;
procedure PutObject(Index: Integer; AObject: TObject); override;
procedure Changed;
public
constructor Create(Quantum: TSPAQuantum);
destructor Destroy; override;
procedure ReadData(Reader: TReader);
procedure WriteData(Writer: TWriter);
procedure DefineProperties(Filer: TFiler); override;
procedure Delete(Index: Integer); override;
procedure Exchange(Index1, Index2: Integer); override;
procedure Insert(Index: Integer; const S: String); override;
procedure Clear; override;
property List: TFlatSparseList read FList;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
{ TFlatSparseArray }
const
SPAIndexMask: array[TSPAQuantum] of Byte = (15, 255);
SPASecShift: array[TSPAQuantum] of Byte = (4, 8);
{ Expand Section Directory to cover at least `newSlots' slots. Returns: Possibly
updated pointer to the Section Directory. }
function ExpandDir(secDir: PSecDir; var slotsInDir: Word;
newSlots: Word): PSecDir;
begin
Result := secDir;
ReallocMem(Result, newSlots * SizeOf(Pointer));
FillChar(Result^[slotsInDir], (newSlots - slotsInDir) * SizeOf(Pointer), 0);
slotsInDir := newSlots;
end;
{ Allocate a section and set all its items to nil. Returns: Pointer to start of
section. }
function MakeSec(SecIndex: Integer; SectionSize: Word): Pointer;
var
SecP: Pointer;
Size: Word;
begin
Size := SectionSize * SizeOf(Pointer);
GetMem(secP, size);
FillChar(secP^, size, 0);
MakeSec := SecP
end;
constructor TFlatSparseArray.Create(Quantum: TSPAQuantum);
begin
SecDir := nil;
SlotsInDir := 0;
FHighBound := -1;
FSectionSize := Word(SPAIndexMask[Quantum]) + 1;
IndexMask := Word(SPAIndexMask[Quantum]);
SecShift := Word(SPASecShift[Quantum]);
CachedIndex := -1
end;
destructor TFlatSparseArray.Destroy;
var
i: Integer;
size: Word;
begin
{ Scan section directory and free each section that exists. }
i := 0;
size := FSectionSize * SizeOf(Pointer);
while i < slotsInDir do begin
if secDir^[i] <> nil then
FreeMem(secDir^[i], size);
Inc(i)
end;
{ Free section directory. }
if secDir <> nil then
FreeMem(secDir, slotsInDir * SizeOf(Pointer));
end;
function TFlatSparseArray.GetAt(Index: Integer): Pointer;
var
byteP: PChar;
secIndex: Cardinal;
begin
{ Index into Section Directory using high order part of
index. Get pointer to Section. If not null, index into
Section using low order part of index. }
if Index = cachedIndex then
Result := cachedPointer
else begin
secIndex := Index shr secShift;
if secIndex >= slotsInDir then
byteP := nil
else begin
byteP := secDir^[secIndex];
if byteP <> nil then begin
Inc(byteP, (Index and indexMask) * SizeOf(Pointer));
end
end;
if byteP = nil then Result := nil else Result := PPointer(byteP)^;
cachedIndex := Index;
cachedPointer := Result
end
end;
function TFlatSparseArray.MakeAt(Index: Integer): PPointer;
var
dirP: PSecDir;
p: Pointer;
byteP: PChar;
secIndex: Word;
begin
{ Expand Section Directory if necessary. }
secIndex := Index shr secShift; { Unsigned shift }
if secIndex >= slotsInDir then
dirP := expandDir(secDir, slotsInDir, secIndex + 1)
else
dirP := secDir;
{ Index into Section Directory using high order part of
index. Get pointer to Section. If null, create new
Section. Index into Section using low order part of index. }
secDir := dirP;
p := dirP^[secIndex];
if p = nil then begin
p := makeSec(secIndex, FSectionSize);
dirP^[secIndex] := p
end;
byteP := p;
Inc(byteP, (Index and indexMask) * SizeOf(Pointer));
if Index > FHighBound then
FHighBound := Index;
Result := PPointer(byteP);
cachedIndex := -1
end;
procedure TFlatSparseArray.PutAt(Index: Integer; Item: Pointer);
begin
if (Item <> nil) or (GetAt(Index) <> nil) then
begin
MakeAt(Index)^ := Item;
if Item = nil then
ResetHighBound
end
end;
function TFlatSparseArray.ForAll(ApplyFunction: Pointer {TSPAApply}):
Integer;
var
itemP: PChar; { Pointer to item in section }
item: Pointer;
i, callerBP: Cardinal;
j, index: Integer;
begin
{ Scan section directory and scan each section that exists,
calling the apply function for each non-nil item.
The apply function must be a far local function in the scope of
the procedure P calling ForAll. The trick of setting up the stack
frame (taken from TurboVision's TCollection.ForEach) allows the
apply function access to P's arguments and local variables and,
if P is a method, the instance variables and methods of P's class }
Result := 0;
i := 0;
asm
mov eax,[ebp] { Set up stack frame for local }
mov callerBP,eax
end;
while (i < slotsInDir) and (Result = 0) do begin
itemP := secDir^[i];
if itemP <> nil then begin
j := 0;
index := i shl SecShift;
while (j < FSectionSize) and (Result = 0) do begin
item := PPointer(itemP)^;
if item <> nil then
{ ret := ApplyFunction(index, item.Ptr); }
asm
mov eax,index
mov edx,item
push callerBP
call ApplyFunction
pop ecx
mov @Result,eax
end;
Inc(itemP, SizeOf(Pointer));
Inc(j);
Inc(index)
end
end;
Inc(i)
end;
end;
procedure TFlatSparseArray.ResetHighBound;
var
NewHighBound: Integer;
function Detector(TheIndex: Integer; TheItem: Pointer): Integer; far;
begin
if TheIndex > FHighBound then
Result := 1
else
begin
Result := 0;
if TheItem <> nil then NewHighBound := TheIndex
end
end;
begin
NewHighBound := -1;
ForAll(@Detector);
FHighBound := NewHighBound
end;
{ TFlatSparseList }
constructor TFlatSparseList.Create(Quantum: TSPAQuantum);
begin
NewList(Quantum)
end;
destructor TFlatSparseList.Destroy;
begin
if FList <> nil then FList.Destroy
end;
procedure TFlatSparseList.Clear;
begin
FList.Destroy;
NewList(FQuantum);
FCount := 0
end;
procedure TFlatSparseList.Delete(Index: Integer);
var
I: Integer;
begin
if (Index < 0) or (Index >= FCount) then Exit;
for I := Index to FCount - 1 do
FList[I] := FList[I + 1];
FList[FCount] := nil;
Dec(FCount);
end;
procedure TFlatSparseList.Exchange(Index1, Index2: Integer);
var
temp: Pointer;
begin
temp := Get(Index1);
Put(Index1, Get(Index2));
Put(Index2, temp);
end;
{ Jump to TFlatSparseArray.ForAll so that it looks like it was called
from our caller, so that the BP trick works. }
function TFlatSparseList.ForAll(ApplyFunction: Pointer {TSPAApply}): Integer; assembler;
asm
MOV EAX,[EAX].TFlatSparseList.FList
JMP TFlatSparseArray.ForAll
end;
function TFlatSparseList.Get(Index: Integer): Pointer;
begin
if Index < 0 then TList.Error(SListIndexError, Index);
Result := FList[Index]
end;
procedure TFlatSparseList.Insert(Index: Integer; Item: Pointer);
var
i: Integer;
begin
if Index < 0 then TList.Error(SListIndexError, Index);
I := FCount;
while I > Index do
begin
FList[i] := FList[i - 1];
Dec(i)
end;
FList[Index] := Item;
if Index > FCount then FCount := Index;
Inc(FCount)
end;
procedure TFlatSparseList.Move(CurIndex, NewIndex: Integer);
var
Item: Pointer;
begin
if CurIndex <> NewIndex then
begin
Item := Get(CurIndex);
Delete(CurIndex);
Insert(NewIndex, Item);
end;
end;
procedure TFlatSparseList.NewList(Quantum: TSPAQuantum);
begin
FQuantum := Quantum;
FList := TFlatSparseArray.Create(Quantum)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -