Habe Edels Beispiel mal etwas aufgepeppt. Es ist immer noch ein Beispiel, da Save + Load fehlen, aber doch etwas flexibler.
Code: Alles auswählen
;Bitte beachten: Ab PB 5.30 (x86)
DeclareModule LvCheckbox
; Alle Elemente in diesem Abschnitt sind für den Zugriff von außerhalb verfügbar
EnableExplicit
#PB_EventType_ChangeCheckBox = #PB_Event_FirstCustomValue + 100
Declare.i LvCheckbox_SetColumn(gadget, col, datacol = #PB_Any)
Declare.i LvCheckBox_GetState(gadget, row, col)
Declare.i LvCheckbox_Callback(hWnd, msg, wParam, lParam)
EndDeclareModule
Module LvCheckbox
; TODO Colors in extra Prozedur
; TODO Save + load ?
; TODO Multiselect checked abfragen
;Allgemein
; Verschieben von Spalten wird nicht unterstützt.
; Anhängen von Spalten ist gestattet,
; da es egal ist welche Spalte den Status der Checkboxen aufnimmt.
; Warum gibt es eine Statusspalte ? Wegen Save/Load !
; Warum braucht man einen MainCallback ? Weil #WM_DRAWITEM nur ans Parentwindow gesendet wird
; und darum Subclassing des ListIcongadgets so einfach nicht geht.
EnableExplicit
Structure checkboxdata
datacolumn.i ;Spalte welche den Status der Checkbox(en) enthält
colornormal.i ;Text normal
colorchecked.i ;Text wenn Checkbox hat Haken
colorselected.i ;Text wenn Checkbox hat Haken und Zeile select
colorbackbrush.i ;Hintergrund wenn Zeile select
Array checkbox.i(0) ;Internes Feld, Index gleich Spalte und ist 1 = hat Checkbox
EndStructure
Procedure.i CheckBox_State(gadget, row, col)
Protected t$, state
Protected *ckb.checkboxdata = GetWindowLongPtr_(GadgetID(gadget), #GWL_USERDATA)
If *ckb\checkbox(col)
t$ = GetGadgetItemText(gadget, row, *ckb\datacolumn)
If Mid(t$, col+1, 1) = "1"
state = #True
Else
state = #False
EndIf
EndIf
ProcedureReturn state
EndProcedure
Procedure.i LvCheckBox_GetState(gadget, row, col)
Protected state, boxdata$
Protected *ckb.checkboxdata = GetWindowLongPtr_(GadgetID(gadget), #GWL_USERDATA)
If *ckb
If row > -1
boxdata$ = GetGadgetItemText(gadget, row, *ckb\datacolumn)
If Mid(boxdata$, col + 1, 1) = "1"
state = 1
EndIf
EndIf
EndIf
ProcedureReturn state
EndProcedure
Procedure.i CheckBox_SetState(gadget, row, col, state)
Protected t$, l$, r$
Protected *ckb.checkboxdata = GetWindowLongPtr_(GadgetID(gadget), #GWL_USERDATA)
Protected datalg = ArraySize(*ckb\checkbox()) + 1
If *ckb\checkbox(col)
t$ = GetGadgetItemText(gadget, row, *ckb\datacolumn)
t$ = LSet(t$, datalg, "-")
l$ = Left(t$, col)
r$ = Mid(t$, col+2)
If state = 1
t$ = l$ + "1" + r$
Else
t$ = l$ + "0" + r$
EndIf
SetGadgetItemText(gadget, row, t$, *ckb\datacolumn)
EndIf
EndProcedure
Procedure.i LvCheckbox_SetColumn(gadget, col, datacol = #PB_Any)
Protected *ckb.checkboxdata = GetWindowLongPtr_(GadgetID(gadget), #GWL_USERDATA)
;internes Mem
If *ckb = #False
*ckb = AllocateStructure(checkboxdata)
SetWindowLongPtr_(GadgetID(gadget), #GWL_USERDATA, *ckb)
EndIf
;weils einfacher ist, Array immer Redim
Protected header = SendMessage_(GadgetID(gadget), #LVM_GETHEADER, 0, 0)
Protected colanz = SendMessage_(header, #HDM_GETITEMCOUNT, 0, 0) - 1
ReDim *ckb\checkbox(colanz)
;diese Column bekommt eine Checkbox
*ckb\checkbox(col) = #True
;in diese Col kommt der DataString
If datacol = #PB_Any
*ckb\datacolumn = colanz ;letzte Column
Else
*ckb\datacolumn = datacol ;User definierte Col
EndIf
;könnte auch in einer extra Prozedur stehen
*ckb\colornormal = #Black
*ckb\colorchecked = #Blue
*ckb\colorselected = $C20000
*ckb\colorbackbrush = $FFBFBF
EndProcedure
Procedure.i LvCheckbox_Callback(hWnd, msg, wParam, lParam)
;Variablen allgemein
Protected pbnr ;Gadgetnr
Protected pbid ;GadgetID()
Protected item ;Row
Protected subitem ;Column
Protected rc.RECT ;Rechteck einer Zelle
Protected *ckb.checkboxdata ;Userdaten für die Checkboxen
;Variablen #WM_NOTIFY
Protected *nmia.NMITEMACTIVATE
;Variablen #WM_DRAWITEM
Protected text.s
Protected head
Protected cols
Protected backbrush
Protected cc.RECT
Protected *draw.DRAWITEMSTRUCT
Select msg
Case #WM_NOTIFY
;- WM_notify
*nmia = lParam
; Click in das Listview ?
If *nmia\hdr\code = #NM_CLICK
pbnr = *nmia\hdr\idFrom
pbid = *nmia\hdr\hwndFrom
item = *nmia\iItem
subitem = *nmia\iSubItem
If IsGadget(pbnr)
If GadgetType(pbnr) = #PB_GadgetType_ListIcon
;Userdata holen
*ckb = GetWindowLongPtr_(pbid, #GWL_USERDATA)
If *ckb
;hat Subitem eine Checkbox ?
If *ckb\checkbox(subitem) = #True
rc\top = subitem
rc\left = #LVIR_BOUNDS
SendMessage_(pbid, #LVM_GETSUBITEMRECT, item, rc)
rc\left + 4
rc\right = rc\left + 14
; Click in die Checkbox?
If PtInRect_(rc, PeekQ(*nmia\ptAction))
;CheckBox_State speichern
If CheckBox_State(pbnr, item, subitem) = 0
;auf 1 setzen
CheckBox_SetState(pbnr, item, subitem, 1)
Else
CheckBox_SetState(pbnr, item, subitem, 0)
EndIf
;Neuzeichnen erzwingen
InvalidateRect_(pbid, 0, 0)
;Event abschicken
PostEvent(#PB_Event_Gadget, #PB_Ignore, pbnr, #PB_EventType_ChangeCheckBox, subitem)
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
Case #WM_DRAWITEM
;- #WM_DRAWITEM
*draw = lParam
If *draw\CtlType = #ODT_LISTVIEW
pbnr = *draw\CtlID
pbid = *draw\hwndItem
item = *draw\itemID
subitem = 0
If IsGadget(pbnr)
If GadgetType(pbnr) = #PB_GadgetType_ListIcon
;Userdata holen
*ckb = GetWindowLongPtr_(pbid, #GWL_USERDATA)
If *ckb
backbrush = CreateSolidBrush_(*ckb\colorbackbrush)
head = SendMessage_(pbid, #LVM_GETHEADER, 0, 0)
cols = SendMessage_(head, #HDM_GETITEMCOUNT, 0, 0) ; Spaltenanzahl
; alle Spalten durchlaufen
For subitem = 0 To cols - 1
;Rect für Subitem bis Ende der Zeile ermitteln
rc\top = subitem
rc\left = #LVIR_BOUNDS
SendMessage_(pbid, #LVM_GETSUBITEMRECT, item, rc)
; Ist die Zeile selektiert? dann blauer Balken (backbrush)
If *draw\itemState & #ODS_SELECTED
FillRect_(*draw\hdc, rc, backbrush)
EndIf
;Right begrenzen für aktuelles Subitem
rc\right = rc\left + GetGadgetItemAttribute(*draw\CtlID, *draw\itemID, #PB_ListIcon_ColumnWidth, subitem)
;Text holen
text = GetGadgetItemText(pbnr, item, subitem)
; ein wenig Luft in der Spalte, jeweils für Text und Checkbox
rc\left + 4
rc\right - 4
CopyRect_(cc, rc)
;für Checkbox muß \right kleiner sein
cc\right = cc\left + 16
SetTextColor_(*draw\hdc, *ckb\colornormal)
If *ckb\checkbox(subitem) = #True ; nur die definierten Spalten bekommen eine Checkbox !
; CheckBox_State abfragen und Checkbox zeichnen
If CheckBox_State(*draw\CtlID, *draw\itemID, subitem) = #True
If *draw\itemState & #ODS_SELECTED
SetTextColor_(*draw\hdc, *ckb\colorselected)
Else
SetTextColor_(*draw\hdc, *ckb\colorchecked)
EndIf
DrawFrameControl_(*draw\hDC, cc, #DFC_BUTTON, #DFCS_BUTTONCHECK | #DFCS_CHECKED)
Else
DrawFrameControl_(*draw\hDC, cc, #DFC_BUTTON, #DFCS_BUTTONCHECK)
EndIf
; Text verschieben
rc\left + 20
; Text zeichnen
DrawText_(*draw\hDC, text, -1, rc, #DT_SINGLELINE | #DT_VCENTER)
Else
; Text ohne Checkbox zeichnen
DrawText_(*draw\hDC, text, -1, rc, #DT_SINGLELINE | #DT_VCENTER)
EndIf
Next
DeleteObject_(backbrush)
EndIf
EndIf
EndIf
EndIf
EndSelect
EndProcedure
EndModule
UseModule LvCheckbox
Enumeration Window
#window
EndEnumeration
Enumeration Gadget
#list
#list2
#button0
#button1
#button2
#button3
#button4
EndEnumeration
Procedure.i MainCallback(hWnd, msg, wParam, lParam)
LvCheckbox_Callback(hWnd, msg, wParam, lParam)
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
Procedure Main()
Protected j, event, rowlv1, rowlv2
If OpenWindow(#window, #PB_Ignore, #PB_Ignore, 999, 400, "")
SetWindowCallback(@MainCallback())
ButtonGadget(#button0, 11, 350, 89, 22, "Col 0")
ButtonGadget(#button1, 111, 350, 89, 22, "Col 1")
ButtonGadget(#button2, 211, 350, 89, 22, "Col 2")
ButtonGadget(#button3, 311, 350, 89, 22, "Col 3")
ButtonGadget(#button4, 411, 350, 89, 22, "Col 4")
ListIconGadget(#list, 5, 10, 650, 300, "Col0", 111, #LVS_OWNERDRAWFIXED|#PB_ListIcon_GridLines|#PB_ListIcon_MultiSelect )
AddGadgetColumn(#list, 1, "Col1", 111)
AddGadgetColumn(#list, 2, "Col2", 111)
AddGadgetColumn(#list, 3, "Col3", 111)
AddGadgetColumn(#list, 4, "Col4", 111)
AddGadgetColumn(#list, 5, "Data", 70)
LvCheckbox_SetColumn(#list, 1)
LvCheckbox_SetColumn(#list, 2)
LvCheckbox_SetColumn(#list, 4) ;oder LvCheckbox_SetColumn(#list, 4, 5) 5 steht für DataColumn
For j = 0 To 23
AddGadgetItem(#list, -1, "Col0" + #LF$ + "Col1" + #LF$ + "Col2" + #LF$ + "Col3" + #LF$ + "Col4" + #LF$ + "00101")
AddGadgetItem(#list, -1, "Col0" + #LF$ + "Col1" + #LF$ + "Col2" + #LF$ + "Col3" + #LF$ + "Col4" + #LF$ + "01100")
AddGadgetItem(#list, -1, "Col0" + #LF$ + "Col1" + #LF$ + "Col2" + #LF$ + "Col3" + #LF$ + "Col4" + #LF$ + "01001")
Next
ListIconGadget(#list2, 680, 10, 300, 300, "Col0", 66, #LVS_OWNERDRAWFIXED|#LVS_NOCOLUMNHEADER|#PB_ListIcon_GridLines|#PB_ListIcon_MultiSelect )
AddGadgetColumn(#list2, 1, "Col1", 95)
AddGadgetColumn(#list2, 2, "Col2", 115)
AddGadgetColumn(#list2, 3, "Data", 0)
LvCheckbox_SetColumn(#list2, 1)
LvCheckbox_SetColumn(#list2, 2)
For j = 0 To 23
AddGadgetItem(#list2, -1, "Hans" + #LF$ + "Eier" + #LF$ + "Bananen" + #LF$ + "001")
AddGadgetItem(#list2, -1, "Otto" + #LF$ + "Grünkohl" + #LF$ + "Äpfel" + #LF$ + "011")
AddGadgetItem(#list2, -1, "Werner" + #LF$ + "Käse" + #LF$ + "Birnen" + #LF$ + "010")
Next
Repeat
event = WaitWindowEvent()
If event = #PB_Event_Gadget
rowlv1 = GetGadgetState(#list)
rowlv2 = GetGadgetState(#list2)
Select EventGadget()
Case #list
If EventType() = #PB_EventType_ChangeCheckBox
Debug "State ist jetzt " + LvCheckBox_GetState(#list, rowlv1, EventData())
EndIf
Case #list2
If EventType() = #PB_EventType_ChangeCheckBox
Debug "State ist jetzt " + LvCheckBox_GetState(#list2, rowlv2, EventData())
EndIf
Case #button0
Debug LvCheckBox_GetState(#list, rowlv1, 0)
Case #button1
Debug LvCheckBox_GetState(#list, rowlv1, 1)
Case #button2
Debug LvCheckBox_GetState(#list, rowlv1, 2)
Case #button3
Debug LvCheckBox_GetState(#list, rowlv1, 3)
Case #button4
Debug LvCheckBox_GetState(#list, rowlv1, 4)
EndSelect
EndIf
Until event = #PB_Event_CloseWindow
EndIf
EndProcedure
Main()