mvctypes.pas

来自「本系统前端界面采用WINDOWS 窗口风格」· PAS 代码 · 共 569 行 · 第 1/2 页

PAS
569
字号
                   end;


implementation

{ Let's go }

{ *********************************************************************** }

constructor TMVCNode.Create;
begin
  inherited Create;
  FChildren:=TList.Create;
end;

destructor TMVCNode.Destroy;
begin
  if Assigned(FParent) then
    with FParent do
      RemoveChild(FChildren.IndexOf(Self));
  { When destroying free all children. }
  while ChildCount>0 do DestroyChild(0);

  inherited Destroy;
end;

function TMVCNode.GetImageIndex:integer;
begin
  { Take a close look at your data and return the index of whatever image
    you want next to it. Here we base the choice on the length of the
    caption. No caption, no icon. }
  if Caption=''
    then Result:=-1 else Result:=(Length(Caption) mod 4);
end;

procedure TMVCNode.InvalidateVirtualNode;
var T:TBaseVirtualTree;
begin
  { If the tree has a node that displays this Node then invalidate it. }
  if Assigned(FVirtualNode) then
  begin
    T := TreeFromNode(FVirtualNode);
    T.InvalidateNode(FVirtualNode);
  end;
end;

procedure TMVCNode.SetCheckState(aCheckState:TCheckState);
begin
  { Update the checkstate that is stored in our Node. If the tree has a
    node for the Node then invalidate it. }
  if aCheckState=FCheckstate then exit;
  FCheckState:=aCheckState;
  if Assigned(FVirtualNode) then FVirtualNode.CheckState:=aCheckState;
  InvalidateVirtualNode;
end;

procedure TMVCNode.SetIncidence(aValue:integer);
begin
  { Set the Nodes property Incidence and invalidate the node in the tree
    if there is one. We fix the value into its valid range. }
  if aValue=FIncidence then exit;
  FIncidence:=aValue;
  if FIncidence<0
    then FIncidence:=0
    else
      if FIncidence>63
        then FIncidence:=63;
  InvalidateVirtualNode;
end;

procedure TMVCNode.SetCaption(aCaption:string);
begin
  { Set the Nodes property Caption and invalidate the node in the tree
    if there is one. }
  if aCaption=FCaption then exit;
  FCaption:=aCaption;
  InvalidateVirtualNode;
end;

procedure TMVCNode.SetSubCaption(aSubCaption:string);
begin
  { Set the Nodes property Subcaption and invalidate the node in the tree
    if there is one. }
  if aSubCaption=FSubCaption then exit;
  FSubCaption:=aSubCaption;
  InvalidateVirtualNode;
end;

function TMVCNode.GetChildCount:integer;
begin
  Result:=FChildren.Count;
end;

function TMVCNode.GetChild(n:integer):TMVCNode;
begin
  Result:=TMVCNode(FChildren[n]);
end;

function TMVCNode.CreateChild:TMVCNode;
begin
  Result:=TMVCNode.Create;
  Result.FParent:=Self;
  FChildren.Add(Result);
  if Assigned(FVirtualNode) then
    with TreeFromNode(FVirtualNode) do
      begin
        ReinitNode(FVirtualNode,False);
        InvalidateToBottom(FVirtualNode);
      end;
end;

procedure TMVCNode.RemoveChild(n:integer);
var C:TMVCNode;
begin
  { Remove Child number n from our Children-List and the tree }
  C:=Child[n];
  C.FParent:=NIL;
  FChildren.Delete(n);
  if Assigned(C.FVirtualNode) then
    TreeFromNode(C.FVirtualNode).DeleteNode(C.FVirtualNode);
end;

procedure TMVCNode.DestroyChild(n:integer);
var C:TMVCNode;
begin
  C:=Child[n];
  RemoveChild(n);
  C.Free;
end;

{*************************************************************************}

constructor TMVCTree.Create;
begin
  inherited Create;
  FRoot:=TMVCNode.Create;
end;

destructor TMVCTree.Destroy;
begin
  { Upon destruction we need to break the link to the Viewer and free
    all our Nodes and last the list itself. }
  Viewer:=NIL;
  FRoot.Free;
  FRoot:=NIL;
  inherited Destroy;
end;

procedure TMVCTree.SetViewer(aViewer:TObject);
begin
  { Assign a viewer, De-Assign a viewer (by passing NIL) and assigning
    a different viewer than the one that is already linked. }

  { Prevent recursion when the viewer itself sets this property. }
  if FSettingViewer>0 then exit;

  inc(FSettingViewer);
  try
    { First de-assign any viewer that is already linked. }
    if Assigned(FViewer) then TMVCTreeView(FViewer).Tree:=NIL;
    { Set our field to point to the new viewer. }
    FViewer:=aViewer;
    { Now assign this List to the new viewer. }
    if Assigned(FViewer) then TMVCTreeView(FViewer).Tree:=Self;
  finally
    dec(FSettingViewer);
  end;
end;

procedure TMVCTree.BeginUpdate;
begin
  if Assigned(FViewer) then TMVCTreeView(FViewer).BeginUpdate;
end;

procedure TMVCTree.EndUpdate;
begin
  if Assigned(FViewer) then TMVCTreeView(FViewer).EndUpdate;
end;

{ *********************************************************************** }

{ Now the tree. }

{ The internal node-data assigned to every virtual node consist only of
  a reference to an instance of TMVCNode. }
type PMyNodeData=^TMyNodeData;
     TMyNodeData=packed record Node:TMVCNode end;

destructor TMVCTreeView.Destroy;
begin
  { When destroying the tree, break the link with the list. Note that
    we do NOT set FNodes:=NIL. By using the Set-Method it is made sure
    that the List gets notified of our demise and sets its own reference
    to NIL too. }
  Tree:=NIL;
  inherited Destroy;
end;

procedure TMVCTreeView.SetTree(aTree:TMVCTree);
begin
  if FTree=aTree then exit;

  { If we already have a list, break the link to it. }
  if Assigned(FTree) then FTree.Viewer:=NIL;

  { Now make a link to the new structure: }
  FTree:=aTree;
  if Assigned(FTree)
    then
      begin
        FTree.Viewer:=Self;
        RootNodeCount:=FTree.Root.ChildCount;
        if FTree.Root.ChildCount>0 then ValidateNode(GetFirst, False);
      end
    else RootNodeCount:=0;
end;

function TMVCTreeView.GetMVCNode(VirtualNode:PVirtualNode):TMVCNode;
begin
  { Return the reference to the TMVCNode that is represented by
    Virtualnode }
  if VirtualNode=NIL
    then Result:=NIL
    else Result:=PMyNodeData(InternalData(VirtualNode)).Node;
end;

procedure TMVCTreeView.SetMVCNode(VirtualNode:PVirtualNode;aNode:TMVCNode);
begin
  { Note the relationship between a VirtualNode and the TMVCNode it
    represents in the Nodes data. }
  PMyNodeData(InternalData(VirtualNode)).Node:=aNode;
end;

function TMVCTreeView.DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink;
var Link:TMVCEditLink;
begin
  Result:=inherited DoCreateEditor(Node,Column);
  if Result=nil then
  begin
    Link:=TMVCEditLink.Create;
    Result:=Link;
  end;
end;

function TMVCTreeView.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer;
{ How wide is the the node in pixels. This is interesting if the graphic
  representation includes elements that are not text and whose width needs
  to be calculated. Here we draw a bar whose width corresponds to the
  value of the Incidence-property of the MVCNode. }
var N:TMVCNode;
  Text: string;
begin
  N:=GetMVCNode(Node);
  if Canvas = nil then
    Canvas := Self.Canvas;
  if not Assigned(N)
    then Result:=0
    else
      begin
        Text:=GetNodeText(N, Column);
        Result:=Canvas.TextWidth(Text);
        if Column + 1 in [0, 1] then
          Result := Result + 8 + N.Incidence;
      end;
end;

function TMVCTreeView.GetNodeText(aNode:TMVCNode;aColumn:integer):string;
{ This method returns the text that is to be displayed in aColumn for
  the Node aNode. It is in a separate function so that it can be used
  for the calculation of width and for the actual drawing. You could
  also process the data from the actual Node as stored in your structure
  to give some other text as shown here for the third column. }
begin
  case aColumn of
    -1,0:Result:=aNode.Caption;
       1:Result:=aNode.SubCaption;
       2:case aNode.Incidence of
             0..5:Result:='under 6';
            6..20:Result:='6 to 21';
           21..62:Result:='21 or above';
               63:Result:='Max.';
             else Result:='What?';
         end; (* of case Incidence *)
    else Result:='What *"

⌨️ 快捷键说明

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