Post by coda on Jun 12, 2024 3:26:03 GMT -5
While trying to solve the problem of how a program I am currently writing can best interface with the user and perform a certain task, I had been struggling for some time to find a solution that was, at the same time, practical, sensible, that used familiar Windows metaphors and most importantly was doable in LB.
While mulling this over, it eventually hit me that the mechanism I really needed was a multiple selection listbox… This was the perfect answer! The trouble is that once this realisation hit me, the realisation also dawned on me that although LB can create a multi-selection lisbox, LB has no native way to interact with multi-selection listboxes once made. To begin with, I was not daunted by this fact because I thought that I’d just use API calls. While this would certainly seem possible (and would be in other languages) the problem is that making this particular function call requires pointers to arrays to be passed. LB knows nothing about pointers to arrays. I was devastated…
But not for long!!![:)](//storage.proboards.com/forum/images/smiley/smiley.png)
I have written a DLL file that does the job for LB, giving LB programmers the ability to implement multi-selection listboxes. My DLL works by taking care of the array pointers on behalf of LB and passes the selection data back to LB via something LB DOES understand… a string.
I am not sure if this has been done before (perhaps it has) or if it is of use to other LB programmers at all but if it is of use, then I offer this to the community for use in their programs.
It is free to use in both personal programs and in any paid programs you produce using it and there is no need to credit me but that would nice if you would like to. For this purpose, my actual name is ‘Napier Thompson’. Just something I feel might help someone and a small way I can give back to the amazing community who is always there for me when I get stuck on a programming conundrum.![:)](//storage.proboards.com/forum/images/smiley/smiley.png)
You will need to download both the annotated example program and the DLL file and put them in the same folder. If you have any questions/suggestions please let me know.
Happy Programming!![:)](//storage.proboards.com/forum/images/smiley/smiley.png)
Here is the DLL: LB_MULTISEL.dll (33.5 KB)
While mulling this over, it eventually hit me that the mechanism I really needed was a multiple selection listbox… This was the perfect answer! The trouble is that once this realisation hit me, the realisation also dawned on me that although LB can create a multi-selection lisbox, LB has no native way to interact with multi-selection listboxes once made. To begin with, I was not daunted by this fact because I thought that I’d just use API calls. While this would certainly seem possible (and would be in other languages) the problem is that making this particular function call requires pointers to arrays to be passed. LB knows nothing about pointers to arrays. I was devastated…
But not for long!!
![:)](http://storage.proboards.com/forum/images/smiley/smiley.png)
I have written a DLL file that does the job for LB, giving LB programmers the ability to implement multi-selection listboxes. My DLL works by taking care of the array pointers on behalf of LB and passes the selection data back to LB via something LB DOES understand… a string.
I am not sure if this has been done before (perhaps it has) or if it is of use to other LB programmers at all but if it is of use, then I offer this to the community for use in their programs.
It is free to use in both personal programs and in any paid programs you produce using it and there is no need to credit me but that would nice if you would like to. For this purpose, my actual name is ‘Napier Thompson’. Just something I feel might help someone and a small way I can give back to the amazing community who is always there for me when I get stuck on a programming conundrum.
![:)](http://storage.proboards.com/forum/images/smiley/smiley.png)
You will need to download both the annotated example program and the DLL file and put them in the same folder. If you have any questions/suggestions please let me know.
Happy Programming!
![:)](http://storage.proboards.com/forum/images/smiley/smiley.png)
[StartCode]
'nomainwin
'Set the number of items the listbox contains
NumberOfItems = 15 'must be 32,767 or less as restricted by Windows OS. (In practice, this usually won't be more than a few hundred at absolute most).
'Dimension arrays for the selected items and listbox contents
dim Selected(NumberOfItems + 1)
dim Option$(NumberOfItems - 1)
'Open my dll for use
open "LB_MULTISEL.dll" for dll as #LBMultiSel 'Make sure you either have my dll in the same path as this .bas file or that you edit this path to point to the dll
'Initialise listbox contents array
for i = 0 to NumberOfItems - 1:read temp$:Option$(i) = temp$:next i
'Define window dimensions
WindowWidth = 275:WindowHeight = 300
'Set window invisible and define controls for window
stylebits #main, 0, _WS_VISIBLE, 0, 0 'set initial state of window to invisible
stylebits #main.listbox, _LBS_EXTENDEDSEL, 0, 0, 0 'set listbox to multiple selection type
listbox #main.listbox, Option$(), [DoNothing], 5, 35, 250, 220 'define listbox control
button #main.buttonChoose, "Choose", [SelectionMade], UL, 5, 5, 50, 20 'define 'Choose' button control
button #main.buttonSelect, "Select All", [SelectAll], UL, 85, 5, 70, 20 'define 'Select All' button control
button #main.buttonCancel, "Clear All", [ClearAll], UL, 185, 5, 70, 20 'define 'Clear All' button control
'Open & show window, trap program closure and set font size for controls
open "Make A Multi-Selection..." for window as #main
#main, "trapclose [Quit]"
#main.listbox, "font ms_sans_serif 8"
#main.buttonChoose, "!font ms_sans_serif 8"
#main.buttonSelect, "!font ms_sans_serif 8"
#main.buttonCancel, "!font ms_sans_serif 8"
#main "show"
'Set Up Variables etc.
LBHandle = HWnd(#main.listbox) 'This returns the windows handle to your multi-selection listbox
'********** Algorithm to calculate exact length required for return string **********
Number = NumberOfItems
NumberOfItems$ = str$(NumberOfItems)
Numlength = len(NumberOfItems$)
LowestCharacterCount = 2 'This is set to '2' because the lowest character count for each item is 2 ie. "0," or "3," etc. = 2 characters (number + comma)
'N.B. If you ever wanted to use this algorithm to determine the sum off all digits in all positive integers including zero below any given number,
'including the digits in that number, itself, you would set this value to '1'.
for i = Numlength to 1 step -1
Digits = Digits+((Number-(10^(i-1)))+1)*(i+LowestCharacterCount-1)
Number = Number-((Number-(10^(i-1)))+1)
next i
Digits = Digits+LowestCharacterCount
'************************************************************************************
SelString$ = space$(Digits)+chr$(0) 'This is a dummy string into which the multi-selection data will be returned
'We set its size using the value of the variable, Digits, that we just calculated.
'Main loop
[DoNothing] 'someone clicks on the listbox... we do nothing in response because, we aren't going to determine what the user's
'multi-selection is until after it is complete and a button is pushed.
wait
'Action of choose button
[SelectionMade]
'Call the "GetLBMultiSelection" function from my dll. The parameters passed are the Windows handle to the listbox, the number of items in the listbox and
'a pointer to the dummy string we prepared ealier. The returned value (NumberSelected) contains the number of items selected. The dummy string is filled with
'a comma separated list showing the Windows indexes of the selected items in the listbox. NOTE: Windows indexes for this purpose (unlike Liberty BASIC's)
'start at zero NOT 1.
calldll #LBMultiSel, "GetLBMultiSelection",_
LBHandle as ulong,_
NumberOfItems as ushort,_
SelString$ as PTR,_
NumberSelected as ushort
'Truncate the dummy string into a new variable at the first null character. NOTE: Do NOT truncate the original string (SelString$), itself.
'You'll need it just the way it it is with null termination for the next time your user makes a multi-selection.
TruncatedString$ = left$(SelString$, instr(SelString$, chr$(0)) - 1)
'Initialize all values of an array to contain the listbox's selected item indexes to a value of -1.
for i = 1 to NumberOfItems + 1
Selected(i) = -1
next i
'Fill the array above with the indexes of the selected items from the listox that were returned in the string as a comma separated list
if TruncatedString$ <> "" then
ii = 0:iii = 1
for i = 1 to len(TruncatedString$)
ii = ii+1:temp$ = mid$(TruncatedString$,ii,1)
'NOTE: If you want to use 1-based indexes (LB style) rather than 0-based indexes (Windows style) replace "Val(Selected$)" below with
'"Val(Selected$) + 1" and replace 'dim Option$(NumberOfItems - 1)' above with 'dim Option$(NumberOfItems)'.
'If you choose to do this, you can replace the 'for next' loop above with a redim statement as you do not need to initiatlise the array contents to -1
'to tell when a selection has been made of the first listbox item apart from the case that no selection has been made. Realistically, you could always
'use redim anyway, even with 0-based indexes and simply use the return value of the function (the number of items selected) to distinguish these two
'cases and determine the end of the list of indexes...the point is, you have options...
if temp$ <> "," then Selected$ = Selected$+temp$ else Selected(iii) = Val(Selected$):Selected$ = "":iii = iii+1
next i
end if
'Print array containing the numerical indexes of the selected listbox items to the main window
cls
i = 1
while Selected(i) > -1
print "Selected("+str$(i)+") = "+str$(Selected(i)):i = i+1
wend
'Create a notice reporting the selected indexes and the number of selected items
notice TruncatedString$+" was/were chosen. That's "+str$(NumberSelected)+" item(s)."
wait
[SelectAll]
'Call the send message function. The parameters passed are the Windows handle to the listbox, the Windows constant _LB_SETSEL, the number 1 and the number -1.
'You pass 1 to this function to select items and 0 to the same function to deselect or clear items. The value -1 invokes ALL items.
calldll #user32, "SendMessageA",_
LBHandle as ulong,_
_LB_SETSEL as ulong,_
1 as boolean,_
-1 as long,_
result as long
'Print "All Selected!" to the main window
cls
print"All Selected!"
'Create a notice reporting that all items have been selected
notice "All Selected!"
wait
[ClearAll]
'Call the send message function. The parameters passed are the Windows handle to the listbox, the Windows constant _LB_SETSEL, the number 0 and the number -1.
'You pass 1 to this function to select items and 0 to the same function to deselect or clear items. The value -1 invokes ALL items.
calldll #user32, "SendMessageA",_
LBHandle as ulong,_
_LB_SETSEL as ulong,_
0 as boolean,_
-1 as long,_
result as long
'Print "Selection cancelled!" to the main window
cls
print"Selection cancelled!"
'Create a notice reporting that all items have been deselected
notice "Selection cancelled!"
wait
[Quit]
close #LBMultiSel 'Close my dll
close #main 'Close window
end
[ProgramData]
'Data for listbox items
data "Broccoli", "Turnip", "Spinach", "Celeriac", "Radish", "Kale", "Pumpkin", "Potato", "Zucchini", "Cucumber", "Tomato", "Capsicum", "Swede", "Corn", "Peas"
Here is the DLL: LB_MULTISEL.dll (33.5 KB)