TAChart: Convert TChartListBox code to standard style

git-svn-id: trunk@31633 -
This commit is contained in:
ask 2011-07-10 02:59:52 +00:00
parent 77e81e6501
commit 8d895ef46b

View File

@ -1,11 +1,4 @@
{ {
/***************************************************************************
TAChartListbox.pas
------------------
Component Library Standard Graph Listbox
***************************************************************************/
***************************************************************************** *****************************************************************************
* * * *
@ -39,29 +32,29 @@ unit TAChartListbox;
interface interface
uses uses
Classes, Controls, SysUtils, LCLType, StdCtrls, Classes, Controls, StdCtrls,
TAChartUtils, TACustomSeries, TALegend, TAGraph; TAChartUtils, TACustomSeries, TALegend, TAGraph;
type type
TChartListboxIndexEvent = procedure ( TChartListboxIndexEvent = procedure (
Sender: TObject; Index: Integer) of object; ASender: TObject; AIndex: Integer) of object;
TCheckBoxesStyle = (cbsCheckbox, cbsRadiobutton); TCheckBoxesStyle = (cbsCheckbox, cbsRadiobutton);
TChartListbox = class(TCustomListbox) TChartListbox = class(TCustomListbox)
private private
FChart: TChart; FChart: TChart;
FListener: TListener;
FLegendItems: TChartLegendItems;
FShowSeriesIcons: Boolean;
FShowCheckboxes: Boolean;
FCheckStyle: TCheckBoxesStyle; FCheckStyle: TCheckBoxesStyle;
FLegendItems: TChartLegendItems;
FListener: TListener;
FLockCount: Integer; FLockCount: Integer;
FSeriesIconClicked: Integer;
FOnCheckboxClick: TChartListboxIndexEvent; FOnCheckboxClick: TChartListboxIndexEvent;
FOnSeriesIconClick: TChartListboxIndexEvent;
FOnItemClick: TChartListboxIndexEvent; FOnItemClick: TChartListboxIndexEvent;
FOnPopulate: TNotifyEvent; FOnPopulate: TNotifyEvent;
FOnSeriesIconClick: TChartListboxIndexEvent;
FSeriesIconClicked: Integer;
FShowCheckboxes: Boolean;
FShowSeriesIcons: Boolean;
function GetChecked(AIndex: Integer): Boolean; function GetChecked(AIndex: Integer): Boolean;
function GetLegendItem(AIndex: Integer): TLegendItem; function GetLegendItem(AIndex: Integer): TLegendItem;
function GetSeries(AIndex: Integer): TCustomChartSeries; function GetSeries(AIndex: Integer): TCustomChartSeries;
@ -73,24 +66,25 @@ type
procedure SetShowCheckboxes(AValue: Boolean); procedure SetShowCheckboxes(AValue: Boolean);
procedure SetShowSeriesIcons(AValue: Boolean); procedure SetShowSeriesIcons(AValue: Boolean);
protected
procedure DrawItem(
AIndex: Integer; ARect: TRect; AState: TOwnerDrawState); override;
procedure KeyDown(var AKey: Word; AShift: TShiftState); override;
procedure MouseDown(
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer); override;
procedure Notification(
AComponent: TComponent; AOperation: TOperation); override;
protected protected
procedure CalcRects( procedure CalcRects(
const AItemRect: TRect; out CheckboxRect, SeriesIconRect: TRect); const AItemRect: TRect; out ACheckboxRect, ASeriesIconRect: TRect);
procedure ClickedCheckbox(AIndex: Integer); virtual; procedure ClickedCheckbox(AIndex: Integer); virtual;
procedure ClickedItem(AIndex: Integer); virtual; procedure ClickedItem(AIndex: Integer); virtual;
procedure ClickedSeriesIcon(AIndex: Integer); virtual; procedure ClickedSeriesIcon(AIndex: Integer); virtual;
function CreateLegendItems: TChartLegendItems; function CreateLegendItems: TChartLegendItems;
procedure DblClick; override; procedure DblClick; override;
procedure DrawItem(
Index: Integer; ARect: TRect; AState: TOwnerDrawState); override;
function FirstCheckedIndex: Integer; function FirstCheckedIndex: Integer;
function IsLocked: Boolean; function IsLocked: Boolean;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure Lock; procedure Lock;
procedure MouseDown(
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer); override;
procedure Notification(
AComponent: TComponent; AOperation: TOperation); override;
procedure Populate; procedure Populate;
procedure Unlock; procedure Unlock;
@ -98,7 +92,7 @@ type
constructor Create(AOwner: TComponent); override; constructor Create(AOwner: TComponent); override;
destructor Destroy; override; destructor Destroy; override;
function FindSeriesIndex(ASeries: TCustomChartSeries): Integer; function FindSeriesIndex(ASeries: TCustomChartSeries): Integer;
procedure MeasureItem(Index: Integer; var AHeight: Integer); override; procedure MeasureItem(AIndex: Integer; var AHeight: Integer); override;
procedure RemoveSeries(ASeries: TCustomChartSeries); procedure RemoveSeries(ASeries: TCustomChartSeries);
property Checked[AIndex: Integer]: Boolean read GetChecked write SetChecked; property Checked[AIndex: Integer]: Boolean read GetChecked write SetChecked;
property Series[AIndex: Integer]: TCustomChartSeries read GetSeries; property Series[AIndex: Integer]: TCustomChartSeries read GetSeries;
@ -112,15 +106,15 @@ type
read FShowCheckboxes write SetShowCheckboxes default true; read FShowCheckboxes write SetShowCheckboxes default true;
property ShowSeriesIcons: Boolean property ShowSeriesIcons: Boolean
read FShowSeriesIcons write SetShowSeriesIcons default true; read FShowSeriesIcons write SetShowSeriesIcons default true;
published
property OnCheckboxClick: TChartListboxIndexEvent property OnCheckboxClick: TChartListboxIndexEvent
read FOnCheckboxClick write FOnCheckboxClick; read FOnCheckboxClick write FOnCheckboxClick;
property OnItemClick: TChartListboxIndexEvent property OnItemClick: TChartListboxIndexEvent
read FOnItemClick write FOnItemClick; read FOnItemClick write FOnItemClick;
property OnPopulate: TNotifyEvent read FOnPopulate write FOnPopulate;
property OnSeriesIconClick: TChartListboxIndexEvent property OnSeriesIconClick: TChartListboxIndexEvent
read FOnSeriesIconClick write FOnSeriesIconClick; read FOnSeriesIconClick write FOnSeriesIconClick;
property OnPopulate: TNotifyEvent published
read FOnPopulate write FOnPopulate;
property Align; property Align;
// property AllowGrayed; // property AllowGrayed;
property Anchors; property Anchors;
@ -132,8 +126,8 @@ type
property Constraints; property Constraints;
property DragCursor; property DragCursor;
property DragMode; property DragMode;
property ExtendedSelect;
property Enabled; property Enabled;
property ExtendedSelect;
property Font; property Font;
property IntegralHeight; property IntegralHeight;
// property Items; // property Items;
@ -144,21 +138,21 @@ type
// property OnClickCheck; // property OnClickCheck;
property OnContextPopup; property OnContextPopup;
property OnDblClick; property OnDblClick;
property OnDrawItem;
property OnDragDrop; property OnDragDrop;
property OnDragOver; property OnDragOver;
property OnDrawItem;
property OnEndDrag; property OnEndDrag;
property OnEnter; property OnEnter;
property OnExit; property OnExit;
// property OnItemClick; // property OnItemClick;
property OnKeyPress;
property OnKeyDown; property OnKeyDown;
property OnKeyPress;
property OnKeyUp; property OnKeyUp;
property OnMouseMove;
property OnMouseDown; property OnMouseDown;
property OnMouseUp;
property OnMouseEnter; property OnMouseEnter;
property OnMouseLeave; property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheel; property OnMouseWheel;
property OnMouseWheelDown; property OnMouseWheelDown;
property OnMouseWheelUp; property OnMouseWheelUp;
@ -185,7 +179,8 @@ procedure Register;
implementation implementation
uses uses
Math, LCLIntf, Themes, TAGeometry, TADrawUtils, TADrawerCanvas; Math, LCLIntf, LCLType, SysUtils, Themes,
TAGeometry, TADrawUtils, TADrawerCanvas;
procedure Register; procedure Register;
begin begin
@ -209,27 +204,27 @@ begin
end; end;
procedure TChartListbox.CalcRects( procedure TChartListbox.CalcRects(
const AItemRect: TRect; out CheckboxRect, SeriesIconRect: TRect); const AItemRect: TRect; out ACheckboxRect, ASeriesIconRect: TRect);
{ based on the rect of a listbox item, calculates the locations of the { based on the rect of a listbox item, calculates the locations of the
checkbox and of the series icon } checkbox and of the series icon }
var var
w, x: Integer; w, x: Integer;
begin begin
CheckBoxRect := Rect(-1, -1, -1, -1); ACheckBoxRect := Rect(-1, -1, -1, -1);
SeriesIconRect := Rect(-1, -1, -1, -1); ASeriesIconRect := Rect(-1, -1, -1, -1);
w := GetSystemMetrics(SM_CYMENUCHECK); w := GetSystemMetrics(SM_CYMENUCHECK);
x := 2; x := 2;
if FShowCheckboxes then begin if FShowCheckboxes then begin
CheckboxRect := Bounds(AItemRect.Left + 1, AItemRect.Top + 1, w, w); ACheckboxRect := Bounds(AItemRect.Left + 1, AItemRect.Top + 1, w, w);
if FShowSeriesIcons then if FShowSeriesIcons then
inc(x, CheckboxRect.Right); x += ACheckboxRect.Right;
end end
else begin else begin
if FShowSeriesIcons then if FShowSeriesIcons then
inc(x, AItemRect.Left); x += AItemRect.Left;
end; end;
if FShowSeriesIcons then if FShowSeriesIcons then
SeriesIconRect := Rect( ASeriesIconRect := Rect(
x, AItemRect.Top + 2, x + FChart.Legend.SymbolWidth, AItemRect.Bottom - 2); x, AItemRect.Top + 2, x + FChart.Legend.SymbolWidth, AItemRect.Bottom - 2);
end; end;
@ -262,13 +257,10 @@ var
begin begin
Result := TChartLegendItems.Create; Result := TChartLegendItems.Create;
try try
if FChart <> nil then if FChart = nil then exit;
for i := 0 to FChart.SeriesCount - 1 do begin for i := 0 to FChart.SeriesCount - 1 do
if FChart.Series[i] is TCustomChartSeries then begin if FChart.Series[i] is TCustomChartSeries then
TCustomChartSeries(FChart.Series[i]).GetSingleLegendItem(Result); TCustomChartSeries(FChart.Series[i]).GetSingleLegendItem(Result);
Result[i].Owner := FChart.Series[i];
end;
end;
for i := Result.Count - 1 downto 0 do for i := Result.Count - 1 downto 0 do
if Result[i].Order = LEGEND_ITEM_ORDER_AS_ADDED then begin if Result[i].Order = LEGEND_ITEM_ORDER_AS_ADDED then begin
Result[i].Order := j; Result[i].Order := j;
@ -288,18 +280,23 @@ begin
end; end;
procedure TChartListbox.DrawItem( procedure TChartListbox.DrawItem(
Index: Integer; ARect: TRect; AState: TOwnerDrawState); AIndex: Integer; ARect: TRect; AState: TOwnerDrawState);
{ draws the listbox item } { draws the listbox item }
const const
IS_CHECKED: array[TCheckboxesStyle, Boolean] of Integer = ( UNTHEMED_FLAGS: array [TCheckboxesStyle, Boolean] of Integer = (
(DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED), (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED),
(DFCS_BUTTONRADIO, DFCS_BUTTONRADIO or DFCS_CHECKED) (DFCS_BUTTONRADIO, DFCS_BUTTONRADIO or DFCS_CHECKED)
); );
THEMED_FLAGS: array [TCheckboxesStyle, Boolean] of TThemedButton = (
(tbCheckBoxUncheckedNormal, tbCheckBoxCheckedNormal),
(tbRadioButtonUnCheckedNormal, tbRadioButtonCheckedNormal)
);
var var
id: IChartDrawer; id: IChartDrawer;
rcb, ricon: TRect; rcb, ricon: TRect;
te: TThemedElementDetails; te: TThemedElementDetails;
x: Integer; x: Integer;
ch: Boolean;
begin begin
Unused(AState); Unused(AState);
@ -308,24 +305,14 @@ begin
CalcRects(ARect, rcb, ricon); CalcRects(ARect, rcb, ricon);
if FShowCheckboxes then begin if FShowCheckboxes then begin
ch := Checked[AIndex];
if ThemeServices.ThemesEnabled then begin if ThemeServices.ThemesEnabled then begin
case FCheckStyle of te := ThemeServices.GetElementDetails(THEMED_FLAGS[FCheckStyle, ch]);
cbsCheckbox :
if Checked[Index] then
te := ThemeServices.GetElementDetails(tbCheckBoxCheckedNormal)
else
te := ThemeServices.GetElementDetails(tbCheckBoxUncheckedNormal);
cbsRadioButton :
if Checked[Index] then
te := ThemeServices.GetElementDetails(tbRadioButtonCheckedNormal)
else
te := ThemeServices.GetElementDetails(tbRadioButtonUnCheckedNormal);
end;
ThemeServices.DrawElement(Canvas.Handle, te, rcb); ThemeServices.DrawElement(Canvas.Handle, te, rcb);
end end
else else
DrawFrameControl( DrawFrameControl(
Canvas.Handle, rcb, DFC_BUTTON, IS_CHECKED[FCheckStyle, Checked[Index]]); Canvas.Handle, rcb, DFC_BUTTON, UNTHEMED_FLAGS[FCheckStyle, ch]);
x := rcb.Right; x := rcb.Right;
end end
else else
@ -334,37 +321,25 @@ begin
if FShowSeriesIcons then begin if FShowSeriesIcons then begin
id := TCanvasDrawer.Create(Canvas); id := TCanvasDrawer.Create(Canvas);
id.Pen := Chart.Legend.SymbolFrame; id.Pen := Chart.Legend.SymbolFrame;
FLegendItems[Index].Draw(id, ricon); FLegendItems[AIndex].Draw(id, ricon);
end else end
Canvas.TextOut(x + 2, ARect.Top, FLegendItems.Items[Index].Text); else
Canvas.TextOut(x + 2, ARect.Top, FLegendItems.Items[AIndex].Text);
end; end;
function TChartListbox.FindSeriesIndex(ASeries: TCustomChartSeries): Integer; function TChartListbox.FindSeriesIndex(ASeries: TCustomChartSeries): Integer;
{ searches the internal legend items list for the specified series } { searches the internal legend items list for the specified series }
var
i: Integer;
ser: TBasicChartSeries;
begin begin
for i := 0 to FLegendItems.Count - 1 do begin for Result := 0 to FLegendItems.Count - 1 do
ser := GetSeries(i); if GetSeries(Result) = ASeries then exit;
if ser = ASeries then begin
Result := i;
exit;
end;
end;
Result := -1; Result := -1;
end; end;
function TChartListbox.FirstCheckedIndex: Integer; function TChartListbox.FirstCheckedIndex: Integer;
{ Returns the index of the first listbox series that is active } { Returns the index of the first listbox series that is active }
var
i: Integer;
begin begin
for i := 0 to FLegendItems.Count - 1 do for Result := 0 to FLegendItems.Count - 1 do
if Checked[i] then begin if Checked[Result] then exit;
Result := i;
exit;
end;
Result := -1; Result := -1;
end; end;
@ -375,7 +350,7 @@ var
ser: TBasicChartSeries; ser: TBasicChartSeries;
begin begin
ser := GetSeries(AIndex); ser := GetSeries(AIndex);
Result := ser.Active; Result := (ser <> nil) and ser.Active;
end; end;
function TChartListbox.GetLegendItem(AIndex: Integer): TLegendItem; function TChartListbox.GetLegendItem(AIndex: Integer): TLegendItem;
@ -409,29 +384,29 @@ begin
Result := FLockCount <> 0; Result := FLockCount <> 0;
end; end;
procedure TChartListBox.KeyDown(var Key: Word; Shift: TShiftState); procedure TChartListBox.KeyDown(var AKey: Word; AShift: TShiftState);
{ allows checking/unchecking of items by means of pressing the space bar } { allows checking/unchecking of items by means of pressing the space bar }
begin begin
if (Key = VK_SPACE) and (Shift = []) and FShowCheckboxes then begin if (AKey = VK_SPACE) and (AShift = []) and FShowCheckboxes then begin
ClickedCheckbox(ItemIndex); ClickedCheckbox(ItemIndex);
Key := VK_UNKNOWN; AKey := VK_UNKNOWN;
end end
else else
inherited KeyDown(Key,Shift); inherited KeyDown(AKey, AShift);
end; end;
procedure TChartListBox.Lock; procedure TChartListBox.Lock;
{ locking mechanism to avoid excessive broadcasting of chart changes. { locking mechanism to avoid excessive broadcasting of chart changes.
See also: IsLocked and UnLock } See also: IsLocked and UnLock }
begin begin
inc(FLockCount); FLockCount += 1;
end; end;
procedure TChartListBox.MeasureItem(Index: Integer; var AHeight: Integer); procedure TChartListBox.MeasureItem(AIndex: Integer; var AHeight: Integer);
{ inherited from ancestor: measures the height of a listbox item taking into { inherited from ancestor: measures the height of a listbox item taking into
account the height of the checkbox } account the height of the checkbox }
begin begin
Unused(Index); Unused(AIndex);
AHeight := CalculateStandardItemHeight; AHeight := CalculateStandardItemHeight;
if FShowCheckboxes then if FShowCheckboxes then
AHeight := Max(AHeight, GetSystemMetrics(SM_CYMENUCHECK) + 2); AHeight := Max(AHeight, GetSystemMetrics(SM_CYMENUCHECK) + 2);
@ -493,7 +468,7 @@ begin
try try
Items.BeginUpdate; Items.BeginUpdate;
Items.Clear; Items.Clear;
if FChart <> nil then begin if FChart = nil then exit;
FreeAndNil(FLegendItems); FreeAndNil(FLegendItems);
FLegendItems := CreateLegendItems; FLegendItems := CreateLegendItems;
for i := 0 to FLegendItems.Count - 1 do for i := 0 to FLegendItems.Count - 1 do
@ -503,7 +478,6 @@ begin
if Assigned(OnPopulate) then if Assigned(OnPopulate) then
OnPopulate(self); OnPopulate(self);
end;
finally finally
Items.EndUpdate; Items.EndUpdate;
end; end;
@ -515,12 +489,11 @@ var
index: Integer; index: Integer;
begin begin
index := FindSeriesIndex(ASeries); index := FindSeriesIndex(ASeries);
if index <> -1 then begin if index = -1 then exit;
FLegendItems.Delete(index); FLegendItems.Delete(index);
Items.Delete(index); Items.Delete(index);
Invalidate; Invalidate;
end; end;
end;
procedure TChartListbox.SeriesChanged(ASender: TObject); procedure TChartListbox.SeriesChanged(ASender: TObject);
{ Notification procedure of the listener. Responds to chart broadcasts { Notification procedure of the listener. Responds to chart broadcasts
@ -528,7 +501,7 @@ procedure TChartListbox.SeriesChanged(ASender: TObject);
var var
index: Integer; index: Integer;
begin begin
if not IsLocked then begin if IsLocked then exit;
Populate; Populate;
{ in case of radiobutton mode, it is necessary to uncheck the other { in case of radiobutton mode, it is necessary to uncheck the other
series; there can be only one active series in this mode } series; there can be only one active series in this mode }
@ -539,7 +512,6 @@ begin
Checked[index] := (ASender as TCustomChartSeries).Active; Checked[index] := (ASender as TCustomChartSeries).Active;
end; end;
end; end;
end;
procedure TChartListbox.SetChart(AValue: TChart); procedure TChartListbox.SetChart(AValue: TChart);
{ connects the ListBox to the chart } { connects the ListBox to the chart }
@ -551,7 +523,7 @@ begin
FChart := AValue; FChart := AValue;
if FChart <> nil then if FChart <> nil then
FChart.Broadcaster.Subscribe(FListener); FChart.Broadcaster.Subscribe(FListener);
SeriesChanged(nil); SeriesChanged(Self);
end; end;
procedure TChartListbox.SetChecked(AIndex: Integer; AValue: Boolean); procedure TChartListbox.SetChecked(AIndex: Integer; AValue: Boolean);
@ -562,7 +534,7 @@ var
i: Integer; i: Integer;
begin begin
ser := GetSeries(AIndex); ser := GetSeries(AIndex);
if ser <> nil then begin if ser = nil then exit;
Lock; Lock;
try try
ser.Active := AValue; ser.Active := AValue;
@ -577,7 +549,6 @@ begin
Unlock; Unlock;
end; end;
end; end;
end;
procedure TChartlistbox.SetCheckStyle(AValue: TCheckBoxesStyle); procedure TChartlistbox.SetCheckStyle(AValue: TCheckBoxesStyle);
{ selects "checkbox" or "radiobutton" styles. In radiobutton mode, only { selects "checkbox" or "radiobutton" styles. In radiobutton mode, only
@ -585,37 +556,33 @@ procedure TChartlistbox.SetCheckStyle(AValue: TCheckBoxesStyle);
var var
j: Integer; j: Integer;
begin begin
if AValue <> FCheckStyle then begin if FCheckStyle = AValue then exit;
if AValue = cbsRadioButton then
j := FirstCheckedIndex
else
j := -1;
FCheckStyle := AValue; FCheckStyle := AValue;
if (FCheckStyle = cbsRadioButton) and (j <> -1) then if FCheckStyle = cbsRadioButton then begin
j := FirstCheckedIndex;
if j <> -1 then
Checked[j] := true; Checked[j] := true;
Invalidate;
end; end;
Invalidate;
end; end;
procedure TChartListbox.SetShowCheckboxes(AValue: Boolean); procedure TChartListbox.SetShowCheckboxes(AValue: Boolean);
begin begin
if AValue <> FShowCheckboxes then begin if FShowCheckboxes = AValue then exit;
FShowCheckboxes := AValue; FShowCheckboxes := AValue;
Invalidate; Invalidate;
end; end;
end;
procedure TChartListbox.SetShowSeriesIcons(AValue: Boolean); procedure TChartListbox.SetShowSeriesIcons(AValue: Boolean);
begin begin
if AValue <> FShowSeriesIcons then begin if FShowSeriesIcons = AValue then exit;
FShowSeriesIcons := AValue; FShowSeriesIcons := AValue;
Invalidate; Invalidate;
end; end;
end;
procedure TChartListbox.Unlock; procedure TChartListbox.Unlock;
begin begin
dec(FLockCount); FLockCount -= 1;
end; end;
end. end.