TListItem erweitern
-
Hallo,
ich möchte gerne in meinem Listview verschiedene Einträge fettdrucken. Dies soll man beim Hinzufügen des Items festlegen können, was ja erstmal als solches nicht geht. In der "OnItemDraw" Methode habe ich bisher etwas aufgesetzt, mit dem ich einen Eintrag fettdrucken kann, das Problem ist nur, dass nur bestimmte Items fett sein sollen.
Perfekt wäre es für micht, wenn die Klasse TListItem eine Eigenschaft wie "Tag" hätte, da ich ja dann einfach 0 für normal und 1 für bold definieren könnte und anschließend einfach im OnDrawItem Event den Tag überprüfen. Leider ist diese Eigenschaft nicht vorhanden. Habe ich die Möglichkeit, diese Nachträglich hinzuzufügen, bzw eine Klasse zu schreiben, die von TListItem erbt, diese aber dann überschreibt?
Vielen Dank für eure Antwort!
-
Nein, das geht nicht, weil du dem
TListView
dann auch beibringen müsstest, deine neue ListItem-Klasse zu erzeugen.
TListItem
hat allerdings einData
Element, das du benutzen kannst.
-
Doch, das geht.
TCustomListView
hat eineprotected virtual
-Methode namensCreateListItem()
, die du in einer abgeleiteten Klasse überschreiben kannst, um ein Objekt deiner eigenen vonTListItem
abgeleitete Klasse zurückzugeben. Ebenso kannst du die MethodeCreateListItems()
überschreiben und eine vonTListItems
abgeleitete Klasse erstellen und zurückgeben, die eine neueAdd()
-Methode mit dem richtigen Rückgabewert bereitstellt.Leider konnte Delphi noch keine Generics, als die VCL entstand. Die meisten VCL-Collections sind deshalb nur so halbwegs typsicher, weil sie mit Type Erasure implementiert sind. (Richtige Generics, z.B. in heutigem Delphi oder in .NET, haben diesen Nachteil nicht. Aber z.B. die Generics in Java verwenden intern auch Type Erasure
) Außerdem ist relativ viel Tipparbeit erforderlich, um die abgeleitete Klasse einigermaßen bequem benutzen zu können.
Unten ein Beispiel in Delphi. Du kannst es nach C++ übersetzen, ich würde es aber einfach in Delphi belassen. Idealerweise plazierst du die Klasse in einem separaten Komponenten-Package, und Delphi bietet sich an, weil es dort Class Completion gibt (du tippst nur die Klassendefinition und die IDE erzeugt auf Knopfdruck [Ctrl+Shift+C] die Funktionsprototypen), und man so einigen Code aus ComCtrls.pas mit Copy & Paste recyclen kann. (Wohlgemerkt kann auch C++Builder Delphi-Units kompilieren, das geht also auch, wenn du nicht das RAD Studio, sondern nur C++Builder hast.)
unit FormattedListView; interface uses Types, ComCtrls; type TFormattedListItem = class; TFormattedListItems = class; TFormattedListItemsEnumerator = class private FIndex: Integer; FListItems: TFormattedListItems; public constructor Create(AListItems: TFormattedListItems); function GetCurrent: TFormattedListItem; function MoveNext: Boolean; property Current: TFormattedListItem read GetCurrent; end; TFormattedListItems = class (TListItems) private function DoGetItem(Index: Integer): TFormattedListItem; procedure DoSetItem(Index: Integer; Value: TFormattedListItem); public function Add: TFormattedListItem; function AddItem(Item: TFormattedListItem; Index: Integer = -1): TFormattedListItem; function GetEnumerator: TFormattedListItemsEnumerator; function Insert(Index: Integer): TFormattedListItem; property Item[Index: Integer]: TFormattedListItem read DoGetItem write DoSetItem; default; end; TFormattedListItem = class (TListItem) { TODO: hier die gewünschten Eigenschaften einfügen } end; TCustomFormattedListView = class (TCustomListView) protected function CreateListItem: TListItem; override; function CreateListItems: TListItems; override; procedure DrawItem(Item: TListItem; Rect: TRect; State: TOwnerDrawState); override; end; TFormattedListView = class (TCustomFormattedListView) published { TODO: hier die ganzen Properties einfügen, die in ComCtrls.TListView als published markiert sind } end; procedure Register; implementation uses Classes, Graphics, Controls; { TFormattedListItems } function TFormattedListItems.Add: TFormattedListItem; begin Result := inherited Add as TFormattedListItem; end; function TFormattedListItems.AddItem(Item: TFormattedListItem; Index: Integer): TFormattedListItem; begin Result := inherited AddItem (Item, Index) as TFormattedListItem; end; function TFormattedListItems.DoGetItem(Index: Integer): TFormattedListItem; begin Result := inherited Item[Index] as TFormattedListItem; end; procedure TFormattedListItems.DoSetItem(Index: Integer; Value: TFormattedListItem); begin inherited Item[Index] := Value; end; function TFormattedListItems.GetEnumerator: TFormattedListItemsEnumerator; begin Result := TFormattedListItemsEnumerator.Create (Self); end; function TFormattedListItems.Insert(Index: Integer): TFormattedListItem; begin Result := inherited Insert (Index) as TFormattedListItem; end; { TFormattedListItemsEnumerator } constructor TFormattedListItemsEnumerator.Create(AListItems: TFormattedListItems); begin { Copy & Paste aus ComCtrls.TListItemsEnumerator } inherited Create; FIndex := -1; FListItems := AListItems; end; function TFormattedListItemsEnumerator.GetCurrent: TFormattedListItem; begin Result := FListItems[FIndex]; end; function TFormattedListItemsEnumerator.MoveNext: Boolean; begin Result := FIndex < FListItems.Count - 1; if Result then Inc(FIndex); end; { TCustomFormattedListView } function TCustomFormattedListView.CreateListItem: TListItem; var LClass: TListItemClass; begin { Copy & Paste aus TCustomListView.CreateListItem() mit Substitution TListItem -> TFormattedListItem } LClass := TFormattedListItem; if Assigned(OnCreateItemClass) then OnCreateItemClass(Self, LClass); Result := LClass.Create(Items); end; function TCustomFormattedListView.CreateListItems: TListItems; begin Result := TFormattedListItems.Create(Self); end; procedure TCustomFormattedListView.DrawItem(Item: TListItem; Rect: TRect; State: TOwnerDrawState); begin TControlCanvas(Canvas).UpdateTextFlags; if Assigned(OnDrawItem) then OnDrawItem(Self, Item, Rect, State) else if { TODO: spezielle Darstellung erforderlich? } then begin { TODO: spezielle Darstellung durchführen } end else inherited; { Standarddarstellung } end; procedure Register; begin RegisterComponents ('My components', [TFormattedListView]); end; end.
Edit:
TFormattedListView
undRegister()
-Prozedur hinzugefügt