unit Unit1; interface {$I ..\..\..\Source\Compilers.inc} uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ImgList, ExtCtrls, ActiveX, ComCtrls, {$IFDEF COMPILER_6_UP} Variants, DateUtils, {$ENDIF COMPILER_6_UP} {$IFDEF COMPILER_7_UP} XPMan, {$ENDIF COMPILER_7_UP} EasyListview, MPCommonUtilities, MPCommonObjects; const COLUMNSTRINGS: array[0..4] of WideString = ( 'Name', 'Address', 'Phone', 'Contact', 'ID' ); COLUMNWIDTHS: array[0..4] of Integer = ( 120, 180, 90, 90, 40 ); type // // First some data object is defined for the task // TBusinessType = ( btIndividual, btCompany ); // We are going to use reference counting for our objects by using // TEasyInterfacedPersistent as the ancestor. This class also implements // IEasyExtractObj which allows us to extract the TObject out of the interface // I know it is very un-COM like but most don't like to create a new interface // to do it right TBusinessObject = class(TEasyInterfacedPersistent) private FBusinessType: TBusinessType; public property BusinessType: TBusinessType read FBusinessType write FBusinessType; end; TCustomer = class(TBusinessObject) private FName: WideString; FAddress: WideString; FLastContact: TDateTime; FPhone: WideString; FRecordID: Integer; public constructor Create; destructor Destroy; override; property Address: WideString read FAddress write FAddress; property Name: WideString read FName write FName; property Phone: WideString read FPhone write FPhone; property LastContact: TDateTime read FLastContact write FLastContact; property RecordID: Integer read FRecordID write FRecordID; end; // // Now we "teach" it to interact with our EasyListview through interfaces // Currently the following interfaces are defined // IEasyCaptions // IEasyCaptionsEditable // IEasyImages // IEasyImagesEditable // IEasyChecks // IEasyCompareData // IEasyNotifier // IEasyExtractObj // // Our customer Data will need Editable captions but the Images are // hard coded and known by the class so we don't need to implement // IEasyImageEditable // // A little gotcha here. We must also put IEasyCaptions which is // IEasyCaptionsEditable's ancestor. If you don't a QueryInterface to // IEasyCaptions fails and ELV can't query for the Caption. TCustomerData = class(TCustomer, IEasyCaptions, IEasyCaptionsEditable, IEasyImages, IEasyNotifier, IEasyCompare, IEasyDetails, IEasyChecks) private FNotifier: IEasyNotificationSink; FChecked: Boolean; function GetDetail(Line: Integer): Integer; function GetDetailCount: Integer; public destructor Destroy; override; // IEasyNotifier procedure OnRegisterNotify(const ANotifier: IEasyNotificationSink); procedure OnUnRegisterNotify(const ANotifier: IEasyNotificationSink); // IEasyCaptions, IEasyCaptionsEditable function GetCaption(Column: Integer): Variant; function SetCaption(Column: Integer; const Value: Variant): Boolean; // IEasyImages function GetImageIndex(Column: Integer; ImageKind: TEasyImageKind): Integer; // IEasyCompareData function Compare(const Data: IUnknown; Column: TEasyColumn): Integer; // IEasyCaptions, IEasyCaptionsEditable function GetChecked(Column: Integer): Boolean; procedure SetChecked(Column: Integer; const Value: Boolean); property Captions[Column: Integer]: Variant read GetCaption; property Checked[Column: Integer]: Boolean read GetChecked write SetChecked; property Images[Column: Integer; ImageKind: TEasyImageKind]: Integer read GetImageIndex; property Detail[Line: Integer]: Integer read GetDetail; property DetailCount: Integer read GetDetailCount; property Notifier: IEasyNotificationSink read FNotifier write FNotifier; end; type TForm1 = class(TForm) ImageListSmall: TImageList; Splitter1: TSplitter; Panel1: TPanel; Memo1: TMemo; ComboBox1: TComboBox; Button1: TButton; ImageListLarge: TImageList; ImageListExLarge: TImageList; ButtonAddCustomers: TButton; EditCustomerAddCount: TEdit; StatusBar1: TStatusBar; Button2: TButton; ButtonChangeCaption: TButton; ButtonLoadData: TButton; ELV: TEasyListview; CheckBoxAutoSort: TCheckBox; procedure ComboBox1Change(Sender: TObject); procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ButtonAddCustomersClick(Sender: TObject); procedure Button2Click(Sender: TObject); procedure ButtonChangeCaptionClick(Sender: TObject); procedure ButtonLoadDataClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure CheckBoxAutoSortClick(Sender: TObject); private { Private declarations } procedure AddCustomers(Count: Integer); public { Public declarations } RecordID: Integer; end; var Form1: TForm1; implementation {$R *.dfm} { TCustomer } constructor TCustomer.Create; begin LastContact := Now end; destructor TCustomer.Destroy; begin inherited; end; { TCustomerData } function TCustomerData.Compare(const Data: IUnknown; Column: TEasyColumn): Integer; var Customer: TCustomerData; begin // Pull our object out of the interface Customer := TCustomerData( (Data as ICommonExtractObj).Obj); case Column.Index of 0: Result := WideStrIComp(PWideChar(Customer.Name), PWideChar( Name)); 1: Result := WideStrIComp(PWideChar(Customer.Address), PWideChar( Address)); 2: Result := WideStrIComp(PWideChar(Customer.Phone), PWideChar( Phone)); 3: Result := CompareTime(Customer.LastContact, LastContact); 4: Result := Customer.RecordID - RecordID else Result := 0 end; if Column.SortDirection = esdDescending then Result := -Result end; destructor TCustomerData.Destroy; begin // Unhook from the EasyObject if Assigned(FNotifier) then Notifier.UnRegister; inherited; end; function TCustomerData.GetCaption(Column: Integer): Variant; begin case Column of 0: begin // Flag it if it is checked if FChecked then Result := Name + '**' else Result := Name end; 1: Result := Address; 2: Result := Phone; 3: Result := LastContact; 4: Result := RecordID; else // Empty the Variant Result := '' end; end; function TCustomerData.GetChecked(Column: Integer): Boolean; begin if Column = 0 then Result := FChecked else Result := False end; function TCustomerData.GetDetail(Line: Integer): Integer; begin Result := 0; case Line of 0: Result := 0; /// Main Column caption 1: Result := 3; /// Column 3 caption 2: Result := 2; /// Column 2 caption end end; function TCustomerData.GetDetailCount: Integer; begin Result := 3 end; function TCustomerData.GetImageIndex(Column: Integer; ImageKind: TEasyImageKind): Integer; begin Result := -1; case ImageKind of eikNormal: begin if Column < 1 then begin case BusinessType of btIndividual: Result := 0; btCompany: Result := 1; end; end end; eikOverlay: begin end; eikState: begin end end end; procedure TCustomerData.OnRegisterNotify(const ANotifier: IEasyNotificationSink); begin Notifier := ANotifier end; procedure TCustomerData.OnUnRegisterNotify(const ANotifier: IEasyNotificationSink); begin Notifier := nil end; function TCustomerData.SetCaption(Column: Integer; const Value: Variant): Boolean; begin Result := True; case Column of 0: Name := Value; 1: Address := Value; 2: Phone := Value; 3: LastContact := Value; 4: RecordID := Value end end; procedure TCustomerData.SetChecked(Column: Integer; const Value: Boolean); begin if Column = 0 then begin FChecked := Value; Notifier.InvalidateItem(True); end; end; { TForm1 } procedure TForm1.ComboBox1Change(Sender: TObject); begin ELV.View := TEasyListStyle(ComboBox1.ItemIndex) end; procedure TForm1.Button1Click(Sender: TObject); begin AddCustomers(1); end; procedure TForm1.FormCreate(Sender: TObject); begin ComboBox1.ItemIndex:= 0; end; procedure TForm1.ButtonAddCustomersClick(Sender: TObject); begin AddCustomers(StrToInt(EditCustomerAddCount.Text)); end; procedure TForm1.AddCustomers(Count: Integer); var CustomerData: TCustomerData; Group: TEasyGroup; i: Integer; TickCount: Cardinal; begin TickCount := GetTickCount; ELV.BeginUpdate; try if ELV.Groups.Count = 0 then begin Group := ELV.Groups.Add; Group.Caption := 'Group 1'; end else Group := ELV.Groups[0]; for i := 0 to Count -1 do begin CustomerData := TCustomerData.Create; CustomerData.BusinessType := TBusinessType( Random(2)); CustomerData.Name := 'New Customer ' + IntToStr(RecordID); CustomerData.Address := '123 Elm St. Anytown USA, 99999'; CustomerData.Phone := '102-555-7890'; CustomerData.LastContact := Now; CustomerData.RecordID := RecordID; // Our Data object will freed automatically when the Item is freed // because it is decended from TInterfacedObject Group.Items.AddInterfaced(CustomerData); Inc(RecordID) end finally ELV.Sort.SortAll; ELV.EndUpdate; Statusbar1.Panels[0].Text := 'Elapsed Time: ' + IntToStr(GetTickCount - TickCount) end end; procedure TForm1.Button2Click(Sender: TObject); var TickCount: Cardinal; begin TickCount := GetTickCount; if ELV.Groups.Count > 0 then ELV.Groups.Clear; Statusbar1.Panels[0].Text := 'Elapsed Time: ' + IntToStr(GetTickCount - TickCount); RecordID := 0; end; procedure TForm1.ButtonChangeCaptionClick(Sender: TObject); begin { if Assigned(LocalData) then begin LocalData.SetCaption(0, 'John Smith'); LocalData.SetCaption(1, '4523 WayEasy Way, Coolssville USA, 45687'); LocalData.SetCaption(2, '406-555-6913'); LocalData.Notifier.InvalidateItem(True); end } end; procedure TForm1.ButtonLoadDataClick(Sender: TObject); var CustomerData: TCustomerData; Group: TEasyGroup; i: Integer; TickCount: Cardinal; S: TStringList; begin S := TStringList.Create; S.LoadFromFile('Data.txt'); TickCount := GetTickCount; ELV.BeginUpdate; try ELV.Groups.Clear; Group := ELV.Groups.Add; for i := 0 to (S.Count div 3) - 1 do begin CustomerData := TCustomerData.Create; CustomerData.BusinessType := TBusinessType( Random(2)); CustomerData.Name := S[i*3]; CustomerData.Address := S[i*3+1]; CustomerData.Phone := S[i*3+2]; CustomerData.LastContact := Now; CustomerData.RecordID := RecordID; // Our Data object will freed automatically when the Item is freed // because it is decended from TInterfacedObject Group.Items.AddInterfaced(CustomerData); Inc(RecordID) end finally ELV.EndUpdate; Statusbar1.Panels[0].Text := 'Elapsed Time: ' + IntToStr(GetTickCount - TickCount) end; S.Free end; procedure TForm1.FormShow(Sender: TObject); var i: Integer; Column: TEasyColumn; begin ComboBox1.ItemIndex := Integer(ELV.View); CheckBoxAutoSort.Checked := ELV.Sort.AutoSort; ELV.Header.Columns.Clear; for i := 0 to High(COLUMNSTRINGS) do begin Column := ELV.Header.Columns.Add; Column.Caption := COLUMNSTRINGS[i]; Column.Width := COLUMNWIDTHS[i]; Column.AutoToggleSortGlyph := True; end; end; procedure TForm1.CheckBoxAutoSortClick(Sender: TObject); begin ELV.Sort.AutoSort := CheckBoxAutoSort.Checked end; end.