Kleiner Dateibetrachter für große Dateien (1.6 GB) Update
Verfasst: 14.03.2012 19:22
Habe mal einen alten Code an PB 4.6 angepasst. Weil ich gerade einen kleinen Dateiviewer brauchte.
Hoffe die Erklärungen im Code reichen um das virtuelle Listview (ListIconGadget) zu verstehen, gedacht für die unter uns, welche noch nie damit gearbeitet haben.
Ist als Stand Alone gedacht, aber ein jeder mag damit machen was er will.
Wer will kann noch eine Abfrage für die satzanzahl einbauen
Hinweis: Weiter unten habe ich ein Update eingestellt !
Hoffe die Erklärungen im Code reichen um das virtuelle Listview (ListIconGadget) zu verstehen, gedacht für die unter uns, welche noch nie damit gearbeitet haben.
Ist als Stand Alone gedacht, aber ein jeder mag damit machen was er will.
Wer will kann noch eine Abfrage für die satzanzahl einbauen
Hinweis: Weiter unten habe ich ein Update eingestellt !
Code: Alles auswählen
;ab PB 4.3 X86 - Windows XP
EnableExplicit
Enumeration
#menu
#menu_Datei
#menu_Ende
#menu_View
EndEnumeration
#columnanzahl = 4
#columnbytes = 4
#zeilenbytes = #columnanzahl * #columnbytes
#chrkleiner32 = 183
Structure vlv_variablen
window.i
lvnr.i
lvid.i
datnr.i
datname.s
dezimal.i
;müssen hier nicht sein, ist aber einfacher
datlg.i
satzlg.i
satzanz.i
;eine Zeile ist aufgeteilt in 4 Columns a 4 Bytes = 16 Bytes = 1.StructureUnion
;und in jeder Spalte beansprucht 1 Byte den Platz von 4 Zeichen, bestehend aus
;ein Space + 3 Zeichen für Dezimal Darstellung = 16 Bytes = 2.StructureUnion
StructureUnion
zeile.s{#zeilenbytes} ;nimmt eine Zeile auf = 16 Bytes
zchar.c[0] ;Bytezugriff auf die Zeile
EndStructureUnion
null1.c ;wichtig für StringEnde
StructureUnion
spalte.s{#zeilenbytes} ;eine einzelne Spalte, besteht aus 16 Bytes
spcols.s{#columnbytes}[0] ;für die einzelnen Columns einer Spalte, besteht aus je 4 Bytes
EndStructureUnion
null2.c
EndStructure
Global pvlv.vlv_variablen
Procedure.i VLV_GetSubItem(item, subitem)
;pvlv.mylvdaten ist global
;item ist die Zeile, subitem die Spalte
;der Callback verlangt zuerst subitem null für Column null
;pointer wird die Adresse eines Dummy$ zugewiesen, da diese Spalte leer bleibt.
;Dann werden die Daten für eine Zeile geladen nach \zeile. \satzlg ist Sizeof von \zeile
;dieser Bereich wird mit null gefüllt durch \zeile = "", weil beim Anzeigen der letzten Bytes
;einer Datei sonst ev. der Inhalt der vorherigen Zeile teilweise gezeigt wird.
;wir lesen also bei subitem 0 die Daten für eine ganze Zeile.
;wenn subitem 1 dran ist, weisen wir pointer die Adresse von \spalte zu
;dann schreiben wir die Byteposition in den String \spalte
;es werden subitem 2-5 angefordert
;pointer bleibt auf \spalte und wir zerlegen die Daten aus \zeile in die 4 Columns und
;schreiben diese Daten nach \spalte. Beim zerlegen hilft '\spcols' und '\zchar'.
;Durch StrukturUnion haben wir mit diesen Variablen Zugriff auf \spalte und \zeile.
;zuletzt ist subitem 6 für die Textausgabe dran. Wir benutzen die Adresse von \zeile = ganze Zeile.
;Wir müssen nun aber alle char < 32 austauschen gegen irgend ein anderes Zeichen
With pvlv
Static j, idx, byte, pointer ;kann auch Protected sein
Static dummy$ = " "
Static bytepos ;muß Static sein
Select subitem
Case 0 ;Column null ist die nicht sichtbare Spalte
pointer = @dummy$
bytepos = item * \satzlg
;könnte man zur Sicherheit einfügen,
;bytepos kann nur größer werden, wenn \satzanz zu groß
;If bytepos > \datlg: bytepos = \datlg: EndIf
\zeile = "" ;Inhalt löschen, wichtig für das Ende der Datei
FileSeek(\datnr, bytepos)
ReadData(\datnr, @\zeile, \satzlg)
Case 1
pointer = @\spalte
\spalte = Str(bytepos)
Case 2,3,4,5
pointer = @\spalte
idx = subitem - 2 ; - 2, weil 1.Datencolumn Col 2 ist
For j = 0 To #columnanzahl - 1 ; - 1, weil wir bei null anfangen
byte = #columnbytes * idx + j
If \dezimal
\spcols[j] = " " + RSet(Str(\zchar[byte]), 3, "0")
Else
\spcols[j] = " " + RSet(Hex(\zchar[byte]), 2, "0")
EndIf
Next
Case 6
pointer = @\zeile
;Char austauschen für Textausgabe
For j = 0 To SizeOf(\zeile) - 1
If \zchar[j] < 32: \zchar[j] = #chrkleiner32: EndIf
Next
Default
EndSelect
EndWith
ProcedureReturn pointer
EndProcedure
Procedure.i VLV_WindowCallback(hwnd, message, wParam, lParam)
;pvlv ist global
Protected result = #PB_ProcessPureBasicEvents
Protected *nm_listview.NM_LISTVIEW
Protected *lv_dispinfo.LV_DISPINFO
Static iItem, iSubitem
If message = #WM_NOTIFY
*nm_listview = lParam
;Id der Liste abfragen
If *nm_listview\hdr\hwndFrom = pvlv\lvid
If *nm_listview\hdr\code = #LVN_GETDISPINFO ; -150
; Item text zuweisen
*lv_dispinfo = lParam
If *lv_dispinfo\item\mask & #LVIF_TEXT
iitem = *lv_dispinfo\item\iItem
isubitem = *lv_dispinfo\item\iSubItem
;pointer auf subitem holen
*lv_dispinfo\item\pszText = VLV_GetSubItem(iItem, iSubItem)
EndIf
ElseIf *nm_listview\hdr\code = #LVN_HOTTRACK ; -121
;weitere Anzeigen etc
EndIf
EndIf
EndIf
ProcedureReturn result
EndProcedure
Procedure.i VLV_MainWindow()
With pvlv
Protected fontid = FontID(LoadFont(#PB_Any,"courier new",10))
Protected size.size, dc = GetDC_(0)
;Zeichenbreite ermitteln, steht in size\cx
SelectObject_(dc, fontid)
GetTextExtentPoint32_(dc, "x", 1, size)
DeleteDC_(dc)
;Window
Protected colbr = size\cx * (3 + SizeOf(\spalte))
Protected winbr = colbr * 6
Protected winhh = 610
Protected flags = #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered
\window = OpenWindow(#PB_Any, 0, 0, winbr, winhh, "V-Listview", flags)
AddKeyboardShortcut(\window, #PB_Shortcut_D, #menu_view)
CreateStatusBar(0, WindowID(\window))
AddStatusBarField(#PB_Ignore)
CreateMenu(#menu, WindowID(\window))
MenuTitle("&Datei")
MenuItem(#menu_Datei, "&Datei öffnen")
MenuBar()
MenuItem(#menu_Ende, "&Ende")
MenuTitle("&Ansicht")
MenuItem(#menu_View, "&Dezimal / Hex Anzeige" + #TAB$ + "D")
;Liste
flags = #LVS_OWNERDATA|#PB_ListIcon_GridLines
\lvnr = ListIconGadget(#PB_Any, 0, 0, winbr, winhh-StatusBarHeight(0)-MenuHeight(), "", 0, flags)
\lvid = GadgetID(\lvnr)
SetGadgetFont(\lvnr, fontid)
AddGadgetColumn(\lvnr, 1, "BytePosition", colbr - 22) ;Scrollbalken pauschal abziehen
AddGadgetColumn(\lvnr, 2, " 0 1 2 3", colbr)
AddGadgetColumn(\lvnr, 3, " 4 5 6 7", colbr)
AddGadgetColumn(\lvnr, 4, " 8 9 10 11", colbr)
AddGadgetColumn(\lvnr, 5, " 12 13 14 15", colbr)
AddGadgetColumn(\lvnr, 6, " Text", colbr)
;Spalten ausrichten
Protected lvc.LV_COLUMN
lvc\mask = #LVCF_FMT
lvc\fmt = #LVCFMT_RIGHT
SendMessage_(\lvid, #LVM_SETCOLUMN, 1, lvc)
lvc\fmt = #LVCFMT_CENTER
SendMessage_(\lvid, #LVM_SETCOLUMN, 2, lvc)
SendMessage_(\lvid, #LVM_SETCOLUMN, 3, lvc)
SendMessage_(\lvid, #LVM_SETCOLUMN, 4, lvc)
SendMessage_(\lvid, #LVM_SETCOLUMN, 5, lvc)
lvc\fmt = #LVCFMT_LEFT
SendMessage_(\lvid, #LVM_SETCOLUMN, 6, lvc)
;rechte Scrollbar erzwingen
;ShowScrollBar_(\lvid, #SB_VERT,#True)
;Farben
SetGadgetColor(\lvnr, #PB_Gadget_BackColor, $F8FEDC) ;D5E6F7
SetGadgetColor(\lvnr, #PB_Gadget_FrontColor, #Blue)
SetGadgetColor(\lvnr, #PB_Gadget_LineColor, #Red)
;Header sperren
EnableWindow_(SendMessage_(\lvid, #LVM_GETHEADER, 0, 0), 0)
SetWindowCallback(@VLV_WindowCallback())
;Start
pvlv\dezimal = 1 ;Start mit Dezimal Anzeige
pvlv\datname = ProgramParameter()
EndWith
EndProcedure
Procedure.i VLV_OpenFile(flag = 0)
With pvlv
Protected erg$, info$
If \datnr: CloseFile(\datnr): EndIf
If Not \datname
;bei Progstart ohne Parameter ist \datname = ""
\datname = GetCurrentDirectory()
VLV_OpenFile(1)
ProcedureReturn
EndIf
If flag
erg$ = OpenFileRequester("V-Listview - Datei öffnen", \datname, "*.*", 0)
If erg$: \datname = erg$: EndIf
EndIf
\datnr = ReadFile(#PB_Any, \datname)
If Not \datnr
info$ = \datname + " kann nicht geöffnet werden" + #LF$ + #LF$
info$ + "Dateiname existiert nicht oder Datei ist gesperrt oder ..."
MessageRequester("Readfile: Info", info$)
ProcedureReturn
EndIf
\datlg = Lof(\datnr)
\satzlg = SizeOf(\zeile)
\satzanz = 1 + (\datlg / \satzlg)
;Info
StatusBarText(0, 0, \datname + " - " + Str(\datlg) + " Bytes")
;!!!!! teilt dem ListIconGadget mit wieviele Datensätze zu verwalten sind !!!!!
SendMessage_(\lvid, #LVM_SETITEMCOUNT, \satzanz, 0)
;rechte Scrollbar erzwingen,
ShowScrollBar_(\lvid, #SB_VERT,#True)
EndWith
EndProcedure
Procedure.i VLV_ChangeView()
With pvlv
If \dezimal
\dezimal = 0
Else
\dezimal = 1
EndIf
Protected topindex = SendMessage_(\lvid, #LVM_GETTOPINDEX, 0, 0)
Protected countpage = SendMessage_(\lvid, #LVM_GETCOUNTPERPAGE, 0, 0)
SendMessage_(\lvid, #LVM_REDRAWITEMS, topindex, topindex + countpage + 1)
EndWith
EndProcedure
Procedure.i VLV_EventLoop()
Protected event
Repeat
event = WaitWindowEvent()
Select event
Case #PB_Event_Menu
Select EventMenu()
Case #menu_Datei: VLV_OpenFile(1)
Case #menu_View: VLV_ChangeView()
Case #menu_Ende: event = #PB_Event_CloseWindow
EndSelect
EndSelect
Until event = #PB_Event_CloseWindow
If pvlv\datnr: CloseFile(pvlv\datnr): EndIf
EndProcedure
DisableExplicit
VLV_MainWindow()
VLV_OpenFile()
VLV_EventLoop()
End