Containers in Delphi (3)

Source: Internet
Author: User
Tags email account

TBucketList and TObjectBucketList

From Delphi6, two new container classes TBucketList and TObjectBucketList are added to the Contnrs unit of VCL. TBucketList is actually a simple pointer-pointer pair list based on hash tables. The interface is defined as follows:

 TBucketList = class(TCustomBucketList)

 public
  destructor Destroy; override;
  procedure Clear;
  function Add(AItem, AData: Pointer): Pointer;
  function Remove(AItem: Pointer): Pointer;
  function ForEach(AProc: TBucketProc; AInfo: Pointer = nil): Boolean;
  procedure Assign(AList: TCustomBucketList);
  function Exists(AItem: Pointer): Boolean;
  function Find(AItem: Pointer; out AData: Pointer): Boolean;
  property Data[AItem: Pointer]: Pointer read GetData write SetData; default;
 end;

The Add method of the class now accepts two parameters: AItem and AData. we can regard it as a Map implementation of the pointer version (from the perspective of the container class, Delphi Language Not as flexible as C ++. To implement different types of hash Map containers, Delphi needs to derive many classes, while C ++ Map is implemented based on the template technology, the type of the container element can be specified after a simple declaration, which is very convenient to use. In terms of simplicity, it is not as good as the Java container class, because the String in Delphi is a native type rather than a class, and Delphi also provides support for pointers, therefore, we need to provide different Map derived classes for pointers and strings). methods such as Exists and Find in the class use hash tables to quickly locate data. In addition, TBucketList does not provide the function to retrieve the elements in the list by using the integer subscript. However, you can use the ForEach method to traverse the elements in the container.

TObjectBucketList is a base class derived from TBucketList without any new features. The only difference is that the elements in the container are not pointers but objects, and more powerful type checks are implemented.

Other containers

TThreadList class

The tthreadlist class is actually a thread-safe tlist class. Each time a pointer is easily added or deleted, tthreadlist calls the entercriticalsection function to enter the thread blocking status, in this case, other subsequent operations on the list will be blocked until tthreadlist calls unlocklist to release the control on the list. In multi-threaded development, we need to use tthreadlist to save shared resources to avoid confusion and conflicts caused by multithreading. Note that tthreadlist has a duplicates Boolean attribute. The default value is true, indicating that no repeated pointer exists in the list. If it is set to false, repeated elements are allowed in the container.

Tinterfacelist class

In the classes unit, VCL also defines a list class that can save interfaces. We can add an interface type to the list. The operation methods of this class are no different from those of other List classes, but the internal use of tthreadlist as the container implements thread security.

Quasi-container tbits

There is also a special tbits class in classes. Pas. The interface definition is as follows:

 TBits = class

 public
  destructor Destroy; override;
  function OpenBit: Integer;
  property Bits[Index: Integer]: Boolean read GetBit write SetBit; default;
  property Size: Integer read FSize write SetSize;
 end;

It can store Boolean values by bit, so it can be considered as a native Boolean value container class. However, it lacks many methods and features of the List class and cannot be regarded as a complete container, therefore, we call it a quasi-container class.

During our development process, we often need to express some binary States similar to switches. In this case, it is very convenient to use tbits to represent a group of binary states, at the same time, member functions of the tbits class are mainly written in assembly languages, and bit operations are very fast. The size of a binary state group is dynamically adjusted by setting the size attribute of the tbits class. You can use subscript to access the bits attribute of the tbits class. As for the openbit function, it returns the subscript of the first Boolean value that is not true. From the interface definition, we can see that the tbits class interface is very simple and provides limited functions. I guess this is only a class that Borland's R & D team needs to meet the limited internal development needs, it is not designed as a general class. For example, it does not open an interface for internal data access and cannot obtain internal data expressions, this makes it impossible to save and load the status.

Tcollection class

We mentioned earlier that Delphi IDE can automatically save the string list in the DFM file, and can load the string list edited during the design period into the memory at runtime (that is, the sustainability of the class we usually call ). TStrings is more suitable for saving the association between multiple strings of an object and comparing the relationship between one person and multiple Email account addresses in real life. However, attributes of the TStrings type have a major limitation that they can only be used to save simple string lists during design, rather than complex object lists. The aggregation relationship between a parent object and multiple child objects may be more common. For example, a train may have many trains, each of which has a carriage number and carriage type (sleeper, or hard seat), number of carriage seats, name of carriage attendants, and other attributes. If we want to customize the train compartment function during the design period and save the attributes of the train compartment to the form file, defining the attributes of the carriage collection as TStrings will not work.

For this problem, Delphi provides a solution such as TCollection container class attributes. TCollection and its container element TCollectionItem interfaces are defined as follows:

 TCollection = class(TPersistent)
 …
 protected
  procedure Added(var Item: TCollectionItem); virtual; deprecated;
  procedure Deleting(Item: TCollectionItem); virtual; deprecated;
  property NextID: Integer read FNextID;
  procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); virtual;
  { Design-time editor support }
  function GetAttrCount: Integer; dynamic;
  function GetAttr(Index: Integer): string; dynamic;
  function GetItemAttr(Index, ItemIndex: Integer): string; dynamic;
  procedure Changed;
  function GetItem(Index: Integer): TCollectionItem;
  procedure SetItem(Index: Integer; Value: TCollectionItem);
  procedure SetItemName(Item: TCollectionItem); virtual;
  procedure Update(Item: TCollectionItem); virtual;
  property PropName: string read GetPropName write FPropName;
  property UpdateCount: Integer read FUpdateCount;
 public
  constructor Create(ItemClass: TCollectionItemClass);
  destructor Destroy; override;
  function Owner: TPersistent;
  function Add: TCollectionItem;
  procedure Assign(Source: TPersistent); override;
  procedure BeginUpdate; virtual;
  procedure Clear;
  procedure Delete(Index: Integer);
  procedure EndUpdate; virtual;
  function FindItemID(ID: Integer): TCollectionItem;
  function GetNamePath: string; override;
  function Insert(Index: Integer): TCollectionItem;
  property Count: Integer read GetCount;
  property ItemClass: TCollectionItemClass read FItemClass;
  property Items[Index: Integer]: TCollectionItem read GetItem write SetItem;
 end;
 TCollectionItem = class(TPersistent)

 protected
  procedure Changed(AllItems: Boolean);
  function GetOwner: TPersistent; override;
  function GetDisplayName: string; virtual;
  procedure SetCollection(Value: TCollection); virtual;
  procedure SetIndex(Value: Integer); virtual;
  procedure SetDisplayName(const Value: string); virtual;
 public
  constructor Create(Collection: TCollection); virtual;
  destructor Destroy; override;
  function GetNamePath: string; override;
  property Collection: TCollection read FCollection write SetCollection;
  property ID: Integer read FID;
  property Index: Integer read GetIndex write SetIndex;
  property DisplayName: string read GetDisplayName write SetDisplayName;
 end;

The TCollection class is a complex and special container class. However, it seems to be a container class of the TCollectionItem object. Similar to the TList class in the List class, the TCollection class also maintains an index array of the TCollectionItem object. The Count attribute indicates the number of tcollectionitems contained in the container, the Add and Delete methods are also provided to Add and Delete TCollectionItem objects and to access the properties of TCollectionItem through subscript. It seems similar to the container class, but the TReader and TWriter classes used to save and load components in VCL provide two special methods: WriteCollection and ReadCollection, which are used to load and save collection attributes of the TCollection type. IDE uses these two methods to achieve the sustainability of TCollection type attributes.

Assume that a train component TTrain needs to be designed. The TTrain component has a TCollection type attribute Carriages, which indicates the set attribute composed of multiple trains. Each carriage corresponds to the element of the set attribute, inherited from the TCollectionItem class, there are attributes such as Carriage number, carriage type (sleeper, or hard seat), number of carriage seats, and carriage attendant name. below is the interface of the components I designed:

Type
// Carriage type, hard seat, sleeper
TCarriageType = (ctHard, ctSleeper );
// Carriage
TCarriageCollectionItem = class (TCollectionItem)
...
Published
// Carriage number
Property CarriageNum: Integer read FCarriageNum write FCarriageNum;
// Number of seats
Property SeatCount: Integer read FSeatCount write FSeatCount;
// Carriage type
Property CarriageType: TCarriageType read FCarriageType write FCarriageType;
// Waiter name
Property ServerName: string read FServerName write FServerName;
End;
TTrain = class;
// Compartment Container attributes
TCarriageCollection = class (TCollection)
*******
FTrain: TTrain;
Function GetItem (Index: Integer): TCarriageCollectionItem;
Procedure SetItem (Index: Integer; const Value: TCarriageCollectionItem );
Protected
Function GetOwner: TPersistent; override;
Public
Constructor Create (ATrain: TTrain );
Function Add: TCarriageCollectionItem;
Property Items [Index: Integer]: TCarriageCollectionItem read GetItem
Write SetItem; default;
End;
// Train
TTrain = class (TComponent)
*******
FItems: TCarriageCollection;
Procedure SetItems (Value: TCarriageCollection );
Public
Constructor Create (AOwner: TComponent); override;
Destructor Destroy; override;
Published
Property Carriages: TCarriageCollection read FItems write SetItems;
End;

The definition of carriage classes is very simple, but only four attributes are defined. The carriage collection class redefines the static Add method and Items attributes. The returned result type is changed to TCarriageCollectionItem. The following is the implementation code of the carriage collection class:

function TCarriageCollection.Add: TCarriageCollectionItem;
begin
 Result:=TCarriageCollectionItem(inherited Add);
end;
  
constructor TCarriageCollection.Create(ATrain: TTrain);
begin
 inherited Create(TCarriageCollectionItem);
 FTrain:=ATrain;
end;
  
function TCarriageCollection.GetItem(
 Index: Integer): TCarriageCollectionItem;
begin
 Result := TCarriageCollectionItem(inherited GetItem(Index));
end;
  
function TCarriageCollection.GetOwner: TPersistent;
begin
 Result:=FTrain;
end;
  
procedure TCarriageCollection.SetItem(Index: Integer;
 const Value: TCarriageCollectionItem);
begin
 inherited SetItem(Index, Value);
end;

Add, GetItem, and SetItem are both very simple. They call the base class method and remap the returned results of the base class method to the TCollectionItem type. In the constructor, The TTrain component is passed as the parent component, and the GetOwner method is reloaded to return the TTrain component, the reason for this is that IDE will call the GetOwner of the Collection class to confirm the parent control of the property when saving the set property so that the Set property can be written to the DFM file, in order to store them in the correct location and establish the correct aggregation relationship.

The implementation of train components is also very simple. You only need to define a Published Carriages attribute. The implementation code is as follows:

constructor TTrain.Create(AOwner: TComponent);
begin
 inherited;
 FItems := TCarriageCollection.Create(Self);
end;
  
destructor TTrain.Destroy;
begin
 FItems.Free;
 inherited;
end;
  
procedure TTrain.SetItems(Value: TCarriageCollection);
begin
 FItems.Assign(Value);
end;

After registering our components on the system panel, you can put a TTrain component on the form, select the Object Inspector, and double-click the Carriages attribute, the system's default set property editor is displayed. Use the Add button to Add two carriages to the list and modify the attributes, as shown in the following figure:

 

From the Attribute Editor above, we can see that by default, the Attribute Editor list box displays the name of the carriage by adding a horizontal bar to the project index, which does not look natural. To modify the display string, you need to overload the GetDisplayName method of TCarriageCollectionItem. The modified GetDisplayName method is used to display the carriage addition Number:

Function TCarriageCollectionItem. GetDisplayName: string;
Begin
Result: = 'Carriage '+ IntToStr (CarriageNum );
End;

:

 

Save the file and use the right-click View As Text menu command to View the DFM file. We can see that the property of the carriage class we designed is indeed written to the DFM file, and the father of the Carriages attribute is Train1:

Object Train1: TTrain
Carriages = <
Item
CarriageNum = 1
Seat COUNT = 100
CarriageType = ctHard
ServerName = 'Mr Chen'
End
Item
Carriagenum = 2
Seat COUNT = 200
Carriagetype = cthard
Servername = 'hubdog'
End>
Left = 16
Top = 8
End

TOwnedCollection

VCL added a TOwnedCollection class starting with Delphi4, which is a subclass of the TCollection class. If our TCarriageCollection class is inherited from the TOwnedCollection class, in this case, we no longer need to reload the GetOwner method above and return the parent control to the IDE, so that the TCarriageCollection attribute can appear in the Object Inspector.

Summary

This chapter describes almost all the important container classes in VCL. The TList and its subclass are equivalent to the general container classes. Although they are not as powerful as C ++ and Java, however, the use of TStrings is enough to meet 90% of our development needs. TStrings, its subclasses, and TCollection are the key classes to achieve WYSIWYG design, it is essential for developing flexible and powerful custom components.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.