Delphi 7 - How to assign ListView items into a combobox - delphi

I'm using this code to assign values:
combobox1.Text:=form1.listview1.Selected.Caption;
But i'm getting this error: Cannot assign a TListItems to a TComboBox

You can't add a ListView.Items to a ComboBox.Items (as the compiler has told you, one is a TListItems collection and the other is a descendant of TStrings, and they're not type compatible). You can add the caption of a selected ListItem to the ComboBox.Items.
You need to add it to the ComboBox.Items:
ComboBox1.Items.Add(ListView1.Selected.Caption);
If you want to add all selected items, you need to use a loop:
var
Item: TListItem;
begin
Item := ListView1.Selected;
while Item <> nil do
begin
ComboBox1.Items.Add(Item.Caption);
Item := ListView1.GetNextItem(Item, sdAll, [isSelected]);
end;
If you just want to add all items from the ListView to the ComboBox (which seems pretty pointless, as they're already displayed in the ListView):
var
i: Integer;
begin
for i := 0 to ListView1.Items.Count - 1 do
ComboBox1.Items.Add(ListView1.Items[i].Caption);
end;

Related

Delphi firemonkey how to remove a menuitem programmatically?

How can I remove a menuitem I dynamically added to a menu?
I add dynamically menu items with for example:
m:=TMenuItem.Create(nil);
m.Text:='bla bla bla';
mnuMain.AddObject(m);
I could not find ANY function to remove the entry again.
I tried delete, free, removeobject etc. and the item is still nor removed and still visible. What is the trick?
If you are adding a item like so :
var
M : TMenuItem;
begin
M := TMenuItem.Create(nil);
M.Text := 'Bla Bla Bla';
MenuBar1.AddObject(M);
Then you are just giving it a parent, just set the parent of the menu items to nil ARC will then swoop in and do the rest seeing as there are no more references to the object
Just write a loop to go through and set all the parents to nil/ Or if you are targeting Windows as well (Or only Windows) in your code, make use of DisposeOf, or make use of compiler directives
var
I: Integer;
begin
for I := MenuBar1.ItemsCount-1 downto 0 do
begin
{$IFNDEF AUTOREFCOUNT}
MenuBar1.Items[I].disposeOf;
{$ELSE}
MenuBar1.Items[I].parent := nil;
{$ENDIF}
end;
end;
I faced the same issue: TMenuItem.RemoveObject is not working and the private member FContent of TMenuView is not accessable without tricks over RTTI.
That is why I build my own workaround by using a stringlist that stores the remaining menu child items before I call TMenuItem.Clear:
function RemoveFromMenu(mnuMain: TMenuItem; const MenuText: string);
var
list: TStringList;
c: integer;
Menu: TMenuItem;
begin
list := TStringList.Create;
try
for c := 0 to mnuMain.ItemsCount - 1 do
if mnuMain.Items[c].Text <> MenuText then
list.Add(mnuMain.Items[c].Text);
mnuMain.Clear;
for c := 0 to list.Count - 1 do
begin
Menu := TMenuItem.Create(self);
Menu.Text := list[c];
Menu.OnClick := mnuMainSubMenuClick; // The menu event handler
mnuMain.InsertObject(0, Menu);
end;
finally
list.Free;
end;
end;
In case your sub menu have for each menu item an own menu handler than you have also store this event handler. In such situations a generic list of TMenuItem (TList< TMenuItem >) would be a better approach than using the string list.

Sort PopupMenu items by caption

I have TPopupMenu, items added at runtime. I want to sort em by caption: "Abc", "MyItem", "Zztop". I cannot find Sort method in lists of menu items.
Delphi7.
Since you add the items at runtime the preferred way would by adding the already sorted.
If you have to add items to a menu already containing items you might sort them by setting the MenuIndex for the items to the desired value.
An easy way would be to take the Items to a sorted StringList and apply the MenuIndex form the list.
Procedure SortMenuItems(Menu: TPopupMenu);
var
i: Integer;
sl: TStringList;
begin
sl := TStringList.Create;
try
sl.Sorted := true;
for i := 0 to Menu.Items.Count - 1 do
begin
sl.AddObject(Menu.Items[i].Caption, Menu.Items[i]);
end;
for i := 0 to sl.Count - 1 do
TMenuItem(sl.Objects[i]).MenuIndex := i;
finally
sl.Free;
end;
end;

Dual ComboBox selection dependency

I would like to have a 2 drop down combobox with the following items:
Combo1:
Pets
Fruits.
Combo2:
If Pets is picked then combobox2items.Add:
Dog, Cat, Chicken
If Fruits is picked then combobox2items.Add:
Melon, Orange, Apple
So I try to do this:
procedure TForm1.FormCreate(Sender: TObject);
begin
ComboBox1.Items.Add('Pets');
ComboBox1.Items.Add('Fruits');
end;
procedure TForm1.ComboBox2Change(Sender: TObject);
begin
if ComboBox1.ItemIndex = 1) then
ComboBox2.Items.Add('Dog');
ComboBox2.Items.Add('Cat');
ComboBox2.Items.Add('Chicken');
if ComboBox1.ItemIndex = 2) then
ComboBox2.Items.Add('Melon');
ComboBox2.Items.Add('Orange');
ComboBox2.Items.Add('Apple');
end;
My code is not working. How to figure this out in simple way?
You need to use begin..end like this:
if ComboBox1.ItemIndex = 1 then
begin
ComboBox2.Items.Add ('Dog');
ComboBox2.Items.Add ('Cat');
ComboBox2.Items.Add ('Chicken');
end;
if ComboBox1.ItemIndex = 2 then
begin
ComboBox2.Items.Add ('Melon');
ComboBox2.Items.Add ('Orange');
ComboBox2.Items.Add ('Apple');
end;
Also you need to clear the combobox before adding in the new items;
When it comes to Combo Box dependencies, I like to build a Dictionary that represents these dependencies. Basically, you have your Dictionary keep the items of ComboBox1 as keys. When ComboBox1 changes, you re-assign ComboBox2's Items property to the StringList behind the selected Key. This saves you the trouble of removing/adding individual strings every time ComboBox1's index is changed.
procedure TForm1.FormCreate(Sender: TObject);
begin
FComboBoxDependencies := TDictionary<string,TStringList>.Create;
FComboBoxDependencies.Add('Pets',TStringList.Create);
FComboBoxDependencies['Pets'].Add('Dog');
FComboBoxDependencies['Pets'].Add('Cat');
FComboBoxDependencies['Pets'].Add('Chicken');
FComboBoxDependencies.Add('Fruit',TStringList.Create);
FComboBoxDependencies['Fruits'].Add('Orange');
FComboBoxDependencies['Fruits'].Add('Apple');
FComboBoxDependencies['Fruits'].Add('Melon');
//Trigger Change Event at start to display the selected Key
ComboBox1Change(self);
end;
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
ComboBox2.Items := FComboBoxDependencies[ComboBox1.Text]; //Grab Items to be displayed from dictionary
ComboBox2.ItemIndex := 0; //Set Itemindex to 0 to show first item
end;
Of course, this can be refined and tweaked to be more reliable, but the core of this works pretty good.

How do I add an item to a TListBox and associate it with a data object?

See the code:
function ShowItem(MyData: TMyData): TListItem;
var
vListItem: TListItem;
begin
vListItem := ListView1.Items.Add;
vListItem.Data := MyData;
vListItem.ImageIndex := 1;
vListItem.Caption := MyData.Caption;
Result := vListItem;
end;
What do I need to do to get this to work for TListBox? ListView.Items property seems to be that of TListItem, where as ListBox.Items is not, which means the function will not be able to return the correct parameter for TListBox.
How may I convert this for TListBox?
Thanks
This should do:
function ShowItem(MyData: TMyData): Integer;
begin
Result := ListBox1.Items.AddObject(MyData.Caption, MyData);
end;
There is no equivalent since the ImageIndex property for list views has no analogue for list boxes (unless you implement it yourself and custom draw).

Delphi Popup Menu Checks

I am using a popup menu in Delphi. I want to use it in a "radio group" fashion where if the user selects an item it is checked and the other items are not checked. I tried using the AutoCheck property, but this allows multiple items to be checked. Is there a way to set the popup menu so that only one item can be checked?
To treat the popup (or any other) menu items like radio group items, set the 'RadioItem' property to true for each item you want to have in the radio group.
Instead of showing a checkmark, it will show a bullet by the selected item, but it will work the way you want, and the visual cue will actually match a windows standard.
Zartog is right, but if you want to keep the checkbox, assign this event to every item in the popup menu.
Note that this code is a little hairy looking because it does not depend on knowing the name of your popup menu (hence, looking it up with "GetParentComponent").
procedure TForm2.OnPopupItemClick(Sender: TObject);
var
i : integer;
begin
with (Sender as TMenuItem) do begin
//if they just checked something...
if Checked then begin
//go through the list and *un* check everything *else*
for i := 0 to (GetParentComponent as TPopupMenu).Items.Count - 1 do begin
if i <> MenuIndex then begin //don't uncheck the one they just clicked!
(GetParentComponent as TPopupMenu).Items[i].Checked := False;
end; //if not the one they just clicked
end; //for each item in the popup
end; //if we checked something
end; //with
end;
You can assign the event at runtime to every popup box on your form like this (if you want to do that):
procedure TForm2.FormCreate(Sender: TObject);
var
i,j: integer;
begin
inherited;
//look for any popup menus, and assign our custom checkbox handler to them
if Sender is TForm then begin
with (Sender as TForm) do begin
for i := 0 to ComponentCount - 1 do begin
if (Components[i] is TPopupMenu) then begin
for j := 0 to (Components[i] as TPopupMenu).Items.Count - 1 do begin
(Components[i] as TPopupMenu).Items[j].OnClick := OnPopupItemClick;
end; //for every item in the popup list we found
end; //if we found a popup list
end; //for every component on the form
end; //with the form
end; //if we are looking at a form
end;
In response to a comment below this answer: If you want to require at least one item to be checked, then use this instead of the first code block. You may want to set a default checked item in the oncreate event.
procedure TForm2.OnPopupItemClick(Sender: TObject);
var
i : integer;
begin
with (Sender as TMenuItem) do begin
//go through the list and make sure *only* the clicked item is checked
for i := 0 to (GetParentComponent as TPopupMenu).Items.Count - 1 do begin
(GetParentComponent as TPopupMenu).Items[i].Checked := (i = MenuIndex);
end; //for each item in the popup
end; //with
end;
To enlarge on Zartog's post: Popup menus in Delphi (from at least D6) have a GroupIndex property which allow you to have multiple sets of radio items within a menu. Set GroupIndex to 1 for the first group, 2 for a second etc.
So:
Set AutoCheck = True
Set RadioItem = True
Set GroupIndex if you need more than one group of radio items

Resources