ich habe mich mal die Woche hingesetzt und ein kleines Beispiel für das
ListIconGadget gebastelt, mit dem man über einen einfachen Callback das
Editieren der einzelnen Einträge ermöglichen kann. Statt einem Editierfeld ist es auch möglich eine Liste aufklappen zu lassen, mit der man sein
Auswahl treffen möchte.
///Edit 1 (16.04.2008, 23:41)
Fixed: ListBox wurde nicht komplett dargestellt, wenn man einen unteren Eintrag ausgewählt hat
///Edit 2 (17.04.2008, 17:13)
New: In der ListBox wird jetzt beim Öffnen der erste Eintrags ausgewählt, der mit dem String in der gewählten Zelle beginnt. Dabei wird Groß- und Kleinschreibung ignoriert.
Hier also die Include:
Code: Alles auswählen
EnableExplicit
Prototype ListIconGadget_Request(GadgetID.l, row.l, column.l, msg.l, *out, *userdata)
Enumeration 1
;Msg
#ListIconGadget_Click
#ListIconGadget_EditChange
#ListIconGadget_EditEscape
;Return für *out
#ListIconGadget_NoOpen
#ListIconGadget_Edit
#ListIconGadget_List
EndEnumeration
;Hier kann man maximal 32768 angeben. Mehr Zeichen unterstützt das Edit Control nicht.
#ListIconGadget_MaxChars = 1024
Structure ListIconGadget_S
id.l
*hnd
msg.l[4]
direct.l
*oldCB
*hedit
item.l
subitem.l
type.l
r.RECT
*edit_oldCb
*requestCB.ListIconGadget_Request
*userdata
EndStructure
;Der Callback für das ListIconGadget
Procedure ListIconGadget_CB(hwnd.l, Msg.l, wParam.l, lParam.l)
Protected *li.ListIconGadget_S = GetWindowLong_(hwnd, #GWL_USERDATA)
Protected hit.LVHITTESTINFO, itemdata.LVITEM, open.l, *out, *c.Character, char.c, *begin
Protected minpos.l, maxpos.l, cpp.l, delta.l, i.l, length.l, type.l, client.RECT
If hwnd = *li\hnd
Select Msg
Case *li\msg[0], *li\msg[1], *li\msg[2], *li\msg[3]
;Case #WM_LBUTTONDOWN, #WM_LBUTTONDBLCLK
;Mauskoordinaten relativ zum Gadget
hit\pt\x = lparam & $FFFF
hit\pt\y = (lparam >> 16) & $FFFF
;Zeile und Spalte ermitteln
SendMessage_(hwnd, #LVM_SUBITEMHITTEST, 0, hit)
If hit\iItem >= 0
If *li\requestCB
type = *li\requestCB(*li\id, hit\iItem, hit\iSubitem, #ListIconGadget_Click, @*out, *li\userdata)
Else
type = #ListIconGadget_Edit
EndIf
;Koordinaten des Eintrags errechnen
*li\r\left = #LVIR_BOUNDS
*li\r\top = hit\iSubItem
SendMessage_(hwnd, #LVM_GETSUBITEMRECT, hit\iItem, *li\r)
If hit\iSubItem = 0 ;Bei erster Spalte muss die Breite korrigiert werden
*li\r\left - 2
*li\r\right = *li\r\left + SendMessage_(hwnd, #LVM_GETCOLUMNWIDTH, 0, 0) + 2
EndIf
;Text des Eintrags auslesen
itemdata\iSubItem = hit\iSubItem
itemdata\pszText = AllocateMemory((#ListIconGadget_MaxChars + 1) * SizeOf(Character))
itemdata\cchTextMax = #ListIconGadget_MaxChars
SendMessage_(hwnd, #LVM_GETITEMTEXT, hit\iItem, itemdata)
;Falls schon Edit Control/ListBox besteht, dann schließen und Änderungen übernehmen
If *li\hedit
Select *li\type
Case #ListIconGadget_Edit
SendMessage_(*li\hedit, #WM_KILLFOCUS, #VK_RETURN, 0)
Case #ListIconGadget_List
SendMessage_(*li\hedit, #WM_KILLFOCUS, #VK_ESCAPE, 0)
EndSelect
If Not *li\direct : ProcedureReturn 0 : EndIf
EndIf
Select type
Case #ListIconGadget_NoOpen
ProcedureReturn 0
;do nothing
Case #ListIconGadget_Edit ;{
*li\type = type
*li\r\left + 6
*li\r\bottom - 1
;neues StringGadget erstellen
*li\hedit = CreateWindow_("edit", 0, #ES_AUTOHSCROLL | #WS_CHILD | #ES_LEFT, *li\r\left, *li\r\top, *li\r\right - *li\r\left, *li\r\bottom - *li\r\top, *li\hnd, 0, GetWindowLong_(*li\hnd, #GWL_HINSTANCE), 0)
If *li\hedit
;Text zuweisen
SendMessage_(*li\hedit, #WM_SETFONT, SendMessage_(hwnd, #WM_GETFONT, 0, 0), 0)
SendMessage_(*li\hedit, #EM_REPLACESEL, #False, itemdata\pszText)
*li\item = hit\iItem
*li\subitem = hit\iSubItem
SetWindowLong_(*li\hedit, #GWL_USERDATA, *li)
*li\edit_oldCB = SetWindowLong_(*li\hedit, #GWL_WNDPROC, @ListIconGadget_CB())
ShowWindow_(*li\hedit, #SW_SHOW)
SetFocus_(*li\hedit)
EndIf
If itemdata\pszText : FreeMemory(itemdata\pszText) : EndIf
ProcedureReturn 0 ;}
Case #ListIconGadget_List ;{
*li\type = type
*li\r\left + 6
*li\r\bottom = *li\r\top + (*li\r\bottom - *li\r\top) * 6 - 1
GetClientRect_(hwnd, client)
If *li\r\bottom > client\bottom
*li\r\top - (*li\r\bottom - client\bottom)
*li\r\bottom = client\bottom
EndIf
;neue ListBox erstellen
*li\hedit = CreateWindow_("listbox", 0, #WS_VSCROLL | #WS_CHILD | #WS_BORDER, *li\r\left, *li\r\top, *li\r\right - *li\r\left, *li\r\bottom - *li\r\top, *li\hnd, 0, GetWindowLong_(*li\hnd, #GWL_HINSTANCE), 0)
If *li\hedit
SendMessage_(*li\hedit, #WM_SETFONT, SendMessage_(hwnd, #WM_GETFONT, 0, 0), 0)
*li\item = hit\iItem
*li\subitem = hit\iSubItem
SetWindowLong_(*li\hedit, #GWL_USERDATA, *li)
*li\edit_oldCB = SetWindowLong_(*li\hedit, #GWL_WNDPROC, @ListIconGadget_CB())
ShowWindow_(*li\hedit, #SW_SHOW)
SetFocus_(*li\hedit)
If *out
*c = *out
char = *c\c
*c + SizeOf(Character)
*begin = *c
i = 0
Repeat
If *c\c = char
If *c = *begin
Break
Else
*c\c = 0
SendMessage_(*li\hedit, #LB_ADDSTRING, 0, *begin)
*begin = *c + SizeOf(Character)
i + 1
EndIf
EndIf
*c + SizeOf(Character)
ForEver
FreeMemory(*out)
SendMessage_(*li\hedit, #LB_SELECTSTRING, -1, itemdata\pszText)
EndIf
EndIf
If itemdata\pszText : FreeMemory(itemdata\pszText) : EndIf
ProcedureReturn 0 ;}
EndSelect
EndIf
Case #WM_PAINT ;{
If *li\hedit
;Koordinaten des Eintrags errechnen
*li\r\left = #LVIR_BOUNDS
*li\r\top = *li\subitem
SendMessage_(hwnd, #LVM_GETSUBITEMRECT, *li\item, *li\r)
If *li\subitem = 0 ;Bei erster Spalte muss die Breite korrigiert werden
*li\r\left - 2
*li\r\right = *li\r\left + SendMessage_(hwnd, #LVM_GETCOLUMNWIDTH, 0, 0) + 2
EndIf
Select *li\type
Case #ListIconGadget_Edit
*li\r\left + 6
*li\r\bottom - 1
MoveWindow_(*li\hedit, *li\r\left, *li\r\top, *li\r\right - *li\r\left, *li\r\bottom - *li\r\top, 0)
Case #ListIconGadget_List
*li\r\left + 6
*li\r\bottom = *li\r\top + (*li\r\bottom - *li\r\top) * 6 - 1
GetClientRect_(hwnd, client)
If *li\r\bottom > client\bottom
*li\r\top - (*li\r\bottom - client\bottom)
*li\r\bottom = client\bottom
EndIf
MoveWindow_(*li\hedit, *li\r\left, *li\r\top, *li\r\right - *li\r\left, *li\r\bottom - *li\r\top, 0)
EndSelect
InvalidateRect_(*li\hedit, 0, 0)
;Komplette erste Spalte neuzeichnen
client\top = 0
client\left = *li\r\left
client\bottom = *li\r\bottom
client\right = *li\r\right
InvalidateRect_(hwnd, client, 0)
EndIf ;}
;Aufpassen, dass das Edit Control nicht nach oben oder unten aus dem Fenster rutscht, links und rechts ist egal (vorerst)
Case #WM_VSCROLL ;{
If *li\hedit
cpp = SendMessage_(hwnd, #LVM_GETCOUNTPERPAGE, 0, 0)
minpos = SendMessage_(hwnd, #LVM_GETTOPINDEX, 0, 0)
maxpos = minpos + cpp
Select wParam & $FFFF
Case #SB_THUMBPOSITION, #SB_THUMBTRACK
minpos = (wParam >> 16) & $FFFF
If *li\item < minpos Or *li\item >= minpos + cpp : ProcedureReturn 0: EndIf
Case #SB_LINEDOWN : If *li\item < minpos + 1 : ProcedureReturn 0 : EndIf
Case #SB_LINEUP : If *li\item >= maxpos - 1 : ProcedureReturn 0 : EndIf
Case #SB_PAGEDOWN : If *li\item < minpos + cpp : ProcedureReturn 0 : EndIf
Case #SB_PAGEUP : If *li\item >= maxpos - cpp : ProcedureReturn 0 : EndIf
Default : ProcedureReturn 0
EndSelect
EndIf ;}
;Wenn jemand rumscrollen will, lass das ja nicht zu :)
Case #WM_MOUSEWHEEL ;{
If *li\hedit
; delta = ((wParam >> 16) & $FFFF)
; If delta > $7FFF : delta = -$10000 + delta : EndIf
; minpos = SendMessage_(hwnd, #LVM_GETTOPINDEX, 0, 0)
; maxpos = minpos + cpp
ProcedureReturn 0
EndIf ;}
EndSelect
ProcedureReturn CallWindowProc_(*li\oldCB, hwnd, Msg, wParam, lParam)
;***********************************************
;**** EVENT HANDLING FOR THE OTHER CONTROLS ****
;***********************************************
ElseIf hwnd = *li\hedit
Select *li\type
Case #ListIconGadget_Edit ;{
;***********************************************
;***************** EDIT CONTROL ****************
;***********************************************
Select Msg
Case #WM_KILLFOCUS
;Text aus dem Stringgadget nehmen
itemdata\pszText = AllocateMemory((#ListIconGadget_MaxChars + 1) * SizeOf(Character))
PokeW(itemdata\pszText, #ListIconGadget_MaxChars)
SendMessage_(hwnd, #EM_GETLINE, 0, itemdata\pszText)
;Text in ListIconGadget schreiben und Speicher wieder freigeben
itemdata\iSubItem = *li\subitem
SendMessage_(*li\hnd, #LVM_SETITEMTEXT, *li\item, itemdata)
FreeMemory(itemdata\pszText)
;StringGadget schließen
DestroyWindow_(hwnd)
*li\hedit = 0
If *li\requestCB
*li\requestCB(*li\id, *li\item, *li\subitem, #ListIconGadget_EditChange, 0, *li\userdata)
EndIf
Case #WM_KEYDOWN
Select wParam
Case #VK_RETURN
;Text aus dem Stringgadget nehmen
itemdata\pszText = AllocateMemory((#ListIconGadget_MaxChars + 1) * SizeOf(Character))
PokeW(itemdata\pszText, #ListIconGadget_MaxChars)
SendMessage_(hwnd, #EM_GETLINE, 0, itemdata\pszText)
;Text in ListIconGadget schreiben und Speicher wieder freigeben
itemdata\iSubItem = *li\subitem
SendMessage_(*li\hnd, #LVM_SETITEMTEXT, *li\item, itemdata)
FreeMemory(itemdata\pszText)
;StringGadget schließen
DestroyWindow_(hwnd)
*li\hedit = 0
If *li\requestCB
*li\requestCB(*li\id, *li\item, *li\subitem, #ListIconGadget_EditChange, 0, *li\userdata)
EndIf
Case #VK_ESCAPE ;Wenn Escape gedrückt wurde
;StringGadget schließen
DestroyWindow_(hwnd)
*li\hedit = 0
If *li\requestCB
*li\requestCB(*li\id, *li\item, *li\subitem, #ListIconGadget_EditEscape, 0, *li\userdata)
EndIf
EndSelect
EndSelect
ProcedureReturn CallWindowProc_(*li\edit_oldCB, hwnd, Msg, wParam, lParam)
;}
Case #ListIconGadget_List ;{
;***********************************************
;******************* LIST BOX ******************
;***********************************************
Select msg
Case #WM_KILLFOCUS
*li\hedit = 0
DestroyWindow_(hwnd)
If *li\requestCB
*li\requestCB(*li\id, *li\item, *li\subitem, #ListIconGadget_EditEscape, 0, *li\userdata)
EndIf
Case #WM_LBUTTONUP
i = SendMessage_(hwnd, #LB_GETCURSEL, 0, 0)
If i >= 0
itemdata\cchTextMax = SendMessage_(hwnd, #LB_GETTEXTLEN, i, 0)
itemdata\pszText = AllocateMemory((itemdata\cchTextMax + 1) * SizeOf(Character))
SendMessage_(hwnd, #LB_GETTEXT, i, itemdata\pszText)
;Text in ListIconGadget schreiben und Speicher wieder freigeben
itemdata\iSubItem = *li\subitem
SendMessage_(*li\hnd, #LVM_SETITEMTEXT, *li\item, itemdata)
FreeMemory(itemdata\pszText)
*li\hedit = 0
DestroyWindow_(hwnd)
If *li\requestCB
*li\requestCB(*li\id, *li\item, *li\subitem, #ListIconGadget_EditChange, i, *li\userdata)
EndIf
EndIf
Case #WM_KEYDOWN
If wParam = #VK_ESCAPE
*li\hedit = 0
DestroyWindow_(hwnd)
If *li\requestCB
*li\requestCB(*li\id, *li\item, *li\subitem, #ListIconGadget_EditEscape, 0, *li\userdata)
EndIf
EndIf
EndSelect
ProcedureReturn CallWindowProc_(*li\edit_oldCB, hwnd, Msg, wParam, lParam)
;}
EndSelect
EndIf
EndProcedure
;Die Procedure zum Initialisieren von allem oben drüber
Procedure ListIconGadget_SetEditable(*li.ListIconGadget_S, *requestCB = 0, *userdata = 0)
*li\hnd = GadgetID(*li\id)
SetWindowLong_(*li\hnd, #GWL_USERDATA, *li)
*li\oldCB = SetWindowLong_(*li\hnd, #GWL_WNDPROC, @ListIconGadget_CB())
*li\requestCB = *requestCB
*li\userdata = *userdata
EndProcedure
Code: Alles auswählen
XIncludeFile "ListIconGadget editable.pbi"
;Der Callback macht folgendes:
;Bei Klick in die erste Spalte, klappt eine Auswahlliste aus
;Bei Klick in die zweite und dritte Spalte kann editiert werden
;Bei Klick in die dritte Spalte wechselt diese zwischen Ja und Nein
;Wenn man in Spalte 2 und 3 nichts eingegeben hat, dann wird '(nichts)' hineingeschrieben
Procedure requestEdit(GadgetID.l, row.l, column.l, msg.l, *out, *userdata)
Protected *pout.Long = *out
Select msg
Case #ListIconGadget_Click
If column = 0
*pout\l = AllocateMemory(1024)
If *pout\l
;Zuerst das Trennzeichen, dann die Elemente und dann zweimal das Trennzeichen
PokeS(*pout\l, ";Hallo;das;ist;die;Auswahlliste;für;die;" + Str(row) + ". Zeile;;")
;*pout\l wird danach wieder mit FreeMemory() freigegeben
ProcedureReturn #ListIconGadget_List
EndIf
ProcedureReturn #ListIconGadget_NoOpen
ElseIf column = 3
If GetGadgetItemText(GadgetID, row, column) = "Ja"
SetGadgetItemText(GadgetID, row, "Nein", column)
Else
SetGadgetItemText(GadgetID, row, "Ja", column)
EndIf
ProcedureReturn #ListIconGadget_NoOpen
EndIf
ProcedureReturn #ListIconGadget_Edit
Case #ListIconGadget_EditChange
If GetGadgetItemText(GadgetID, row, column) = ""
SetGadgetItemText(GadgetID, row, "(nichts)", column)
EndIf
Debug "Zeile " + Str(row) + ", Spalte " + Str(column) + " geändert: '" + GetGadgetItemText(GadgetID, row, column) + "'"
Case #ListIconGadget_EditEscape
Debug "Zeile " + Str(row) + ", Spalte " + Str(column) + " NICHT geändert: '" + GetGadgetItemText(GadgetID, row, column) + "'"
EndSelect
EndProcedure
Define li.ListIconGadget_S, i.l, s.s
If OpenWindow(0, 0, 0, 400, 300, "bla", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
If CreateGadgetList(WindowID(0))
li\id = ListIconGadget(#PB_Any, 0, 0, 400, 300, "Column0", 75, #PB_ListIcon_FullRowSelect | #PB_ListIcon_GridLines)
AddGadgetColumn(li\id, 1, "Column1", 75)
AddGadgetColumn(li\id, 2, "Column2", 75)
AddGadgetColumn(li\id, 3, "Column3", 75)
For i = 0 To 100
AddGadgetItem(li\id, i, "Row" + Str(i) + Chr(10) + "C1" + Chr(10) + "C2" + Chr(10) + "X")
Next
;Messages, bei denen reagiert werden soll
li\msg[0] = #WM_RBUTTONDOWN
li\msg[1] = #WM_RBUTTONDBLCLK
;Steht 'direct' auf #True, kann man von einem Edit direkt ins andere klicken
li\direct = #True
ListIconGadget_SetEditable(li, @requestEdit(), 2)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
EndIf
End