- NSIS Discussion
- Iterate through ComboBox items
Archive: Iterate through ComboBox items
Yathosho
28th January 2013 12:51 UTC
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!
demiller9
28th January 2013 16:32 UTC
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.
Anders
28th January 2013 21:10 UTC
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)
Yathosho
28th January 2013 23:29 UTC
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.)
Yathosho
30th January 2013 11:29 UTC
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
Anders
30th January 2013 16:43 UTC
Cb_getlbtext
Yathosho
30th January 2013 20:56 UTC
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.
Anders
31st January 2013 00:33 UTC
To receive a string you have to use System::Call user32::SendMessage... (See GetText in nsdialogs.nsh)
Yathosho
2nd February 2013 23:08 UTC
i don't see how this is supposed to help
Anders
3rd February 2013 05:34 UTC
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...
Yathosho
4th February 2013 14:08 UTC
unfortunately, i don't understand any of that. which is why i kindly asked for an example in the first place.
Yathosho
5th February 2013 13:15 UTC
looking good so far, thanks a lot!
Yathosho
19th February 2013 13:53 UTC
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"
Yathosho
19th February 2013 19:50 UTC
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?
Anders
20th February 2013 06:09 UTC
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...
Yathosho
20th February 2013 08:38 UTC
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?
Yathosho
23rd February 2013 00:02 UTC
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?
kichik
3rd March 2013 07:14 UTC
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.
Yathosho
5th March 2013 22:40 UTC
thanks for the help, love how this works. can this be blocked for certain keystrokes (e.g. cursor keys)?