Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ComboBox: a button on every item (to delete the item from list)

I need to add a button (maybe TSpeedButton?) on every item of ComboBox. When one clicks the button the corresponding item is deleted from the list. For example:

enter image description here

I've seen similar discussion on SpeedButtons in string grids (here: TStringGrid with SpeedButtons), but I don't know how to implement all those things on ComboBox. Could you please give me some advice or links for further reading on the topic.

like image 741
Alex Avatar asked Jun 01 '15 19:06

Alex


1 Answers

Besides the user experience comments aside, to which I agree, a solution to the question isn't really that hard.

You can do this by setting the Style property to csOwnerDrawFixed, drawing the items yourself in the OnDrawItem event, and deleting the selected item in the OnSelect event for example, as follows:

unit Unit1;

interface

uses
  Winapi.Windows, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls,
  Vcl.Imaging.PNGIMage;

type
  TForm1 = class(TForm)
    ComboBox1: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ComboBox1DrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure ComboBox1Select(Sender: TObject);
  private
    FDeleteGraphic: TPNGImage;
    FDeleteRect: TRect;
  end;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
  ComboBox1.Canvas.FillRect(Rect);
  if Index >= 0 then
    ComboBox1.Canvas.TextOut(Rect.Left + 2, Rect.Top, ComboBox1.Items[Index]);
  if (odSelected in State) and not (odComboBoxEdit in State) then
  begin
    FDeleteRect := Rect;
    FDeleteRect.Left := FDeleteRect.Right - FDeleteGraphic.Width;
    ComboBox1.Canvas.Draw(FDeleteRect.Left, FDeleteRect.Top, FDeleteGraphic);
  end;
end;

procedure TForm1.ComboBox1Select(Sender: TObject);
var
  MousePos: TPoint;
begin
  MousePos := ComboBox1.ScreenToClient(Mouse.CursorPos);
  MousePos.Offset(0, -ComboBox1.Height);
  if PtInRect(FDeleteRect, MousePos) then
  begin
    ComboBox1.Items.Delete(ComboBox1.ItemIndex);
    ComboBox1.Invalidate;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FDeleteGraphic := TPNGImage.Create;
  FDeleteGraphic.LoadFromFile('H:\Icons\FamFam Common\Delete.png');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FDeleteGraphic.Free;
end;

end.

With this result:

Screen shot

You might want to (re)store the previous ItemIndex setting. Customize to your wishes.

like image 105
NGLN Avatar answered Sep 22 '22 09:09

NGLN