Archive: Iterate through ComboBox items


Iterate through ComboBox items
would anyone be so kind a provide an example how to iterate through the items of a combobox?

actually a working example using CB_GETITEMDATA for any position in the combobox would be enough, i can wrap a loop around that myself. it's only that i haven't found a clear example and (as always) msdn provides near to zero information, let alone examples.

thanks!


I have an installer with a combobox but I didn't need to use CB_GETITEMDATA. The user's choice is read with ${NSD_GetText} and I set a default selection with ${NSD_CB_SelectString} when building the list or modify it later with

SendMessage $hComboBox ${CB_SETCURSEL} $1 0
When I need to modify the selection the item number is determined by using ${WordFind} on the list of items I put in the combobox list. This works for us because our list is under a dozen items.

GET/SETITEMDATA only stores a pointer sized number (32bit), if you wanted to store an extra string in addition to the displayed text you need to allocate memory/struct with the system plugin and just store the memory address as the item data. (Just storing the item data in a .ini is probably less work)


Originally posted by demiller9
I have an installer with a combobox but I didn't need to use CB_GETITEMDATA. The user's choice is read with ${NSD_GetText} and I set a default selection with ${NSD_CB_SelectString} when building the list or modify it later with
SendMessage $hComboBox ${CB_SETCURSEL} $1 0
When I need to modify the selection the item number is determined by using ${WordFind} on the list of items I put in the combobox list. This works for us because our list is under a dozen items.
i'm not looking for the user choice, i'd like to hide all entries in the combobox that don't partially fit what the user entered.

example:
the combobox is populated with all css properties. when the user types "background" into the box i want to hide all items that are not background properties (background-color, background-image etc.)

ok, i got a bit further. turns out i can use CB_FINDSTRING to iterate through all items in the combobox. what i haven't figured out yet is how i can read a string from its index (i guess this is where CB_GETITEMDATA comes in)

i tried the following without success

SendMessage $ComboBox ${CB_GETITEMDATA} $index $string

Cb_getlbtext


phew, i'm not getting this to work. as always, i find msdn's documentation more than scarce. here's what i've bee using

${NSD_GetText} $ComboBox $R0
SendMessage $ComboBox ${CB_FINDSTRING} -1 "STR:$R0" $0
SendMessage $ComboBox ${CB_GETLBTEXT} $0 $1


must be the last line and i tried several variants (e.g. providing three arguments after CB_GETLBTEXT) - no success. i don't even understand what a TCHAR is, so i'd really appreciate a working example.

To receive a string you have to use System::Call user32::SendMessage... (See GetText in nsdialogs.nsh)


i don't see how this is supposed to help


To receive the string you need the "t.r1" syntax of the system plugin, the built-in basic sendmessage cannot convert the raw memory buffer back to a nsis variable...


unfortunately, i don't understand any of that. which is why i kindly asked for an example in the first place.


http://forums.winamp.com/showthread.php?t=314626


looking good so far, thanks a lot!


i've attached a first working version showcasing what i'm trying to accomplish. unfortunately, this is currently a one-way, older combobox items do not get restored. not sure what would be the best practice to do so, should i listen whether the delete key was pressed (and how does that work?) or simply compare whether the input length got shorter compared to a previous input?

edit: to see what this example does, start typing any command from the combobox, e.g. "border"


big problem: typing works, but selecting an item with the mouse breaks the whole thing. it seems that when clicking, nsd_gettext will always get the previous item, how could this be?


nsDialogs hooks CBN_EDITUPDATE and CBN_SELCHANGE, that callback might be too soon, use something other than nsd_gettext (CB_*) or try a timer hack...


Originally posted by Anders
nsDialogs hooks CBN_EDITUPDATE and CBN_SELCHANGE, that callback might be too soon, use something other than nsd_gettext (CB_*) or try a timer hack...
hm, i was taking a look at nsDialogs.nsh hoping to find any of the keywords you delivered. changed quite a lot, i remember tinkering around in that file years ago, but it looks nothing like that anymore. got some further leads?

i'm wondering how that can be a desired behaviour, onChange should really listen to both cases, especially since combining onChange and onClick doesn't work as one would expect. if there's need for seperating both (and i can't think of a scenario), it'd probably good to have a third macro. any thoughts on this?


You probably want to iterate all of the available options and not all of the items in the combobox when filtering. This way, if someone hits the backspace, you still get all the other options.

To get text from a combobox item, one System::Call is enough. No need to allocate stuff and use the built-in SendMessage.

# new
System::Call "user32::SendMessage(i $ComboBox, i ${CB_GETLBTEXT}, i r9, t.r2)"

# old
#System::Alloc ${NSIS_MAX_STRLEN}
#Pop $1
#SendMessage $ComboBox ${CB_GETLBTEXT} $9 $1
#System::Call "*$1(&t32.r2)"
#System::Free $1


As for the last issue of choosing something with the mouse, I'm not sure why this happens, but Anders is probably right. In any case, you can work around it by calling CB_GETCURSEL first and checking if it returns -1 or not. If it returns a value, the user selected that item. If not, the user typed something.

SendMessage $ComboBox ${CB_GETCURSEL} 0 0 $9
${If} $9 != -1
# user selected something
System::Call "user32::SendMessage(i $ComboBox, i ${CB_GETLBTEXT}, i r9, t .R0)"
${Else}
${NSD_GetText} $ComboBox $R0
${EndIf}


Attached is my almost working version. I'm sure you can take it from here.

thanks for the help, love how this works. can this be blocked for certain keystrokes (e.g. cursor keys)?