Skip to content
⌘ NSIS Forum Archive

having trouble with NSD_OnNotify with ListBox

5 posts

DrBonzo#

having trouble with NSD_OnNotify with ListBox

I'm trying to respond to clicks on a listbox. Here's the setup:

nsDialogs::Create /NOUNLOAD 1018
Pop $ListBoxPage
${NSD_CreateListBox} 0 20 100% 80% "Backup folders"
Pop $ListBox
Call PopulateListBox
${NSD_OnNotify} $ListBox ListClicked
nsDialogs::Show

The list box is getting populated, but ListClicked is never getting called.

What am I missing?
Anders#
Not every notification works for every control. OnNotify hooks WM_NOTIFY and a listbox does not use that message IIRC
DrBonzo#edited
Thanks, Anders, for your reply.

Yes, indeed, listboxes neither generate nor receive WM_NOTIFY messages for selection changes. I had been encouraged by another thread (http://forums.winamp.com/showthread....ght=lbs_notify) mentioning LBS_NOTIFY, but that poster was looking for OnChange notifications.

The MSDN dox say that the list box's *parent* ($ListBoxPage in my example) receives selection change notifications and I've verified with Spy++ that, in fact, this notification is in the form of a WM_COMMAND message with a wNotifyCode (HIWORD of wParam) of LBN_SELCHANGE.

So it looks like I need to subclass $ListBoxPage. I've found WndSubclass - http://nsis.sourceforge.net/WndSubclass_plug-in (yours, Anders?), which looks like it might do the trick. If so, I'll post the results. If not, I'll probably ask for more help...
DrBonzo#edited
Thanks to WndSubclass, here's a working example :


Page custom ListBoxDialogPage
OutFile ListBoxTest.exe

Section "Empty section"
SectionEnd

!include LogicLib.nsh
!include NsDialogs.nsh
!include WinMessages.nsh
!include WndSubclass.nsh

var ListBox
var ListBoxPage

!define __NSD_ListBoxMulti_CLASS LISTBOX
!define __NSD_ListBoxMulti_STYLE ${DEFAULT_STYLES}|${WS_TABSTOP}|${WS_VSCROLL}|${LBS_EXTENDEDSEL}|${LBS_HASSTRINGS}|${LBS_NOTIFY}
!define __NSD_ListBoxMulti_EXSTYLE ${WS_EX_WINDOWEDGE}|${WS_EX_CLIENTEDGE}

!insertmacro __NSD_DefineControl ListBoxMulti

Function PopulateListBox
SendMessage $ListBox ${LB_ADDSTRING} 0 "STR:Abel"
SendMessage $ListBox ${LB_ADDSTRING} 0 "STR:Baker"
SendMessage $ListBox ${LB_ADDSTRING} 0 "STR:Charlie"
FunctionEnd

Function ListClicked
SendMessage $ListBox ${LB_GETCURSEL} 0 0 $0
MessageBox MB_OK "Cursel: $0"
FunctionEnd

Var CommandCaptureVar

!define LBN_SELCHANGE 1

Function CommandCapture
${If} $2 = ${WM_COMMAND}
Var /Global HiWord
IntOp $HiWord $3 >> 16
IntOp $HiWord $HiWord & 0xff
${If} $HiWord = ${LBN_SELCHANGE}
Call ListClicked
${EndIf}
${EndIf}
FunctionEnd

Function ListBoxDialogPage
nsDialogs::Create /NOUNLOAD 1018
Pop $ListBoxPage
${NSD_CreateListBoxMulti} 0 20 100% 80% ""
Pop $ListBox
Call PopulateListBox
${WndSubclass_Subclass} $ListBoxPage CommandCapture $CommandCaptureVar $CommandCaptureVar
nsDialogs::Show
FunctionEnd
shadowpoa#
Old Thread, but much useful

I have done a lot of research in the forums, and got portions of code at this thread that may help to solve a lot of problem with those using listbox control and wanting real time notifications.

The DrBonzo´s solution works, but rely´s on the handle of listbox on called on function ''ListClicked'' because it is abstracted that will exist only one listbox on the dialog, so, I understand that this solution only works with a single listbox.

My purpose is to get the handle of active listbox and get current selection of that listbox.

This is the approach, works fine, here's the code for that, adapted from code from DrBonzo.

Note that WndSubclass receive the $Listbox handle instead of dialog's handle, and this handle is passed to a function by WndSubclass at $1.

Page custom ListBoxDialogPage
OutFile ListBoxTest.exe
Section "Empty section"
SectionEnd
!include LogicLib.nsh
!include NsDialogs.nsh
!include WinMessages.nsh
!include WndSubclass.nsh
var ListBoxPage
Var hCtl_JANELA_ListBox1
Var hCtl_JANELA_ListBox2
!define __NSD_ListBoxMulti_CLASS LISTBOX
!define __NSD_ListBoxMulti_STYLE ${DEFAULT_STYLES}|${WS_TABSTOP}|${WS_VSCROLL}|${LBS_EXTENDEDSEL}|${LBS_HASSTRINGS}|${LBS_NOTIFY}
!define __NSD_ListBoxMulti_EXSTYLE ${WS_EX_WINDOWEDGE}|${WS_EX_CLIENTEDGE}
!insertmacro __NSD_DefineControl ListBoxMulti
Function PopulateListBox
    SendMessage $hCtl_JANELA_ListBox2 ${LB_ADDSTRING} 0 "STR:Abel"
    SendMessage $hCtl_JANELA_ListBox2 ${LB_ADDSTRING} 0 "STR:Baker"
    SendMessage $hCtl_JANELA_ListBox2 ${LB_ADDSTRING} 0 "STR:Charlie"
    
    SendMessage $hCtl_JANELA_ListBox1 ${LB_ADDSTRING} 0 "STR:Abel"
    SendMessage $hCtl_JANELA_ListBox1 ${LB_ADDSTRING} 0 "STR:Baker"
    SendMessage $hCtl_JANELA_ListBox1 ${LB_ADDSTRING} 0 "STR:Charlie"
FunctionEnd
Function ListClicked
    SendMessage $1 ${LB_GETCURSEL} 0 0 $0
    MessageBox MB_OK "Cursel: $0"
FunctionEnd
Var CommandCaptureVar
Function CommandCapture
    ${If} $2 = ${WM_LBUTTONUP}
              Call ListClicked
    ${EndIf}
    
FunctionEnd
Function ListBoxDialogPage
    nsDialogs::Create /NOUNLOAD 1018
    Pop $ListBoxPage
    
  ; === ListBox1 (type: ListBox) ===
  ${NSD_CreateListBox} 32u 32u 79u 53u ""
  Pop $hCtl_JANELA_ListBox1
  ; === ListBox2 (type: ListBox) ===
  ${NSD_CreateListBox} 152u 32u 79u 53u ""
  Pop $hCtl_JANELA_ListBox2
    Call PopulateListBox
    
    ${WndSubclass_Subclass} $hCtl_JANELA_ListBox1 CommandCapture $CommandCaptureVar $CommandCaptureVar
    ${WndSubclass_Subclass} $hCtl_JANELA_ListBox2 CommandCapture $CommandCaptureVar $CommandCaptureVar
    nsDialogs::Show
FunctionEnd 
Hope This Helps anyone.