Recent

Author Topic: [solved] sorry - again TDatePointHintTool  (Read 2273 times)

Nicole

  • Hero Member
  • *****
  • Posts: 1009
[solved] sorry - again TDatePointHintTool
« on: February 14, 2023, 02:43:59 pm »
@wp:
I added your demo and it looked great. All I dreamed about. The TPageControl looks better than everything I made.
This demo I put on a new frame in my project and tried to add my data - my whole operating system (Win 7) was shot.

So I started again from the beginning.

The problem are IMHO not the input data, but a type confusion.
The data look fine, they are drawn fine and they are written into a RichMemo fine.

So I took my backup with the most acceptable working version and try to put my question differently:

There is a chart with TSeriesOpenHighLowClose working fine:
Drawing fine, HintToolFine, "MouseOver" writes the figures fine.

Then I add 2 new series to my chart, still fine.
This changes - - , when I populate the first series by
Code: Pascal  [Select][+][-]
  1.  K_Volume.AddXY(IBQuery_Zeichne.FieldByName('FK_JDATUM').AsDateTime, IBQuery_Zeichne.FieldByName('volume').AsInteger);
  2.  

I think the error must be here, in the event of the TChartTool (see below).
In this event the type of the added TLineSeries causes a mess. IMHO
Expected is a TSeriesOpenHighLowClose and suddenly there is an additional TLineSeries.
On putting the TLineSeries population line into commentary, the problem is gone.

Code: Pascal  [Select][+][-]
  1. // Mouse-over bewirkt die Ausgabe der Kurse im Memo
  2. procedure TFrame_Zeichne.AusgabeHint(ATool: TDataPointHintTool; const APoint: TPoint; var AHint: String);
  3. var ser: TOpenHighLowCloseSeries;
  4.     punkt: Integer;
  5.     o, h, l, c: double;
  6.     tmp: integer;  // aus Delpi
  7.     s: String;
  8.     d: double;
  9.     dat: TDate;
  10.  
  11. begin
  12.   Memo_AusgabeKerze.Clear; // die Ausgabe soll immer nur eine Kerze zeigen
  13.  
  14.   with TDatapointHintTool(ATool) do begin   // was das tut, weiß ich nicht genau. Es ist aus der Vorlage und vermutl. wichtig
  15.    ser := ATool.Series as TOpenHighLowCloseSeries;
  16.    punkt := PointIndex;
  17.   end;
  18.  
  19.  if ser <> nil then begin
  20.    With Ser do begin
  21.       O:=YValues[punkt, YIndexOpen];
  22.       H:=YValues[punkt, YIndexHigh];
  23.       L:=YValues[punkt, YIndexLow];
  24.       c:=YValues[punkt, YIndexClose];
  25.       dat:=ser.GetXValue(punkt);
  26.  
  27.       s:=Zeit.FORMATIERE_DATUM_nur_Wochentag_KURZ(Dat);
  28.       s := DateToStr(Dat) + ', ' + s + #13#10; // + #13#10;
  29.       s := s + 'open=' + FloatToStrF(O,ffFixed,4,4) + #13#10;
  30.       s := s + 'high=' + FloatToStrF(h,ffFixed,4,4) + #13#10;
  31.       s := s + 'low=' + FloatToStrF(L,ffFixed,4,4) + #13#10;
  32.       s := s + 'close=' + FloatToStrF(C,ffFixed,4,4) + #13#10;
  33.       d:=H - L;
  34.  
  35.       s := s + 'range=' + FloatToStrF(d,ffFixed,4,4) + #13#10;  // letzte Zahl=Kommastellen
  36.       Memo_AusgabeKerze.Lines.Add(s);
  37.                 end;
  38.         end;
  39.  
  40.        Label_BigCandle.Caption:= s; // auf Label
  41.    Series_BigCKontr.Clear;                   // USD hier nicht, weil 2 mal DB dazu nötig
  42.    Series_BigCKontr.AddXOHLC(dat, o, h, l, c);  // erzeugt große Kerze
  43.  
  44.  //    else  AHint := '';
  45. end;
« Last Edit: February 15, 2023, 10:10:00 am by Nicole »

wp

  • Hero Member
  • *****
  • Posts: 12456
Re: sorry - again TDatePointHintTool
« Reply #1 on: February 14, 2023, 04:36:25 pm »
Code: Pascal  [Select][+][-]
  1.   with TDatapointHintTool(ATool) do begin   // was das tut, weiß ich nicht genau. Es ist aus der Vorlage

This type conversion is not necessary since the ATool parameter passed to the OnHint event already is type TDataPointHintTool (it shouldn't be harmful here, neither). Type conversions are needed quite often when handling TAChart tool events because some events are fired very early in the class hierarchy where the actual type of the firing tool is not known.

Code: Pascal  [Select][+][-]
  1.    ser := ATool.Series as TOpenHighLowCloseSeries;
I wouldn't do it like this because this raises an excelption when ATool.Series is NOT an OHLC. Better:
Code: Pascal  [Select][+][-]
  1.   if (ATool.Series is TOpenHighLowCloseSeries) then
  2.     ser := TOpenHighLowCloseSeries(ATool.Series);
This type conversion is needed because the DatapointHinttool cooperates with any kind of series, the actual type of the series is not known to the tool. So, if you need some parameters typical of the OHLC you must check if the series is an OHLC and then apply the typecast to TOpenHighLowCloseSeries.

I am not sure about the code which populates the Series_BigCKontr in the OnHint handler because both Series_BigCKontr.Clear and Series_BigCKontr.AddXOHLC trigger a chart repaint which might confuse the tool event handling - just a wild guess. But I assume that Series_BigCKontr is in a different chart, so this should not be a problem. But you never know... Please comment this piece of code out for further tests.

A latent possibility for crashes could be that the OHLC series requires a chartsource with 4 y values, the Lineseries with 1 y value. When you add a point by AddXOHLC and by AddXY, respectively, this should be checked. But who knows... Please add a "WriteLn(OHLCLSeries.Source.YCount)" and "WriteLn(LineSeries.Source.YCount)" before adding the points. (if you are on Windows, you must uncheck the box "Win32 gui application" in the project options > Config and targets; don't forget to remove the WriteLn and to check the box again later).

It is my impression that your crashes occur already when the modified form is loaded. Therefore I'd recommend to remove the event handlers from the object inspector and to assign them later at runtime. This would mean that, if the issue is in the event handlers, the form still would load, but you would see an exception at runtime which you can chase with the debugger.

Nicole

  • Hero Member
  • *****
  • Posts: 1009
Re: sorry - again TDatePointHintTool
« Reply #2 on: February 14, 2023, 08:32:54 pm »
Thank you for searching this trick.

The Big Candle is fine. It is done by the last lines of the hint-event and posted above already.
Code: Pascal  [Select][+][-]
  1.    Series_BigCKontr.Clear;                  
  2.    Series_BigCKontr.AddXOHLC(dat, o, h, l, c);  // erzeugt große Kerze

I would not expect the problem there.

It shall be below.
This I did: I put the first paragraph into commentary and filled in the line you suggested.
Unfortunately I cannot do the "punkt"-assignment any more. The compiler says something strange and not helpful.


 
Code: Pascal  [Select][+][-]
  1.  {
  2.   with TDatapointHintTool(ATool) do begin   // was das tut, weiß ich nicht genau. Es ist aus der Vorlage und vermutl. wichtig
  3.    ser := ATool.Series as TOpenHighLowCloseSeries; // => I wouldn't do it like this because this raises an excelption when ATool.Series is NOT an OHLC.
  4.    punkt := PointIndex;
  5.   end;
  6.  }
  7.  
  8.    if (ATool.Series is TOpenHighLowCloseSeries) then begin
  9.     ser := TOpenHighLowCloseSeries(ATool.Series);
  10. //    punkt := PointIndex;
  11.    end;

And these hint I did not understand:

Code: Text  [Select][+][-]
  1. //   But who knows... Please add a "WriteLn(OHLCLSeries.Source.YCount)" and "WriteLn(LineSeries.Source.YCount)"
  2. before adding the points.  

Writeln?! - thsi was the word, which I used in Turbo Pascal 2.0 to have an output including a line break.
and "adding the points"? - In the main code or in a hint - äh, I am puzzled.


The project-option for Win 32 I found and unchecked.

wp

  • Hero Member
  • *****
  • Posts: 12456
Re: sorry - again TDatePointHintTool
« Reply #3 on: February 14, 2023, 10:37:18 pm »
Unfortunately I cannot do the "punkt"-assignment any more. The compiler says something strange and not helpful.
 
Code: Pascal  [Select][+][-]
  1.  {
  2.   with TDatapointHintTool(ATool) do begin   // was das tut, weiß ich nicht genau. Es ist aus der Vorlage und vermutl. wichtig
  3.    ser := ATool.Series as TOpenHighLowCloseSeries; // => I wouldn't do it like this because this raises an excelption when ATool.Series is NOT an OHLC.
  4.    punkt := PointIndex;
  5.   end;
  6.  }
  7.  
  8.    if (ATool.Series is TOpenHighLowCloseSeries) then begin
  9.     ser := TOpenHighLowCloseSeries(ATool.Series);
  10. //    punkt := PointIndex;
  11.    end;
Of course I meant to have the entire code inside the "if (ATool.Series is TOpenHighLighCloseSeries)" condition. Like this:
Code: Pascal  [Select][+][-]
  1. procedure TFrame_Zeichne.AusgabeHint(ATool: TDataPointHintTool; const APoint: TPoint; var AHint: String);
  2. var ser: TOpenHighLowCloseSeries;
  3.     punkt: Integer;
  4.     o, h, l, c: double;
  5.     tmp: integer;  // aus Delpi
  6.     s: String;
  7.     d: double;
  8.     dat: TDate;
  9.  
  10. begin
  11.   Memo_AusgabeKerze.Clear; // die Ausgabe soll immer nur eine Kerze zeigen
  12.  
  13.   AHint := '';
  14.  
  15.   if ATool.Series is TOpenHighLowCloseSeries) then
  16.   begin
  17.     ser := TOpenHighLowCloseSeries(ATool.Series);
  18.     // if ser <> nil then   // can be skipped since "if ATool.Series is TOpenHighLowCloseSeries" would be false if AToo.Series = nil.
  19.     // begin
  20.       punkt := ATool.PointIndex;
  21.       With Ser do begin
  22.         O:=YValues[punkt, YIndexOpen];
  23.         H:=YValues[punkt, YIndexHigh];
  24.         L:=YValues[punkt, YIndexLow];
  25.         c:=YValues[punkt, YIndexClose];
  26.         dat:=ser.GetXValue(punkt);
  27.  
  28.         s := FormatDateTime('dd/mm/yyyy, ddd', date) + #13#10;
  29.         s := s + 'open=' + FloatToStrF(O,ffFixed,4,4) + #13#10;
  30.         s := s + 'high=' + FloatToStrF(h,ffFixed,4,4) + #13#10;
  31.         s := s + 'low=' + FloatToStrF(L,ffFixed,4,4) + #13#10;
  32.         s := s + 'close=' + FloatToStrF(C,ffFixed,4,4) + #13#10;
  33.         d:=H - L;
  34.  
  35.         s := s + 'range=' + FloatToStrF(d,ffFixed,4,4) + #13#10;  // letzte Zahl=Kommastellen
  36.         Memo_AusgabeKerze.Lines.Add(s);
  37.       end;
  38.  
  39.       Label_BigCandle.Caption:= s; // auf Label
  40.       Series_BigCKontr.Clear;                   // USD hier nicht, weil 2 mal DB dazu nötig
  41.       Series_BigCKontr.AddXOHLC(dat, o, h, l, c);  // erzeugt große Kerze
  42.   end;
  43. end;

And these hint I did not understand:

Quote
But who knows... Please add a "WriteLn(OHLCLSeries.Source.YCount)" and "WriteLn(LineSeries.Source.YCount)"
before adding the points. 

Writeln?! - thsi was the word, which I used in Turbo Pascal 2.0 to have an output including a line break.
and "adding the points"? - In the main code or in a hint - äh, I am puzzled.
Of course you could also set a breakpoint and try to query the results by means of the debugger. But since it is often quite difficult to resolve complex properties in the debugger, the old-old-old fashioned WriteLn is much easier. If you don't like it, you could also add LazLogger to the uses clause and call DebugLn instead of WriteLn (put all arguments in square brackets). It has the same effect, but its advantage is that it does not crash your application when the checkbox that I mentioned in not unchecked - well, I should have mentioned this in the first place. The values written will be visible in the black console window which is now displayed in addition to the form window because of the unchecked "Win32 gui application" checkbox.

Anyway, the point is: Does the OHLC series provide enough memory for 4 y values? If it does not you will overwrite some other data when you add the data points. Such a memory overrun can crash the application (this would be easy to fix) or cause some malfunction some time late (and this is hard to find). So, please do this: Somewhere you have code in which you read the data values from the database and add them to the OHLC series. Add the DebugLn here:

Code: Pascal  [Select][+][-]
  1. ...
  2.   DebugLn([' OHLCSeries: YCount is: ', OHLCSeries.Source.YCount]);
  3.   OHLCSeries.AddXOHLC(.....);
  4.   ....

When you now run the application, have a look at the black console window. It always should show the value 4. Set a breakpoint on OHLCSeries.AddXOHLC to see the first value written to the console.

If this is correct, you can remove the DebugLn again.

You can also test, in the same way, the YCount in the OnHint code, but I think this is not critical because nothing is written to YList here (well - except for the Series_BigCKontr, but you said that this "is fine"...).

The YCount idea is just a wild guess and may lead to nothing. I cannot give you any more precise suggestions. Add more DebugLn instructions at various places and check whether the displayed data are reasonable. Do not restrict your attention to the OnHint procedure, I am suspecting that the error is somewhere else.

Nicole

  • Hero Member
  • *****
  • Posts: 1009
Re: sorry - again TDatePointHintTool
« Reply #4 on: February 15, 2023, 08:56:22 am »
Thank you so much!
This looks good, I am carefully optimistic. Somehow it feels stable now.

Memory is not the problem: The VM has 4 GB, the database 100 MB (oh yes, I am proud of, it is done tricky, more than 20 years of data inside).

About "writeln" - this is the idea!
Sure, we need it. And I needed it too. I used "showmessage" in the past. With the named disadvantage.

 

TinyPortal © 2005-2018