ich habe inzwischen den Überblick über die vielen Datagrids im Forum verloren und daher ein eigenes geschrieben. Wer Lust hat, möge es bitte testen. Manches wie die Anpassung an eine Datenbank bzw. Löschen und Hinzufügen von Datensätzen fehlt noch, ist aber relativ leicht zu ergänzen.
Die Grundidee: Man definiert ein Listicongadget als Datagrid und zu jeder Spalte einen geeigneten Datentyp, für den automatisch ein passendes Gadget (z.B. Dategadget oder ComboboxGadget erstellt wird.Durch Doppelklick auf ein Listenelement wird das Gadget für die Datenänderung aktiviert. Klickt man im Datenfenster außerhalb des aktivierten Gadgets, um dieses zu verlassen, wird dessen eingestellter Wert in das Listicongadget übernommen. Schwer zu beseitigender Schönheitsfehler: Nach dem Verlassen ist die Zeile mit dem zuvor aktivierten Gadget markiert, auch, wenn man zuvor woanders hinklickt, d.h: Es ist ein Mausklick mehr als nötig.
Code: Alles auswählen
;DataGrid mit diversen Datentypen (Windows only....)
;Autor ProgOldie (Fremdprogrammteile s. Prozeduren)
;Grundidee mit jeweils einem Spaltengadget von hjBremer.
;Allerdings hier nicht ausschließlich mit Stringgadgets,
;sondern mit Gadgets, die an den Datentyp angepasst sind.
EnableExplicit
;Bezeichner für die letztlich im ListIcon benutzten Datentypen
Global ColTypes.s="|INTEGER|FLOAT|ENUM|STRING|BOOLEAN|DATE|"
Structure Column
ColName.s
ColType.s
ColPref.s
ColNr.i ;Zählung beginnt ab 1
ColGadNr.i ;GadgetNr wie durch #PB_Any erzeugt
changeableCol.i ;Änderungen in dieser Spalte erlaubt?
EndStructure
Structure GridProps
x.i ;Eigenschaften des zugehörigen ListiconGadgets
y.i ;x,y Position
Width.i
Height.i
ListGadNr.i ;GadgetNr wie durch #PB_Any erzeugt
Cols.i ;Anzahl der bereits definierten Spalten
IDCol.i ;Spalte, die eindeutig eine Zeile definiert
; falls ein Gadget zum Bearbeiten aktiviert ist
activeCol.i
activeLine.i
List ColList.Column()
EndStructure
Procedure createGridProps(*GProps.GridProps,Title.s,x.i,y.i,Width.i,Height.i,IDCol.i)
;Die Zählung für SelectElement beginnt ab 0
Protected res.i
With *GProps
\Cols=0 ; noch keine Spalten definiert
\x=x
\y=y
\Width=\Width
\Height=Height
\activeLine=-1 ; noch kein Spaltengadget aktiv
\activeCol=-1
EndWith
res=ListIconGadget(#PB_Any,x,y,Width,Height,Title,60,#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
*GProps\ListGadNr=res
GadgetToolTip(res,"Edit: Doppelklick auf Listenelement")
If IDCol
*GProps\IDCol=IDCol
Else
MessageRequester("Hinweis","Keine ID-Spalte definiert")
EndIf
If ListSize(*GProps\ColList())=0
NewList *GProps\ColList()
EndIf
EndProcedure
Procedure.i make_Gadget(*GProps.GridProps) ;,DatType.s,Vorgabe.s,maxLen.i)
; Erzeugt an der Stelle x=0,y=0 im Fenster ein zu DatType passendes Gadget
; res ist die Nummer des Gadgets
;Die Datentypen für die Spalte müssen definiert sein
Protected res.i,W.i,H.i,Tip1.s,DatTyp1.s,ColPref.s,p.i,n.i
;Der Wert für H wird später noch automatisch angepasst
W=100
Tip1.s="<RET>:Ende <ESC>: Abbruch der Dateneingabe"
;ForEach *GProps\ColList()
DatTyp1=*GProps\ColList()\ColType
ColPref=*GProps\ColList()\ColPref
Select DatTyp1
Case "STRING" ;**Besser einen Typzusatz definieren, nach dem der Wert nicht angezeigt wird (gut in ColPref())
res=StringGadget(#PB_Any,0,0,W,H,"")
GadgetToolTip(res,"Typ=STRING;"+Tip1)
Case "INTEGER"
res=StringGadget(#PB_Any, 0,0,W,H,ColPref,#PB_String_Numeric)
GadgetToolTip(res,"Typ=INTEGER "+Tip1)
Case "DATE"
res=DateGadget(#PB_Any,0,0, W,H,"%dd.%mm.%yyyy",0)
GadgetToolTip(res,"Typ=DATE ")
Case "ENUM"
res=ComboBoxGadget(#PB_Any,0,0,W,H)
ColPref=RTrim(LTrim(ColPref,",")) ; ggf. , am Anfang bzw. Ende eliminieren
p=CountString(ColPref,",") +1 ; Zahl der Elemente ermitteln
;Fehler bei 0 Elementen noch nicht abgefangen
For n=1 To p
AddGadgetItem(res,-1,StringField(ColPref,n,","))
Next
;SetWindowLongPtr_(GadgetID(res),#GWL_STYLE,GetWindowLongPtr_(GadgetID(res),#GWL_STYLE) | #BS_BOTTOM)
GadgetToolTip(res,"Typ=ENUM ")
Case "FLOAT"
res=StringGadget(#PB_Any, 0,0,W,H,ColPref)
GadgetToolTip(res,"TYP=FLOAT "+Tip1)
Case "BOOLEAN"
res=ComboBoxGadget(#PB_Any,0,0, W,H)
;SetWindowLongPtr_(GadgetID(res),#GWL_STYLE,GetWindowLongPtr_(GadgetID(res),#GWL_STYLE) | #BS_TOP)
AddGadgetItem(res,-1,"JA")
AddGadgetItem(res,-1,"NEIN")
GadgetToolTip(res,"Typ=BOOLEAN ")
EndSelect
*GProps\ColList()\ColGadNr=res
HideGadget(res,1) ;Gadget für die Spalte zunächst unsichtbar
;Next
EndProcedure
Procedure addGridCol(*GProps.GridProps,Name.s,Type.s,Pref.s,changeable.i)
;changeable=1 : Die Spalte kann geändert werden.
;Trotzdem wird das zugehörige Gadget erzeugt (wg. ggf. neuem Datensatz)
If FindString(ColTypes,"|"+Type+"|")
AddElement(*GProps\ColList())
With *GProps\ColList()
\ColName=Name
\ColType=Type
\ColPref=Pref
\ColNr=*GProps\Cols+1
EndWith
If changeable
*GProps\ColList()\changeableCol=1
EndIf
*GProps\Cols=*GProps\Cols +1 ;Zahl der Spalten um 1 erhöhen
If *GProps\Cols=1 ;Falls 1. Spalte:Überschrift ändern
SetGadgetItemText(*GProps\ListGadNr,-1,Name)
Else
AddGadgetColumn(*GProps\ListGadNr,*GProps\ColList()\ColNr,Name,80) ; zusätzliche Spalte auch im Listicon
EndIf
Else
MessageRequester(Type,"undefinierter Spaltentyp")
EndIf
make_Gadget(*GProps.GridProps)
EndProcedure
Procedure LvMausclick(lvid,*p.Point)
;von hjBremer
;Zeile und Spalte des Mausklicks im Gadget mit der ID lvid
;ermitteln und in p.Point notieren
;Wert steht dann in p\x bzw. p\y (Zählung ab Zeile,Spalte =0)
Protected lvhit.LVHITTESTINFO
GetCursorPos_(*p) ;wo ist Maus
MapWindowPoints_(0, lvid, *p, 1) ;Cursorpos mappen zum LV
lvhit\pt\x = *p\x
lvhit\pt\y = *p\y
SendMessage_(lvid, #LVM_SUBITEMHITTEST, 0, lvhit)
*p\y = lvhit\iItem ;row ab 0
*p\x = lvhit\iSubItem ;col ab 0
EndProcedure
Procedure.i ColHeight(ListIcGadNr.i)
;Autor Fluid Byte
;setzt voraus, dass eine Zeile existiert
Protected lrc.RECT
lrc\left = #LVIR_LABEL
SendMessage_(GadgetID(ListIcGadNr),#LVM_GETITEMRECT,0,lrc)
ProcedureReturn lrc\bottom -lrc\top
EndProcedure
Procedure.i headerHeight(GadNr.i)
Protected LV_Header.i,RECT.RECT
LV_Header = SendMessage_(GadgetID(GadNr), #LVM_GETHEADER, 0, 0)
GetWindowRect_(LV_Header, @RECT)
ProcedureReturn RECT\Bottom-RECT\Top
EndProcedure
Procedure handleEvents(*Props.GridProps,aktDatWin.i)
Protected Ev.i,EventWin.i,EvType.i,EvGad.i,visGadNr.i,LIcNr.i,p.POINT,ColBeginx.i,RowBeginy.i
Protected Col.i,topIndex.i,aktColWidth.i,LGadHeight.i
Protected visGadText.s
AddKeyboardShortcut(aktDatWin,#PB_Shortcut_Return,13) ; RETURN für Übernahme der Gadgeteingabe
AddKeyboardShortcut(aktDatWin,#PB_Shortcut_Escape,27) ; ESC für Abbruch der Gadgeteingabe
LIcNr=*Props\ListGadNr
Repeat
Ev=WaitWindowEvent()
If Ev
EventWin=EventWindow()
If EventWin=aktDatWin ; Ereignis betrifft das Tabellenfenster
If Ev=#PB_Event_Gadget
EvType=EventType()
EvGad=EventGadget()
Select EvGad
Case LIcNr ; das Listicongadget wurde angeklickt
LvMausclick(GadgetID(LIcNr),@p.Point)
If (1+p\y) ;Gibt es im LIcGadget überhaupt eine Zeile?
SelectElement(*Props\ColList(),p\x) ;Welche Eigenschaften hat die Spalte?
If *Props\ColList()\changeableCol
ColBeginx=GadgetX(LIcNr) ;x-Offset Window-->ListiconGadget
RowBeginy=GadgetY(LIcNr) ;y-Offset Window
For Col=0 To p\x -1 ;aktuelle Längen der vorhergehenden Spalten addieren
ColBeginx+SendMessage_(GadgetID(LIcNr),#LVM_GETCOLUMNWIDTH,Col,0)
Next
;Horizontale Scrollposition abziehen
ColBeginx-GetScrollPos_(GadgetID(LIcNr),#SB_HORZ)
;Doppelklick in Zeile=1+p\y und Spalte=1+p\x Zählung jeweils ab 1
topIndex=1+SendMessage_(GadgetID(LIcNr), #LVM_GETTOPINDEX, 0, 0)
RowBeginy+headerHeight(LIcNr)+(1+p\y-topIndex)*ColHeight(LIcNr)
aktColWidth=SendMessage_(GadgetID(LIcNr),#LVM_GETCOLUMNWIDTH,p\x,0)
EndIf
EndIf
Select EvType
Case #PB_EventType_LeftDoubleClick ;Doppelklick auf ListiconGadget
If *Props\ColList()\changeableCol ;Spalte darf editiert werden
visGadNr=*Props\ColList()\ColGadNr
DisableGadget(visGadNr,0) ;Spaltengadget aktivieren
HideGadget(visGadNr,0)
ResizeGadget(visGadNr,ColBeginx+1,RowBeginy+1,aktColWidth,ColHeight(LIcNr)+3)
visGadText=GetGadgetItemText(LIcNr,p\y,p\x)
;+3, damit Schrift bei ComboBox besser lesbar ?
;Gadget sichtbar machen, mit Wert aus ListiconGadget vorbelegen und Focus darauf
Select *Props\ColList()\ColType
Case "STRING"
SetGadgetText(visGadNr,visGadText) ;LIcon_Inhalt zunächst übernehmen
Case "INTEGER"
SetGadgetText(visGadNr,visGadText) ;LIcon_Inhalt zunächst übernehmen
Case "FLOAT"
SetGadgetText(visGadNr,visGadText) ;LIcon_Inhalt zunächst übernehmen
Case "DATE"
SetGadgetState(visGadNr,ParseDate("%dd.%mm.%yyyy",visGadText))
Case "ENUM"
SetGadgetText(visGadNr,visGadText)
Case "BOOLEAN"
SetGadgetText(visGadNr,visGadText)
EndSelect
SetActiveGadget(visGadNr)
DisableGadget(LIcNr,1)
*Props\activeCol=p\x
*Props\activeLine=p\y
Else
MessageRequester("Forbidden action","Spalte darf nicht editiert werden")
EndIf
EndSelect
EndSelect
ElseIf Ev=#PB_Event_Menu And visGadNr ; Menü im Datenfenster bei aktivem Spaltengadget
If GadgetType(visGadNr)=#PB_GadgetType_String
Select EventMenu()
Case 13 ; Return-Taste gedrückt; Eingabe abgeschlossen;
HideGadget(visgadNr,1) ;SpaltenGadget unsichtbar machen
DisableGadget(LIcNr,0) ;Listicon wieder aktivieren
SetActiveGadget(LIcNr)
;If changed(*DWin,visGadNr,GetGadgetText(visGadNr),1+p\y,1+p\x) ;korrekt in DB übernommen?
SetGadgetItemText(LIcNr,p\y,GetGadgetText(visGadNr),p\x)
;EndIf
visGadNr=0 ; Gadget nicht mehr sichtbar
Case 27 ; ESC Abbruch Gadgetwert wird nicht übernommen
HideGadget(visGadNr,1)
DisableGadget(LIcNr,0)
SetActiveGadget(LIcNr)
visGadNr=0
EndSelect
EndIf
ElseIf Ev=#PB_Event_LeftClick And visGadNr
;kein GadgetEvent, aber Mausklick im Fenster-->Klick außerhalb des aktiven Gadgets
visGadText=GetGadgetText(visGadNr) ;Text des Spaltengadgets zwischenspeichern
HideGadget(visgadNr,1) ;SpaltenGadget unsichtbar machen
DisableGadget(visGadNr,1)
DisableGadget(LIcNr,0) ;Listicon wieder aktivieren
SetActiveGadget(LIcNr)
;If changed(*DWin,visGadNr,GetGadgetText(visGadNr),1+p\y,1+p\x) ;korrekt in DB übernommen?
SetGadgetItemText(LIcNr,*Props\activeLine,visGadText,*Props\activeCol)
*Props\activeCol=-1 ; ListGad_Eigenschaften:kein Spaltengadget mehr aktiv
*Props\activeLine=-1
visGadNr=0
;Hier evntuell noch über mit WindowMouseX und WindowMouseY ggf.
;Zeile und Spalte des Klicks zurückrechnen
;Debug "X="+Str(WindowMouseX(aktDatWin)) + "Y="+Str(WindowMouseY(aktDatWin))
ElseIf Ev=#PB_Event_CloseWindow
CloseWindow(aktDatWin)
EndIf
Else
;**** anderes Fenster als Tabellenfenster
EndIf
EndIf
Until EventWin=aktDatWin And Ev = #PB_Event_CloseWindow
EndProcedure
Procedure showGadParams(*GProps.GridProps)
;Listet die Eigenschaften der GadgetSpalten für Testzwecke auf
Protected ColText.s
ColText="Sp Nr , GadgetNr, SpName , SpTyp , SpPref"+Chr(10)
If ListSize(*GProps\ColList()) > 0 ;Spaltenliste nicht leer
ForEach *GProps\ColList()
ColText+"Sp"+Str(*GProps\ColList()\ColNr)+" "
ColText+Str(*GProps\ColList()\ColGadNr)+" "
ColText+*GProps\ColList()\ColName+" "
ColText+*GProps\ColList()\ColType+" "
ColText+*GProps\ColList()\ColPref+Chr(10)
Next
MessageRequester("Spaltenliste",ColText)
Else
MessageRequester("ListIconGadget","keine Spalten definiert")
EndIf
EndProcedure
Code: Alles auswählen
Define.GridProps TestGrid ;def. Eigenschaften eines Datengrids
OpenWindow(1,50,100,600,300,"Testwindow",#PB_Window_SystemMenu|#PB_Window_SizeGadget)
createGridProps(@TestGrid,"Datenfenster",1,1,600,300,1) ;def.TestGrid . Für spätere DB-Anwendungen (update):
;Spalte 1 definiert hier eindeutig die Zeile (z.B. ID)
;Spaltentypen des DataGrids definieren
addGridCol(@TestGrid,"ID","INTEGER","",0) ;0: Diese Spalte darf nicht geändert werden
addGridCol(@TestGrid,"ausgemustert","BOOLEAN","",1)
addGridCol(@TestGrid,"Artikel","STRING","",1) ;1: Spalteninhalt kann geändert werden
addGridCol(@TestGrid,"ArtikelNr","INTEGER","",1)
addGridCol(@TestGrid,"Kaufdatum","DATE","3.5.2012",1)
addGridCol(@TestGrid,"Zustand","ENUM","neu,gebraucht,wertlos",1) ;ComboBox mit 3 Auswahlmöglichkeiten
addGridCol(@TestGrid,"Anzahl","INTEGER","",1)
addGridCol(@TestGrid,"Einzelpreis","FLOAT","",1)
addGridCol(@TestGrid,"Abverkauf","BOOLEAN","",1) ;Für Boolean sind die Werte "JA,NEIN" vordefiniert
;DataGrid mit Werten füllen
AddGadgetItem(TestGrid\ListGadNr,-1,"1"+Chr(10)+"JA"+Chr(10)+"Zange"+Chr(10)+"249"+Chr(10)+"13.02.2011"+Chr(10)+"neu"+Chr(10)+"5"+Chr(10)+"3.20"+Chr(10)+"NEIN")
AddGadgetItem(TestGrid\ListGadNr,-1,"2"+Chr(10)+"JA"+Chr(10)+"Säge"+Chr(10)+"222"+Chr(10)+"25.07.2011"+Chr(10)+"gebraucht"+Chr(10)+"2"+Chr(10)+"5.50"+Chr(10)+"JA")
AddGadgetItem(TestGrid\ListGadNr,-1,"4"+Chr(10)+"JA"+Chr(10)+"Beil"+Chr(10)+"504"+Chr(10)+"03.08.2012"+Chr(10)+"neu"+Chr(10)+"6"+Chr(10)+"16.50"+Chr(10)+"NEIN")
AddGadgetItem(TestGrid\ListGadNr,-1,"5"+Chr(10)+"NEIN"+Chr(10)+"Pinzette"+Chr(10)+"249"+Chr(10)+"23.09.2011"+Chr(10)+"neu"+Chr(10)+"5"+Chr(10)+"1.54"+Chr(10)+"JA")
AddGadgetItem(TestGrid\ListGadNr,-1,"3"+Chr(10)+"NEIN"+Chr(10)+"Axt"+Chr(10)+"222"+Chr(10)+"04.07.2011"+Chr(10)+"gebraucht"+Chr(10)+"2"+Chr(10)+"34.50"+Chr(10)+"NEIN")
AddGadgetItem(TestGrid\ListGadNr,-1,"7"+Chr(10)+"NEIN"+Chr(10)+"Raspel"+Chr(10)+"504"+Chr(10)+"18.09.2012"+Chr(10)+"neu"+Chr(10)+"6"+Chr(10)+"16.50"+Chr(10)+"JA")
handleEvents(@TestGrid,1) ; dieser Aufruf darf erst nach Wertzuweisung zu einer Zeile erfolgen.