⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbtree.pas

📁 delphi编程控件
💻 PAS
📖 第 1 页 / 共 5 页
字号:
unit dbTree;

{ TDBTreeView component: Data-Aware TTreeView component.
  Version 0.83  Nov-01-1997  (C) 1997 Christoph R. Kirchner
  !! This component is currently UNDER CONSTRUCTION !!
}
{ Users of this unit must accept this disclaimer of warranty:
    "This unit is supplied as is. The author disclaims all warranties,
    expressed or implied, including, without limitation, the warranties
    of merchantability and of fitness for any purpose.
    The author assumes no liability for damages, direct or
    consequential, which may result from the use of this unit."

  This Unit is donated to the public as public domain.

  This Unit can be freely used and distributed in commercial and
  private environments provided this notice is not modified in any way.

  If you do find this Unit handy and you feel guilty for using such a
  great product without paying someone - sorry :-)

  Please forward any comments or suggestions to Christoph Kirchner at:
  ckirchner@geocities.com

  Maybe you can find an update of this component at my
  "Delphi Component Building Site":
  http://www.geocities.com/SiliconValley/Heights/7874/delphi.htm

  Thanks to Maxim Monin for his TDBOutline-component I could start with.
}


interface

uses
  SysUtils, Windows, Messages, Classes, Graphics, Controls,
  CommCtrl, Dialogs, BDE, Dbconsts, DB, DBTables, StdCtrls, ComCtrls,
  TreeVwEx, ECDataLink, dbTvRecordList;

type

  TCustomDBTreeView = class;

  TDBTreeOption = (
    dtAllowDelete, dtAllowInsert, dtAutoDragMove, dtAutoExpand,
    dtAutoShowRoot, dtCancelOnExit, dtConfirmDelete, dtFocusOnEdit,
    dtInsertAsChild, dtMouseMoveSelect, dtRebuildFocusedOnly,
    dtRootItemReadOnly, dtSynchronizeDataSet);
  TDBTreeOptions = set of TDBTreeOption;

{ Options:

  dtAutoDragMove:
    The user can move items by dragging them in the DBTreeView.
    The parent-field of the record of the moved item will be set to the
    ID of the new parent automatically.

  dtAutoExpand:
    The tree will get expanded completely after building.

  dtAutoShowRoot:
    The ShowRoot property specifies whether lines connecting root (top-
    level) items are displayed. If dtAutoShowRoot is in Options, the
    DBTreeView will set the ShowRoot property itself, depending on the
    numbers of root-items: If are more then one of them, the DBTreeView
    will set the ShowRoot property to True, otherwise it will set the
    ShowRoot property to False.
    ShowRoot = True will show lines connecting the root items if the
    ShowLines property is True, and If ShowButtons is set to True, a
    button will appear to the left of each root item.

  dtCancelOnExit:
    An insertion-operation get canceled if the user leaves the DbTreeView
    without changing the inserted record. This avoids empty records in the
    table. DtCancelOnExit is similar to dgCancelOnExit of TDBGrid.

  dtConfirmDelete:
    The user gets asked if he really want to delete the current record
    after he pressed the Del-key. If the current record has children, the
    user gets asked if he want to delete them first.

  dtFocusOnEdit:
    If the dataset changes to edit- or insert-mode, the DbTreeView will
    get the focus. This allows to user to edit the tree-node directly
    after pressing edit or insert on a navigation-button. Also, if the
    dateaset is in edit- or insert-mode and the DbTreeView receives the
    focus, the selected node goes into the edit-mode. Please do not set
    dtFocusOnEdit if there is TDBEdit, TDBMemo or TDBGrid on the form
    connected to the same dataset - the user could get confused too much.
    Also, please set dtSynchronizeDataSet too if you use dtFocusOnEdit.
    Setting dtFocusOnEdit is recommended if there is - more or less -
    only a DbTreeView and a DBNavigator on the form.

  dtInsertAsChild:
    The new item that is created by pressing the insert key gets
    inserted after the selected node if tveInsertAsChild is false or
    it gets inserted as a child of the selected node if tveInsertAsChild
    is true.

  dtMouseMoveSelect:
    If the user moves the mouse, the nearest node gets selected.
    If the user moves the mouse to the upper or lower border of the
    DbTreeView while left button pressed, the DbTreeView will scroll.
    This scrolling happens anyway if the user drags a node.
    The option dtMouseMoveSelect makes sense if the DbTreeView is shown
    in a dropdown-panel.

  dtRebuildFocusedOnly:
    If dtRebuildFocusedOnly is in Options, the DbTreeView will not
    rebuild the tree after the dataset changed unless the DbTreeView gets
    the focus. This is not set by default. The TDbTreeLookupComboBox uses
    this option to avoid needless rebuilds of the DbTreeView in the drop-
    down-panel until it gets visible.

  dtRootItemReadOnly:
    If there is a record in the dataset with the ID of RootID, then you
    can set it to read-only by setting RootItemReadOnly to true.

  dtSynchronizeDataSet:
    The current selected treenode will always represent the current record
    of the DataSet. If not dtSynchronizeDataSet in Options, selecting
    treenodes gets faster.
  }

  TDBTVGetNextIDEvent =
    function (Sender: TObject; DataSet: TDataSet): string of object;

  TTVFindTextOption = (tvftCaseInsensitive, tvftPartial);
  TTVFindTextOptions = set of TTVFindTextOption;

  TDBTreeViewState = (
    dtvsBuilding, dtvsDatasetInEditMode, dtvsEditAfterReBuild,
    dtvsDatasetInInsertMode, dtvsLostFocusWhileDatasetInEditModes,
    dtvsChangingDataset, dtvsNeedReBuildAfterPost, dtvsNeedReBuild,
    dtvsDataSetNeedsRefresh);
  TDBTreeViewStates = set of TDBTreeViewState;


  TTreeViewLink = class(TECDataLink)
  private
    FTreeView: TCustomDBTreeView;
  protected
    procedure DatasetRefreshed; override;
    procedure ActiveChanged; override;
    procedure DataSetChanged; override;
    procedure DataSetScrolled(Distance: Integer); override;
    procedure RecordChanged(Field: TField); override;
    procedure EditingChanged; override;
  { procedure UpdateData; override; }
    procedure DoBeforePost(DataSet: TDataSet); override;
    procedure DoAfterPost(DataSet: TDataSet); override;
    procedure DoAfterCancel(DataSet: TDataSet); override;
    procedure DoBeforeDelete(DataSet: TDataSet); override;
    procedure DoAfterDelete(DataSet: TDataSet); override;
    procedure DoBeforeEdit(DataSet: TDataSet); override;
    procedure DoBeforeInsert(DataSet: TDataSet); override;
  public
    constructor Create(ATreeView: TCustomDBTreeView);
  end;

  TTreeIDNode = class(TTreeNode)
  private
    FID: string;
  public
    constructor Create(AOwner: TTreeNodes);
    procedure Assign(Source: TPersistent); override;
    property ID: string read FID write FID;
  end;

  TCustomDBTreeView = class(TCustomTreeViewEx)
  private
    FOptions: TDBTreeOptions;
    FTreeViewLink: TTreeViewLink;
    FTableIDField: string;
    FTableParentField: string;
    FTableTextField: string;
    FRootID: string;
    FPrevState: TDataSetState;
    FDelRootID: string;
    FIDOfDeleted: string;
    FState: TDBTreeViewStates;
    FTVRecordList: TTVRecordList;
    FReBuildTimer: Longint;
    FSaveIDList: TStringList;
    FUserOnEdited: TTVEditedEvent;
    FOnClosedLoop: TNotifyEvent;
    FOnRootNotFound: TNotifyEvent;
    FOnGetNextID: TDBTVGetNextIDEvent;
    function  GetDataSource: TDataSource;
    procedure SetDataSource(ADataSource: TDataSource);
    procedure SetTableIDField(const Value: string);
    procedure SetTableParentField(const Value: string);
    procedure SetTableTextField(const Value: string);
    function  GetDataSet: TDataSet;
    procedure SetRootID(ID: string);
    procedure SetOptions(Value: TDBTreeOptions);
    function CreateTVRecordList: TTVRecordList;
    function  NeedRebuild: Boolean;
    procedure CreateTree(ParentNode: TTreeNode;
      const AParent: string; TempRecordList: TTVRecordList);
    function  AddNewNodeFromDataset(
      Node: TTreeNode; AsChild: Boolean): TTreeNode;
    function  GetDataSetIDNode: TTreeNode;
    function  GetID(AIndex: Integer): string;
    function  GetSelectedID: string;
    procedure SelectID(const Value: string);
    procedure IndexChanged;
    procedure AfterEdit(Sender: TObject; Node: TTreeNode; var S: string);
    procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
    procedure WMSetFocus(var Message: TMessage); message WM_SETFOCUS;
    procedure WMTimer(var Msg: TWMTimer); message WM_TIMER;
  protected
    procedure CreateWnd; override;
    procedure DestroyWnd; override;
    function CreateNode: TTreeNode; override;
    function CanEdit(Node: TTreeNode): Boolean; override;
    procedure Edit(const Item: TTVItem); override;
    procedure Change(Node: TTreeNode); override;
    procedure Expand(Node: TTreeNode); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure Notification(AComponent: TComponent;
                           Operation: TOperation); override;
    procedure KillAllTimer; override;
    function DragAllowed(Node: TTreeNode): Boolean; override;
    procedure ActiveChanged(Value: Boolean);
    procedure DataChanged;
    procedure RecordNumberChanged;
    procedure RecordChanged(Field: TField);
    procedure EditingChanged;
    procedure DataSetBeforePost;
    procedure DataSetAfterPost;
    procedure DataSetAfterCancel;
    procedure DataSetBeforeDelete;
    procedure DataSetAfterDelete;
    procedure DatasetRefreshed;
    procedure ClosedLoop;
    procedure RootNotFound;
    function DataSetLocate(const ID: string): Boolean;
    function GetDeleteQuestion(Node: TTreeNode): string; override;
    function DoDelete(Node: TTreeNode): Boolean; override;
  { Called by procedure Insert, GetNewID has to calculate the ID of a
    new record. It calls OnGetNextID: }
    function GetNewID: string; virtual;
    procedure BuildTree; virtual;
    property  TreeViewLink: TTreeViewLink read FTreeViewLink;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure RebuildTree;
    procedure BuildTreeIfNeeded;
    procedure Insert(AsChild: Boolean); override;
    procedure Delete; override;
    function MoveNode(Source, Destination: TTreeNode;
                      Mode: TNodeAttachMode): Boolean; override;
    function FindTextID(const S: string; var ID: string;
      TVFindTextOptions: TTVFindTextOptions): Boolean;
    function TextIDList(const S: string;
      TVFindTextOptions: TTVFindTextOptions): TStringList;
  { With GetExpanded you can save all Items[].Expanded in a string
    (e.g. to save this in an INI-file)
    to restore all Items[].Expanded with SetExpanded: }
    function GetExpanded(Separator: Char): string;
    procedure SetExpanded(const List: string; Separator: Char);
  { If not dtSynchronizeDataSet in Options, use this procedure to show
    the current record of the dataset in the tree: }
    procedure SynchronizeSelectedNodeToCurrentRecord;
  { If not dtSynchronizeDataSet in Options, use this procedure to move
    the dataset to the selected node of the tree: }
    procedure SynchronizeCurrentRecordToSelectedNode;
(*
  { IsRootNode is true if the node has no parent: }
    function IsRootNode(Node: TTreeNode): Boolean;
  { IsSingleRootNode is true if the node is the only one without parent: }
    function IsSingleRootNode(Node: TTreeNode): Boolean;
*)
  { To get the ID of a Node: }
    function IDOfNode(Node: TTreeNode): string;
  { To get the Node that has the ID: }
    function GetIDNode(const aID: string): TTreeNode;
  { DataSource.DataSet: }
    property DataSet: TDataSet read GetDataSet;
  { The ID of the current selected node,
    or set Selected with SelectedID := ID: }
    property SelectedID: string read GetSelectedID write SelectID;
  { ID of Items[Index]. Index is 0 to Items.Count -1: }
    property IDs[Index: Integer]: string read GetID;
  { possible published: }
    property DataSource: TDataSource read GetDataSource write SetDataSource;
    property TableIDField: string read FTableIDField write SetTableIDField;
    property TableParentField: string
      read FTableParentField write SetTableParentField;
    property TableTextField: string
      read FTableTextField write SetTableTextField;
    property RootID: string read FRootID write SetRootID;
    property OnClosedLoop: TNotifyEvent read FOnClosedLoop write FOnClosedLoop;
  { Called by the procedure Insert, OnGetNextID has to calculate the ID of
    a new record. This is not needed if the type of the ID-field is ftAutoInc.
    You have to override GetNewID if you hide the record with the highest
    ID and the type of the ID-field is not ftAutoInc:
    - DataSet is TQuery and TQuery.SQL uses 'WHERE ...'
    - DataSet.MasterSource is set.
    If you use a TQuery as Dataset, it is recommended to calculate the
    new ID yourself.
    If you set the new ID on Dataset.OnNewRecord, please use OnGetNextID
    or your own GetNewID because the ID is needed before the Dataset gets
    into insert-mode.}
    property OnGetNextID: TDBTVGetNextIDEvent
      read FOnGetNextID write FOnGetNextID;
    property OnRootNotFound: TNotifyEvent
      read FOnRootNotFound write FOnRootNotFound;
    property Options: TDBTreeOptions read FOptions write SetOptions;
  public
  { possible published, inherited from TCustomTreeView: }
    property ShowButtons;
    property BorderStyle;
    property DragCursor;
    property ShowLines;
    property ShowRoot;
    property ReadOnly;
    property DragMode;
    property HideSelection;
    property Indent;
    property OnEditing;
    property OnEdited;
    property OnExpanding;
    property OnExpanded;
    property OnCollapsing;
    property OnCompare;
    property OnCollapsed;
    property OnChanging;
    property OnChange;
    property OnDeletion;
    property OnGetImageIndex;
    property OnGetSelectedIndex;
    property Align;
    property Enabled;
    property Font;
    property Color;
    property Items; { stored false, items are loaded from a table }
    property ParentColor;
    property ParentCtl3D;
    property Ctl3D;
    property SortType;
    property TabOrder;
    property TabStop default True;
    property Visible;
    property OnClick;
    property OnEnter;
    property OnExit;
    property OnDragDrop;
    property OnDragOver;
    property OnStartDrag;
    property OnEndDrag;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnDblClick;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property PopupMenu;
    property ParentFont;
    property ParentShowHint;
    property ShowHint;
    property Images;
    property StateImages;
  end;


  TDBTreeView = class(TCustomDBTreeView)
  published
    property ShowButtons;
    property BorderStyle;
    property DragCursor;
    property ShowLines;
    property ShowRoot;
    property ReadOnly;
    property DragMode;
    property HideSelection;
    property Indent;
    property OnEditing;
    property OnEdited;
    property OnExpanding;
    property OnExpanded;
    property OnCollapsing;
    property OnCompare;
    property OnCollapsed;
    property OnChanging;
    property OnChange;
    property OnDeletion;
    property OnGetImageIndex;
    property OnGetSelectedIndex;
    property OnMouseSelect;
    property Align;
    property Enabled;
    property Font;
    property Color;
    property ParentColor;
    property ParentCtl3D;
    property Ctl3D;
    property SortType;
    property TabOrder;
    property TabStop default True;
    property Visible;
    property OnClick;
    property OnEnter;
    property OnExit;
    property OnDragDrop;
    property OnDragOver;
    property OnStartDrag;
    property OnEndDrag;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnDblClick;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property PopupMenu;
    property ParentFont;
    property ParentShowHint;
    property ShowHint;
    property Images;
    property StateImages;
    property DataSource;
    property TableIDField;
    property TableParentField;
    property TableTextField;
    property RootID;
    property OnClosedLoop;
    property OnGetNextID;
    property OnRootNotFound;
    property Options
      default [dtAllowDelete, dtAllowInsert, dtAutoDragMove, dtAutoExpand,
               dtAutoShowRoot, dtRootItemReadOnly, dtConfirmDelete,
               dtCancelOnExit, dtSynchronizeDataSet];
  end;


var
  sdbtvDefaultDeleteQuestion: string;


implementation

⌨️ 快捷键说明

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