Odd behaviour when adding a toolbutton to the delphi ide

208 Views Asked by At

I was trying out some things and wanted to make a delphi IDE extension. My basic idea was expanding the ToDo list feature that is currently in the IDE.

Step one was adding a toolbutton to the IDE which would open a form showing the todo items.

But I noticed some weird things that I hopefully caused myself since that would mean it can be easily fixed.

I am adding my toolbutton to the CustomToolbar, which is the one with the blue questionmark (see screenshot later)

The thing that happens: I install my package and the button is added with the correct image, right next to the existing button. Now I close the modal form with the installed packages and then the blue questionmark changes.

enter image description here

Don't mind the icon I used, I will use a different one eventually but ok.
So basicly the existing item changes to my own icon but disabled for some reason. And I can't figure out why this happens.

As suggested in the guide I found online I used a TDatamodule to implement my code.

My code:

procedure TDatamoduleToDoList.Initialize;
var
  LResource, LhInst: Cardinal;
begin
  LhInst := FindClassHInstance(Self.ClassType);
  if LhInst > 0 then
  begin
    LResource := FindResource(LhInst, 'icon', RT_Bitmap);
    if LResource > 0 then
    begin
      FBMP := Vcl.Graphics.TBitmap.Create;
      FBMP.LoadFromResourceName(LhInst, 'icon');
    end
    else
      DoRaise('Resource not found');
  end
  else
    DoRaise('HInstance Couldn''t be found');
  FToDoAction := TTodoAction.Create(Self);
  FToDoAction.Category := actionCat;
  FToDoAction.ImageIndex := FIntaServices.ImageList.Add(FBMP, nil);
  FToDoAction.Name := 'my_very_own_action_man';
end;

procedure TDatamoduleToDoList.DataModuleCreate(Sender: TObject);
begin
  //Create extension
  if Supports(BorlandIDEServices, INTAServices, FIntaServices) then
  begin
    Initialize;
    if FToDoAction <> nil then
      FCustBut := TSpeedButton(FIntaServices.AddToolButton(sCustomToolBar, 'CstmToDoList', FToDoAction))
    else
      DoRaise('Initialize failed');
  end
  else
    DoRaise('Something went wrong');
end;

DoRaise is my own procedure that simply destroys all of my objects and raises an exception, did this to prevent mem leaks in the ide.

But, I think, I don't do anything weird but yet this problem occurs.
So I'm hoping someone here might have done something simular and sees the error in my code.

Thanks in advance.

P.s. if you need any more info or see the rest of the unit let me know and ill put the entire unit on github or something like that.

Edit: Thanks to @Uwe Raabe I managed to solve this problem. The problem was found in the comments of INTAServices.AddImages

AddImages takes all the images from the given image list and adds them to the main application imagelist. It also creates an internal mapping array from the original image indices to the new indices in the main imagelist. This mapping is used by AddActionMenu to remap the ImageIndex property of the action object to the new ImageIndex. This should be the first method called when adding actions and menu items to the main application window. The return value is the first index in the main application image list of the first image in the source list. Call this function with an nil image list to clear the internal mapping array. Unlike the AddImages function from the ancestor interface, this version takes an Ident that allows the same base index to be re-used. This is useful when the IDE implements demand-loading of personalities so that the images will only get registered once and the same image indices can be used.

The solution eventually was adding my image to a local imagelist which was added to the imagelist of IntaServices Code:

procedure TDatamoduleToDoList.DataModuleCreate(Sender: TObject);
begin
  //Create extension
  if Supports(BorlandIDEServices, INTAServices, FIntaServices) then
  begin
    Initialize;
    if FToDoAction <> nil then
    begin
      FCustBut := TSpeedButton(FIntaServices.AddToolButton(sCustomToolBar, 'CstmToDoList', FToDoAction));
      FToDoAction.ImageIndex := FIntaServices.AddImages(FImages);//This is the fix
    end
    else
      DoRaise('Initialize failed');
  end
  else
    DoRaise('Something went wrong');
end;
1

There are 1 best solutions below

3
On BEST ANSWER

You are not supposed to fiddle around with the INTAServices.ImageList directly. Instead use either INTAServices.AddMasked or INTAServices.AddImages (in case you have a local imagelist in your datamodule).

You can safely use the INTAServices.ImageList to be connected to your controls, but you should neither Add nor Delete the images in it directly.