Listview with images and multline text

Just starting out? Need help? Post your questions and find answers here.
User avatar
Michael Vogel
Addict
Addict
Posts: 2680
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Listview with images and multline text

Post by Michael Vogel »

I'd like to create a window with one main gadget which looks like this:
Screenshot

I am unsure, if a CanvasGadget or a ListIconGadget would be the better choice - regarding the following needs:
  • there is just one symbol on the left but more text lines (in different font sizes) for each entry
  • each item has to selectable (by mouse and cursor keys)
  • scrolling is needed because there will be many items to show
  • the window (and so the gadget) should be resizable
  • the content may change from time to time so I need to redraw the list when needed
How would you do this?
BarryG
Addict
Addict
Posts: 3330
Joined: Thu Apr 18, 2019 8:17 am

Re: Listview with images and multline text

Post by BarryG »

What app is that window from? Because you could probably examine it with WinSpy++ to see what type of control it is, or if it's made up from more than type of control.
User avatar
Thorsten1867
Addict
Addict
Posts: 1366
Joined: Wed Aug 24, 2005 4:02 pm
Location: Germany

Re: Listview with images and multline text

Post by Thorsten1867 »

Try it with the new version of ListEx (look at: #Example = 1).
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 11 x64] [PB V5.7x]
User avatar
CELTIC88
Enthusiast
Enthusiast
Posts: 154
Joined: Thu Sep 17, 2015 3:39 pm

Re: Listview with images and multline text

Post by CELTIC88 »

A quick example using "listicon" may help you

Code: Select all

Global id_Listview
#ListIcon_separator_line = "&newline&"
#Font_height = 14
#ListIcon_NumberOfLine = 3

Procedure WinCallback(hWnd, uMsg, WParam, LParam)
	If uMsg = #WM_NOTIFY
		Protected *tNMHDR.NMHDR=lParam
		If *tNMHDR\hwndFrom = id_Listview
			Select *tNMHDR\code
				Case #NM_CUSTOMDRAW
					Protected *tNMCustomDraw.NMLVCUSTOMDRAW = lParam
					Select *tNMCustomDraw\nmcd\dwDrawStage
						Case #CDDS_PREPAINT               
							ProcedureReturn #CDRF_NOTIFYITEMDRAW
						Case #CDDS_ITEMPREPAINT
							ProcedureReturn #CDRF_NOTIFYSUBITEMDRAW
						Case #CDDS_ITEMPREPAINT | #CDDS_SUBITEM
							ProcedureReturn #CDRF_NOTIFYPOSTPAINT
						Case #CDDS_ITEMPOSTPAINT | #CDDS_SUBITEM
							Protected rec.rect\top = *tNMCustomDraw\iSubItem
							rec\left = #LVIR_LABEL
							If rec\top:rec\left = #LVIR_BOUNDS:EndIf
							SendMessage_(id_Listview, #LVM_GETSUBITEMRECT, *tNMCustomDraw\nmcd\dwItemSpec, rec)
							If SendMessage_(id_Listview, #LVM_GETITEMSTATE, *tNMCustomDraw\nmcd\dwItemSpec, #LVIS_SELECTED)
								FillRect_(*tNMCustomDraw\nmcd\hdc, rec, GetSysColorBrush_( #COLOR_HIGHLIGHT ))
							Else
								FillRect_(*tNMCustomDraw\nmcd\hdc, rec, CreateSolidBrush_( $FFFFFF ))
							EndIf
							Protected itstr.s =  GetGadgetItemText(0,*tNMCustomDraw\nmcd\dwItemSpec, *tNMCustomDraw\iSubItem)
							Protected rec2.rect
							Protected sbline =  ((rec\bottom - rec\top) -  #Font_height*#ListIcon_NumberOfLine) / #ListIcon_NumberOfLine
							SelectObject_( *tNMCustomDraw\nmcd\hdc, FontID(2) ) 
							Protected i:For i = 1 To CountString(itstr,#ListIcon_separator_line) + 1
								If i = 2 And *tNMCustomDraw\iSubItem And *tNMCustomDraw\nmcd\dwItemSpec = 0
									CopyStructure(rec, rec2,rect)
									rec2\bottom = rec2\top + #Font_height + sbline
									FillRect_(*tNMCustomDraw\nmcd\hdc, rec2, CreateSolidBrush_( $E5F6BB ))
									SelectObject_( *tNMCustomDraw\nmcd\hdc, FontID(3) ) 
								EndIf
								SetTextColor_( *tNMCustomDraw\nmcd\hdc,  Random($ffFFFF,0) )
								DrawText_(*tNMCustomDraw\nmcd\hdc, StringField(itstr, i,#ListIcon_separator_line),-1,rec,#DT_WORD_ELLIPSIS)
								rec\top + #Font_height + sbline
							Next
							ProcedureReturn #CDRF_NEWFONT                     
					EndSelect
					
			EndSelect
		EndIf
	EndIf
	ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

If OpenWindow(0, 100, 100, 400, 600, "ListIcon Example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	SetWindowCallback(@WinCallback())   
	ListIconGadget(0, 0, 0, 400, 600, "Name", 100, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection)
	
	;get listicon system id
	id_Listview = GadgetID(0)
	
	SendMessage_(id_Listview, #LVM_SETEXTENDEDLISTVIEWSTYLE, #LVS_EX_DOUBLEBUFFER, 0)
	;Set listicon default font
	LoadFont(0, "Arial", 22)
	SetGadgetFont(0, FontID(0))
	
	; Set height of ListView items
	LoadFont(1, "Arial", #Font_height*#ListIcon_NumberOfLine)
	SetGadgetFont(0, FontID(1))
	FreeFont(1)
	
	;Set lv header default height
	SendMessage_(SendMessage_(id_Listview ,#LVM_GETHEADER,0,0), #WM_SETFONT, FontID(0), 1)
	
	;use different fonts
	LoadFont(2, "Arial", #Font_height)
	LoadFont(3,"Arial", #Font_height-4, #PB_Font_StrikeOut|#PB_Font_Italic)
	
	AddGadgetColumn(0, 1, "Address", 250)
	UseJPEGImageDecoder()
	LoadImage(0, #PB_Compiler_Home + "Examples/3D/Data/Textures/Clouds.jpg")
	AddGadgetItem(0, -1, "Harry"+#ListIcon_separator_line+" Rannit"+Chr(10)+"12 Parliament Way, "+#ListIcon_separator_line+"Battle Street, "+#ListIcon_separator_line+"By the Bay",ImageID(0))
	AddGadgetItem(0, -1, "Ginger| Brokeit"+Chr(10)+"130 PureBasic Road, "+#ListIcon_separator_line+" BigTown, CodeCity")
	Repeat
		Event = WaitWindowEvent()
	Until Event = #PB_Event_CloseWindow
EndIf
Last edited by CELTIC88 on Sun Dec 01, 2019 9:56 am, edited 2 times in total.
interested in Cybersecurity..
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Listview with images and multline text

Post by IdeasVacuum »

Hi Michael

You might want to consider an HTML table (.html file). It can be constructed on-the-fly in PB and a bit of java script can report which row was clicked. That sort of thing is probably discussed on Spider Basic forum. I use HTML a lot for Android (but not with Spider Basic).
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
Michael Vogel
Addict
Addict
Posts: 2680
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Listview with images and multline text

Post by Michael Vogel »

Great - so many different approaches :shock:

BTW - the example shows the windows file explorer. All your ideas are fine, I will play around now. But it will take a while...

Tried to get a single column in ListExStart (which looks impressive): removed ListEx::#CheckBoxes and changed the column in the example to "0", but an empty column is seen at the moment. Anyhow, the multiline solution is not (absolute) perfect for me: while clicking an item, the text is seen in a single line then and it is not possible to have different font sizes for each text line).

Never would have thought for HTML - must also investigate this more deeply...

Found also a fine code from Stargate which could be changed easily to look perfect for me. But key handling (things like 'Tab', Ctrl+Cursor', etc.) and modifying the content (delete or change a single item, etc.) has to be done...

Code: Select all

; Define

	EnableExplicit

	Enumeration
		#FontTitle
		#FontTitleSelected
		#FontInfo
	EndEnumeration

	LoadFont(#FontTitle,"Segoe UI",20)
	LoadFont(#FontTitleSelected,"Segoe UI",20)
	LoadFont(#FontInfo,"Segoe UI",11)

	Structure ListImageGadgetOptions
		LineCount.i
		LineHeight.i
		LineWidth.i
		Space.i
		ImageWidth.i
		ImageHeight.i
		ImagePos.i
		TitleFont.i
		TitleFont_.i
		InfoFont.i
		TitlePos.i
		InfoPos.i
		ColorBackground.i
		ColorCursor.i
		ColorTitle.i
		ColorInfo1.i
		ColorInfo2.i
		ColorSelectedText.i
	EndStructure

	Structure ListImageGadgetItem
		Gadget.i
		State.i
		Title.s
		Info1.s
		Info2.s
		Image.i
		BackgroundImage.i
		BackgroundImageGadget.i
		ImageGadget.i
	EndStructure

	Global NewList ListImageGadgetItem.ListImageGadgetItem()
	Global Options.ListImageGadgetOptions

	With Options
		\LineCount=	0
		\LineHeight=	60
		\LineWidth=	540
		\Space=		10
		\ImageWidth= 60
		\ImageHeight=50
		\ImagePos=	(\LineHeight-\ImageHeight)>>1
		\TitleFont=	FontID(#FontTitle)
		\TitleFont_=	FontID(#FontTitleSelected)
		\InfoFont=	FontID(#FontInfo)
		\InfoPos=	Options\LineHeight-26
		\ColorBackground=	#White
		\ColorCursor=		$F6E0BE
		\ColorTitle=			$602000
		\ColorInfo1=			$604020
		\ColorInfo2=			\ColorInfo1
		\ColorSelectedText=	$000000
	EndWith

; EndDefine

Procedure ListImageGadget(Gadget, x, y, Width, Height)

	ScrollAreaGadget(Gadget,x,y,Width,Height,Width-30,1)
	CloseGadgetList()

	SetGadgetColor(Gadget,#PB_Gadget_BackColor,Options\ColorBackground)

EndProcedure
Procedure SetListImageGadgetItem(*ListImageGadgetItem.ListImageGadgetItem,State,Initialize=#Null)

	With *ListImageGadgetItem

		If State
			StartDrawing(ImageOutput(\BackgroundImage))
			Box(0,0,Options\LineWidth,Options\LineHeight,Options\ColorCursor)
			DrawAlphaImage(ImageID(\Image),Options\Space,Options\ImagePos)
			DrawingMode(#PB_2DDrawing_Transparent)
			DrawingFont(Options\TitleFont_)
			DrawText(Options\ImageWidth+Options\Space<<1,Options\TitlePos,\Title,Options\ColorSelectedText)
			DrawingFont(Options\InfoFont)
			DrawText(Options\ImageWidth+Options\Space<<1,Options\InfoPos,\Info1,Options\ColorSelectedText)
			DrawText(Options\LineWidth-Options\Space-TextWidth(\Info2),Options\InfoPos,\Info2,Options\ColorSelectedText)
			StopDrawing()

		Else
			StartDrawing(ImageOutput(\BackgroundImage))
			Box(0,0,Options\LineWidth,Options\LineHeight,Options\ColorBackground)
			DrawAlphaImage(ImageID(\Image),Options\Space,Options\ImagePos)
			DrawingMode(#PB_2DDrawing_Transparent)
			DrawingFont(Options\TitleFont)
			DrawText(Options\ImageWidth+Options\Space<<1,Options\TitlePos,\Title,Options\ColorTitle)
			DrawingFont(Options\InfoFont)
			DrawText(Options\ImageWidth+Options\Space<<1,Options\InfoPos,\Info1,Options\ColorInfo1)
			DrawText(Options\LineWidth-Options\Space-TextWidth(\Info2),Options\InfoPos,\Info2,Options\ColorInfo2)
			StopDrawing()

		EndIf
		If Initialize=#Null
			SetGadgetState(\BackgroundImageGadget, ImageID(\BackgroundImage))
		EndIf
		\State = State
	EndWith

EndProcedure
Procedure AddListImageGadgetItem(Gadget,Position,Title.s,Info1.s,Info2.s,Image)

	With ListImageGadgetItem()
		AddElement(ListImageGadgetItem())

		\Gadget= Gadget
		\State=	#False
		\Title=	Title
		\Info1=	Info1
		\Info2=	Info2
		\Image = Image
		\BackgroundImage = CreateImage(#PB_Any, Options\LineWidth,Options\LineHeight)

		SetListImageGadgetItem(ListImageGadgetItem(),0,#True)

		OpenGadgetList(Gadget)
		\BackgroundImageGadget=ImageGadget(#PB_Any,0,(Options\LineCount)*Options\LineHeight,ImageWidth(\BackgroundImage),ImageHeight(\BackgroundImage),ImageID(\BackgroundImage))
		CloseGadgetList()

		Options\LineCount+1
		SetGadgetAttribute(Gadget,#PB_ScrollArea_InnerHeight,Options\LineCount*Options\LineHeight+2)

	EndWith

EndProcedure
Procedure GetListImageGadgetState(Gadget)
	Protected Index
	ForEach ListImageGadgetItem()
		If ListImageGadgetItem()\Gadget = Gadget
			If ListImageGadgetItem()\State
				ProcedureReturn Index
				Break
			EndIf
			Index + 1
		EndIf
	Next
EndProcedure
Procedure.s GetListImageGadgetText(Gadget)
	ForEach ListImageGadgetItem()
		If ListImageGadgetItem()\Gadget = Gadget
			If ListImageGadgetItem()\State
				ProcedureReturn ListImageGadgetItem()\Title
				Break
			EndIf
		EndIf
	Next
EndProcedure
Procedure SetListImageGadgetState(Gadget, State)
	Protected Index
	ForEach ListImageGadgetItem()
		If ListImageGadgetItem()\Gadget = Gadget
			If ListImageGadgetItem()\State
				SetListImageGadgetItem(ListImageGadgetItem(), #False)
			EndIf
			If Index = State
				SetListImageGadgetItem(ListImageGadgetItem(), #True)
			EndIf
			Index + 1
		EndIf
	Next
EndProcedure
Procedure ListImageGadgetCallback(WindowID, Message, wParam, lParam)

	Protected *ListImageGadgetItem.ListImageGadgetItem

	With ListImageGadgetItem()

		If Message=#WM_COMMAND
			ForEach ListImageGadgetItem()
				If GadgetID(\BackgroundImageGadget) = lParam
					SetListImageGadgetItem(ListImageGadgetItem(), #True)
					SetActiveGadget(\Gadget)
					Break
				ElseIf GadgetID(\Gadget) = lParam
					SetActiveGadget(\Gadget)
				EndIf
			Next
			If IsGadget(\Gadget)
				ForEach ListImageGadgetItem()
					If \State = #True And GadgetID(\BackgroundImageGadget) <> lParam
						SetListImageGadgetItem(ListImageGadgetItem(), #False)
					EndIf
				Next
			EndIf

		ElseIf Message=#WM_KEYFIRST
			Select wParam

			Case #VK_RETURN
				Debug "* "+Str(GetListImageGadgetState(GetActiveGadget()))
				If GetKeyState_(#VK_SHIFT)&128
					Debug \BackgroundImage
					;Debug \BackgroundImageGadget
					;CreateImage(ListImageGadgetItem()\BackgroundImageGadget,20,20,32,#Red)
				Else
					SetListImageGadgetItem(ListImageGadgetItem(),1)
				EndIf

			Case #VK_UP
				If LastElement(ListImageGadgetItem())
					Repeat
						If GetActiveGadget() = \Gadget And \State = #True
							*ListImageGadgetItem = @ListImageGadgetItem()
							While PreviousElement(ListImageGadgetItem())
								If \Gadget = *ListImageGadgetItem\Gadget
									SetListImageGadgetItem(*ListImageGadgetItem, #False)
									SetListImageGadgetItem(ListImageGadgetItem(), #True)
									If GetGadgetAttribute(\Gadget, #PB_ScrollArea_Y) > GadgetY(\BackgroundImageGadget)-1
										SetGadgetAttribute(\Gadget, #PB_ScrollArea_Y, GadgetY(\BackgroundImageGadget)-1)
									EndIf
									Break
								EndIf
							Wend
							Break
						EndIf
					Until Not PreviousElement(ListImageGadgetItem())
				EndIf

			Case #VK_DOWN
				If FirstElement(ListImageGadgetItem())
					Repeat
						If GetActiveGadget() = \Gadget And \State = #True
							*ListImageGadgetItem = @ListImageGadgetItem()
							While NextElement(ListImageGadgetItem())
								If \Gadget = *ListImageGadgetItem\Gadget
									SetListImageGadgetItem(*ListImageGadgetItem, #False)
									SetListImageGadgetItem(ListImageGadgetItem(), #True)
									If GetGadgetAttribute(\Gadget, #PB_ScrollArea_Y) < GadgetY(\BackgroundImageGadget)+GadgetHeight(\BackgroundImageGadget)-GadgetHeight(\Gadget)+5
										SetGadgetAttribute(\Gadget, #PB_ScrollArea_Y, GadgetY(\BackgroundImageGadget)+GadgetHeight(\BackgroundImageGadget)-GadgetHeight(\Gadget)+5)
									EndIf
									Break
								EndIf
							Wend
							Break
						EndIf
					Until Not NextElement(ListImageGadgetItem())
				EndIf

			EndSelect

		EndIf
	EndWith

	ProcedureReturn #PB_ProcessPureBasicEvents

EndProcedure

SetWindowCallback(@ListImageGadgetCallback())

OpenWindow(0,0,0,600,440,"-*-",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ListImageGadget(1, 10, 10, 580, 380)
ButtonGadget(2,10,400, 580,30,"Quit")

Define n.i,event.i

For n = 1 To 20
	AddListImageGadgetItem(1, -1, "Title "+Str(n),"Information Text",Str(Random(20000)),CreateImage(#PB_Any,Options\ImageWidth,Options\ImageHeight,32,Random(#White)))
Next

SetActiveGadget(1)
SetListImageGadgetState(1,0)

Repeat
	Event = WaitWindowEvent()
	Select Event
	Case #PB_Event_CloseWindow
		End
	Case #PB_Event_Gadget
		Select EventGadget()
			Case 2
				End
			Debug "[_]"
		EndSelect
	Case #PB_Event_Menu
		Select EventMenu()
		Case 1
			Debug "_/¯"
		EndSelect
	EndSelect
ForEver
Post Reply