Steema Issues Database

Note: This database is for bugs and wishes only. For technical support help, if you are a customer please visit our online forums;
otherwise you can use StackOverflow.
Before using this bug-tracker we recommend a look at this document, Steema Bug Fixing Policy.



Bug 758 - Inner TColorLineTool component of TColorBandTool has no name, thus causing corrupt DFM file
Summary: Inner TColorLineTool component of TColorBandTool has no name, thus causing co...
Status: RESOLVED FIXED
Alias: None
Product: VCL TeeChart
Classification: Unclassified
Component: Tools (show other bugs)
Version: 140512
Hardware: PC Windows
: --- critical
Target Milestone: ---
Assignee: Steema Issue Manager
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-04-30 14:22 EDT by Jarl Balgruuf the Greater
Modified: 2015-05-27 04:38 EDT (History)
3 users (show)

See Also:
Chart Series: ---
Delphi / C++ Builder RAD IDE Version: RAD XE5, RAD XE6


Attachments
List index out of bounds error adding a TFrame with a TChart and a TColorBandTool at designtime (2.34 KB, application/octet-stream)
2014-05-02 07:58 EDT, yeray alonso
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jarl Balgruuf the Greater 2014-04-30 14:22:57 EDT
Disclaimer: I filed it as version '140220' but I am actually using '2014.11.140425 BETA'. But I believe this does not matter [1]

As the title says: TeeTools::TColorBandTool.NewColorLine() creates a TColorLineTool that has no name. Therefore, a TColorBandTool gets written to the DFM like this:

object Chart1: TChart
	[...]
	object ChartTool1: TColorBandTool <-- It has a name. All is well.
	  Color = 8388863
	  EndValue = 8.000000000000000000
	  ResizeEnd = True
	  ResizeStart = True
	  StartValue = 6.000000000000000000
	  Transparency = 12
	  AxisID = 0
	  object TColorLineTool  <-- THIS IS BAD
		DragRepaint = True
		Value = 6.000000000000000000
		AxisID = 0
		object TAnnotationTool <-- THIS IS BAD
		  Shape.Alignment = taCenter
		  Shape.Shadow.Visible = False
		  Shape.TextAlignment = taCenter
		  TextAlignment = taCenter
		end
	  end
	  object TColorLineTool <-- THIS IS BAD
		DragRepaint = True
		Value = 8.000000000000000000
		AxisID = 0
		object TAnnotationTool
		  Shape.Alignment = taCenter
		  Shape.Shadow.Visible = False
		  Shape.TextAlignment = taCenter
		  TextAlignment = taCenter
		end
      end
	end
end


As a side effect, the form designer refuses to place frames that have a chart with a TColorBandTool. However, if a chart is placed directly on a form, you're only going to find with an access violation in VCLTee.TeEngine.pas at runtime!

I believe the classless function TeeTools::CreateAnnotation(..) also suffers from this: The annotation also does not have a name.


Workaround:
Not sure. I'll edit the TeeChart source files (Never done that before) and see how this goes...

[1] The only difference between 140220 and 140425 regarding my issue is that
" procedure TColorBandTool.InitColorLine(var Value:TColorLineTool); "
changed to
" procedure TColorBandTool.InitColorLine(const Value:TColorLineTool); ".
Comment 1 Jarl Balgruuf the Greater 2014-04-30 15:06:29 EDT
(1)

Modifying the source in order to give those components names in the DFM somehow gave them names, but the application still crashes at runtime when a TColorBandTool is present


(2) It works flawlessly on TeeChart Pro VCL 130920. The resulting TColorBandTool looks completely different (and valid) in the DFM:

	object ChartTool1: TColorBandTool
	  EndLinePen.EndStyle = esFlat
	  EndValue = 8.000000000000000000
	  StartLinePen.EndStyle = esFlat
	  StartValue = 2.000000000000000000
	  AxisID = 0
	end
Comment 2 Jarl Balgruuf the Greater 2014-04-30 15:17:54 EDT
I hope I'm not stealing too much of your time and/or making a fool out of myself, but this is probably related to TColorBandTool.ReadState(..), starting at line 3779 of Build '2014.11.140425' in Sources\VCL\VCLTee.TeeTools.pas. I can only take a wild guess because I honestly cannot understand those methods.
Comment 3 yeray alonso 2014-05-02 07:58:11 EDT
Created attachment 199 [details]
List index out of bounds error adding a TFrame with a TChart and a TColorBandTool at designtime

Reproduced with XE6 at design time with the attached project.

If you try to add the TFrame2 to the TForm1 at designtime, it gives you a
"List index out of bounds (0)" exception (complete error message below).

However, if you add it at runtime (as done in the project at TForm1.FormCreate), it works without problems.

[5017640D]{rtl200.bpl  } System.Classes.TComponent.GetComponent (Line 16136, "System.Classes.pas" + 1) + $F
[01214C1F]{designide200.bpl} Update.TUpdateObject.AddChild (Line 753, "Update.pas" + 10) + $B
[193465D0]{TeePro920.bpl} Vcltee.Teetools.TColorBandTool.GetChildren + $1C
[01214B3B]{designide200.bpl} Update.TUpdateObject.Create (Line 722, "Update.pas" + 31) + $1E
[01214C42]{designide200.bpl} Update.TUpdateObject.AddChild (Line 755, "Update.pas" + 12) + $1A
[422A772C]{Tee920.bpl  } Vcltee.Chart.TCustomChart.GetChildren + $40
[01214B3B]{designide200.bpl} Update.TUpdateObject.Create (Line 722, "Update.pas" + 31) + $1E
[01214C42]{designide200.bpl} Update.TUpdateObject.AddChild (Line 755, "Update.pas" + 12) + $1A
[504FADE7]{vcl200.bpl  } Vcl.Controls.TWinControl.GetChildren (Line 12430, "Vcl.Controls.pas" + 4) + $D
[5063800B]{vcl200.bpl  } Vcl.Forms.TCustomFrame.GetChildren (Line 3491, "Vcl.Forms.pas" + 1) + $A
[5005F18E]{rtl200.bpl  } System.@CallDynaInst (Line 16236, "System.pas" + 4) + $0
[01214B3B]{designide200.bpl} Update.TUpdateObject.Create (Line 722, "Update.pas" + 31) + $1E
[01215A7A]{designide200.bpl} Update.TUpdateManager.Create (Line 1202, "Update.pas" + 9) + $14
[01232E1B]{designide200.bpl} ComponentDesigner.TComponentRoot.FrameCreateComponent (Line 3195, "ComponentDesigner.pas" + 36) + $2D
[01232FF5]{designide200.bpl} ComponentDesigner.TComponentRoot.ReaderFindComponentClass (Line 3243, "ComponentDesigner.pas" + 13) + $20
[01232F2F]{designide200.bpl} ComponentDesigner.TComponentRoot.ReaderCreateComponent (Line 3223, "ComponentDesigner.pas" + 1) + $7
[50166B0C]{rtl200.bpl  } System.Classes.CreateComponent (Line 10147, "System.Classes.pas" + 5) + $14
[50166D90]{rtl200.bpl  } System.Classes.TReader.ReadComponent (Line 10202, "System.Classes.pas" + 10) + $6
[5016812A]{rtl200.bpl  } System.Classes.TReader.ReadComponents (Line 10741, "System.Classes.pas" + 11) + $1
[0123378E]{designide200.bpl} ComponentDesigner.TComponentRoot.ReadStream (Line 3422, "ComponentDesigner.pas" + 28) + $14
[01233400]{designide200.bpl} ComponentDesigner.TComponentRoot.SelectReadStream (Line 3348, "ComponentDesigner.pas" + 4) + $10
[012328D3]{designide200.bpl} ComponentDesigner.TComponentRoot.PasteSelectionFromStream (Line 3057, "ComponentDesigner.pas" + 3) + $A
[0123CEA7]{designide200.bpl} ComponentDesigner.TComponentDesigner.PasteSelectionFromStream (Line 6670, "ComponentDesigner.pas" + 2) + $9
[21D3E331]{delphicoreide200.bpl} CompPalMgr.TFramePalettePageItemDelegate.CreateComponent (Line 3098, "CompPalMgr.pas" + 44) + $17
[01230F39]{designide200.bpl} ComponentDesigner.TComponentRoot.DoCreateComponent (Line 2440, "ComponentDesigner.pas" + 25) + $17
[01236B5A]{designide200.bpl} ComponentDesigner.TComponentRoot.CreateCurrentComponent (Line 4619, "ComponentDesigner.pas" + 2) + $32
[01252002]{designide200.bpl} Surface.TDesignSurface.CreateItem (Line 196, "Surface.pas" + 1) + $11
[01201D92]{designide200.bpl} Designer.TDesigner.DoDragCreate (Line 795, "Designer.pas" + 1) + $F
[01202640]{designide200.bpl} Designer.TDesigner.DragEnd (Line 975, "Designer.pas" + 19) + $3
[01204C80]{designide200.bpl} Designer.TDesigner.MouseUp (Line 1764, "Designer.pas" + 1) + $2
[51FBEF52]{vcldesigner200.bpl} VCLSurface.MouseEvent (Line 3187, "VCLSurface.pas" + 45) + $11
[5005FA4F]{rtl200.bpl  } System.TMonitor.Exit (Line 17352, "System.pas" + 2) + $7
[51FBFB3F]{vcldesigner200.bpl} VCLSurface.TVclDesignSurface.IsDesignMsg (Line 3448, "VCLSurface.pas" + 48) + $6
[5005F042]{rtl200.bpl  } System.@IsClass (Line 16068, "System.pas" + 1) + $8
[504F297B]{vcl200.bpl  } Vcl.Controls.TControl.WndProc (Line 7145, "Vcl.Controls.pas" + 4) + $21
[50177B88]{rtl200.bpl  } System.Classes.StdWndProc (Line 17064, "System.Classes.pas" + 6) + $1
[504F6F6F]{vcl200.bpl  } Vcl.Controls.TWinControl.IsControlMouseMsg (Line 9815, "Vcl.Controls.pas" + 1) + $9
[504F7739]{vcl200.bpl  } Vcl.Controls.TWinControl.WndProc (Line 10047, "Vcl.Controls.pas" + 153) + $6
[50639B40]{vcl200.bpl  } Vcl.Forms.TCustomForm.WndProc (Line 4426, "Vcl.Forms.pas" + 206) + $5
[51FC866F]{vcldesigner200.bpl} VCLFormContainer.TControlSizer.ControlWndProc (Line 313, "VCLFormContainer.pas" + 33) + $C
[504F6D80]{vcl200.bpl  } Vcl.Controls.TWinControl.MainWndProc (Line 9759, "Vcl.Controls.pas" + 3) + $6
[50177B88]{rtl200.bpl  } System.Classes.StdWndProc (Line 17064, "System.Classes.pas" + 6) + $1
[506A301B]{vcl200.bpl  } Vcl.AppEvnts.TMultiCaster.GetAppEvents (Line 654, "Vcl.AppEvnts.pas" + 1) + $5
[50644441]{vcl200.bpl  } Vcl.Forms.TApplication.CancelHint (Line 11180, "Vcl.Forms.pas" + 6) + $D
[506430DF]{vcl200.bpl  } Vcl.Forms.TApplication.ProcessMessage (Line 10351, "Vcl.Forms.pas" + 23) + $1
[50643122]{vcl200.bpl  } Vcl.Forms.TApplication.HandleMessage (Line 10381, "Vcl.Forms.pas" + 1) + $4
[50643455]{vcl200.bpl  } Vcl.Forms.TApplication.Run (Line 10519, "Vcl.Forms.pas" + 26) + $3
Comment 4 Jarl Balgruuf the Greater 2014-05-02 08:10:25 EDT
The suggested workaround (adding the TFrame with the corrupted DFM at runtime) does not work (at least on XE5): Here is the callstack:

:00674126 TTeeCustomToolAxis.ReadAxis + $12
:006740b2 TTeeCustomToolAxis.DefineProperties + $2E
:004be096 TReader.ReadDataInner + $1A
:004be078 TReader.ReadData + $6C
:004c8c0e TComponent.ReadState + $6
:004be10a TReader.ReadDataInner + $8E
:004be078 TReader.ReadData + $6C
:004c8c0e TComponent.ReadState + $6
:004be10a TReader.ReadDataInner + $8E
:004be078 TReader.ReadData + $6C
:004c8c0e TComponent.ReadState + $6
:00633ddb TCustomTeePanel.ReadState + $27
:004bdeee TReader.ReadComponent + $122
:004be10a TReader.ReadDataInner + $8E
:004be049 TReader.ReadData + $3D
:004c8c0e TComponent.ReadState + $6
:004bf006 TReader.ReadRootComponent + $1DA
:004b8f03 TStream.ReadComponent + $37
:004ae9c0 InternalReadComponentRes + $5C
:004b0314 InitComponent + $64
:004b03a2 InitInheritedComponent + $66
:005c4315 TCustomFrame.Create + $69
Unit1.TForm1.FormCreate($8338E0)
:005c4afb TCustomForm.DoCreate + $37
:005c471b TCustomForm.AfterConstruction + $17
:005c46cc TCustomForm.Create + $1A0
:005cf611 TApplication.CreateForm + $79
Project1.Project1
Comment 5 david berneda 2014-06-20 15:16:38 EDT
Just tried the last attachment with XE6, no errors at all, both at design-time and run-time.
Comment 6 Jarl Balgruuf the Greater 2014-06-23 05:35:46 EDT
(In reply to david berneda from comment #5)
> Just tried the last attachment with XE6, no errors at all, both at
> design-time and run-time.

Placing the frame on the form (design-time) and THEN running the program will still fail: The program crashes then at runtime, failing to create the form. Tested with XE6 Update 1 + TeeChart Pro v2014.11.140512 32bit VCL.
Comment 7 david berneda 2015-05-26 11:19:32 EDT
Note: The same problem also happens with simple inherited forms (not TFrame).

Naming the ColorLine objects is not possible as it'll interfere in the Object TreeView and other places. (Other kind of Streaming load/save errors)
Comment 8 david berneda 2015-05-27 04:37:37 EDT
Fixed.
The fix is not the ideal, but its the only solution I've found so far to solve the problem.

To avoid the Delphi ide to raise the design-time exception when loading a form or frame inherited from another form or frame, the solution is to not store the inherited StartLine and EndLine properties of the ColorBand tool.

ie: All properties in the ancestor can be modified and will be saved as usually, but any change in the inherited form or frame will not be stored at design-time.  
Changes can be done at runtime by code:

procedure TForm2.FormCreate(Sender: TObject);
begin
  inherited;
  ChartTool1.StartLine.Value:=123;
end;

At least, loading the form will not raise any error.
Not ideal, but there is no other workaround as this is a limitation of the default TReader.FindAncestorComponent method.
Comment 9 david berneda 2015-05-27 04:38:13 EDT
btw: The same problem happens when using simple inherited forms, with no Frame involved.