Blog
All Blog Posts | Next Post | Previous PostEasy extensibility with poly list controls
Sunday, June 20, 2010
The TMS Advanced Poly List controls were designed from the ground up with extensibility in mind. Both at design time and at run time, custom item class instances can be added to the list. The developers guide explains how this can be done with a simple sample showing how to create an item class that shows a triangle. While this shows the techniques needed, displaying a triangle is of limited usefulness. For an application, we needed an item with a progress bar. We could reuse the smooth controls progress bar drawing with the added bonus that it looks nicer than an average progress bar. All in all, in about 30 minutes, a new item class that shows a progress bar is ready to be used.You can download the sample with the full source code of the new progress bar item class here so you can easily add this progress bar in any of the TMS Poly List controls you're using.
Now, for those interested to learn how this was created, here is a short description:
1) Create class descending from TCustomItem
TCustomItem is defined in the unit GDIPCustomItem. Create a new unit with a new class descending from TCustomItem
type TProgressItem = class(TCustomItem) end;
function CreateNewItem(AOwner: TComponent): TCustomItem;
This function creates a new instance of the item
function GetClassType: TComponentClass;
This function returns the type of the class
function CustomClassName: String;
This function returns a friendly class description
3) Add properties relevant for the progress bar
This consists of the progress bar minimum, maximum and position properties. A property to control whether the value is displayed and the format to use for displaying the value and most importantly, the Appearance property that holds all color / gradient settings for the progressbar:
type TProgressItem = class(TCustomItem) published property Appearance: TGDIPProgress; property Min: integer; property Max: integer; property Margin: integer; property Position: integer; property ShowValue: boolean; property ValueFormat: string; end;
4) Implement the custom drawing
The custom drawing is implemented by overriding the virtual method DrawInRect()
The DrawInRect method parameters return the graphics device context, the default item appearance and the rectangle of the item. The default item appearance holds settings such as normal state background fill, selected state background fill, hovered state background fill. In the case of this TProgressItem, the TMS smooth controls TGDIPProgress class is used. This class has a method that draws the progress bar on the graphics device context.
5) Register the class
In the Register procedure, the function RegisterPolyItem(TProgressItem) is called and when installed via a package in the IDE, this makes the progressbar available in the designer.
Using the new TProgressItem class
Using the new class is equally simple. The code snippet here shows how a new instance of the TProgressItem is inserted in the poly list control and its properties being initialized:
var pi: TProgressItem; begin pi := TProgressItem(AdvVerticalPolyList2.InsertItem(1, TProgressItem)); pi.Min := 0; pi.Max := 100; pi.Position := 75; pi.ValueFormat := 'Download progress: %d%%'; pi.Margin := 4; end;
The full source code of the TProgressItem class is here:
unit GDIPProgressItem; interface uses Classes, GDIPCustomItem, AdvGDIP, GDIPFill; type TProgressItem = class(TCustomItem) private FAppearance: TGDIPProgress; FMax: integer; FMin: integer; FPosition: integer; FValueFormat: string; FShowValue: boolean; FMargin: integer; procedure SetAppearance(const Value: TGDIPProgress); procedure SetMax(const Value: integer); procedure SetMin(const Value: integer); procedure SetPosition(const Value: integer); procedure SetShowValue(const Value: boolean); procedure SetValueFormat(const Value: string); procedure SetMargin(const Value: integer); protected public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Assign(Source: TPersistent); override; function CreateNewItem(AOwner: TComponent): TCustomItem; override; function GetClassType: TComponentClass; override; class function CustomClassName: String; override; procedure DrawInRect(g: TGPGraphics; ItemAppearance: TItemAppearance; R: TGPRectF); override; published property Appearance: TGDIPProgress read FAppearance write SetAppearance; property Min: integer read FMin write SetMin default 0; property Max: integer read FMax write SetMax default 100; property Margin: integer read FMargin write SetMargin default 2; property Position: integer read FPosition write SetPosition default 0; property ShowValue: boolean read FShowValue write SetShowValue default true; property ValueFormat: string read FValueFormat write SetValueFormat; end; procedure Register; implementation uses SysUtils, Graphics, Windows; { TProgressItem } procedure TProgressItem.Assign(Source: TPersistent); begin inherited; FAppearance.Assign((Source as TProgressItem).Appearance); end; constructor TProgressItem.Create(AOwner: TComponent); begin inherited; FShowValue := true; FValueFormat := '%d%%'; FMargin := 2; Height := 40; FAppearance := TGDIPProgress.Create; with FAppearance do begin BackGroundFill.Color := $00FFD2AF; BackGroundFill.ColorTo := $00FFD2AF; BackGroundFill.BorderColor := $00C0C0C0; ProgressFill.Color := $00EBFDFF; ProgressFill.ColorTo := $00ABEBFF; ProgressFill.ColorMirror := $0069D6FF; ProgressFill.ColorMirrorTo := $0096E4FF; ProgressFill.BorderColor := clSilver; ProgressFill.GradientMirrorType := gtVertical; end; end; function TProgressItem.CreateNewItem(AOwner: TComponent): TCustomItem; begin Result := TProgressItem.Create(AOwner); end; class function TProgressItem.CustomClassName: String; begin Result := 'Progressbar item'; end; destructor TProgressItem.Destroy; begin FAppearance.Free; inherited; end; procedure TProgressItem.DrawInRect(g: TGPGraphics; ItemAppearance: TItemAppearance; R: TGPRectF); var f: TGDIPFill; dr,tr: TRect; valstr: string; h,tw,th: integer; begin if Visible then begin DoItemStartDraw(Self, g, Self, r); DoInternalItemStartDraw(Self, g, Self, r); f := GetFill(ItemAppearance); if Assigned(f) then f.Fill(g, r); if ItemAppearance.Focus and (State = isSelected) then DrawFocus(g, r, ItemAppearance); dr := Rect(Trunc(r.X), Trunc(r.Y), Trunc(R.X + R.Width), Trunc(R.Y + R.Height)); InflateRect(dr, -Margin, - Margin); h := dr.Bottom - dr.Top; if ShowValue then h := h div 2; tr := Rect(dr.Left, dr.Top, dr.Right, dr.Top + h); // draw progressbar FAppearance.Draw(g, tr ,FMin,FMax,FPosition); if ShowValue then begin tr := Rect(dr.Left, dr.Top + h, dr.Right, dr.Top + 2*h); valstr := Format(FValueFormat, [FPosition]); // measure text value size th := g.DrawText(valstr, length(valstr), tr, GetFont(ItemAppearance), DT_CALCRECT); tw := tr.Right - tr.Left; // center text tr := Rect(dr.Left + (dr.Right - dr.Left - tw) div 2, dr.Top + (dr.Bottom - dr.Top - th + h) div 2, dr.Right, dr.Bottom); // draw text g.DrawText(valstr, length(valstr), tr, GetFont(ItemAppearance), 0); end; DoItemEndDraw(Self, g, Self, r); DoInternalItemEndDraw(Self, g, Self, r); end; end; function TProgressItem.GetClassType: TComponentClass; begin Result := TProgressItem; end; procedure TProgressItem.SetAppearance(const Value: TGDIPProgress); begin FAppearance.Assign(Value); end; procedure TProgressItem.SetMargin(const Value: integer); begin if (FMargin <> Value) then begin FMargin := Value; Changed; end; end; procedure TProgressItem.SetMax(const Value: integer); begin if (FMax <> Value) then begin FMax := Value; Changed; end; end; procedure TProgressItem.SetMin(const Value: integer); begin if (FMin <> Value) then begin FMin := Value; Changed; end; end; procedure TProgressItem.SetPosition(const Value: integer); begin if (FPosition <> Value) then begin FPosition := Value; Changed; end; end; procedure TProgressItem.SetShowValue(const Value: boolean); begin if FShowValue <> Value then begin FShowValue := Value; Changed; end; end; procedure TProgressItem.SetValueFormat(const Value: string); begin if (FValueFormat <> Value) then begin FValueFormat := Value; Changed; end; end; procedure Register; begin RegisterPolyItem(TProgressItem); end; end.
Bruno Fierens
This blog post has not received any comments yet.
All Blog Posts | Next Post | Previous Post