Kleiner Dateibetrachter für große Dateien (1.6 GB) Update

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Kleiner Dateibetrachter für große Dateien (1.6 GB) Update

Beitrag von hjbremer »

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 !

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
Zuletzt geändert von hjbremer am 20.03.2012 22:32, insgesamt 2-mal geändert.
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Kleiner Dateibetrachter für beliebig große Dateien

Beitrag von ts-soft »

:allright:

Hab ich schon oft gebraucht!

Beliebig groß stimmt aber nicht, > 2 GB passiert nichts mehr, auch unter x64 nicht.
Aber mit dieser Limitation wird man wohl leben können :wink:

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Kleiner Dateibetrachter für beliebig große Dateien

Beitrag von RSBasic »

Gefällt mir. :allright:
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Re: Kleiner Dateibetrachter für beliebig große Dateien

Beitrag von hjbremer »

ts-soft hat geschrieben: Beliebig groß stimmt aber nicht, > 2 GB passiert nichts mehr, auch unter x64 nicht.
Aber mit dieser Limitation wird man wohl leben können :wink:
Uuups 2 GB, habe kein x64 und darum steht im code auch x86

wäre schön wenn jemand den Code ergänzt für x64, damit ich mal sehen kann, worauf ich achten muß, damit es unter x64 funktioniert
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Kleiner Dateibetrachter für beliebig große Dateien

Beitrag von ts-soft »

hjbremer hat geschrieben:wäre schön wenn jemand den Code ergänzt für x64, damit ich mal sehen kann, worauf ich achten muß, damit es unter x64 funktioniert
Funktionieren tut es unter X64, aber auch mit dem 2 GB limit, ansonsten
würde ich gerne machen, aber ich finde die Ursache nicht /:->
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Kleiner Dateibetrachter für beliebig große Dateien

Beitrag von NicTheQuick »

Ich würde es auch gerne machen, aber unter Ubuntu läuft es wohl schlecht. ;)
Benutzeravatar
7x7
Beiträge: 591
Registriert: 14.08.2007 15:41
Computerausstattung: ganz toll
Wohnort: Lelbach

Re: Kleiner Dateibetrachter für beliebig große Dateien

Beitrag von 7x7 »

Schönes Programm und guter Code.
- alles was ich hier im Forum sage/schreibe ist lediglich meine Meinung und keine Tatsachenbehauptung
- unkommentierter Quellcode = unqualifizierter Müll
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Re: Kleiner Dateibetrachter für beliebig große Dateien

Beitrag von hjbremer »

Nach längerem Suchen und etwas Probieren habe nun rausgefunden es gibt ein Limit fürs Listview Control
und zwar 100 000 000 Zeilen entspricht ca 1.6 Gb
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Re: Kleiner Dateibetrachter für große Dateien (1.6 GB) Updat

Beitrag von hjbremer »

Da hier zuletzt viel über selber zeichnen des ListIconGadgets geredet wurde, habe ich ebenfalls mein kleines Programm überarbeitet und Ownerdraw eingebaut um es viel schöner zu machen. :mrgreen:

Ich poste die neue Version hier, falls jemand die kleine Version lieber mag.

Code: Alles auswählen

;ab PB 4.3 X86 - Windows XP mit Skin, siehe Hinweise im Callback
;Anzeige Byteposition ab null, da PBs FileSeek() auch bei null beginnt

;Aufruf: Programmname [Parameter]

EnableExplicit

#DBlue = $8B0000 
#DRed  = $00008B 

Enumeration
   #menu
   #menu_Datei
   #menu_Ende
   #menu_Dezi
   #menu_Hexa
   #menu_Char
   #menu_PopUp = 10 ; von 10 bis 266 reserviert
EndEnumeration

#columnanzahl = 4
#columnbytes  = 4
#zeilenbytes  = #columnanzahl * #columnbytes

Structure vlv_variablen
   
   window.i
   lvnr.i
   lvid.i
   datnr.i 
   datname.s
   
   dezimal.i
   greenchar.i
   fontnormal.i
   fontsymbol.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 zur Sicherheit
   
   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 

Structure lvc_text            ;Struktur um auf den Inhalt der letzten Spalte zu zugreifen
   StructureUnion
      text.s{#zeilenbytes}    ;eine einzelne Zeile
      cols.s{#columnbytes}[0] ;für die einzelnen Columns einer Spalte der Zeile
      char.s{1}[0]            ;für die einzelnen Chars der Zeile der letzten Spalte
      asci.c[0]               ;wie char.s nur als Ascii Wert
   EndStructureUnion
   null.c                     ;wichtig für StringEnde zur Sicherheit 
EndStructure 

Global pvlv.vlv_variablen

Procedure.i VLV_ShowMousePos(iitem, isubitem, *pt.Point)
   ;pvlv ist global
   
   Static rc.RECT
   Static bytebr.f, posinrect, posinsubitem, byteposition
   
   rc\top = isubitem 
   rc\left = #LVIR_BOUNDS
   SendMessage_(pvlv\lvid, #LVM_GETSUBITEMRECT, iitem, rc) 
   
   Select iSubItem
      Case 2,3,4,5
         bytebr = (rc\right - rc\left) / #columnbytes
         posinrect = *pt\x - rc\left
         posinsubitem = Int(posinrect / bytebr)
         byteposition = posinsubitem + (iitem * #zeilenbytes) + ((iSubItem-2) * #columnbytes)
         StatusBarText(0, 1, Str(byteposition))
      Case 0,1,6
         ;StatusBarText(0, 1, "")
   EndSelect  

EndProcedure

Procedure.i VLV_GetSubItem(item, subitem)
   ;pvlv 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.q              ;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 aber 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] = 0: \zchar[j] = 1: EndIf
            Next
            
         Default
      EndSelect
      
   EndWith    
      
   ProcedureReturn pointer
EndProcedure

Procedure.i VLV_WindowCallback(hwnd, message, wParam, lParam) 
   ;pvlv ist global
   
   ;allgemeine Hinweise: 
   ;mit XP Skin ist die Anzeige sehr viel besser, kein flackern !!!
   ;mit XP Skin wird #LVN_HOTTRACK unterstützt, ebenso #LVN_BEGINSCROLL und #LVN_ENDSCROLL
   
   Protected result = #PB_ProcessPureBasicEvents 
   
   Protected *nm_listview.NM_LISTVIEW
   Protected *lv_dispinfo.LV_DISPINFO
      
   ;muß nur für #LVN_HOTTRACK Static sein
   Static iItem, iSubitem 
   
   Protected j, k
   Protected *NMLVCustomDraw.NMLVCUSTOMDRAW
   Protected lvcitem, lvcsubitem, lvccolbr
   Protected lvc.lvc_text, lvitem.LVITEM
   Protected lvcsubitemRect.RECT, lvccopyrect.RECT
   
   If message = #WM_NOTIFY 
      
      *nm_listview = lParam
      *NMLVCustomDraw = lParam
      
      ;Id der Liste abfragen
      If *nm_listview\hdr\hwndFrom = pvlv\lvid 
         
         If *nm_listview\hdr\code = #NM_CUSTOMDRAW
                        
            Select *NMLVCustomDraw\nmcd\dwDrawStage 
               Case #CDDS_PREPAINT:     ProcedureReturn #CDRF_NOTIFYITEMDRAW 
               Case #CDDS_ITEMPREPAINT: ProcedureReturn #CDRF_NOTIFYSUBITEMDRAW 
                  
               Case #CDDS_ITEMPREPAINT | #CDDS_SUBITEM 
                  With *NMLVCustomDraw
                     
                     ;Zeile + Spalte
                     lvcitem = \nmcd\dwItemSpec
                     lvcsubitem = \iSubItem    
                      
                     ;subitem rect 
                     lvcsubItemRect\left = #LVIR_LABEL 
                     lvcsubItemRect\top = lvcsubitem
                     SendMessage_(pvlv\lvid, #LVM_GETSUBITEMRECT, lvcitem, lvcsubItemRect)
                                          
                     If \iSubItem   ;wenn \iSubItem = 0, tue nix
                        
                        ;zeichne GridLines, mit einer Rect-Kopie arbeiten, da es verändert wird
                        CopyRect_(lvccopyrect, lvcsubItemRect)
                        lvccopyrect\top - 1
                        lvccopyrect\left - 1
                        FrameRect_(\nmcd\hdc, lvccopyrect, GetStockObject_(#LTGRAY_BRUSH))
                        
                        ;hole subitem Text, GetGadgetItemText() funktioniert im VLV nicht
                        lvc\text = ""
                        lvitem\Mask = #LVIF_TEXT
                        lvitem\iItem = lvcitem
                        lvitem\iSubItem = lvcsubitem
                        lvitem\pszText    = @lvc\text
                        lvitem\cchTextMax = #zeilenbytes
                        SendMessage_(pvlv\lvid, #LVM_GETITEM, 0, @lvitem) 
                        
                        ;für Drawtext das Rect verkleinern                     
                        lvcsubItemRect\top + 2 
                        lvcsubItemRect\right - 4 
                        
                     EndIf
                     
                     ;die einzelnen Columns
                     Select \iSubItem 
                        Case 0
                           ;tue nix
                           
                        Case 1 
                           SetTextColor_(\nmcd\hdc, #Black) 
                           SelectObject_(\nmcd\hdc, pvlv\fontnormal) 
                           DrawText_(\nmcd\hdc, @lvc\text, -1, lvcsubItemRect, #DT_RIGHT)
                           
                        Case 2, 3, 4, 5  
                           lvccolbr = (lvcsubItemRect\right - lvcsubItemRect\left) / #columnbytes
                           CopyRect_(lvccopyrect, lvcsubItemRect) ;immer mit einer Kopie arbeiten
                           lvccopyrect\top - 1
                           For j = 0 To #columnbytes - 1
                              lvccopyrect\left = lvcsubItemRect\left + (lvccolbr * j)
                              lvccopyrect\right = lvccopyrect\left + lvccolbr - 2 ; -2 sieht besser aus
                              SetTextColor_(\nmcd\hdc, #DBlue) 
                              ;Dezimal oder Hex Anzeige 
                              If pvlv\dezimal: k = Val(lvc\cols[j])
                                 Else:         k = Val("$" + Trim(lvc\cols[j]))
                              EndIf
                              ;andere Farbe
                              If k < 32: SetTextColor_(\nmcd\hdc, #Gray): EndIf
                              If k = pvlv\greenchar: SetTextColor_(\nmcd\hdc, #Green): EndIf
                              SelectObject_(\nmcd\hdc, pvlv\fontnormal) 
                              DrawText_(\nmcd\hdc, @lvc\cols[j], #columnbytes, lvccopyrect, #DT_RIGHT)
                           Next
                           
                        Case 6
                           lvccolbr = (lvcsubItemRect\right - lvcsubItemRect\left) / #zeilenbytes
                           CopyRect_(lvccopyrect, lvcsubItemRect)
                           lvccopyrect\top - 1
                           ;jeden Char einzeln ausgeben, damit < 32 andere Farbe/Font bekommen
                           For j = 0 To #zeilenbytes - 1
                              lvccopyrect\left = lvcsubItemRect\left + (lvccolbr * j) + 2
                              lvccopyrect\right = lvccopyrect\left + lvccolbr
                              If lvc\asci[j] < 32
                                 SetTextColor_(\nmcd\hdc, #Gray) 
                                 SelectObject_(\nmcd\hdc, pvlv\fontsymbol) 
                                 lvc\char[j] = Chr(78) 
                                 lvccopyrect\top + 1  ;Char etwas nach unten
                                 DrawText_(\nmcd\hdc, @lvc\char[j], 1, lvccopyrect, #DT_RIGHT)
                                 lvccopyrect\top - 1
                              Else   
                                 SetTextColor_(\nmcd\hdc, #DRed) 
                                 SelectObject_(\nmcd\hdc, pvlv\fontnormal) 
                                 DrawText_(\nmcd\hdc, @lvc\char[j], 1, lvccopyrect, #DT_RIGHT)
                              EndIf
                           Next    
                           
                     EndSelect
                  EndWith

                  ;Überspringe Windows Zeichenoperationen (oder PBs) da wir fast alles selbst machen
                  ProcedureReturn #CDRF_SKIPDEFAULT   

            EndSelect
            
         ElseIf *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
            ;iitem muß Static sein, da der Wert in NM_LISTVIEW jetzt -1 ist
            VLV_ShowMousePos(iitem, *nm_listview\isubitem, *nm_listview\ptAction)
            
         EndIf      
         
      EndIf 
      
   EndIf 
   
   ProcedureReturn result 
EndProcedure 

Procedure.i VLV_MainWindow()   
   With pvlv
      
      Protected size.size, dc = GetDC_(0)
      
      \fontnormal = FontID(LoadFont(#PB_Any, "courier new", 10)) 
      \fontsymbol = FontID(LoadFont(#PB_Any, "wingdings", 9)) 

      ;Zeichenbreite ermitteln, steht in size\cx
      SelectObject_(dc, \fontnormal)
      GetTextExtentPoint32_(dc, "x", 1, size)
      DeleteDC_(dc)
      
      size\cx + 2
      
      ;Window
      Protected j, id
      Protected colbr = size\cx * (1 + 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) 
      
      CreateStatusBar(0, WindowID(\window)) 
      AddStatusBarField(#PB_Ignore)
      AddStatusBarField(190)
      
      CreateMenu(#menu, WindowID(\window))
      MenuTitle("&Datei")
      MenuItem(#menu_Datei, "&Datei öffnen")
      MenuBar()
      MenuItem(#menu_Ende, "&Ende")
      MenuTitle("&Ansicht")
      MenuItem(#menu_Dezi, "&Dez Anzeige")
      MenuItem(#menu_Hexa, "&Hex Anzeige")
      MenuItem(#menu_Char, "Highlight &Character")
      
      CreatePopupMenu(#menu_PopUp): id = MenuID(#menu_PopUp)
      For j = 0 To 255
         flags = #MF_STRING
         If Mod(j, 26) = 0: flags = #MF_STRING|#MF_MENUBREAK: EndIf         
         AppendMenu_(id, flags, #menu_PopUp + j + 1, Str(j)) 
      Next
           
      ;Liste 
      flags = #LVS_OWNERDATA	
      \lvnr = ListIconGadget(#PB_Any, 0, 0, winbr, winhh-StatusBarHeight(0)-MenuHeight(), "", 0, flags)
      \lvid = GadgetID(\lvnr)
      SetGadgetFont(\lvnr, \fontnormal)

      ;SetWindowTheme_(SendMessage_(\lvid, #LVM_GETHEADER, 0, 0), "", "")
      
      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)
      
      ;Farben
      SetGadgetColor(\lvnr, #PB_Gadget_BackColor, $FAFFF5)
      
      ;Header sperren
      EnableWindow_(SendMessage_(\lvid, #LVM_GETHEADER, 0, 0), 0) 
            
      SetWindowCallback(@VLV_WindowCallback())
 
      ;Start
      \dezimal = 1  ;Start mit Dezimal Anzeige
      \datname = ProgramParameter()
      \greenchar = -1
      
      SetActiveGadget(\lvnr)
      
   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)
      
      If \satzanz >= 100000000
         MessageRequester("Hinweis", "Datei zu groß, nur bis ca 1.6 GB")
         ProcedureReturn
      EndIf
      
      ;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()
      
   Protected topindex = SendMessage_(pvlv\lvid, #LVM_GETTOPINDEX, 0, 0)
   Protected countpage = SendMessage_(pvlv\lvid, #LVM_GETCOUNTPERPAGE, 0, 0)
   
   SendMessage_(pvlv\lvid, #LVM_REDRAWITEMS, topindex, topindex + countpage + 1)

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_Dezi:  pvlv\dezimal = 1: VLV_ChangeView()
               Case #menu_Hexa:  pvlv\dezimal = 0: VLV_ChangeView()
               Case #menu_Char:  DisplayPopupMenu(#menu_PopUp, WindowID(pvlv\window))
               Case #menu_PopUp To #menu_PopUp + 256
                  pvlv\greenchar = EventMenu() - #menu_PopUp - 1
                  VLV_ChangeView()
                  
               Case #menu_Ende:  event = #PB_Event_CloseWindow
            EndSelect
            
      EndSelect 
   Until event = #PB_Event_CloseWindow
   
   If pvlv\datnr: CloseFile(pvlv\datnr): EndIf
   
EndProcedure

VLV_MainWindow()
VLV_OpenFile()
VLV_EventLoop()

End
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Antworten