TAchart, BeforeCustomDrawBackWall lazarus / 39-Graphics ---------------------------------------------------------------------- arneolav · 2019-11-10 20:56 Hi! From TAChart Tutorial: Background design If you have Lazarus version 1.9 or newer you many notice that the events OnBeforeDrawBackground and OnBeforeDrawBackWall are marked as deprecated, it is recommended to use OnBeforeCustomDrawBackground and OnBeforeCustomDrawBackWall. This was introduced because the new events support the TAChart drawing backend architecture which enables drawing on devices which do not have an LCL-compatible canvas (e.g. an OpenGL rendering context, or an SVG file). A chart drawer essentially provides the same commands as TCanvas, however, some differences exist here and there - unfortunately also in drawing of images and gradients: Images are requested as descendants of TFPCustomImage. And gradients are not supported at all, but may be provided after painting on an auxiliary bitmap. An example from the wiki showing "GradientFill" does work ok, but i need no gradient, only any user selectable color color. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure MyChart.Chart_SensorBeforeCustomDrawBackWall(ASender: TChart;  ADrawer: IChartDrawer; const ARect: TRect; var ADoDefaultDrawing: Boolean);var  bmp: TBitmap;  img: TLazIntfImage;begin  img := TLazIntfImage.Create(0, 0);  try    bmp := TBitmap.Create;    try    bmp.SetSize(ARect.Right - ARect.Left, ARect.Bottom - ARect.Top); This does work ok:     // bmp.Canvas.GradientFill(Rect(0, 0, bmp.Width, bmp.Height), clWhite, clYellow , gdVertical);    Tried this, nothing seems to work, all examles result in a black backwall:  (using clYellow as test)       // bmp.Canvas.FloodFill (bmp.Width, bmp.Height, clYellow, fsSurface  );      // bmp.Canvas.Brush.Color := clYellow;      // bmp.Canvas.pen.Color:= clYellow;       img.LoadFromBitmap(bmp.Handle, bmp.MaskHandle);    finally      bmp.Free;    end;    ADrawer.PutImage(ARect.Left, ARect.Top, img);    ADoDefaultDrawing := false;  finally    img.Free;  end;end; ---------------------------------------------------------------------- wp · 2019-11-10 22:03 If you only need a user-selectable color then you should set the properties Chart.Color and/or Chart.BackColor -- no need for a dedicated event handler. Anyway, the FloodFill is working, it's just a bit difficult to use. See https://forum.lazarus.freepascal.org/index.php/topic,26963.msg1664 45.html Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Chart1BeforeCustomDrawBackground(ASender: TChart;  ADrawer: IChartDrawer; const ARect: TRect; var ADoDefaultDrawing: Boolean);var  bmp: TBitmap;  img: TLazIntfImage;begin  img := TLazIntfImage.Create(0, 0);  try    bmp := TBitmap.Create;    try    bmp.SetSize(ARect.Right - ARect.Left, ARect.Bottom - ARect.Top);      // fill the entire bitmap with clSkyBlue as background color      bmp.Canvas.Brush.Color := clSkyBlue;      bmp.Canvas.FillRect(0, 0, bmp.Width, bmp.Height);      // draw some shape, here: a rectangle    bmp.Canvas.Rectangle(10, 10, bmp.Width-10, bmp.Height-10);      bmp.Canvas.Brush.Color := clYellow;  // this sets up the replacement color for the shape's interior.      bmp.Canvas.FloodFill(bmp.Width div 2, bmp.Height div 2, clSkyBlue, fsSurface);  // clSkyblue is the color to be replaced by the brush color      img.LoadFromBitmap(bmp.Handle, bmp.MaskHandle);    finally      bmp.Free;    end;    ADrawer.PutImage(ARect.Left, ARect.Top, img);    ADoDefaultDrawing := false;  finally    img.Free;  end;end; And be aware that the function may not be available on all widgetsets; I only tested on Windows. Just to fill a rectangle you should call the Canvas method FillRect(x1, y1, x2, y2) (borderless fill with the current Canvas.Brush) or Rectangle(x1, y1, x2, y2) (fill with current Canvas.Brush, border with current Canvas.Pen). In r62229, I updated the background tutorial code coming with Lazarus in folder components/tachart/tutorials/background to avoid the deprecated events. Thanks for the hint. ---------------------------------------------------------------------- arneolav · 2019-11-10 22:50 Thanks, it works fine and the xtra frame makes it nice, may be i'll keep it as an user option. .... My idea too was using Chart.Color and/or Chart.BackColor in (old)event BeforeDrawBackWall to change color "on the fly" but got error SIGDEVG. This does work ok in event BeforeDrawBackWall: ACanvas.GradientFill(ARect, color... , color.., gdVertical); ---------------------------------------------------------------------- wp · 2019-11-10 23:25 No no! Chart.Color and Chart.BackColor are properties. You only set the values, for example in an OnClick event of a button or a menu item, and the chart is automatically redrawn with the new colors. No need for the custom draw events. Even worse: Setting Color and/or BackColor in these events probably will result in a stack overflow because the events are fired during the painting operation, but changing these properties triggers another painting operation. Just try the attached demo, and I hope you get the idea. ---------------------------------------------------------------------- arneolav · 2019-11-11 09:30 I see ofcorse! THANKS! I have a setup pgm where all "user stuff" is done, and on return from the setup i found the events BeforeDrawBackWall and BeforeDrawBackground is fired... .... But I foregot to mention: if one, by some reason, "have to use the event", one could use the GradientFill with same color  as from/to like this: bmp.Canvas.GradientFill(Rect(0, 0, bmp.Width, bmp.Height), clSkyBlue, clSkyBlue , gdVertical); ... May be there should be some derivat of GradientFill, called just "Fill".. ---------------------------------------------------------------------- wp · 2019-11-14 10:18 I guess you mean: How to allow the user to select between a uniform, gradient or image background? Instead of many words, I wrote a small demo application - see attachment. Quote from: arneolav on November 11, 2019, 10:30:41 amMay be there should be some derivat of GradientFill, called just "Fill".. I don't understand this. Why rename? I could understand that you'd request a dedicated gradient fill method for all the TAChart drawers. The problem with this is that a general gradient method is quite complicated (in addition to the default horizontal/vertical gradients: linear gradients at any angle, circular gradient, conical gradient, controllable center of the circular/conical gradient, several gradient colors etc). It requires a lot of code which the "normal" user of TAChart does not need. Therefore, I think that this is something which should not be inside TAChart to keep it slim (it is already quite fat...). ---------------------------------------------------------------------- arneolav · 2019-12-19 19:17 Finally I got back to this "small" problem; The demo of wp solved all, THANKS!