List-View label editing for subitems

Windows specific forum
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

List-View label editing for subitems

Post by Fluid Byte »

The included code demonstrates how to edit the labels of subitems of a List-View control. It obtains the handle of the Edit control, initializes it with the text of the appropiate subitem and repositions it accordingly via a callback.

The problem is that the label of the item in the first column is always empty. I assume this is because normally the edit control would be over that item (without repositioning it) and you won't recognize it. I already tried to change the text via SetGadgetItemText() but it doesn't have any effect. Actually this should be perfectly normal because as long as the edit control is on screen the program doesn't recieve any input.

Code: Select all

#LST_Items = 101

OpenWindow(0,0,0,320,240,"void",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
CreateGadgetList(WindowID(0))
ListIconGadget(#LST_Items,5,5,310,230,"Firstname",100,#PB_ListIcon_FullRowSelect | #PB_ListIcon_GridLines | #LVS_EDITLABELS)
AddGadgetColumn(#LST_Items,1,"Lastname",100)

AddGadgetItem(#LST_Items,-1,"Steve" + Chr(10) + "Martin")
AddGadgetItem(#LST_Items,-1,"John" + Chr(10) + "Candy")
AddGadgetItem(#LST_Items,-1,"Chavey" + Chr(10) + "Chase")
AddGadgetItem(#LST_Items,-1,"Eddie" + Chr(10) + "Murphy")

Global lpPrevFunc

Procedure EditLabelProc(hWnd,uMsg,wParam,lParam)
    Select uMsg
        Case #WM_WINDOWPOSCHANGING
			Protected *lpwp.WINDOWPOS = lParam
			
			*lpwp\x = GetGadgetItemAttribute(#LST_Items,0,#PB_ListIcon_ColumnWidth) + 4

			ProcedureReturn 0
    EndSelect
     
    ProcedureReturn CallWindowProc_(lpPrevFunc,hWnd,uMsg,wParam,lParam)
EndProcedure

Procedure WindowCallback(hWnd,uMsg,wParam,lParam)
	Select uMsg
		Case #WM_NOTIFY
		*nmh.NMHDR = lParam
		 		
		If *nmh\hwndFrom = GadgetID(#LST_Items)
			Select *nmh\code
				Case #LVN_BEGINLABELEDIT
				Protected hwndLVEdit = SendMessage_(*nmh\hwndFrom,#LVM_GETEDITCONTROL,0,0)
				Protected Result$ = GetGadgetItemText(#LST_Items,GetGadgetState(#LST_Items),1)
				
				SendMessage_(hwndLVEdit,#WM_SETTEXT,0,@Result$)
				
				lpPrevFunc = SetWindowLong_(hwndLVEdit,#GWL_WNDPROC,@EditLabelProc())

				ProcedureReturn 0
								
				Case #LVN_ENDLABELEDIT
				*nmpdi.NMLVDISPINFO = lParam
				
				If *nmpdi\item\pszText
					SetGadgetItemText(#LST_Items,GetGadgetState(#LST_Items),PeekS(*nmpdi\item\pszText),1)
				EndIf
				
				ProcedureReturn 0
			EndSelect
		EndIf
		
		ProcedureReturn 0	
	EndSelect
	
	ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

SetWindowCallback(@WindowCallback())

While WaitWindowEvent() ! #PB_Event_CloseWindow : Wend
* ACTIVATES BATSIGNAL *
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Without taking a close look, my first thought is to create a column 0 with a width of 0, lock that column so it can't be resized, and then readjust your code from there.

I'll see if there is a better way when I get a chance or maybe wait until srod gets his arse over here. :P
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

After further review, I'd say you'll have to catch NM_CUSTOMDRAW and do some drawing yourself. If I get a chance, I'll post code later. :)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

@Fluid : I released some code in the tips and tricks section which allows you to edit any cell in a List-View control using exactly this same method. I came across the same problem and decided in the end to simply set the width of column zero to 0 - as Sparkie suggested. :)
I may look like a mule, but I'm not a complete ass.
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Here's some code hacked together that will get you started. It's in need of some TLC so it's up to you to finish it. :P

Code: Select all

#LST_Items = 0 

Global lpPrevFunc  

Procedure EditLabelProc(hwnd,uMsg,wParam,lParam) 
  Select uMsg 
    Case #WM_WINDOWPOSCHANGING 
      Protected *lpwp.WINDOWPOS = lParam 
      
      *lpwp\x = GetGadgetItemAttribute(#LST_Items,0,#PB_ListIcon_ColumnWidth) + 4 
      
      ProcedureReturn 0 
  EndSelect 
  
  ProcedureReturn CallWindowProc_(lpPrevFunc,hwnd,uMsg,wParam,lParam) 
EndProcedure 

Procedure myWindowCallback(hwnd, msg, wParam, lParam) 
  result = #PB_ProcessPureBasicEvents 
  Select msg 
    Case #WM_NOTIFY 
      *nmhdr.NMHDR = lParam 
      *lvCD.NMLVCUSTOMDRAW = lParam 
      
      If *nmhdr\hwndFrom = GadgetID(#LST_Items) 
        Select *nmhdr\code 
          Case #LVN_BEGINLABELEDIT 
            Protected hwndLVEdit = SendMessage_(*nmhdr\hwndFrom,#LVM_GETEDITCONTROL,0,0) 
            Protected Result$ = GetGadgetItemText(#LST_Items,GetGadgetState(#LST_Items),1) 
            
            SendMessage_(hwndLVEdit,#WM_SETTEXT,0,@Result$) 
            
            lpPrevFunc = SetWindowLong_(hwndLVEdit,#GWL_WNDPROC,@EditLabelProc()) 
            
            ProcedureReturn 0 
            
          Case #LVN_ENDLABELEDIT 
            *nmpdi.NMLVDISPINFO = lParam 
            
            If *nmpdi\item\pszText 
              SetGadgetItemText(#LST_Items,GetGadgetState(#LST_Items),PeekS(*nmpdi\item\pszText),1) 
            EndIf 
            
            ProcedureReturn 0 
        EndSelect 
      EndIf 
      
      If *lvCD\nmcd\hdr\hwndFrom  = GadgetID(0) And *lvCD\nmcd\hdr\code = #NM_CUSTOMDRAW    
        Select *lvCD\nmcd\dwDrawStage 
          Case #CDDS_PREPAINT 
            result = #CDRF_NOTIFYITEMDRAW 
          Case #CDDS_ITEMPREPAINT 
            result = #CDRF_DODEFAULT | #CDRF_NOTIFYPOSTPAINT 
          Case #CDDS_ITEMPOSTPAINT 
            thisRow = *lvCD\nmcd\dwItemSpec 
            thisCol = *lvCD\iSubItem 
            ;... Define rect for text 
            subItemRect.RECT\left = #LVIR_LABEL 
            subItemRect.RECT\top = *lvCD\iSubItem 
            ;... Get the subitem rect 
            SendMessage_(*lvCD\nmcd\hdr\hwndFrom, #LVM_GETSUBITEMRECT, thisRow, @subItemRect) 
            subItemText$ = GetGadgetItemText(0, thisRow, thisCol) 
            FillRect_(*lvCD\nmcd\hdc, subItemRect, GetStockObject_(#WHITE_BRUSH))
            ;.. Set left margin 
            subItemRect\left + 3 
            DrawText_(*lvCD\nmcd\hdc, subItemText$, Len(subItemText$), subItemRect, #DT_WORD_ELLIPSIS | #DT_SINGLELINE | #DT_VCENTER) 
            result = #CDRF_DODEFAULT
        EndSelect 
      EndIf 
  EndSelect 
  ProcedureReturn result 
EndProcedure 

If OpenWindow(0, 0, 0, 480, 260, "Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) 
  SetWindowCallback(@myWindowCallback()) 
  ListIconGadget(#LST_Items, 10, 10, 470, 225, "Firstname", 100, #PB_ListIcon_FullRowSelect | #PB_ListIcon_GridLines | #PB_ListIcon_AlwaysShowSelection | #LVS_EDITLABELS) 
  AddGadgetColumn(#LST_Items, 1, "Lastname", 100) 
  AddGadgetItem(#LST_Items,-1,"Steve" + Chr(10) + "Martin") 
  AddGadgetItem(#LST_Items,-1,"John" + Chr(10) + "Candy") 
  AddGadgetItem(#LST_Items,-1,"Chavey" + Chr(10) + "Chase") 
  AddGadgetItem(#LST_Items,-1,"Eddie" + Chr(10) + "Murphy") 
  Repeat 
    event = WaitWindowEvent() 
  Until event = #PB_Event_CloseWindow 
   
EndIf 
End 
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

Indeed that does the Job quite well! :o

Thanks Sparkman!

Image

Da,da,da,DAAAAAAH, dah ... (gotta love this theme)
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
Post Reply