TChartImnage usage lazarus / 55-TAChart ---------------------------------------------------------------------- mtanner · 2016-04-02 10:23 My question is whther the way I am using TChartImage is sensible. I'm not very expert on image list manipulation. On my chart I have a popup menu. This menu contains items unrelated to the charts series, such as a "legend" item to call up a dialog of legend options. Then I have a menu item for each series in the chart. I want to display imeges for all the items, with the image for a series being the legend image for that series. I only want to show menu items for series that are active. So I have a TImageList congaing trhe imeages for the non-series items, and a TChartImage List for the series images. I can't use the normal imagelist/imageindex method because I have two imag lists. Si i the OnPopup event for the menu I assign an image to each item simply by      ImageList1.GetBitmap(indx,menuItemX.Bitmap) and for the series related menu items     ChartImageList1.GetBitmap(indx,MenuItemS.Bitmap); I have to take care of working out the index of the bitmap to use for series, since I have to skip over the inactive series, but that is an application issue and fairly simple. But am I somehow wasting memory by assigning the bitmaps every time the menu is popped up? If so is there a way of cleaning up? I don't have to assign bitmaps every time for the non-series items (and could probbaly do those with imagelist/imageindex in the usual way). Series images may well change as the user can modify series display options suhc as line width and pointer style. I'm writing under and for Windows, but with a view to eventual porting to Linux. Am I sytrying into areas which will give problems when changing platforms? ---------------------------------------------------------------------- mtanner · 2016-04-02 10:29 I should add that all the menu items are created dynamically in the OnPopup event jsut before displaying the menu, so that series-related menu items appear only for active series. One afterthought is that I am assuming that the TChartImageList contains an image for each series that would appear in a complete legend, and therefore omits series for which ShowInlegend=false. ---------------------------------------------------------------------- wp · 2016-04-02 14:29 Initially TChartImageList was designed to contain both regular and series images, but there were some streaming issues, and this feature was removed, and now it contains only the series images. Series images - these are the icons displayed in the legend for each series. If you assign the chart to the corresponding property of the image list the image list is populated, if you remove the chart the image list is erased. If you add a series to the chart or delete one the image list is automatically updated. This means there is no clear correlation between series and image index in the list. Call ImageIndexOfSeries to get the image list index of a specific series. And finally, there's the event OnPopulate which fires whenever the image list is rebuilt, for example after adding a series - use to update anything you need. A popup menu is a bit complicated because there are static items (and images) and fluctuating items (and images) of the series. Therefore I would propose this methodology: Add a standard image list. Use it for the static images.Add a ChartImageList. It will contain the series images later.Decide to use one of them for the popup menu images. I'd propose to use the ChartImageList because this leaves the static image list untouched.To prepare the chart image list for the popup menu, make sure that ChartImageList.Chart is nil. Then copy the static images to the ChartImageList: ChartImageList.AddImages(ImageList1). Now set ChartImages.Chart to Chart1 to add the series images. You can use FirstSeriesIndex to get the image index of the first series icon.You can add the static menu items to the popup menu at designtime. Temporarily use the static image list to find the images - their index will not change. Later assign the ChartImageList to the popup menu Images.Then write a method which populates the Popupmenu with the series items. At first update the ChartImageList: set the Chart property of the ChartImageList to nil to remove the previously used series (but the static images will be kept), and then set it back to Chart1 to re-add the images of the currently available series. Then iterate through the series of the chart that you want to have in the popup menu, create a menu item for each required series, and find the image index of the current series by calling ChartImageList.ImageIndexOfSeries().Call this method in the OnPopup event of the popupmenu.Try it, I did not test it, but it should work in principle. If you are not successful I can write a little demo. ---------------------------------------------------------------------- mtanner · 2016-04-02 17:39 Thank you, that was very helpful.  I understood enough of it for my current purposes, and will no doubt understnd it more later. I think the best solutionn needs to be tailored to the specific applcation design. I do not, for example, dynamically add or remove series from my charts. I have a table of lone descriptions, and there are mulktiple series that relate to each line descriuptio, only one of which appears in the legend. So my solution si to put a pointern to the relevant "legend" series in each entry in the table of line descriptions, a simple bit of code in the OnShow event for the Form is the best in my application to do this (not all the applcation data structures are setup at OnCreate.) When it come to building the menu items, I prefer to do them all dynamically, since that fits better with the way my home-grown preprocessor/code generator works, though I'm sure there are more elegant ways. So I have an ImageList for the menu, and just supply the ImageIndex for each fo the non-series menu items. For the series menu items, or rather the line description menu item,s, I use as you suggest a TChartImagesLis, and code as follows. --------------------------- If LegendSeries<>nil { this is the series in the table of line descriptions} then begin               With MyChartImagesList do begin                   Chart:=nil;  { should be nil anyway, but make sure}                   Chart:=MyChart;  { loads the legend images for the series }                   K:=ImageIndexOfSeries(LegendSeries);                   GetBitMap(K,MyMenuIte,m.Bitmap);                   Chart:=nil;                end;         end; ------------------------------------------ This seems to do the job. I'm assumining, sice you didi not mention it, that I'm not burning up memory by messing around with bitmaps like this every time the menu pops up. ---------------------------------------------------------------------- wp · 2016-04-02 18:28 Quote from: mtanner on April 02, 2016, 07:39:31 pm    GetBitMap(K,MyMenuIte,m.Bitmap); I suppose this should read: GetBitmap(K, MyMenuItem.Bitmap) (no comma between MyMenuIte and m.Bitmap). Then, why do you extract the bitmap explicitly? Isn't it enough to assign the image index to the menuitem? It would have the advantage that the menuitem itself would take care of the bitmap memory. ---------------------------------------------------------------------- mtanner · 2016-04-02 22:16 Yes, sorry for the typos. I'm a little out of my depth here. The menu has an ImageList assigned to it for use by the non-series menu items. So I can't assign the TChartImagesList as the image list for the menu. I could put all the series items in a submenu and use the TChartImagesList as the imagelist for the submenu, I suppose, though I'd rather keep everything on a single-level menu. Perhaps I've not understood enough, so maybe my logic is faulty. As far as it goes I think my solution is straightforward. The key tools appear to be the TChartImageList as an easy way to extract the legend images from the chart, and the ImageIndexOfSeries function to identify the image for a paricular series.  I'm still unclear, and nervous, about the ramifications for memory management of this bitmap manipulation. ---------------------------------------------------------------------- wp · 2016-04-02 23:16 Quote from: mtanner on April 03, 2016, 12:16:45 amSo I can't assign the TChartImagesList as the image list for the menu. Why not? As I explained you only must copy the non-series images from the other image list, and then add the series images by connecting the image list with the chart. Then the ChartImageList is as good as any other image list. ---------------------------------------------------------------------- mtanner · 2016-04-03 17:24 Just been doing a few experiments. First tried doing what you suggested, but the menu items just show black for the images. Tried various adjustments to the value returned by ImageIndexOfSeries, but at best could only cause one of the non- series images to appear.  The most promising was to load up the ChartImageList from the chart, then use AddImages(stdimagelist) to add the non-series images to the ChartImageList,  then use the ChartImageList as the image list for the menu. This sort-of works, except for the curious effect that the first time the menu is popped up the non-series menu items show a black square for the image on each item (series images appear correctly). Second and subsequent popups of the menu show non-series images correctly. Very puzzling, at least to me. ---------------------------------------------------------------------- mtanner · 2016-04-03 17:26 In the first paragrah when I say non-series images appear "black" I mean "BLANK". ---------------------------------------------------------------------- wp · 2016-04-03 20:45 I don't know what you are doing wrong without seeing your code. But to demonstrate that the TChartImageList does work in cooperation with a menu and a popup menu I added a little demo. It's a bit more complex than your requirement, but there's a lot of comments, and I hope that it is helpful in solving the problems