Multi-Listbox

BlitzPlus Forums/BlitzPlus Programming/Multi-Listbox

Does anyone know how to create list boxes with multiple title spaces and how to fill each of them in?

...What?

You could probably use the User32 DLL to change the style of the single columned listbox into a multicolumn one. I don't have an example for you but you could do a search on MSDN for "Multicolumn Listbox". If you find out how to do it please be sure to let me know because having one of those would be a really good idea.

I've used WB3D for that -> http://www.blitzbasic.com/Community/posts.php?topic=68745#768296

You can't use it with BlitzPlus though.

Yes you can:

Global MainWindow% = CreateWindow("Window", ClientWidth(Desktop()) / 2 - 650 / 2, ClientHeight(Desktop()) / 2 - 350 / 2, 650, 350, Desktop(), 1 + 2 + 4 + 8)

Global Tabber% = CreateTabber(0, 5, ClientWidth(MainWindow%) - 200, ClientHeight(MainWindow%) - 5, MainWindow)
Global ListBox% = WB3D_CreateListView(0, 30, ClientWidth(Tabber%), ClientHeight(Tabber%) - 30, QueryObject(Tabber%, 1), 0)
WB3D_SetGadgetExtendedStyle Listbox, LVS_EX_FULLROWSELECT Or LVS_EX_GRIDLINES
WB3D_AddListViewColumn(Listbox%, 0, "Name", 150)
WB3D_AddListViewColumn(Listbox%, 1, "Size", 50)
WB3D_AddListViewColumn(Listbox%, 2, "Description", 100)
WB3D_AddListViewColumn(Listbox%, 3, "Link", 150)


Maybe there's something missing in that code, but i was able to create multicolmn listbox with it.

yea andres correct i have had some feedback from users using winblitz3d under blitzplus. athough im unsure just how much its intergratable.

kev

I found a solution for that. It's very tricky because BlitzPlus doesn't support C-Strings with pointers at all. But finally I did it. Here is the source (standalone code without DLLs but with api-calls):




;BlitzPlus DataGrid demonstration (multi column listbox)
;by M. Uhl (some code is modified and taken from other coders)

;Please note the following important modified userlib declarations which are necessary!!!

;.lib "user32.dll"
;SendMessage%(hWnd%,Msg%,wParam%,lParam%) : "SendMessageA"
;api_SendMessage% (hwnd%, wMsg%, wParam%, lParam*) : "SendMessageA"

;api_GetWindowRect% (hwnd%, lpRect*) : "GetWindowRect"
;api_GetWindowLong% (hwnd%, nIndex%) : "GetWindowLongA"
;api_SetWindowLong% (hwnd%, nIndex%, dwNewLong%) : "SetWindowLongA"

Dim DG_Content$(10,10) ;redimensioned later

Global CStringPuffer

Const LBS_NOTIFY            = $1 
Const LBS_SORT              = $2 
Const LBS_NOREDRAW          = $4 
Const LBS_MULTIPLESEL       = $8 
Const LBS_OWNERDRAWFIXED    = $10 
Const LBS_OWNERDRAWVARIABLE = $20 
Const LBS_HASSTRINGS        = $40 
Const LBS_USETABSTOPS       = $70 
Const LBS_NOINTEGRALHEIGHT  = $100 
Const LBS_MULTICOLUMN       = $200 
Const LBS_WANTKEYBOARDINPUT = $400 
Const LBS_EXTENDEDSEL       = $800 
Const LBS_DISABLENOSCROLL   = $100 
Const LBS_NODATA            = $2000 
Const LBS_NOSEL             = $4000 
Const LBS_STANDARD          = $a00003 

Const LVM_FIRST = $1000 
Const LVM_GETITEMA          = (LVM_FIRST+5) 
Const LVM_SETITEMA          = (LVM_FIRST+6) 
Const LVM_INSERTITEMA       = (LVM_FIRST+7) 
Const LVM_DELETEITEM        = (LVM_FIRST+8) 
Const LVM_DELETEALLITEMS    = (LVM_FIRST+9) 
Const LVM_GETCALLBACKMASK   = (LVM_FIRST+10) 
Const LVM_SETCALLBACKMASK   = (LVM_FIRST+11)
Const LVM_GETNEXTITEM		= (LVM_FIRST+12)
Const LVM_GETCOLUMNA        = (LVM_FIRST+25) 
Const LVM_SETCOLUMNA        = (LVM_FIRST+26) 
Const LVM_INSERTCOLUMNA     = (LVM_FIRST+27) 
Const LVM_DELETECOLUMN      = (LVM_FIRST+28) 
Const LVM_GETCOLUMNWIDTH    = (LVM_FIRST+29) 
Const LVM_SETCOLUMNWIDTH    = (LVM_FIRST+30) 
Const LVM_GETTEXTCOLOR      = (LVM_FIRST+35) 
Const LVM_SETTEXTCOLOR      = (LVM_FIRST+36) 
Const LVM_GETTEXTBKCOLOR    = (LVM_FIRST+37) 
Const LVM_SETTEXTBKCOLOR    = (LVM_FIRST+38) 
Const LVM_SORTITEMS         = (LVM_FIRST+48) 
Const LVM_SETLISTBOXEXSTYLE = (LVM_FIRST+54)
Const LVM_SETSELECTIONMARK	= (LVM_FIRST+67)
Const LVM_GETITEMW          = (LVM_FIRST+75) 
Const LVM_SETITEMW          = (LVM_FIRST+76) 
Const LVM_INSERTITEMW       = (LVM_FIRST+77) 
Const LVM_GETCOLUMNW        = (LVM_FIRST+95) 
Const LVM_SETCOLUMNW        = (LVM_FIRST+96) 
Const LVM_INSERTCOLUMNW     = (LVM_FIRST+97)

Const LVS_EX_GRIDLINES        = $1 
Const LVS_EX_SUBITEMIMAGES    = $2 
Const LVS_EX_CHECKBOXES       = $4 
Const LVS_EX_TRACKSELECT      = $8 
Const LVS_EX_HEADERDRAGDROP   = $10 
Const LVS_EX_FULLROWSELECT    = $20 
Const LVS_EX_ONECLICKACTIVATE = $40 
Const LVS_EX_TWOCLICKACTIVATE = $80 
Const LVS_EX_FLATSB           = $100 
Const LVS_EX_REGIONAL         = $200 
Const LVS_EX_INFOTIP          = $400 
Const LVS_EX_UNDERLINEHOT     = $800 
Const LVS_EX_UNDERLINECOLD    = $1000 
Const LVS_EX_MULTIWORKAREAS   = $2000 
Const LVS_EX_LABELTIP         = $4000 
Const LVS_EX_BORDERSELECT     = $8000 
Const LVS_EX_DOUBLEBUFFER     = $10000 
Const LVS_EX_HIDELABELS       = $20000 
Const LVS_EX_SINGLEROW        = $40000 
Const LVS_EX_SNAPTOGRID       = $80000 
Const LVS_EX_SIMPLESELECT     = $100000 

Const LVCF_FMT     = $1 
Const LVCF_WIDTH   = $2 
Const LVCF_TEXT    = $4 
Const LVCF_SUBITEM = $8 
Const LVCF_IMAGE   = $10 
Const LVCF_ORDER   = $20 

Const LVIF_TEXT        = $1 
Const LVIF_IMAGE       = $2 
Const LVIF_PARAM       = $4 
Const LVIF_STATE       = $8 
Const LVIF_INDENT      = $10 
Const LVIF_GROUPID     = $100 
Const LVIF_COLUMNS     = $200 
Const LVIF_NORECOMPUTE = $800  
Const LVIF_DI_SETITEM  = $1000 

Const LVS_ALIGNTOP        = $0 
Const LVS_ICON            = $0 
Const LVS_REPORT          = $1 
Const LVS_SMALLICON       = $2 
Const LVS_LIST            = $3 
Const LVS_TYPEMASK        = $3 
Const LVS_SINGLESEL       = $4 
Const LVS_SHOWSELALWAYS   = $8 
Const LVS_SORTASCENDING   = $10 
Const LVS_SORTDESCENDING  = $20 
Const LVS_SHAREIMAGELISTS = $40 
Const LVS_NOLABELWRAP     = $80 
Const LVS_AUTOARRANGE     = $100 
Const LVS_EDITLABELS      = $200 
Const LVS_OWNERDRAWFIXED  = $400 
Const LVS_ALIGNLEFT       = $800 
Const LVS_ALIGNMASK       = $C00 
Const LVS_NOSCROLL        = $2000 
Const LVS_NOCOLUMNHEADER  = $4000 
Const LVS_NOSORTHEADER    = $8000 
Const LVS_TYPESTYLEMASK   = $FC00 

Const LVNI_SELECTED = $2
Const GWL_STYLE = -$10 

Type  LVCOLUMN  
   Field mask 
   Field fmt 
   Field cx 
   Field pszText;:Byte Ptr 
   Field cchTextMax 
   Field iSubItem 
End Type 

Type LVITEM 
   Field mask 
   Field iItem 
   Field iSubItem 
   Field iState 
   Field stateMask 
   Field pszText
   Field cchTextMax 
   Field iImage 
   Field lParam
   Field iIndent 
   Field iGroupId 
   Field cColumns 
   Field puColumns 
End Type

Type lpRECT
	Field x1,y1,x2,y2
End Type 


Function DG_AddColumn(DataGrid,ColumnNr,Width) 
	Local DataGridHwnd = QueryObject(DataGrid,1)
	Local Column.LVCOLUMN = New LVCOLUMN 
	Column\mask = LVCF_WIDTH 
	Column\cx = Width 
	api_SendMessage(DataGridHwnd,LVM_INSERTCOLUMNA,ColumnNr,Column) 
	api_SendMessage(DataGridHwnd,LVM_SETCOLUMNA,ColumnNr,Column)
End Function 

Function DG_SetHeading(DataGrid,ColumnNr,HeadingText$,Style=0) 
	Local DataGridHwnd = QueryObject(DataGrid,1) 
	Local Column.LVCOLUMN = New LVCOLUMN 
	Column\mask = LVCF_TEXT Or LVCF_FMT 
	Column\fmt = Style
	Column\pszText = DG_CStringPointer(HeadingText$)
	Local DataGridStyle = api_GetWindowLong(DataGridHwnd,GWL_STYLE) 
	If (DataGridStyle And LVS_NOCOLUMNHEADER ) Then 
		DataGridStyle = DataGridStyle Xor LVS_NOCOLUMNHEADER 
		api_SetWindowLong(DataGridHwnd,GWL_STYLE,DataGridStyle) 
	EndIf 
	api_SendMessage(DataGridHwnd,LVM_SETCOLUMNA,ColumnNr,Column)
	FreeBank Column\pszText
End Function 

Function DG_SetColumnWidth(DataGrid,ColumnNr,Width) 
	Local DataGridHwnd = QueryObject(DataGrid,1) 
	Local Column.LVCOLUMN = New LVCOLUMN 
	Column\mask = LVCF_WIDTH 
	Column\cx = Width 
	api_SendMessage(DataGridHwnd,LVM_SETCOLUMNA,ColumnNr,Column)
End Function

Function DG_ModifyItem(DataGrid,ColumnNr,RowNr,TextContent$) 
	DG_Content$(ColumnNr+1,RowNr)=TextContent$ ;remember content
	Local aa
	For aa=0 To ColumnNr
		If DG_Content$(0,RowNr)="" Then
			DG_Content$(0,RowNr)="y"
			AddGadgetItem DataGrid," " ;create rows if not exist
		EndIf
	Next
	Local DataGridHwnd = QueryObject(DataGrid,1) 
	Local Item.LVITEM = New LVITEM 
	Item\mask = LVIF_TEXT 
	Item\iSubItem = ColumnNr 
	Item\iItem = RowNr 
	Item\pszText = DG_CStringPointer(TextContent$)
	Item\cchTextMax = Len(TextContent$)+1 
	api_SendMessage(DataGridHwnd,LVM_SETITEMA,0,Item)
End Function 

Function DG_GetItemText$(DataGrid,ColumnNr,RowNr)
	
	Return DG_Content$(ColumnNr+1,RowNr)
	
	;the following code does not work because only one memory aera was used
	;while filling the cells so it would always return the last value
	Local DataGridHwnd = QueryObject(DataGrid,1)
	Local ReturnText$
	Local Item.LVITEM = New LVITEM 
	Item\mask = LVIF_TEXT 
	Item\iSubItem = ColumnNr 
	Item\iItem = RowNr 
	Item\pszText = CreateBank(0)
	Item\cchTextMax = 255
	api_SendMessage(DataGridHwnd,LVM_GETITEMA,0,Item)
	Return DG_StringFromCPointer$(Item\pszText)
End Function

Function DG_GetColumnWidth(DataGrid,ColumnNr) 
	Local DataGridHwnd = QueryObject(DataGrid,1) 
	Local Column.LVCOLUMN = New LVCOLUMN 
	Column\mask = LVCF_WIDTH 
	Column\cx = 0
	api_SendMessage(DataGridHwnd,LVM_GETCOLUMNA,ColumnNr,Column)
	Return Column\cx
End Function

Function DG_SetExtendedStyle(DataGrid,Style,txtcolor,bgcolor,multirowselect) 
	Local DataGridHwnd = QueryObject(DataGrid,1)
	If multirowselect
		Local PREVAL=api_GetWindowLong(DataGridHwnd,GWL_STYLE)
		api_SetWindowLong DataGridHwnd,GWL_STYLE,PREVAL-LVS_SINGLESEL ;multirowselect
	End If
	SendMessage(DataGridHwnd,LVM_SETLISTBOXEXSTYLE,Style,Style)
	SendMessage(DataGridHwnd,LVM_SETTEXTCOLOR,txtcolor,txtcolor) ;textcolor
	SendMessage(DataGridHwnd,LVM_SETTEXTBKCOLOR,bgcolor,bgcolor) ;backgroundcolor
End Function

Function DG_Ini_CStringMem() ;generates buffer for c-string in the form of a invisible listbox
	CStringPuffer=CreateListBox(0,0,0,0,Desktop(),0)
	AddGadgetItem CStringPuffer," " ;creates index 0
End Function

Function DG_CStringPointer(PointerString$) ;writes text into a memory block and returns pointer to it
	RemoveGadgetItem CStringPuffer,0
	AddGadgetItem CStringPuffer,PointerString$
	Local DataGridHwnd = QueryObject(CStringPuffer,1)
	Local ReturnText$
	Local Item.LVITEM = New LVITEM 
	Item\mask = LVIF_TEXT 
	Item\iSubItem = 0 ;ColumnNr 
	Item\iItem = 0 ;RowNr
	Item\pszText = CreateBank(0) ;bad but necessary to get a valid memory pointer even if it is a blitz internal one
	Item\cchTextMax = 255
	api_SendMessage(DataGridHwnd,LVM_GETITEMA,0,Item)
	Return Item\pszText	
End Function

Function DG_StringFromCPointer$(IntPointer) ;returns text out of a memory block where it points to
	Local DataGridHwnd = QueryObject(CStringPuffer,1) 
	Local Item.LVITEM = New LVITEM 
	Item\mask = LVIF_TEXT 
	Item\iSubItem = 0 ;ColumnNr 
	Item\iItem = 0 ;RowNr 
	Item\pszText = IntPointer
	Item\cchTextMax = 255
	api_SendMessage(DataGridHwnd,LVM_SETITEMA,0,Item)
	Return GadgetItemText$(CStringPuffer,0)
End Function

Function DG_Free_CStringMem() ;free memory block for c-string in the form of a invisible listbox
	FreeGadget CStringPuffer
End Function

Function DG_SelectedRows$(DataGrid) ;just an expample how to do
	Local DataGridHwnd = QueryObject(DataGrid,1)
	Local SelectedRows$ = ""
	Local item = -1
	Repeat
		item = SendMessage (DataGridHwnd, LVM_GETNEXTITEM, item, LVNI_SELECTED) 
		If item <> -1
			SelectedRows$ = SelectedRows$ + item +","
		EndIf
	Until item = -1
	Return Left$(SelectedRows$,Len(SelectedRows$)-1)
End Function

Function DG_Create(XPos,YPos,Width,Height,MaxColumns,MaxRows,Group,Style=0)
	Dim DG_Content$(MaxColumns,MaxRows) ;maximum dimensions of DataGrid cells
	DG_Ini_CStringMem()
	Return CreateListBox(XPos,YPos,Width,Height,Group,Style)
End Function

Function DG_ClickedColumn(DataGrid)
	;does not work properly if list has been horizontally scrolled!
	Local hwnd=QueryObject(DataGrid,1)
	Local xrel=MouseX()-hwnd_gadgetx(hwnd)-1
	If xrel<0 Or xrel>GadgetWidth(DataGrid) Then Return -1
	Local colnr=0
	Local xpos=0
	Repeat
		xpos=xpos+DG_GetColumnWidth(DataGrid,colnr)
		If xpos<xrel Then colnr=colnr+1
	Until xpos>=xrel
	Return colnr
End Function

Function DG_Free(DataGrid)
	FreeGadget DataGrid
	DG_Free_CStringMem()
End Function

Function hwnd_gadgetx(hwnd)
	Local winpos.lpRECT = New lpRECT
	api_GetWindowRect%(hwnd,winpos)
	Return winpos\x1
End Function

Function hwnd_gadgety(hwnd)
	Local winpos.lpRECT = New lpRECT
	api_GetWindowRect%(hwnd,winpos)
	Return winpos\y1
End Function



;***********************************************
;					EXAMPLE
;***********************************************

win=CreateWindow("DataGrid Example (Multicolumn Listbox)",100,100,550,500)

dg=DG_Create(0,0,550,500,50,100,win) ;DG_Create(XPos,YPos,Width,Height,MaxColumns,MaxRows,Group[,Style]) > Create DataGrid Gadget

Style=LVS_EX_GRIDLINES Or LVS_EX_FULLROWSELECT Or LVS_EX_ONECLICKACTIVATE
DG_SetExtendedStyle(dg,Style,$000000,$cfffff,1) ;DG_SetExtendedStyle(DataGrid,Style,txtcolor,bgcolor,multirowselect) > Set Style of DataGrid / color = bbggrr


For aa=0 To 9
	DG_AddColumn(dg,aa,50) ;DG_AddColumn(DataGrid,ColumnNr,Width) > Add a column to the DataGrid
	DG_SetHeading(dg,aa,"Col_"+aa) ;DG_SetHeading(DataGrid,ColumnNr,HeadingText$[,Style]) > Set the column header text (headline)
Next

;DG_SetColumnWidth(dg,0,100) ;DG_SetColumnWidth(DataGrid,ColumnNr,Width)  > Set the column width

For bb=0 To 20
	For aa=0 To 9
		DG_ModifyItem(dg,aa,bb,"test"+aa+"-"+bb) ;DG_ModifyItem(DataGrid,ColumnNr,RowNr,TextContent$) > Create cell and fill with text
	Next
Next

Repeat
	we=WaitEvent(20)
	If we=1025 Then
		selrows$=DG_SelectedRows$(dg) ;just for example how to get marked rows
		info$="Selected row(s) no.: "+selrows$+Chr$(13)+Chr$(13)
		If Instr(selrows$,",")=0 And selrows$<>"" Then
			;if only one row is selected...
			info$=info$+"Clicked into field (x,y): "+DG_ClickedColumn(dg)+","+selrows$+Chr$(13)
			info$=info$+"Field Content: "+DG_GetItemText$(dg,DG_ClickedColumn(dg),Int(selrows$)) ;DG_GetItemText$(DataGrid,ColumnNr,RowNr) > Get cell content
		End If
		Notify info$
	End If
Until we=$803

DG_Free(dg)