Das Programm ist nun soweit fertig. Ist eine ganze Menge hinzugekommen. ![]()
Ich habe mal den Post #1 geändert. Dort ist das Programm (inkl. Skript und Icons) jetzt zu finden.
Das Programm ist nun soweit fertig. Ist eine ganze Menge hinzugekommen. ![]()
Ich habe mal den Post #1 geändert. Dort ist das Programm (inkl. Skript und Icons) jetzt zu finden.
L3viathan: Eine andere Möglichkeit wäre _GetIP() oder mit TCPNameToIP, also etwas so:
[autoit]
MsgBox(0,0, _IsOnline())
Func _IsOnline()
TCPStartup()
$ret = TCPNameToIP('www.google.de')
TCPShutdown()
Return SetError(@error, 0, $ret <> '')
EndFunc
Du hast recht, die Suche innerhalb der Liste bzw. die Anzeige des Ergebnisses gefiel mir auch nicht so richtig. Nur markieren ist blöd, weil man nicht alle Suchergebnisse überblicken kann.
Ich habe jetzt ein zweites Listview (das ist erstmal versteckt und wird nur als Ergebnis angezeigt) erstellt und da kommen dann die Suchergebnisse rein. Das gefällt mir viel besser. ![]()
Außerdem habe ich jetzt die großen Buttons (zum einlesen der MP3s, laden und speichern usw.) oberhalb der Liste angeordnet. Die SuFu ist weiterhin unterhalb. So sieht das übersichtlicher aus, finde ich.
Ich habe auch noch an verschiedenen Ecken an der Geschwindigkeit gefeilt. Das einlesen der MP3s und das sortieren nach Listviewspalte geht jetzt schneller vonstatten.
Eine Progressbar in die Statusleiste packen geht zwar, aber da gibt es Probleme mit dem Resizing (die Progressbar bleibt nicht da, wo sie hingehört). Vielleicht mache ich aber noch eine Progressbar außerhalb der Statusleiste?! ![]()
Skript:
#include <Array.au3>
#include <ButtonConstants.au3>
#include <Date.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiStatusBar.au3>
#include <ListViewConstants.au3>
#include <ProgressConstants.au3>
#include <StaticConstants.au3>
#include <StructureConstants.au3>
#include <WindowsConstants.au3>
Global $sHeader = 'Title|Artist|Length|Album|Year|MPEG-Version|Bitrate|Sample-Freq.|Path' ; Die Überschriften für das Listview
Global $sInifile = @ScriptDir & '\MP3-Search.ini' ; Inidatei
Global $iWidth = IniRead($sInifile, 'Config', 'Width', 770)
Global $iHeight = IniRead($sInifile, 'Config', 'Height', 406)
Global $iLeft = IniRead($sInifile, 'Config', 'Left', @DesktopWidth / 2 - 385)
Global $iTop = IniRead($sInifile, 'Config', 'Top', @DesktopHeight / 2 - 203)
#region Hauptfenster
Global $sStyle = BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX)
Global $hGui = GUICreate('MP3-Search', 770, 406, $iLeft, $iTop, $sStyle) ; Hauptfenster erstellen
GUISetBkColor(0xAAAAAA)
Global $hListView = GUICtrlCreateListView($sHeader, 5, 55, 760, 240, $LVS_SHOWSELALWAYS, BitOR($LVS_EX_FULLROWSELECT, $WS_EX_WINDOWEDGE)) ; Listview erstellen
GUICtrlSetResizing(-1, 2 + 4 + 32 + 64)
GUICtrlSetBkColor(-1, 0xffffff)
Global $hLVHandle = GUICtrlGetHandle($hListView) ; das Handle vom Listview wird für die UDF-Listview-Funktionen benötigt
_GUICtrlListView_SetColumnWidth($hLVHandle, 0, 180)
_GUICtrlListView_SetColumnWidth($hLVHandle, 1, 180)
_GUICtrlListView_SetColumnWidth($hLVHandle, 2, 60)
_GUICtrlListView_SetColumnWidth($hLVHandle, 3, 120)
_GUICtrlListView_SetColumnWidth($hLVHandle, 4, 60)
_GUICtrlListView_SetColumnWidth($hLVHandle, 5, 100)
_GUICtrlListView_SetColumnWidth($hLVHandle, 6, 100)
_GUICtrlListView_SetColumnWidth($hLVHandle, 7, 90)
_GUICtrlListView_SetColumnWidth($hLVHandle, 8, 800)
Global $hSearchListView = GUICtrlCreateListView($sHeader, 5, 55, 760, 240, $LVS_SHOWSELALWAYS, BitOR($LVS_EX_FULLROWSELECT, $WS_EX_WINDOWEDGE)) ; Listview erstellen
GUICtrlSetResizing(-1, 2 + 4 + 32 + 64)
GUICtrlSetBkColor(-1, 0xaaffbb)
Global $hSearchLVHandle = GUICtrlGetHandle($hSearchListView) ; das Handle vom Listview wird für die UDF-Listview-Funktionen benötigt
_GUICtrlListView_SetColumnWidth($hSearchLVHandle, 0, 180)
_GUICtrlListView_SetColumnWidth($hSearchLVHandle, 1, 180)
_GUICtrlListView_SetColumnWidth($hSearchLVHandle, 2, 60)
_GUICtrlListView_SetColumnWidth($hSearchLVHandle, 3, 120)
_GUICtrlListView_SetColumnWidth($hSearchLVHandle, 4, 60)
_GUICtrlListView_SetColumnWidth($hSearchLVHandle, 5, 100)
_GUICtrlListView_SetColumnWidth($hSearchLVHandle, 6, 100)
_GUICtrlListView_SetColumnWidth($hSearchLVHandle, 7, 90)
_GUICtrlListView_SetColumnWidth($hSearchLVHandle, 8, 800)
GUICtrlSetState($hSearchListView, $GUI_HIDE)
GUICtrlCreateGroup('', 5, 300, 760, 75)
GUICtrlSetResizing(-1, 512 + 64)
GUICtrlCreateLabel('Suchbegriff:', 15, 322, 70, 22, $SS_RIGHT)
GUICtrlSetFont(-1, 10)
GUICtrlSetResizing(-1, 512 + 64)
Global $hInput = GUICtrlCreateInput('', 90, 320, 300, 22)
GUICtrlSetFont(-1, 10)
GUICtrlSetResizing(-1, 512 + 64)
Global $hInputOk = GUICtrlCreateButton('Suche starten', 400, 320, 100, 22, $BS_DEFPUSHBUTTON)
GUICtrlSetFont(-1, 10)
GUICtrlSetResizing(-1, 512 + 64)
Global $hCaseSens = GUICtrlCreateCheckbox('Groß-/Kleinschreibung beachten', 90, 345, 240, 22)
GUICtrlSetFont(-1, 10)
GUICtrlSetResizing(-1, 512 + 64)
GUICtrlCreateGroup('', -99, -99, 1, 1)
Global $hSearch = GUICtrlCreateButton('Alle Festplatten durchsuchen', 10, 10, 100, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 32)
Global $hSearchPath = GUICtrlCreateButton('Verzeichnis durchsuchen', 120, 10, 80, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 32)
Global $hLoad = GUICtrlCreateButton('Liste laden', 230, 10, 70, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 32)
Global $hSave = GUICtrlCreateButton('Liste speichern', 310, 10, 70, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 32)
Global $hDel = GUICtrlCreateButton("Markierte Einträge löschen", 410, 10, 90, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 32)
GUICtrlSetState(-1, $GUI_DISABLE)
Global $hDelAll = GUICtrlCreateButton('Alle Einträge löschen', 510, 10, 90, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 32)
Global $aParts[3] = [300, 360, -1], $aText[3] = ['Fertig.', '0', '']
Global $hStatus = _GUICtrlStatusBar_Create($hGui, $aParts, $aText, $SBARS_SIZEGRIP)
_GUICtrlStatusBar_SetSimple($hStatus, False)
_GUICtrlStatusBar_SetMinHeight($hStatus, 20)
#endregion Hauptfenster
GUISetState(@SW_SHOW, $hGui) ; Hauptfenster sichtbar machen
[/autoit] [autoit][/autoit] [autoit]Global $fStop = False, $iSearchIndex = -1, $iSelCount, $iSelOld, $aListview
HotKeySet('{ESC}', '_Stop')
Dim $aAccelKeys[1][2] = [['{DEL}', $hDel]] ; beim drücken der [Delete]-Taste wird "Case $hDel" ausgeführt
GUISetAccelerators($aAccelKeys, $hGui)
GUIRegisterMsg($WM_SIZE, '_WM_SIZE')
GUIRegisterMsg($WM_MOVE, '_WM_MOVE')
GUIRegisterMsg($WM_GETMINMAXINFO, '_WM_GETMINMAXINFO')
GUIRegisterMsg($WM_NOTIFY, '_WM_NOTIFY')
GUIRegisterMsg($WM_COMMAND, '_WM_COMMAND')
WinMove($hGui, '', $iLeft, $iTop, $iWidth, $iHeight)
[/autoit] [autoit][/autoit] [autoit]While 1
Switch GUIGetMsg() ; anhand der Control-ID das entsprechende Case aufrufen
Case $hSearch
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
_GUICtrlStatusBar_SetText($hStatus, 0, 1)
$iLVCount = 0 ; Zähler auf Null setzen
$aDrives = DriveGetDrive('FIXED') ; Alle Festplatten-Buchstaben holen
If Not @error Then
GUISetCursor(15, 1, $hGui)
For $i = 1 To $aDrives[0] ; Alle Festplatten durchgehen
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Festplatte "' & StringUpper($aDrives[$i]) & '\"', 0)
_DriveSearch(StringUpper($aDrives[$i]))
Next
GUISetCursor(2, 1, $hGui)
EndIf
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, 'Abgebrochen!', 0)
Else
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
EndIf
Case $hSearchPath
$sPath = FileSelectFolder('Verzeichnis auswählen!', '', 2, '', $hGui)
If FileExists($sPath) Then
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
$iLVCount = 0 ; Zähler auf Null setzen
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Verzeichnis "' & $sPath & '"', 0)
_DriveSearch($sPath)
GUISetCursor(2, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, 'Abgebrochen!', 0)
Else
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
EndIf
EndIf
Case $hInputOk
ControlFocus($hGui, '', $hInputOk)
_GUICtrlStatusBar_SetText($hStatus, 'Suche in Liste...', 0)
GUISetCursor(15, 1, $hGui)
_LVSearch()
GUISetCursor(2, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
Case $hListView ; User hat auf eine Spaltenüberschrift geklickt (sortieren)
If _GUICtrlListView_GetItemCount($hLVHandle) > 0 Then
GUISetCursor(15, 1, $hGui)
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, '', 2)
_GUICtrlStatusBar_SetText($hStatus, 'Sortiere Daten! Bitte warten...', 0)
If Not IsArray($aListview) Then
$iCount = _GUICtrlListView_GetItemCount($hLVHandle)
Dim $aListview[$iCount][9]
For $i = 0 To $iCount - 1
For $j = 0 To 8
$aListview[$i][$j] = ControlListView($hGui, '', $hListView, 'GetText', $i, $j)
Next
Next
EndIf
_ArraySort($aListview, 0, 0, 0, GUICtrlGetState($hListView))
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlListView_AddArray($hLVHandle, $aListview)
_GUICtrlStatusBar_SetText($hStatus, _TicksToTimeFormat(TimerDiff($iTimer), '%mm:%ss.%ms'), 2)
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
GUISetCursor(2, 1, $hGui)
EndIf
Case $hLoad ; User hat auf 'Laden' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten...', 0)
Load()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
GUISetCursor(2, 1, $hGui)
$aListview = ''
Case $hSave ; User hat auf 'Speichern' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Speichere Daten...', 0)
Save()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
GUISetCursor(2, 1, $hGui)
Case $hDel
If MsgBox(256 + 32 + 4, 'Markierte Einträge löschen', 'Wollen sie wirklich die markierten Einträge löschen?') = 6 Then
GUISetCursor(15, 1, $hGui)
_GUICtrlListView_DeleteItemsSelected($hLVHandle)
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
GUISetCursor(2, 1, $hGui)
$aListview = ''
EndIf
Case $hDelAll ; User hat auf 'Alle Einträge löschen' geklickt
If MsgBox(256 + 32 + 4, 'Einträge löschen', 'Wollen sie wirklich alle Einträge löschen?') = 6 Then
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlStatusBar_SetText($hStatus, 0, 1)
$aListview = ''
EndIf
Case $GUI_EVENT_CLOSE ; User hat auf das Schließen-Symbol geklickt
;~ If MsgBox(32 + 4, 'Save', 'Wollen sie vor beenden noch Speichern?') = 6 Then Save()
Exit ; Programm beenden
EndSwitch
$iSelCount = _GUICtrlListView_GetSelectedCount($hLVHandle) ; Anzahl der markierten Items holen
If $iSelCount <> $iSelOld Then ; vergleichen ob der Wert vom vorherigen abweicht (Flackern vermeiden)
$iSelOld = $iSelCount ; wenn ja, dann alten gleich neuen Wert
If $iSelCount > 0 Then ; wenn Einträge markiert sind
GUICtrlSetState($hDel, $GUI_ENABLE) ; dann Button aktivieren
GUICtrlSetData($hDel, StringFormat('(%i) Markierte Einträge löschen', $iSelCount)) ; und den Text auf dem Button anpassen
Else ; keine Einträge markiert
GUICtrlSetState($hDel, $GUI_DISABLE) ; dann Button deaktivieren
GUICtrlSetData($hDel, 'Markierte Einträge löschen') ; und den Text auf dem Button anpassen
EndIf
EndIf
WEnd
Func _Stop()
$fStop = True
EndFunc ;==>_Stop
Func _DriveSearch($sPath)
Local $aNewMP3, $aID3Tags, $sNewItem, $aItem, $iTimer = TimerInit(), $iCount = _GUICtrlListView_GetItemCount($hLVHandle)
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
_GUICtrlStatusBar_SetText($hStatus, 'Bitte warten...', 2)
$aNewMP3 = _RecursiveFileListToArray($sPath, '\.mp3', 1) ; Alle MP3s auf der Festplatte auslesen
If Not @error And $aNewMP3[0] > 0 Then
_GUICtrlListView_SetItemCount($hListView, $iCount + $aNewMP3[0])
_GUICtrlStatusBar_SetText($hStatus, 'Lese ID3-Tags... (' & $aNewMP3[0] & ')', 0)
For $j = 1 To $aNewMP3[0] ; die gefundenen MP3s durchgehen
$aID3Tags = _ReadID3Tag($aNewMP3[$j]) ; die ID3-Tags auslesen
If Not @error Then
For $k = 0 To 10
$aID3Tags[$k][1] = StringReplace($aID3Tags[$k][1], '|', '') ; evtl. vorhandene "|" entfernen
Next
If TimerDiff($iTimer) > 50 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $iCount + $j, 1)
_GUICtrlStatusBar_SetText($hStatus, $aNewMP3[$j], 2)
EndIf
$sNewItem = $aID3Tags[0][1] & '|' & $aID3Tags[1][1] & '|' & $aID3Tags[4][1] & '|' & $aID3Tags[2][1] & '|' & $aID3Tags[3][1]
$sNewItem &= '|' & $aID3Tags[8][1] & '|' & $aID3Tags[9][1] & '|' & $aID3Tags[10][1] & '|' & $aNewMP3[$j]
GUICtrlCreateListViewItem($sNewItem, $hListView)
EndIf
If $fStop Then ExitLoop
Next
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
EndIf
EndFunc ;==>_DriveSearch
Func _WM_COMMAND($hWnd, $msg, $wParam, $lParam)
Local $nNotifyCode = BitShift($wParam, 16)
Local $nID = BitAND($wParam, 0xFFFF)
If $nID = $hInput And $nNotifyCode = 256 Then
GUICtrlSetState($hSearchListView, $GUI_HIDE)
GUICtrlSetState($hListView, $GUI_SHOW)
GUICtrlSetBkColor($hInput, 0xffffff)
GUICtrlSetData($hInput, '')
GUICtrlSetState($hInputOk, $GUI_ENABLE)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
_GUICtrlListView_SetItemSelected($hLVHandle, -1, False)
EndIf
Return $GUI_RUNDEFMSG
EndFunc ;==>_WM_COMMAND
Func _LVSearch()
Local $sSearch, $iTimer, $iCount, $iCase, $iFound, $sMsg = ' Einträge'
$iCount = _GUICtrlListView_GetItemCount($hLVHandle)
If $iCount = 0 Then Return
$sSearch = GUICtrlRead($hInput)
If $sSearch = '' Then Return
_GUICtrlListView_SetItemSelected($hLVHandle, -1, False)
_GUICtrlListView_DeleteAllItems($hSearchLVHandle)
$iCase = Number(BitAND(GUICtrlRead($hCaseSens), $GUI_CHECKED) = $GUI_CHECKED)
$iTimer = TimerInit()
For $i = 0 To $iCount - 1
$sItem = ''
For $j = 0 To 8
$sItem &= ControlListView($hGui, '', $hListView, 'GetText', $i, $j) & '|'
Next
If StringInStr($sItem, $sSearch, $iCase) Then GUICtrlCreateListViewItem(StringTrimRight($sItem, 1), $hSearchListView)
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $i, 2)
EndIf
Next
GUICtrlSetState($hInputOk, $GUI_DISABLE)
$iFound = _GUICtrlListView_GetItemCount($hSearchLVHandle)
If $iFound = 1 Then $sMsg = ' Eintrag'
_GUICtrlStatusBar_SetText($hStatus, $iFound & $sMsg & ' gefunden', 2)
If $iFound Then
GUICtrlSetBkColor($hInput, 0xaaffaa)
GUICtrlSetState($hSearchListView, $GUI_SHOW)
GUICtrlSetState($hListView, $GUI_HIDE)
Else
GUICtrlSetBkColor($hInput, 0xffaaaa)
EndIf
EndFunc ;==>_LVSearch
Func _WM_NOTIFY($hWnd, $msg, $wParam, $lParam)
Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $iSelected, $sExecutePath
$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
$hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
$iCode = DllStructGetData($tNMHDR, 'Code')
Switch $hWndFrom
Case $hLVHandle
Switch $iCode
Case $NM_DBLCLK
$iSelected = ControlListView($hGui, '', $hListView, 'GetSelected')
$sExecutePath = _GUICtrlListView_GetItemText($hLVHandle, $iSelected, ![]()
ShellExecute($sExecutePath)
EndSwitch
Case $hSearchLVHandle
Switch $iCode
Case $NM_DBLCLK
$iSelected = ControlListView($hGui, '', $hSearchListView, 'GetSelected')
$sExecutePath = _GUICtrlListView_GetItemText($hSearchLVHandle, $iSelected, ![]()
ShellExecute($sExecutePath)
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>_WM_NOTIFY
Func _WM_SIZE($hWnd, $msg, $wParam, $lParam)
Local $aGuiPos = WinGetPos($hGui)
If Not BitAND(WinGetState($hGui), 16) Then
IniWrite($sInifile, 'Config', 'Width', $aGuiPos[2])
IniWrite($sInifile, 'Config', 'Height', $aGuiPos[3])
EndIf
_GUICtrlStatusBar_Resize($hStatus)
Return $GUI_RUNDEFMSG
EndFunc ;==>_WM_SIZE
Func _WM_MOVE($hWnd, $msg, $wParam, $lParam)
Local $aGuiPos = WinGetPos($hGui)
If Not BitAND(WinGetState($hGui), 16) Then
IniWrite($sInifile, 'Config', 'Left', $aGuiPos[0])
IniWrite($sInifile, 'Config', 'Top', $aGuiPos[1])
EndIf
Return $GUI_RUNDEFMSG
EndFunc ;==>_WM_MOVE
Func _WM_GETMINMAXINFO($hWnd, $msg, $wParam, $lParam)
If $hWnd = $hGui Then
Local $minmaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam)
DllStructSetData($minmaxinfo, 7, 786) ; min X
DllStructSetData($minmaxinfo, 8, 444) ; min Y
;~ DllStructSetData($minmaxinfo, 9, 800) ; max X
;~ DllStructSetData($minmaxinfo, 10, 800) ; max Y
EndIf
EndFunc ;==>_WM_GETMINMAXINFO
Func Load() ; Datenbank-Datei laden
Local $sDBFile, $hFile, $sContent, $aNewItems, $iTimer, $iCount
FileChangeDir(@ScriptDir)
$sDBFile = FileOpenDialog('MP3-Datenbank-Datei auswählen', @ScriptDir, 'MP3-Datenbank (*.db3)', 3, '', $hGui)
If Not FileExists($sDBFile) Then Return
$hFile = FileOpen($sDBFile, 0) ; Datei zum lesen öffnen
If $hFile = -1 Then Return; wenn das öffnen nicht erfolgreich war, dann Funktion verlassen
$sContent = FileRead($hFile) ; Datei komplett einlesen
FileClose($hFile) ; Datei schließen
$sContent = StringTrimRight($sContent, 2) ; das letzte @CRLF entfernen
$aNewItems = StringSplit($sContent, @CRLF, 1) ; Den Dateiinhalt am Zeilenende splitten
If Not IsArray($aNewItems) Then Return ; Wenn $aNewItems kein Array ist, dann Funktion verlassen
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlListView_SetItemCount($hLVHandle, $aNewItems[0])
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten... (' & $aNewItems[0] & ')', 0)
_GUICtrlListView_BeginUpdate($hLVHandle) ; Listview sperren
$iTimer = TimerInit()
For $i = 1 To $aNewItems[0] ; Alle Einträge des Arrays durchgehen
$iCount += 1
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
EndIf
GUICtrlCreateListViewItem($aNewItems[$i], $hListView) ; mit den eingelesenen Daten einen neuen Listview-Eintrag erstellen
Next
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
_GUICtrlListView_EndUpdate($hLVHandle) ; Listview wieder freigeben
EndFunc ;==>Load
Func Save() ; Datenbank-Datei speichern
Local $sDBFile, $hFile, $iCount, $iTimer
$sDBFile = FileSaveDialog('MP3-Datenbank-Datei auswählen', '', 'MP3-Datenbank (*.db3)', 18, '', $hGui)
If @error Then Return
If StringRight($sDBFile, 4) <> '.db3' Then $sDBFile &= '.db3'
$iCount = _GUICtrlListView_GetItemCount($hLVHandle); Anzahl der Listview-Einträge holen
If $iCount = 0 Then Return ; Wenn das Listview keine Einträge enthält, dann Funktion verlassen
$hFile = FileOpen($sDBFile, 2) ; Datei zum speichern (überschreiben) öffnen
If $hFile = -1 Then Return; wenn das öffnen nicht erfolgreich war, dann Funktion verlassen
$iTimer = TimerInit()
For $i = 0 To $iCount - 1 ; Schleife, um alle Listview-Einträge durchzugehen
FileWriteLine($hFile, _GUICtrlListView_GetItemTextString($hLVHandle, $i))
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $i + 1, 2)
EndIf
Next
FileClose($hFile) ; Datei schließen
EndFunc ;==>Save
;===============================================================================
; Function Name: _RecursiveFileListToArray($sPath[, $sPattern][, $iFlag][, $iFormat][, $iRecursion][, $sDelim])
; Description:: gibt Verzeichnisse (rekursiv) und/oder Dateien zurück, die einem RegExp-Pattern entsprechen
; Parameter(s): $sPath = Startverzeichnis
; $sPattern = ein beliebiges RexExp-Pattern für die Auswahl
; $iFlag = Auswahl
; 0 = Dateien & Verzeichnisse
; 1 = nur Dateien
; 2 = nur Verzeichnisse
; $iFormat = Rückgabeformat
; 0 = String
; 1 = Array mit [0] = Anzahl
; 2 = Nullbasiertes Array
; $iRecursion = Verzeichnisse rekursiv durchsuchen
; 0 = Nein
; 1 = Ja
; $sDelim = Trennzeichen für die String-Rückgabe
; Requirement(s): AutoIt 3.3.0.0
; Return Value(s): Array/String mit den gefundenen Dateien/Verzeichnissen
; Author(s): Oscar (http://www.autoit.de)
; Anregungen von: bernd670 (http://www.autoit.de)
;===============================================================================
Func _RecursiveFileListToArray($sPath, $sPattern = '', $iFlag = 0, $iFormat = 1, $iRecursion = 1, $sDelim = @CRLF)
Local $hSearch, $sFile, $sReturn = ''
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
$hSearch = FileFindFirstFile($sPath & '*.*')
If @error Or $hSearch = -1 Then Return SetError(1, 0, $sReturn)
While Not $fStop
$sFile = FileFindNextFile($hSearch)
If @error Then ExitLoop
If @extended Then
If StringRegExp($sPath & $sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 2) Then $sReturn &= $sPath & $sFile & '\' & $sDelim
If $iRecursion Then $sReturn &= _RecursiveFileListToArray($sPath & $sFile & '\', $sPattern, $iFlag, 0)
ContinueLoop
EndIf
If StringRegExp($sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 1) Then $sReturn &= $sPath & $sFile & $sDelim
WEnd
FileClose($hSearch)
If $iFormat And $sReturn = '' Then Return StringSplit($sReturn, '', $iFormat)
If $iFormat Then Return StringSplit(StringTrimRight($sReturn, StringLen($sDelim)), $sDelim, $iFormat)
Return $sReturn
EndFunc ;==>_RecursiveFileListToArray
;===============================================================================
; Function Name: _ReadID3Tag($sPath)
; Description:: gibt ein Array mit den Daten aus den ID3-Tags zurück
; unterstützt werden die ID3-Tag-Versionen 1.0, 1.1, 2.3 und 2.4
; bei v2.4 müssen sich die ID3-Tags am Anfang der Datei befinden
; Parameter(s): $sPath = Pfad zu einer MP3-Datei
; Requirement(s): min. AutoIt v3.3.0.0
; Return Value(s): bei Erfolg: Array mit den ID3-Tagdaten (@error = 0)
; im Fehlerfall bekommt @error:
; 1 = Datei existiert nicht
; 2 = Datei konnte nicht zum lesen geöffnet werden
; 3 = falsche ID3 v2 Version
; 4 = Datei ist keine MP3-Datei
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _ReadID3Tag($sPath)
If Not FileExists($sPath) Then Return SetError(1, 0, 0)
Local $hFile, $sData, $sID3Header, $iID3HeaderSize = 0, $iOffset, $iSize, $tmp
Local $aID3v2Tags[8] = ['TIT2', 'TPE1', 'TALB', 'TYER', 'TLEN', 'TRCK', 'TCON', 'TENC']
Local $aID3[11][2] = [ _
['Title', ''],['Artist', ''],['Album', ''],['Year', ''], _
['Length', '0'],['Track', ''],['Genre', ''],['Encoder', ''], _
['MPEG-Version', ''],['Bitrate', '-'],['Sample-Freq.', '']]
Local $aMP3Version[4] = ['MPEG2.5', 'Reserved', 'MPEG2', 'MPEG1']
Local $aMP3Layer[4] = ['Reserved', 'Layer III', 'Layer II', 'Layer I']
Local $aMP3Bitrate[5][16] = [ _
[000, 032, 064, 096, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 384, 000], _
[000, 032, 040, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 144, 160, 176, 192, 224, 256, 000], _
[000, 008, 016, 024, 032, 040, 048, 056, 064, 080, 096, 112, 128, 144, 160, 000]]
Local $aSampleFreq[3][4] = [[44100, 48000, 32000, 0],[22050, 24000, 16000, 0],[11025, 12000, 8000, 0]]
Local $sMP3FrameHeader, $iMP3Version, $sMP3Version, $sMP3Layer, $iMP3Bitrate, $iMP3SampleFreq
Local $iVBRFrames = -1, $iVBRFilesize, $iVBRFlags
$hFile = FileOpen($sPath, 16)
If $hFile = -1 Then Return SetError(2, 0, 0)
$sData = Binary(FileRead($hFile, 4))
If BinaryMid($sData, 1, 3) = '0x494433' Then ; ID3 v2.x Kennung gefunden
If (BinaryMid($sData, 4, 1) = '0x03') Or (BinaryMid($sData, 4, 1) = '0x04') Then ; nur v2.3 und 2.4
FileRead($hFile, 2) ; 2 Bytes überspringen
For $i = 0 To 3 ; berechne ID3-Headergröße (4 Bytes, jedoch nur jeweils die unteren 7 Bit)
$iID3HeaderSize = BitShift($iID3HeaderSize, -7) + BitAND(Binary(FileRead($hFile, 1)), 0x7F)
Next
If $iID3HeaderSize > 0 Then
$sID3Header = Binary(FileRead($hFile, $iID3HeaderSize)) ; lese gesamten ID3-Header
For $i = 0 To 7
$iOffset = StringInStr(BinaryToString($sID3Header), $aID3v2Tags[$i]) ; Offset zu dem ID3-Tag
If $iOffset > 0 Then
$iSize = Hex(BinaryMid($sID3Header, $iOffset + 4, 4)) ; Größe des ID3-Frames
$tmp = BinaryMid($sID3Header, $iOffset + 11, Dec($iSize) - 1)
If BinaryMid($tmp, 1, 2) = '0xFFFE' Then
For $x = 3 To BinaryLen($tmp) Step 2
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 2), 2)
Next
Else
For $x = 1 To BinaryLen($tmp)
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 1))
Next
EndIf
$aID3[$i][1] = StringReplace($aID3[$i][1], Chr(0), '')
EndIf
Next
EndIf
Do
$sData = String(FileRead($hFile, 1))
If @error Then ExitLoop
If BitAND($sData, 0xff) = 0xff Then
FileSetPos($hFile, -1, 1)
$sData = String(FileRead($hFile, 4))
EndIf
Until BitAND($sData, 0xFFE00000) = 0xFFE00000
Else
FileClose($hFile)
Return SetError(3, 0, 0)
EndIf
Else ; ID3 v1.x
$iOffset = FileGetPos($hFile)
FileSetPos($hFile, -128, 2)
$sID3Header = BinaryToString(FileRead($hFile, 3))
If $sID3Header = 'TAG' Then
$aID3[0][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[1][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[2][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[3][1] = StringReplace(BinaryToString(FileRead($hFile, 4)), Chr(0), '')
EndIf
FileSetPos($hFile, $iOffset, 0)
EndIf
$sMP3FrameHeader = String($sData)
If BitAND($sMP3FrameHeader, 0xFFE00000) <> 0xFFE00000 Then
FileClose($hFile)
Return SetError(4, 0, 0) ; keine MP3-Datei, dann Return
EndIf
$iMP3Version = BitShift(BitXOR($sMP3FrameHeader, 0xFFE00000), 19) ; welche MP3-Version
$sMP3Version = $aMP3Version[$iMP3Version] ; in Textform
$sMP3Layer = $aMP3Layer[BitShift(BitAND($sMP3FrameHeader, 0x60000), 17)] ; welcher Layer
$aID3[8][1] = $sMP3Version & ' / ' & $sMP3Layer ; ins Ausgabe-Array
$iMP3Bitrate = BitShift(BitAND($sMP3FrameHeader, 0xF000), 12) ; Bitraten-Index auslesen
Switch $sMP3Version ; je nach MPEG-Version Bitrate aus der Tabelle holen
Case 'MPEG1'
$aID3[9][1] = $aMP3Bitrate[$iMP3Version - ($iMP3Version > 1)][$iMP3Bitrate]
Case 'MPEG2', 'MPEG2.5'
If $sMP3Layer = 'Layer I' Then
$aID3[9][1] = $aMP3Bitrate[3][$iMP3Bitrate]
Else
$aID3[9][1] = $aMP3Bitrate[4][$iMP3Bitrate]
EndIf
EndSwitch
$iMP3SampleFreq = BitShift(BitAND($sMP3FrameHeader, 0xC00), 10) ; Sample-Frequenz-Index auslesen
$aID3[10][1] = $aSampleFreq[2 - ($iMP3Version - ($iMP3Version > 1))][$iMP3SampleFreq] ; und Wert aus der Tabelle holen
Do ; evtl. Leerbytes überspringen
$tmp = FileRead($hFile, 1)
If @error Then ExitLoop
Until $tmp <> 0x00 Or @error
If $tmp = 0x58 And BinaryToString(FileRead($hFile, 3)) = 'ing' Then ; MP3 mit VBR (Xing-Header gefunden)?
$iVBRFlags = '0x' & Hex(FileRead($hFile, 4)) ; VBR-Flags auslesen
If BitAND($iVBRFlags, 0x3) Then ; wenn die Einträge vorhanden sind, dann...
$iVBRFrames = Dec(Hex(FileRead($hFile, 4))) ; Anzahl der VBR-Frames auslesen
$iVBRFilesize = Dec(Hex(FileRead($hFile, 4))) ; Dateigröße auslesen
$aID3[4][1] = $iVBRFrames * 1152 / $aID3[10][1] * 1000 ; VBR Laufzeit
$aID3[9][1] = 'VBR ~' & Int($iVBRFilesize * 8 / ($aID3[4][1] / 1000) / 1000) ; VBR durchschnittliche Bitrate
EndIf
Else
If $aID3[4][1] = 0 Then $aID3[4][1] = (FileGetSize($sPath) *
/ ($aID3[9][1] * 1000) * 1000 ; alternative CBR Laufzeit
$aID3[9][1] = 'CBR ' & $aID3[9][1]
EndIf
$aID3[4][1] = _TicksToTimeFormat($aID3[4][1]) ; Laufzeit (Ticks to hour:min:sec)
$aID3[9][1] &= ' kBit/s'
$aID3[10][1] &= ' Hz'
FileClose($hFile)
Return SetError(0, 0, $aID3)
EndFunc ;==>_ReadID3Tag
;===============================================================================
; Function Name: _TicksToTimeFormat($iTicks, $sFormat = '%hh:%mm:%ss')
; Description:: Diese Funktion wandelt Millisekunden in ein anzugebenes Zeitformat um
; Parameter(s): $iTicks = Zeit in Millisekunden
; $sFormat:
; %hh für Stunden
; %mm für Minuten
; %ss für Sekunden
; %ms für Millisekunden
; sonstige Zeichen, die dazwischen stehen, werden übernommen
; Requirement(s): -
; Return Value(s): Zeit im ausgewählten Format (String)
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _TicksToTimeFormat($iTicks, $sFormat = '%hh:%mm:%ss')
Local $aTime[4] = [0, 0, 0, 0], $sOut, $aTimeFormat[4] = ['hh', 'mm', 'ss', 'ms'], $aFormat
$aTime[2] = Int($iTicks / 1000)
$aTime[3] = $iTicks - $aTime[2] * 1000
$aTime[0] = Int($aTime[2] / 3600)
$aTime[2] = Mod($aTime[2], 3600)
$aTime[1] = Int($aTime[2] / 60)
$aTime[2] = Mod($aTime[2], 60)
$aFormat = StringRegExp($sFormat, '%([^%]+)', 3)
If Not IsArray($aFormat) Then Return SetError(1, 0, $iTicks)
For $i = 0 To UBound($aFormat) - 1
For $j = 0 To UBound($aTimeFormat) - 1
If StringLeft($aFormat[$i], 2) = $aTimeFormat[$j] Then $sOut &= StringFormat('%02i', $aTime[$j]) & StringMid($aFormat[$i], 3)
Next
Next
Return $sOut
EndFunc ;==>_TicksToTimeFormat
Edit: Man konnte aus dem Suchergebnis das MP3 nicht starten (Doppelklick). Behoben!
Nachdem wir das mit den MP3s geklärt haben, kommt hier die nächste Version: mit Suchfunktion für die Liste. ![]()
Skript:
#include <ButtonConstants.au3>
#include <Date.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiStatusBar.au3>
#include <ListViewConstants.au3>
#include <StaticConstants.au3>
#include <StructureConstants.au3>
#include <WindowsConstants.au3>
Global $sHeader = 'Title|Artist|Length|Album|Year|MPEG-Version|Bitrate|Sample-Freq.|Path' ; Die Überschriften für das Listview
Global $sInifile = @ScriptDir & '\MP3-Search.ini' ; Inidatei
Global $iWidth = IniRead($sInifile, 'Config', 'Width', 770)
Global $iHeight = IniRead($sInifile, 'Config', 'Height', 406)
Global $iLeft = IniRead($sInifile, 'Config', 'Left', @DesktopWidth / 2 - 385)
Global $iTop = IniRead($sInifile, 'Config', 'Top', @DesktopHeight / 2 - 203)
#region Hauptfenster
Global $sStyle = BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX)
Global $hGui = GUICreate('MP3-Search', 770, 406, $iLeft, $iTop, $sStyle) ; Hauptfenster erstellen
GUISetBkColor(0xAAAAAA)
Global $hListView = GUICtrlCreateListView($sHeader, 5, 5, 760, 280, $LVS_SHOWSELALWAYS, BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_DOUBLEBUFFER, $WS_EX_WINDOWEDGE)) ; Listview erstellen
GUICtrlSetResizing(-1, 2 + 4 + 32 + 64)
GUICtrlSetBkColor(-1, 0xaabbff)
Global $hLVHandle = GUICtrlGetHandle($hListView) ; das Handle vom Listview wird für die UDF-Listview-Funktionen benötigt
_GUICtrlListView_SetColumnWidth($hLVHandle, 0, 180)
_GUICtrlListView_SetColumnWidth($hLVHandle, 1, 180)
_GUICtrlListView_SetColumnWidth($hLVHandle, 2, 60)
_GUICtrlListView_SetColumnWidth($hLVHandle, 3, 120)
_GUICtrlListView_SetColumnWidth($hLVHandle, 4, 60)
_GUICtrlListView_SetColumnWidth($hLVHandle, 5, 100)
_GUICtrlListView_SetColumnWidth($hLVHandle, 6, 100)
_GUICtrlListView_SetColumnWidth($hLVHandle, 7, 90)
_GUICtrlListView_SetColumnWidth($hLVHandle, 8, 800)
GUICtrlCreateLabel('Suchbegriff:', 10, 302, 70, 22, $SS_RIGHT)
GUICtrlSetFont(-1, 10)
GUICtrlSetResizing(-1, 512 + 64)
Global $hInput = GUICtrlCreateInput('', 90, 300, 300, 22)
GUICtrlSetFont(-1, 10)
GUICtrlSetResizing(-1, 512 + 64)
Global $hInputOk = GUICtrlCreateButton('Suche starten', 400, 300, 100, 22)
GUICtrlSetFont(-1, 10)
GUICtrlSetResizing(-1, 512 + 64)
Global $hSearch = GUICtrlCreateButton('Alle Festplatten durchsuchen', 10, 340, 120, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $hSearchPath = GUICtrlCreateButton('Verzeichnis durchsuchen', 140, 340, 100, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $hLoad = GUICtrlCreateButton('Laden', 250, 340, 70, 35)
GUICtrlSetResizing(-1, 512 + 64)
Global $hSave = GUICtrlCreateButton('Speichern', 330, 340, 70, 35)
GUICtrlSetResizing(-1, 512 + 64)
Global $hDel = GUICtrlCreateButton("Markierte Einträge löschen", 410, 340, 90, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
GUICtrlSetState(-1, $GUI_DISABLE)
Global $hDelAll = GUICtrlCreateButton('Alle Einträge löschen', 510, 340, 90, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $aParts[3] = [300, 360, -1], $aText[3] = ['Fertig.', '0', '']
Global $hStatus = _GUICtrlStatusBar_Create($hGui, $aParts, $aText)
#endregion Hauptfenster
GUISetState(@SW_SHOW, $hGui) ; Hauptfenster sichtbar machen
[/autoit] [autoit][/autoit] [autoit]Global $fStop = False, $iSearchIndex = -1, $iSelCount, $iSelOld
HotKeySet('{ESC}', '_Stop')
Dim $aAccelKeys[1][2] = [['{DEL}', $hDel]] ; beim drücken der [Delete]-Taste wird "Case $hDel" ausgeführt
GUISetAccelerators($aAccelKeys, $hGui)
GUIRegisterMsg($WM_SIZE, '_WM_SIZE')
GUIRegisterMsg($WM_MOVE, '_WM_MOVE')
GUIRegisterMsg($WM_GETMINMAXINFO, '_WM_GETMINMAXINFO')
GUIRegisterMsg($WM_NOTIFY, '_WM_NOTIFY')
GUIRegisterMsg($WM_COMMAND, '_WM_COMMAND')
WinMove($hGui, '', $iLeft, $iTop, $iWidth, $iHeight)
[/autoit] [autoit][/autoit] [autoit]While 1
Switch GUIGetMsg() ; anhand der Control-ID das entsprechende Case aufrufen
Case $hSearch
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
_GUICtrlStatusBar_SetText($hStatus, 0, 1)
$iLVCount = 0 ; Zähler auf Null setzen
$aDrives = DriveGetDrive('FIXED') ; Alle Festplatten-Buchstaben holen
If Not @error Then
GUISetCursor(15, 1, $hGui)
For $i = 1 To $aDrives[0] ; Alle Festplatten durchgehen
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Festplatte "' & StringUpper($aDrives[$i]) & '\"', 0)
_DriveSearch(StringUpper($aDrives[$i]))
Next
GUISetCursor(2, 1, $hGui)
EndIf
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, 'Abgebrochen!', 0)
Else
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
EndIf
Case $hSearchPath
$sPath = FileSelectFolder('Verzeichnis auswählen!', '', 2, '', $hGui)
If FileExists($sPath) Then
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
$iLVCount = 0 ; Zähler auf Null setzen
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Verzeichnis "' & $sPath & '"', 0)
_DriveSearch($sPath)
GUISetCursor(2, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, 'Abgebrochen!', 0)
Else
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
EndIf
EndIf
Case $hInput, $hInputOk
_GUICtrlStatusBar_SetText($hStatus, 'Suche in Liste...', 0)
GUISetCursor(15, 1, $hGui)
_LVSearch()
GUISetCursor(2, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
Case $hListView ; User hat auf eine Spaltenüberschrift geklickt (sortieren)
If _GUICtrlListView_GetItemCount($hLVHandle) > 0 Then
Dim $aDescending[_GUICtrlListView_GetColumnCount($hLVHandle)]
GUISetCursor(15, 1, $hGui)
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, 'Sortiere Daten! Bitte warten...', 0)
_GUICtrlListView_SimpleSort($hLVHandle, $aDescending, GUICtrlGetState($hListView))
_GUICtrlStatusBar_SetText($hStatus, _TicksToTimeFormat(TimerDiff($iTimer), '%mm:%ss.%ms'), 2)
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
GUISetCursor(2, 1, $hGui)
EndIf
Case $hLoad ; User hat auf 'Laden' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten...', 0)
Load()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
GUISetCursor(2, 1, $hGui)
Case $hSave ; User hat auf 'Speichern' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Speichere Daten...', 0)
Save()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
GUISetCursor(2, 1, $hGui)
Case $hDel
GUISetCursor(15, 1, $hGui)
_GUICtrlListView_DeleteItemsSelected($hLVHandle)
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
GUISetCursor(2, 1, $hGui)
Case $hDelAll ; User hat auf 'Alle Einträge löschen' geklickt
If MsgBox(256 + 32 + 4, 'Einträge löschen', 'Wollen sie wirklich alle Einträge löschen?') = 6 Then
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlStatusBar_SetText($hStatus, 0, 1)
EndIf
Case $GUI_EVENT_CLOSE ; User hat auf das Schließen-Symbol geklickt
;~ If MsgBox(32 + 4, 'Save', 'Wollen sie vor beenden noch Speichern?') = 6 Then Save()
Exit ; Programm beenden
EndSwitch
$iSelCount = _GUICtrlListView_GetSelectedCount($hLVHandle) ; Anzahl der markierten Items holen
If $iSelCount <> $iSelOld Then ; vergleichen ob der Wert vom vorherigen abweicht (Flackern vermeiden)
$iSelOld = $iSelCount ; wenn ja, dann alten gleich neuen Wert
If $iSelCount > 0 Then ; wenn Einträge markiert sind
GUICtrlSetState($hDel, $GUI_ENABLE) ; dann Button aktivieren
GUICtrlSetData($hDel, StringFormat('(%i) Markierte Einträge löschen', $iSelCount)) ; und den Text auf dem Button anpassen
Else ; keine Einträge markiert
GUICtrlSetState($hDel, $GUI_DISABLE) ; dann Button deaktivieren
GUICtrlSetData($hDel, 'Markierte Einträge löschen') ; und den Text auf dem Button anpassen
EndIf
EndIf
WEnd
Func _Stop()
$fStop = True
EndFunc ;==>_Stop
Func _DriveSearch($sPath)
Local $aNewMP3, $aID3Tags, $sNewItem, $aItem
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
_GUICtrlStatusBar_SetText($hStatus, 'Bitte warten...', 2)
$aNewMP3 = _RecursiveFileListToArray($sPath, '\.mp3', 1) ; Alle MP3s auf der Festplatte auslesen
If Not @error And $aNewMP3[0] > 0 Then
_GUICtrlListView_SetItemCount($hListView, _GUICtrlListView_GetItemCount($hLVHandle) + $aNewMP3[0])
_GUICtrlStatusBar_SetText($hStatus, 'Lese ID3-Tags... (' & $aNewMP3[0] & ')', 0)
For $j = 1 To $aNewMP3[0] ; die gefundenen MP3s durchgehen
$aID3Tags = _ReadID3Tag($aNewMP3[$j]) ; die ID3-Tags auslesen
If Not @error Then
For $k = 0 To 10
$aID3Tags[$k][1] = StringReplace($aID3Tags[$k][1], '|', '') ; evtl. vorhandene "|" entfernen
Next
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
_GUICtrlStatusBar_SetText($hStatus, $aNewMP3[$j], 2)
$sNewItem = $aID3Tags[0][1] & '|' & $aID3Tags[1][1] & '|' & $aID3Tags[4][1] & '|' & $aID3Tags[2][1] & '|' & $aID3Tags[3][1]
$sNewItem &= '|' & $aID3Tags[8][1] & '|' & $aID3Tags[9][1] & '|' & $aID3Tags[10][1] & '|' & $aNewMP3[$j]
GUICtrlCreateListViewItem($sNewItem, $hListView)
EndIf
If $fStop Then ExitLoop
Next
EndIf
EndFunc ;==>_DriveSearch
Func _WM_COMMAND($hWnd, $msg, $wParam, $lParam)
Local $nNotifyCode = BitShift($wParam, 16)
Local $nID = BitAND($wParam, 0xFFFF)
If $nID = $hInput And $nNotifyCode = 256 Then
GUICtrlSetBkColor($hInput, 0xffffff)
$iSearchIndex = -1
GUICtrlSetData($hInputOk, 'Suche starten')
_GUICtrlListView_SetItemSelected($hLVHandle, -1, False)
EndIf
Return $GUI_RUNDEFMSG
EndFunc ;==>_WM_COMMAND
Func _LVSearch()
If _GUICtrlListView_GetItemCount($hLVHandle) = 0 Then Return
Local $sSearch
$sSearch = GUICtrlRead($hInput)
$iSearchIndex = _GUICtrlListView_FindInText($hLVHandle, $sSearch, $iSearchIndex)
If $iSearchIndex > -1 Then
_GUICtrlListView_EnsureVisible($hLVHandle, $iSearchIndex)
_GUICtrlListView_SetItemSelected($hLVHandle, $iSearchIndex)
GUICtrlSetBkColor($hInput, 0xaaffaa)
GUICtrlSetData($hInputOk, 'weitersuchen...')
Else
_GUICtrlListView_EnsureVisible($hLVHandle, 0)
_GUICtrlListView_SetItemSelected($hLVHandle, -1, False)
GUICtrlSetBkColor($hInput, 0xffaaaa)
EndIf
EndFunc ;==>_LVSearch
Func _WM_NOTIFY($hWnd, $msg, $wParam, $lParam)
Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $iSelected, $sExecutePath
$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
$hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
$iCode = DllStructGetData($tNMHDR, 'Code')
Switch $hWndFrom
Case $hLVHandle
Switch $iCode
Case $NM_DBLCLK
$iSelected = ControlListView($hGui, '', $hListView, 'GetSelected')
$sExecutePath = _GUICtrlListView_GetItemText($hLVHandle, $iSelected, ![]()
ShellExecute($sExecutePath)
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>_WM_NOTIFY
Func _WM_SIZE($hWnd, $msg, $wParam, $lParam)
Local $aGuiPos = WinGetPos($hGui)
If Not BitAND(WinGetState($hGui), 16) Then
IniWrite($sInifile, 'Config', 'Width', $aGuiPos[2])
IniWrite($sInifile, 'Config', 'Height', $aGuiPos[3])
EndIf
_GUICtrlStatusBar_Resize($hStatus)
Return $GUI_RUNDEFMSG
EndFunc ;==>_WM_SIZE
Func _WM_MOVE($hWnd, $msg, $wParam, $lParam)
Local $aGuiPos = WinGetPos($hGui)
If Not BitAND(WinGetState($hGui), 16) Then
IniWrite($sInifile, 'Config', 'Left', $aGuiPos[0])
IniWrite($sInifile, 'Config', 'Top', $aGuiPos[1])
EndIf
Return $GUI_RUNDEFMSG
EndFunc ;==>_WM_MOVE
Func _WM_GETMINMAXINFO($hWnd, $msg, $wParam, $lParam)
If $hWnd = $hGui Then
Local $minmaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam)
DllStructSetData($minmaxinfo, 7, 786) ; min X
DllStructSetData($minmaxinfo, 8, 444) ; min Y
;~ DllStructSetData($minmaxinfo, 9, 800) ; max X
;~ DllStructSetData($minmaxinfo, 10, 800) ; max Y
EndIf
EndFunc ;==>_WM_GETMINMAXINFO
Func Load() ; Datenbank-Datei laden
Local $sDBFile, $hFile, $sContent, $aNewItems, $iTimer, $iCount
FileChangeDir(@ScriptDir)
$sDBFile = FileOpenDialog('MP3-Datenbank-Datei auswählen', @ScriptDir, 'MP3-Datenbank (*.db3)', 3, '', $hGui)
If Not FileExists($sDBFile) Then Return
$hFile = FileOpen($sDBFile, 0) ; Datei zum lesen öffnen
If $hFile = -1 Then Return; wenn das öffnen nicht erfolgreich war, dann Funktion verlassen
$sContent = FileRead($hFile) ; Datei komplett einlesen
FileClose($hFile) ; Datei schließen
$sContent = StringTrimRight($sContent, 2) ; das letzte @CRLF entfernen
$aNewItems = StringSplit($sContent, @CRLF, 1) ; Den Dateiinhalt am Zeilenende splitten
If Not IsArray($aNewItems) Then Return ; Wenn $aNewItems kein Array ist, dann Funktion verlassen
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlListView_SetItemCount($hLVHandle, $aNewItems[0])
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten... (' & $aNewItems[0] & ')', 0)
_GUICtrlListView_BeginUpdate($hLVHandle) ; Listview sperren
$iTimer = TimerInit()
For $i = 1 To $aNewItems[0] ; Alle Einträge des Arrays durchgehen
$iCount += 1
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
EndIf
GUICtrlCreateListViewItem($aNewItems[$i], $hListView) ; mit den eingelesenen Daten einen neuen Listview-Eintrag erstellen
Next
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
_GUICtrlListView_EndUpdate($hLVHandle) ; Listview wieder freigeben
EndFunc ;==>Load
Func Save() ; Datenbank-Datei speichern
Local $sDBFile, $hFile, $iCount, $iTimer
$sDBFile = FileSaveDialog('MP3-Datenbank-Datei auswählen', '', 'MP3-Datenbank (*.db3)', 18, '', $hGui)
If @error Then Return
If StringRight($sDBFile, 4) <> '.db3' Then $sDBFile &= '.db3'
$iCount = _GUICtrlListView_GetItemCount($hLVHandle); Anzahl der Listview-Einträge holen
If $iCount = 0 Then Return ; Wenn das Listview keine Einträge enthält, dann Funktion verlassen
$hFile = FileOpen($sDBFile, 2) ; Datei zum speichern (überschreiben) öffnen
If $hFile = -1 Then Return; wenn das öffnen nicht erfolgreich war, dann Funktion verlassen
$iTimer = TimerInit()
For $i = 0 To $iCount - 1 ; Schleife, um alle Listview-Einträge durchzugehen
FileWriteLine($hFile, _GUICtrlListView_GetItemTextString($hLVHandle, $i))
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $i + 1, 2)
EndIf
Next
FileClose($hFile) ; Datei schließen
EndFunc ;==>Save
;===============================================================================
; Function Name: _RecursiveFileListToArray($sPath[, $sPattern][, $iFlag][, $iFormat][, $iRecursion][, $sDelim])
; Description:: gibt Verzeichnisse (rekursiv) und/oder Dateien zurück, die einem RegExp-Pattern entsprechen
; Parameter(s): $sPath = Startverzeichnis
; $sPattern = ein beliebiges RexExp-Pattern für die Auswahl
; $iFlag = Auswahl
; 0 = Dateien & Verzeichnisse
; 1 = nur Dateien
; 2 = nur Verzeichnisse
; $iFormat = Rückgabeformat
; 0 = String
; 1 = Array mit [0] = Anzahl
; 2 = Nullbasiertes Array
; $iRecursion = Verzeichnisse rekursiv durchsuchen
; 0 = Nein
; 1 = Ja
; $sDelim = Trennzeichen für die String-Rückgabe
; Requirement(s): AutoIt 3.3.0.0
; Return Value(s): Array/String mit den gefundenen Dateien/Verzeichnissen
; Author(s): Oscar (http://www.autoit.de)
; Anregungen von: bernd670 (http://www.autoit.de)
;===============================================================================
Func _RecursiveFileListToArray($sPath, $sPattern = '', $iFlag = 0, $iFormat = 1, $iRecursion = 1, $sDelim = @CRLF)
Local $hSearch, $sFile, $sReturn = ''
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
$hSearch = FileFindFirstFile($sPath & '*.*')
If @error Or $hSearch = -1 Then Return SetError(1, 0, $sReturn)
While Not $fStop
$sFile = FileFindNextFile($hSearch)
If @error Then ExitLoop
If @extended Then
If StringRegExp($sPath & $sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 2) Then $sReturn &= $sPath & $sFile & '\' & $sDelim
If $iRecursion Then $sReturn &= _RecursiveFileListToArray($sPath & $sFile & '\', $sPattern, $iFlag, 0)
ContinueLoop
EndIf
If StringRegExp($sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 1) Then $sReturn &= $sPath & $sFile & $sDelim
WEnd
FileClose($hSearch)
If $iFormat And $sReturn = '' Then Return StringSplit($sReturn, '', $iFormat)
If $iFormat Then Return StringSplit(StringTrimRight($sReturn, StringLen($sDelim)), $sDelim, $iFormat)
Return $sReturn
EndFunc ;==>_RecursiveFileListToArray
;===============================================================================
; Function Name: _ReadID3Tag($sPath)
; Description:: gibt ein Array mit den Daten aus den ID3-Tags zurück
; unterstützt werden die ID3-Tag-Versionen 1.0, 1.1, 2.3 und 2.4
; bei v2.4 müssen sich die ID3-Tags am Anfang der Datei befinden
; Parameter(s): $sPath = Pfad zu einer MP3-Datei
; Requirement(s): min. AutoIt v3.3.0.0
; Return Value(s): bei Erfolg: Array mit den ID3-Tagdaten (@error = 0)
; im Fehlerfall bekommt @error:
; 1 = Datei existiert nicht
; 2 = Datei konnte nicht zum lesen geöffnet werden
; 3 = falsche ID3 v2 Version
; 4 = Datei ist keine MP3-Datei
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _ReadID3Tag($sPath)
If Not FileExists($sPath) Then Return SetError(1, 0, 0)
Local $hFile, $sData, $sID3Header, $iID3HeaderSize = 0, $iOffset, $iSize, $tmp
Local $aID3v2Tags[8] = ['TIT2', 'TPE1', 'TALB', 'TYER', 'TLEN', 'TRCK', 'TCON', 'TENC']
Local $aID3[11][2] = [ _
['Title', ''],['Artist', ''],['Album', ''],['Year', ''], _
['Length', '0'],['Track', ''],['Genre', ''],['Encoder', ''], _
['MPEG-Version', ''],['Bitrate', '-'],['Sample-Freq.', '']]
Local $aMP3Version[4] = ['MPEG2.5', 'Reserved', 'MPEG2', 'MPEG1']
Local $aMP3Layer[4] = ['Reserved', 'Layer III', 'Layer II', 'Layer I']
Local $aMP3Bitrate[5][16] = [ _
[000, 032, 064, 096, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 384, 000], _
[000, 032, 040, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 144, 160, 176, 192, 224, 256, 000], _
[000, 008, 016, 024, 032, 040, 048, 056, 064, 080, 096, 112, 128, 144, 160, 000]]
Local $aSampleFreq[3][4] = [[44100, 48000, 32000, 0],[22050, 24000, 16000, 0],[11025, 12000, 8000, 0]]
Local $sMP3FrameHeader, $iMP3Version, $sMP3Version, $sMP3Layer, $iMP3Bitrate, $iMP3SampleFreq
Local $iVBRFrames = -1, $iVBRFilesize, $iVBRFlags
$hFile = FileOpen($sPath, 16)
If $hFile = -1 Then Return SetError(2, 0, 0)
$sData = Binary(FileRead($hFile, 4))
If BinaryMid($sData, 1, 3) = '0x494433' Then ; ID3 v2.x Kennung gefunden
If (BinaryMid($sData, 4, 1) = '0x03') Or (BinaryMid($sData, 4, 1) = '0x04') Then ; nur v2.3 und 2.4
FileRead($hFile, 2) ; 2 Bytes überspringen
For $i = 0 To 3 ; berechne ID3-Headergröße (4 Bytes, jedoch nur jeweils die unteren 7 Bit)
$iID3HeaderSize = BitShift($iID3HeaderSize, -7) + BitAND(Binary(FileRead($hFile, 1)), 0x7F)
Next
If $iID3HeaderSize > 0 Then
$sID3Header = Binary(FileRead($hFile, $iID3HeaderSize)) ; lese gesamten ID3-Header
For $i = 0 To 7
$iOffset = StringInStr(BinaryToString($sID3Header), $aID3v2Tags[$i]) ; Offset zu dem ID3-Tag
If $iOffset > 0 Then
$iSize = Hex(BinaryMid($sID3Header, $iOffset + 4, 4)) ; Größe des ID3-Frames
$tmp = BinaryMid($sID3Header, $iOffset + 11, Dec($iSize) - 1)
If BinaryMid($tmp, 1, 2) = '0xFFFE' Then
For $x = 3 To BinaryLen($tmp) Step 2
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 2), 2)
Next
Else
For $x = 1 To BinaryLen($tmp)
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 1))
Next
EndIf
$aID3[$i][1] = StringReplace($aID3[$i][1], Chr(0), '')
EndIf
Next
EndIf
Do
$sData = String(FileRead($hFile, 1))
If @error Then ExitLoop
If BitAND($sData, 0xff) = 0xff Then
FileSetPos($hFile, -1, 1)
$sData = String(FileRead($hFile, 4))
EndIf
Until BitAND($sData, 0xFFE00000) = 0xFFE00000
Else
FileClose($hFile)
Return SetError(3, 0, 0)
EndIf
Else ; ID3 v1.x
$iOffset = FileGetPos($hFile)
FileSetPos($hFile, -128, 2)
$sID3Header = BinaryToString(FileRead($hFile, 3))
If $sID3Header = 'TAG' Then
$aID3[0][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[1][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[2][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[3][1] = StringReplace(BinaryToString(FileRead($hFile, 4)), Chr(0), '')
EndIf
FileSetPos($hFile, $iOffset, 0)
EndIf
$sMP3FrameHeader = String($sData)
If BitAND($sMP3FrameHeader, 0xFFE00000) <> 0xFFE00000 Then
FileClose($hFile)
Return SetError(4, 0, 0) ; keine MP3-Datei, dann Return
EndIf
$iMP3Version = BitShift(BitXOR($sMP3FrameHeader, 0xFFE00000), 19) ; welche MP3-Version
$sMP3Version = $aMP3Version[$iMP3Version] ; in Textform
$sMP3Layer = $aMP3Layer[BitShift(BitAND($sMP3FrameHeader, 0x60000), 17)] ; welcher Layer
$aID3[8][1] = $sMP3Version & ' / ' & $sMP3Layer ; ins Ausgabe-Array
$iMP3Bitrate = BitShift(BitAND($sMP3FrameHeader, 0xF000), 12) ; Bitraten-Index auslesen
Switch $sMP3Version ; je nach MPEG-Version Bitrate aus der Tabelle holen
Case 'MPEG1'
$aID3[9][1] = $aMP3Bitrate[$iMP3Version - ($iMP3Version > 1)][$iMP3Bitrate]
Case 'MPEG2', 'MPEG2.5'
If $sMP3Layer = 'Layer I' Then
$aID3[9][1] = $aMP3Bitrate[3][$iMP3Bitrate]
Else
$aID3[9][1] = $aMP3Bitrate[4][$iMP3Bitrate]
EndIf
EndSwitch
$iMP3SampleFreq = BitShift(BitAND($sMP3FrameHeader, 0xC00), 10) ; Sample-Frequenz-Index auslesen
$aID3[10][1] = $aSampleFreq[2 - ($iMP3Version - ($iMP3Version > 1))][$iMP3SampleFreq] ; und Wert aus der Tabelle holen
Do ; evtl. Leerbytes überspringen
$tmp = FileRead($hFile, 1)
If @error Then ExitLoop
Until $tmp <> 0x00 Or @error
If $tmp = 0x58 And BinaryToString(FileRead($hFile, 3)) = 'ing' Then ; MP3 mit VBR (Xing-Header gefunden)?
$iVBRFlags = '0x' & Hex(FileRead($hFile, 4)) ; VBR-Flags auslesen
If BitAND($iVBRFlags, 0x3) Then ; wenn die Einträge vorhanden sind, dann...
$iVBRFrames = Dec(Hex(FileRead($hFile, 4))) ; Anzahl der VBR-Frames auslesen
$iVBRFilesize = Dec(Hex(FileRead($hFile, 4))) ; Dateigröße auslesen
$aID3[4][1] = $iVBRFrames * 1152 / $aID3[10][1] * 1000 ; VBR Laufzeit
$aID3[9][1] = 'VBR ~' & Int($iVBRFilesize * 8 / ($aID3[4][1] / 1000) / 1000) ; VBR durchschnittliche Bitrate
EndIf
Else
If $aID3[4][1] = 0 Then $aID3[4][1] = (FileGetSize($sPath) *
/ ($aID3[9][1] * 1000) * 1000 ; alternative CBR Laufzeit
$aID3[9][1] = 'CBR ' & $aID3[9][1]
EndIf
$aID3[4][1] = _TicksToTimeFormat($aID3[4][1]) ; Laufzeit (Ticks to hour:min:sec)
$aID3[9][1] &= ' kBit/s'
$aID3[10][1] &= ' Hz'
FileClose($hFile)
Return SetError(0, 0, $aID3)
EndFunc ;==>_ReadID3Tag
;===============================================================================
; Function Name: _TicksToTimeFormat($iTicks, $sFormat = '%hh:%mm:%ss')
; Description:: Diese Funktion wandelt Millisekunden in ein anzugebenes Zeitformat um
; Parameter(s): $iTicks = Zeit in Millisekunden
; $sFormat:
; %hh für Stunden
; %mm für Minuten
; %ss für Sekunden
; %ms für Millisekunden
; sonstige Zeichen, die dazwischen stehen, werden übernommen
; Requirement(s): -
; Return Value(s): Zeit im ausgewählten Format (String)
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _TicksToTimeFormat($iTicks, $sFormat = '%hh:%mm:%ss')
Local $aTime[4] = [0, 0, 0, 0], $sOut, $aTimeFormat[4] = ['hh', 'mm', 'ss', 'ms'], $aFormat
$aTime[2] = Int($iTicks / 1000)
$aTime[3] = $iTicks - $aTime[2] * 1000
$aTime[0] = Int($aTime[2] / 3600)
$aTime[2] = Mod($aTime[2], 3600)
$aTime[1] = Int($aTime[2] / 60)
$aTime[2] = Mod($aTime[2], 60)
$aFormat = StringRegExp($sFormat, '%([^%]+)', 3)
If Not IsArray($aFormat) Then Return SetError(1, 0, $iTicks)
For $i = 0 To UBound($aFormat) - 1
For $j = 0 To UBound($aTimeFormat) - 1
If StringLeft($aFormat[$i], 2) = $aTimeFormat[$j] Then $sOut &= StringFormat('%02i', $aTime[$j]) & StringMid($aFormat[$i], 3)
Next
Next
Return $sOut
EndFunc ;==>_TicksToTimeFormat
Ich denke auch, die wesentlichen Hilfen wurden genannt und wenn nilsheigener nicht ausführlicher darauf eingeht, dann ist das hier zu Ende.
[closed]
Nee, das mit der Datenbank hat damit nichts zu tun (habe ich auch schon getestet).
Tausch mal die Funktion "_WM_NOTIFY" gegen diese hier aus:
[autoit]
Func _WM_NOTIFY($hWnd, $msg, $wParam, $lParam)
Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $iSelected, $sExecutePath
$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
$hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
$iCode = DllStructGetData($tNMHDR, 'Code')
Switch $hWndFrom
Case $hLVHandle
Switch $iCode
Case $NM_DBLCLK
$iSelected = ControlListView($hGui, '', $hListView, 'GetSelected')
$sExecutePath = _GUICtrlListView_GetItemText($hLVHandle, $iSelected, ![]()
ShellExecute($sExecutePath)
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Ändere mal in Zeile 195:
[autoit]$sExecutePath = _GUICtrlListView_GetItemText($hLVHandle, DllStructGetData($tInfo, "SubItem"), ![]()
das "SubItem" in "Item" und teste dann mal.
Es hat mich nämlich schon gewundert, warum da bei mir der Index, also das Item ausgegeben wird. Aber bei mir funktioniert das nur mit "SubItem". Bei "Item" kommt bei mir immer "0" raus. ![]()
Also Win98 wird von AutoIt nicht mehr unterstützt. ![]()
Ich musste beim Löschen ja auch die Einträge aus dem Array löschen (das dauerte so lange, wegen umsortieren/ReDim).
Jetzt bin ich aber noch auf _GUICtrlListView_SimpleSort gestossen und habe das mal ausprobiert. Das dauert zwar etwas länger als mit 2D-Array und _ArraySort, aber der Vorteil ist: das 2D-Array kann wegfallen, was beim Löschen von Einträgen einen erheblichen Zeitvorteil bringt. Kurzum: Ich habe alles wieder umgestellt. ![]()
Außerdem kann man jetzt beim Laden und Speichern die Datei auswählen, wohin gespeichert bzw. von wo geladen werden soll. Das hat den Vorteil, dass man sich mehrere Datenbanken anlegen kann.
Beim speichern wird automatisch die Endung ".db3" (ausgedacht) angehängt. Laden kann man auch nur Dateien mit dieser Endung.
Und man kann jetzt einen Doppelklick auf einen Listview-Eintrag machen. Das entsprechende MP3 wird dann mit dem Standard-MP3-Player abgespielt.
Skript:
#include <Array.au3>
#include <ButtonConstants.au3>
#include <ColorConstants.au3>
#include <Date.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiStatusBar.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
Global $sHeader = 'Title|Artist|Length|Album|Year|MPEG-Version|Bitrate|Sample-Freq.|Path' ; Die Überschriften für das Listview
Global $sInifile = @ScriptDir & '\MP3-Search.ini' ; Inidatei
Global $iWidth = IniRead($sInifile, 'Config', 'Width', 770)
Global $iHeight = IniRead($sInifile, 'Config', 'Height', 406)
Global $iLeft = IniRead($sInifile, 'Config', 'Left', @DesktopWidth / 2 - 385)
Global $iTop = IniRead($sInifile, 'Config', 'Top', @DesktopHeight / 2 - 203)
#region Hauptfenster
Global $sStyle = BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX)
Global $hGui = GUICreate('MP3-Search', 770, 406, $iLeft, $iTop, $sStyle) ; Hauptfenster erstellen
GUISetBkColor(0xAAAAAA)
Global $hListView = GUICtrlCreateListView($sHeader, 5, 5, 760, 330, $LVS_SHOWSELALWAYS) ; Listview erstellen
GUICtrlSetResizing(-1, 2 + 4 + 32 + 64)
Global $hLVHandle = GUICtrlGetHandle($hListView) ; das Handle vom Listview wird für die UDF-Listview-Funktionen benötigt
_GUICtrlListView_SetColumnWidth($hLVHandle, 0, 180)
_GUICtrlListView_SetColumnWidth($hLVHandle, 1, 180)
_GUICtrlListView_SetColumnWidth($hLVHandle, 2, 60)
_GUICtrlListView_SetColumnWidth($hLVHandle, 3, 120)
_GUICtrlListView_SetColumnWidth($hLVHandle, 4, 60)
_GUICtrlListView_SetColumnWidth($hLVHandle, 5, 100)
_GUICtrlListView_SetColumnWidth($hLVHandle, 6, 100)
_GUICtrlListView_SetColumnWidth($hLVHandle, 7, 90)
_GUICtrlListView_SetColumnWidth($hLVHandle, 8, 800)
Global $hSearch = GUICtrlCreateButton('Alle Festplatten durchsuchen', 10, 340, 120, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $hSearchPath = GUICtrlCreateButton('Verzeichnis durchsuchen', 140, 340, 100, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $hLoad = GUICtrlCreateButton('Laden', 250, 340, 70, 35)
GUICtrlSetResizing(-1, 512 + 64)
Global $hSave = GUICtrlCreateButton('Speichern', 330, 340, 70, 35)
GUICtrlSetResizing(-1, 512 + 64)
Global $hDel = GUICtrlCreateButton("Markierte Einträge löschen", 410, 340, 90, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $hDelAll = GUICtrlCreateButton('Alle Einträge löschen', 510, 340, 90, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $aParts[3] = [300, 360, -1], $aText[3] = ['Fertig.', '0', '']
Global $hStatus = _GUICtrlStatusBar_Create($hGui, $aParts, $aText)
#endregion Hauptfenster
GUISetState(@SW_SHOW, $hGui) ; Hauptfenster sichtbar machen
[/autoit] [autoit][/autoit] [autoit]Global $fStop = False, $iLVCount = 0
HotKeySet('{ESC}', '_Stop')
Dim $aAccelKeys[1][2] = [['{DEL}', $hDel]] ; beim drücken der [Delete]-Taste wird "Case $hDel" ausgeführt
GUISetAccelerators($aAccelKeys, $hGui)
GUIRegisterMsg($WM_SIZE, '_WM_SIZE')
GUIRegisterMsg($WM_MOVE, '_WM_MOVE')
GUIRegisterMsg($WM_GETMINMAXINFO, '_WM_GETMINMAXINFO')
GUIRegisterMsg($WM_NOTIFY, '_WM_NOTIFY')
WinMove($hGui, '', $iLeft, $iTop, $iWidth, $iHeight)
[/autoit] [autoit][/autoit] [autoit]While 1
Switch GUIGetMsg() ; anhand der Control-ID das entsprechende Case aufrufen
Case $hSearch
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
_GUICtrlStatusBar_SetText($hStatus, 0, 1)
$iLVCount = 0 ; Zähler auf Null setzen
$aDrives = DriveGetDrive('FIXED') ; Alle Festplatten-Buchstaben holen
If Not @error Then
GUISetCursor(15, 1, $hGui)
For $i = 1 To $aDrives[0] ; Alle Festplatten durchgehen
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Festplatte "' & StringUpper($aDrives[$i]) & '\"', 0)
_DriveSearch(StringUpper($aDrives[$i]))
Next
GUISetCursor(2, 1, $hGui)
EndIf
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, 'Abgebrochen!', 0)
Else
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
EndIf
Case $hSearchPath
$sPath = FileSelectFolder('Verzeichnis auswählen!', '', 2, '', $hGui)
If FileExists($sPath) Then
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
$iLVCount = 0 ; Zähler auf Null setzen
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Verzeichnis "' & $sPath & '"', 0)
_DriveSearch($sPath)
GUISetCursor(2, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, 'Abgebrochen!', 0)
Else
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
EndIf
EndIf
Case $hListView ; User hat auf eine Spaltenüberschrift geklickt (sortieren)
If _GUICtrlListView_GetItemCount($hLVHandle) > 0 Then
Dim $aDescending[_GUICtrlListView_GetColumnCount($hLVHandle)]
GUISetCursor(15, 1, $hGui)
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, 'Sortiere Daten! Bitte warten...', 0)
_GUICtrlListView_SimpleSort($hLVHandle, $aDescending, GUICtrlGetState($hListView))
_GUICtrlStatusBar_SetText($hStatus, _TicksToTimeFormat(TimerDiff($iTimer), '%mm:%ss.%ms'), 2)
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
GUISetCursor(2, 1, $hGui)
EndIf
Case $hLoad ; User hat auf 'Laden' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten...', 0)
Load()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
GUISetCursor(2, 1, $hGui)
Case $hSave ; User hat auf 'Speichern' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Speichere Daten...', 0)
Save()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
GUISetCursor(2, 1, $hGui)
Case $hDel
GUISetCursor(15, 1, $hGui)
_GUICtrlListView_DeleteItemsSelected($hLVHandle)
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
GUISetCursor(2, 1, $hGui)
Case $hDelAll ; User hat auf 'Alle Einträge löschen' geklickt
If MsgBox(256 + 32 + 4, 'Einträge löschen', 'Wollen sie wirklich alle Einträge löschen?') = 6 Then
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlStatusBar_SetText($hStatus, 0, 1)
EndIf
Case $GUI_EVENT_CLOSE ; User hat auf das Schließen-Symbol geklickt
If MsgBox(32 + 4, 'Beenden', 'Wollen sie das Programm wirklich beenden?') = 6 Then _End() ; wenn ja, dann End-Funktion aufrufen
EndSwitch
WEnd
Func _Stop()
$fStop = True
EndFunc ;==>_Stop
Func _End()
;~ Save() ; wenn der vordere Kommentar entfernt wird, dann werden vor dem beenden noch die Daten gespeichert
Exit ; Programm beenden
EndFunc ;==>End
Func _DriveSearch($sPath)
Local $aNewMP3, $aID3Tags, $sNewItem, $aItem
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
_GUICtrlStatusBar_SetText($hStatus, 'Bitte warten...', 2)
$aNewMP3 = _RecursiveFileListToArray($sPath, '\.mp3', 1) ; Alle MP3s auf der Festplatte auslesen
If Not @error And $aNewMP3[0] > 0 Then
_GUICtrlListView_SetItemCount($hListView, _GUICtrlListView_GetItemCount($hLVHandle) + $aNewMP3[0])
_GUICtrlStatusBar_SetText($hStatus, 'Lese ID3-Tags... (' & $aNewMP3[0] & ')', 0)
For $j = 1 To $aNewMP3[0] ; die gefundenen MP3s durchgehen
$aID3Tags = _ReadID3Tag($aNewMP3[$j]) ; die ID3-Tags auslesen
If Not @error Then
For $k = 0 To 10
$aID3Tags[$k][1] = StringReplace($aID3Tags[$k][1], '|', '') ; evtl. vorhandene "|" entfernen
Next
_GUICtrlStatusBar_SetText($hStatus, _GUICtrlListView_GetItemCount($hLVHandle), 1)
_GUICtrlStatusBar_SetText($hStatus, $aNewMP3[$j], 2)
$sNewItem = $aID3Tags[0][1] & '|' & $aID3Tags[1][1] & '|' & $aID3Tags[4][1] & '|' & $aID3Tags[2][1] & '|' & $aID3Tags[3][1]
$sNewItem &= '|' & $aID3Tags[8][1] & '|' & $aID3Tags[9][1] & '|' & $aID3Tags[10][1] & '|' & $aNewMP3[$j]
GUICtrlCreateListViewItem($sNewItem, $hListView)
EndIf
If $fStop Then ExitLoop
Next
EndIf
EndFunc ;==>_DriveSearch
Func _WM_NOTIFY($hWnd, $msg, $wParam, $lParam)
Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $tInfo, $sExecutePath
$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
$hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
$iIDFrom = DllStructGetData($tNMHDR, 'IDFrom')
$iCode = DllStructGetData($tNMHDR, 'Code')
Switch $hWndFrom
Case $hLVHandle
Switch $iCode
Case $NM_DBLCLK
$tInfo = DllStructCreate($tagNMITEMACTIVATE, $lParam)
$sExecutePath = _GUICtrlListView_GetItemText($hLVHandle, DllStructGetData($tInfo, "SubItem"), ![]()
ShellExecute($sExecutePath)
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Func _WM_SIZE($hWnd, $msg, $wParam, $lParam)
Local $aGuiPos = WinGetPos($hGui)
If Not BitAND(WinGetState($hGui), 16) Then
IniWrite($sInifile, 'Config', 'Width', $aGuiPos[2])
IniWrite($sInifile, 'Config', 'Height', $aGuiPos[3])
EndIf
_GUICtrlStatusBar_Resize($hStatus)
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_SIZE
Func _WM_MOVE($hWnd, $msg, $wParam, $lParam)
Local $aGuiPos = WinGetPos($hGui)
If Not BitAND(WinGetState($hGui), 16) Then
IniWrite($sInifile, 'Config', 'Left', $aGuiPos[0])
IniWrite($sInifile, 'Config', 'Top', $aGuiPos[1])
EndIf
Return $GUI_RUNDEFMSG
EndFunc
Func _WM_GETMINMAXINFO($hWnd, $msg, $wParam, $lParam)
If $hWnd = $hGui Then
Local $minmaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam)
DllStructSetData($minmaxinfo, 7, 786) ; min X
DllStructSetData($minmaxinfo, 8, 444) ; min Y
;~ DllStructSetData($minmaxinfo, 9, 800) ; max X
;~ DllStructSetData($minmaxinfo, 10, 800) ; max Y
EndIf
EndFunc
Func Load() ; Datenbank-Datei laden
Local $sDBFile, $hFile, $sContent, $aNewItems, $iTimer, $iCount
FileChangeDir(@ScriptDir)
$sDBFile = FileOpenDialog('MP3-Datenbank-Datei auswählen', @ScriptDir, 'MP3-Datenbank (*.db3)', 3, '', $hGui)
If Not FileExists($sDBFile) Then Return
$hFile = FileOpen($sDBFile, 0) ; Datei zum lesen öffnen
If $hFile = -1 Then Return; wenn das öffnen nicht erfolgreich war, dann Funktion verlassen
$sContent = FileRead($hFile) ; Datei komplett einlesen
FileClose($hFile) ; Datei schließen
$sContent = StringTrimRight($sContent, 2) ; das letzte @CRLF entfernen
$aNewItems = StringSplit($sContent, @CRLF, 1) ; Den Dateiinhalt am Zeilenende splitten
If Not IsArray($aNewItems) Then Return ; Wenn $aNewItems kein Array ist, dann Funktion verlassen
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlListView_SetItemCount($hLVHandle, $aNewItems[0])
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten... (' & $aNewItems[0] & ')', 0)
_GUICtrlListView_BeginUpdate($hLVHandle) ; Listview sperren
$iTimer = TimerInit()
For $i = 1 To $aNewItems[0] ; Alle Einträge des Arrays durchgehen
$iCount += 1
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
EndIf
GUICtrlCreateListViewItem($aNewItems[$i], $hListView) ; mit den eingelesenen Daten einen neuen Listview-Eintrag erstellen
Next
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
_GUICtrlListView_EndUpdate($hLVHandle) ; Listview wieder freigeben
EndFunc ;==>Load
Func Save() ; Datenbank-Datei speichern
Local $sDBFile, $hFile, $iCount, $iTimer
$sDBFile = FileSaveDialog('MP3-Datenbank-Datei auswählen', '', 'MP3-Datenbank (*.db3)', 18, '', $hGui)
If @error Then Return
If StringRight($sDBFile, 4) <> '.db3' Then $sDBFile &= '.db3'
$iCount = _GUICtrlListView_GetItemCount($hLVHandle); Anzahl der Listview-Einträge holen
If $iCount = 0 Then Return ; Wenn das Listview keine Einträge enthält, dann Funktion verlassen
$hFile = FileOpen($sDBFile, 2) ; Datei zum speichern (überschreiben) öffnen
If $hFile = -1 Then Return; wenn das öffnen nicht erfolgreich war, dann Funktion verlassen
$iTimer = TimerInit()
For $i = 0 To $iCount - 1 ; Schleife, um alle Listview-Einträge durchzugehen
FileWriteLine($hFile, _GUICtrlListView_GetItemTextString($hLVHandle, $i))
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $i + 1, 2)
EndIf
Next
FileClose($hFile) ; Datei schließen
EndFunc ;==>Save
;===============================================================================
; Function Name: _RecursiveFileListToArray($sPath[, $sPattern][, $iFlag][, $iFormat][, $iRecursion][, $sDelim])
; Description:: gibt Verzeichnisse (rekursiv) und/oder Dateien zurück, die einem RegExp-Pattern entsprechen
; Parameter(s): $sPath = Startverzeichnis
; $sPattern = ein beliebiges RexExp-Pattern für die Auswahl
; $iFlag = Auswahl
; 0 = Dateien & Verzeichnisse
; 1 = nur Dateien
; 2 = nur Verzeichnisse
; $iFormat = Rückgabeformat
; 0 = String
; 1 = Array mit [0] = Anzahl
; 2 = Nullbasiertes Array
; $iRecursion = Verzeichnisse rekursiv durchsuchen
; 0 = Nein
; 1 = Ja
; $sDelim = Trennzeichen für die String-Rückgabe
; Requirement(s): AutoIt 3.3.0.0
; Return Value(s): Array/String mit den gefundenen Dateien/Verzeichnissen
; Author(s): Oscar (http://www.autoit.de)
; Anregungen von: bernd670 (http://www.autoit.de)
;===============================================================================
Func _RecursiveFileListToArray($sPath, $sPattern = '', $iFlag = 0, $iFormat = 1, $iRecursion = 1, $sDelim = @CRLF)
Local $hSearch, $sFile, $sReturn = ''
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
$hSearch = FileFindFirstFile($sPath & '*.*')
If @error Or $hSearch = -1 Then Return SetError(1, 0, $sReturn)
While Not $fStop
$sFile = FileFindNextFile($hSearch)
If @error Then ExitLoop
If @extended Then
If StringRegExp($sPath & $sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 2) Then $sReturn &= $sPath & $sFile & '\' & $sDelim
If $iRecursion Then $sReturn &= _RecursiveFileListToArray($sPath & $sFile & '\', $sPattern, $iFlag, 0)
ContinueLoop
EndIf
If StringRegExp($sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 1) Then $sReturn &= $sPath & $sFile & $sDelim
WEnd
FileClose($hSearch)
If $iFormat And $sReturn = '' Then Return StringSplit($sReturn, '', $iFormat)
If $iFormat Then Return StringSplit(StringTrimRight($sReturn, StringLen($sDelim)), $sDelim, $iFormat)
Return $sReturn
EndFunc ;==>_RecursiveFileListToArray
;===============================================================================
; Function Name: _ReadID3Tag($sPath)
; Description:: gibt ein Array mit den Daten aus den ID3-Tags zurück
; unterstützt werden die ID3-Tag-Versionen 1.0, 1.1, 2.3 und 2.4
; bei v2.4 müssen sich die ID3-Tags am Anfang der Datei befinden
; Parameter(s): $sPath = Pfad zu einer MP3-Datei
; Requirement(s): min. AutoIt v3.3.0.0
; Return Value(s): bei Erfolg: Array mit den ID3-Tagdaten (@error = 0)
; im Fehlerfall bekommt @error:
; 1 = Datei existiert nicht
; 2 = Datei konnte nicht zum lesen geöffnet werden
; 3 = falsche ID3 v2 Version
; 4 = Datei ist keine MP3-Datei
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _ReadID3Tag($sPath)
If Not FileExists($sPath) Then Return SetError(1, 0, 0)
Local $hFile, $sData, $sID3Header, $iID3HeaderSize = 0, $iOffset, $iSize, $tmp
Local $aID3v2Tags[8] = ['TIT2', 'TPE1', 'TALB', 'TYER', 'TLEN', 'TRCK', 'TCON', 'TENC']
Local $aID3[11][2] = [ _
['Title', ''],['Artist', ''],['Album', ''],['Year', ''], _
['Length', '0'],['Track', ''],['Genre', ''],['Encoder', ''], _
['MPEG-Version', ''],['Bitrate', '-'],['Sample-Freq.', '']]
Local $aMP3Version[4] = ['MPEG2.5', 'Reserved', 'MPEG2', 'MPEG1']
Local $aMP3Layer[4] = ['Reserved', 'Layer III', 'Layer II', 'Layer I']
Local $aMP3Bitrate[5][16] = [ _
[000, 032, 064, 096, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 384, 000], _
[000, 032, 040, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 144, 160, 176, 192, 224, 256, 000], _
[000, 008, 016, 024, 032, 040, 048, 056, 064, 080, 096, 112, 128, 144, 160, 000]]
Local $aSampleFreq[3][4] = [[44100, 48000, 32000, 0],[22050, 24000, 16000, 0],[11025, 12000, 8000, 0]]
Local $sMP3FrameHeader, $iMP3Version, $sMP3Version, $sMP3Layer, $iMP3Bitrate, $iMP3SampleFreq
Local $iVBRFrames = -1, $iVBRFilesize, $iVBRFlags
$hFile = FileOpen($sPath, 16)
If $hFile = -1 Then Return SetError(2, 0, 0)
$sData = Binary(FileRead($hFile, 4))
If BinaryMid($sData, 1, 3) = '0x494433' Then ; ID3 v2.x Kennung gefunden
If (BinaryMid($sData, 4, 1) = '0x03') Or (BinaryMid($sData, 4, 1) = '0x04') Then ; nur v2.3 und 2.4
FileRead($hFile, 2) ; 2 Bytes überspringen
For $i = 0 To 3 ; berechne ID3-Headergröße (4 Bytes, jedoch nur jeweils die unteren 7 Bit)
$iID3HeaderSize = BitShift($iID3HeaderSize, -7) + BitAND(Binary(FileRead($hFile, 1)), 0x7F)
Next
If $iID3HeaderSize > 0 Then
$sID3Header = Binary(FileRead($hFile, $iID3HeaderSize)) ; lese gesamten ID3-Header
For $i = 0 To 7
$iOffset = StringInStr(BinaryToString($sID3Header), $aID3v2Tags[$i]) ; Offset zu dem ID3-Tag
If $iOffset > 0 Then
$iSize = Hex(BinaryMid($sID3Header, $iOffset + 4, 4)) ; Größe des ID3-Frames
$tmp = BinaryMid($sID3Header, $iOffset + 11, Dec($iSize) - 1)
If BinaryMid($tmp, 1, 2) = '0xFFFE' Then
For $x = 3 To BinaryLen($tmp) Step 2
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 2), 2)
Next
Else
For $x = 1 To BinaryLen($tmp)
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 1))
Next
EndIf
$aID3[$i][1] = StringReplace($aID3[$i][1], Chr(0), '')
EndIf
Next
EndIf
Do
$sData = String(FileRead($hFile, 1))
If @error Then ExitLoop
If BitAND($sData, 0xff) = 0xff Then
FileSetPos($hFile, -1, 1)
$sData = String(FileRead($hFile, 4))
EndIf
Until BitAND($sData, 0xFFE00000) = 0xFFE00000
Else
FileClose($hFile)
Return SetError(3, 0, 0)
EndIf
Else ; ID3 v1.x
$iOffset = FileGetPos($hFile)
FileSetPos($hFile, -128, 2)
$sID3Header = BinaryToString(FileRead($hFile, 3))
If $sID3Header = 'TAG' Then
$aID3[0][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[1][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[2][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[3][1] = StringReplace(BinaryToString(FileRead($hFile, 4)), Chr(0), '')
EndIf
FileSetPos($hFile, $iOffset, 0)
EndIf
$sMP3FrameHeader = String($sData)
If BitAND($sMP3FrameHeader, 0xFFE00000) <> 0xFFE00000 Then
FileClose($hFile)
Return SetError(4, 0, 0) ; keine MP3-Datei, dann Return
EndIf
$iMP3Version = BitShift(BitXOR($sMP3FrameHeader, 0xFFE00000), 19) ; welche MP3-Version
$sMP3Version = $aMP3Version[$iMP3Version] ; in Textform
$sMP3Layer = $aMP3Layer[BitShift(BitAND($sMP3FrameHeader, 0x60000), 17)] ; welcher Layer
$aID3[8][1] = $sMP3Version & ' / ' & $sMP3Layer ; ins Ausgabe-Array
$iMP3Bitrate = BitShift(BitAND($sMP3FrameHeader, 0xF000), 12) ; Bitraten-Index auslesen
Switch $sMP3Version ; je nach MPEG-Version Bitrate aus der Tabelle holen
Case 'MPEG1'
$aID3[9][1] = $aMP3Bitrate[$iMP3Version - ($iMP3Version > 1)][$iMP3Bitrate]
Case 'MPEG2', 'MPEG2.5'
If $sMP3Layer = 'Layer I' Then
$aID3[9][1] = $aMP3Bitrate[3][$iMP3Bitrate]
Else
$aID3[9][1] = $aMP3Bitrate[4][$iMP3Bitrate]
EndIf
EndSwitch
$iMP3SampleFreq = BitShift(BitAND($sMP3FrameHeader, 0xC00), 10) ; Sample-Frequenz-Index auslesen
$aID3[10][1] = $aSampleFreq[2 - ($iMP3Version - ($iMP3Version > 1))][$iMP3SampleFreq] ; und Wert aus der Tabelle holen
Do ; evtl. Leerbytes überspringen
$tmp = FileRead($hFile, 1)
If @error Then ExitLoop
Until $tmp <> 0x00 Or @error
If $tmp = 0x58 And BinaryToString(FileRead($hFile, 3)) = 'ing' Then ; MP3 mit VBR (Xing-Header gefunden)?
$iVBRFlags = '0x' & Hex(FileRead($hFile, 4)) ; VBR-Flags auslesen
If BitAND($iVBRFlags, 0x3) Then ; wenn die Einträge vorhanden sind, dann...
$iVBRFrames = Dec(Hex(FileRead($hFile, 4))) ; Anzahl der VBR-Frames auslesen
$iVBRFilesize = Dec(Hex(FileRead($hFile, 4))) ; Dateigröße auslesen
$aID3[4][1] = $iVBRFrames * 1152 / $aID3[10][1] * 1000 ; VBR Laufzeit
$aID3[9][1] = 'VBR ~' & Int($iVBRFilesize * 8 / ($aID3[4][1] / 1000) / 1000) ; VBR durchschnittliche Bitrate
EndIf
Else
If $aID3[4][1] = 0 Then $aID3[4][1] = (FileGetSize($sPath) *
/ ($aID3[9][1] * 1000) * 1000 ; alternative CBR Laufzeit
$aID3[9][1] = 'CBR ' & $aID3[9][1]
EndIf
$aID3[4][1] = _TicksToTimeFormat($aID3[4][1]) ; Laufzeit (Ticks to hour:min:sec)
$aID3[9][1] &= ' kBit/s'
$aID3[10][1] &= ' Hz'
FileClose($hFile)
Return SetError(0, 0, $aID3)
EndFunc ;==>_ReadID3Tag
;===============================================================================
; Function Name: _TicksToTimeFormat($iTicks, $sFormat = '%hh:%mm:%ss')
; Description:: Diese Funktion wandelt Millisekunden in ein anzugebenes Zeitformat um
; Parameter(s): $iTicks = Zeit in Millisekunden
; $sFormat:
; %hh für Stunden
; %mm für Minuten
; %ss für Sekunden
; %ms für Millisekunden
; sonstige Zeichen, die dazwischen stehen, werden übernommen
; Requirement(s): -
; Return Value(s): Zeit im ausgewählten Format (String)
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _TicksToTimeFormat($iTicks, $sFormat = '%hh:%mm:%ss')
Local $aTime[4] = [0, 0, 0, 0], $sOut, $aTimeFormat[4] = ['hh', 'mm', 'ss', 'ms'], $aFormat
$aTime[2] = Int($iTicks / 1000)
$aTime[3] = $iTicks - $aTime[2] * 1000
$aTime[0] = Int($aTime[2] / 3600)
$aTime[2] = Mod($aTime[2], 3600)
$aTime[1] = Int($aTime[2] / 60)
$aTime[2] = Mod($aTime[2], 60)
$aFormat = StringRegExp($sFormat, '%([^%]+)', 3)
If Not IsArray($aFormat) Then Return SetError(1, 0, $iTicks)
For $i = 0 To UBound($aFormat) - 1
For $j = 0 To UBound($aTimeFormat) - 1
If StringLeft($aFormat[$i], 2) = $aTimeFormat[$j] Then $sOut &= StringFormat('%02i', $aTime[$j]) & StringMid($aFormat[$i], 3)
Next
Next
Return $sOut
EndFunc ;==>_TicksToTimeFormat
Edit: Kleinen Bug behoben.
Mit "Geschwindikeit ohne Speichern" meinst Du vermutlich das einlesen/durchsuchen der Festplatten, oder?
Wenn ja, das ist normal. Die Funktion muss ja alle Dateien auf den Festplatten durchgehen. Ganz witzig in diesem Zusammenhang ist, dass, wenn man die Funktion ein zweites Mal (gleich danach) aufruft, es dann wesentlich schneller geht (Verzeichnisse/Dateien befinden sich im Cache).
Ressourcenverbrauch ist normal.
Geschwindigkeit auch, bis auf das mit dem Löschen. Das könnte evtl. auch schneller gehen, wenn man alle Einträge löscht und neu erstellen lässt (analog zum sortieren). Muss ich mal testen...
Das mit dem Fenster anpassen habe ich jetzt mal auf ReSizing gesetzt. Das Fenster kann also in der Größe verändert werden (wird abgespeichert).
Die Buttons waren eigentlich noch nicht vollzählig. ![]()
Da habe ich jetzt noch [Verzeichnis durchsuchen] hinzugefügt und dann etwas zusammengerückt.
Das mit der DEL-Taste kannst Du so nicht machen. Es sieht zwar erstmal richtig aus, aber dabei wird das 2D-Array nicht angepasst und beim nächsten sortieren sind die Einträge wieder da. Ich hab's mal kommentiert (so ist es einfacher).
Beim sortieren wird jetzt unten in der Statusleiste angezeigt, was das Programm gerade macht (mit Zeitstempel wie lange es dafür gebraucht hat).
Skript:
#include <Array.au3>
#include <ButtonConstants.au3>
#include <ColorConstants.au3>
#include <Date.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiStatusBar.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
Global $sHeader = 'Title|Artist|Album|Year|Length|MPEG-Version|Bitrate|Sample-Freq.|Path' ; Die Überschriften für das Listview
Global $sDBFile = @ScriptDir & '\MP3-Search.txt' ; Pfad und Name der Datenbank-Datei
Global $sInifile = @ScriptDir & '\MP3-Search.ini' ; Inidatei
Global $aListview[1][9]
Global $iWidth = IniRead($sInifile, 'Config', 'Width', 770)
Global $iHeight = IniRead($sInifile, 'Config', 'Height', 406)
Global $iLeft = IniRead($sInifile, 'Config', 'Left', @DesktopWidth / 2 - 385)
Global $iTop = IniRead($sInifile, 'Config', 'Top', @DesktopHeight / 2 - 203)
#region Hauptfenster
Global $sStyle = BitOR($GUI_SS_DEFAULT_GUI, $WS_MAXIMIZEBOX, $WS_SIZEBOX)
Global $hGui = GUICreate('MP3-Search', 770, 406, $iLeft, $iTop, $sStyle) ; Hauptfenster erstellen
GUISetBkColor(0xAAAAAA)
Global $hListView = GUICtrlCreateListView($sHeader, 5, 5, 760, 330, $LVS_SHOWSELALWAYS) ; Listview erstellen
GUICtrlSetResizing(-1, 2 + 4 + 32 + 64)
Global $hLVHandle = GUICtrlGetHandle($hListView) ; das Handle vom Listview wird für die UDF-Listview-Funktionen benötigt
_GUICtrlListView_SetColumn($hLVHandle, 0, 'Title', 180, 0)
_GUICtrlListView_SetColumn($hLVHandle, 1, 'Artist', 180, 0)
_GUICtrlListView_SetColumn($hLVHandle, 2, 'Length', 60, 0)
_GUICtrlListView_SetColumn($hLVHandle, 3, 'Album', 120, 0)
_GUICtrlListView_SetColumn($hLVHandle, 4, 'Year', 60, 0)
_GUICtrlListView_SetColumn($hLVHandle, 5, 'MPEG-Version', 100, 0)
_GUICtrlListView_SetColumn($hLVHandle, 6, 'Bitrate', 100, 0)
_GUICtrlListView_SetColumn($hLVHandle, 7, 'Sample-Freq.', 90, 0)
_GUICtrlListView_SetColumn($hLVHandle, 8, 'Path', 800, 0)
Global $hSearch = GUICtrlCreateButton('Alle Festplatten durchsuchen', 10, 340, 120, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $hSearchPath = GUICtrlCreateButton('Verzeichnis durchsuchen', 140, 340, 100, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $hLoad = GUICtrlCreateButton('Laden', 250, 340, 70, 35)
GUICtrlSetResizing(-1, 512 + 64)
Global $hSave = GUICtrlCreateButton('Speichern', 330, 340, 70, 35)
GUICtrlSetResizing(-1, 512 + 64)
Global $hDel = GUICtrlCreateButton("Markierte Einträge löschen", 410, 340, 90, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $hDelAll = GUICtrlCreateButton('Alle Einträge löschen', 510, 340, 90, 35, $BS_MULTILINE)
GUICtrlSetResizing(-1, 512 + 64)
Global $aParts[3] = [300, 360, -1], $aText[3] = ['Fertig.', '0', '']
Global $hStatus = _GUICtrlStatusBar_Create($hGui, $aParts, $aText)
#endregion Hauptfenster
GUISetState(@SW_SHOW, $hGui) ; Hauptfenster sichtbar machen
[/autoit] [autoit][/autoit] [autoit]Global $fStop = False, $iLVCount = 0
HotKeySet('{ESC}', '_Stop')
Dim $aAccelKeys[1][2] = [['{DEL}', $hDel]] ; beim drücken der [Delete]-Taste wird "Case $hDel" ausgeführt
GUISetAccelerators($aAccelKeys, $hGui)
GUIRegisterMsg($WM_SIZE, '_WM_SIZE')
GUIRegisterMsg($WM_MOVE, '_WM_MOVE')
GUIRegisterMsg($WM_GETMINMAXINFO, '_WM_GETMINMAXINFO')
WinMove($hGui, '', $iLeft, $iTop, $iWidth, $iHeight)
[/autoit] [autoit][/autoit] [autoit]While 1
Switch GUIGetMsg() ; anhand der Control-ID das entsprechende Case aufrufen
Case $hSearch
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
$iLVCount = 0 ; Zähler auf Null setzen
$aDrives = DriveGetDrive('FIXED') ; Alle Festplatten-Buchstaben holen
If Not @error Then
GUISetCursor(15, 1, $hGui)
For $i = 1 To $aDrives[0] ; Alle Festplatten durchgehen
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Festplatte "' & StringUpper($aDrives[$i]) & '"', 0)
_DriveSearch(StringUpper($aDrives[$i]))
Next
GUISetCursor(2, 1, $hGui)
EndIf
_GUICtrlStatusBar_SetText($hStatus, $iLVCount, 1)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, 'Abgebrochen!', 0)
Else
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
EndIf
Case $hSearchPath
$sPath = FileSelectFolder('Verzeichnis auswählen!', '', 2, '', $hGui)
If FileExists($sPath) Then
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
$iLVCount = 0 ; Zähler auf Null setzen
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Verzeichnis "' & $sPath & '"', 0)
_DriveSearch($sPath)
GUISetCursor(2, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, $iLVCount, 1)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, 'Abgebrochen!', 0)
Else
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
EndIf
EndIf
Case $hListView ; User hat auf eine Spaltenüberschrift geklickt
If $iLVCount > 0 Then
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetBkColor($hStatus, $CLR_MONEYGREEN)
_GUICtrlStatusBar_SetText($hStatus, 'Sortiere Daten! Bitte warten...', 0)
$iSort = GUICtrlGetState($hListView)
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, '[' & _TicksToTimeFormat(TimerDiff($iTimer), '%mm:%ss.%ms') & '] Sortiere nach Spalte: ' & $iSort, 2)
_ArraySort($aListview, 0, 0, 0, $iSort)
_GUICtrlStatusBar_SetText($hStatus, '[' & _TicksToTimeFormat(TimerDiff($iTimer), '%mm:%ss.%ms') & '] Lösche alle Einträge', 2)
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlStatusBar_SetText($hStatus, '[' & _TicksToTimeFormat(TimerDiff($iTimer), '%mm:%ss.%ms') & '] Einträge neu erstellen', 2)
_GUICtrlListView_BeginUpdate($hLVHandle) ; Listview sperren
_GUICtrlListView_AddArray($hLVHandle, $aListview)
_GUICtrlListView_EndUpdate($hLVHandle) ; Listview wieder freigeben
_GUICtrlStatusBar_SetText($hStatus, '[' & _TicksToTimeFormat(TimerDiff($iTimer), '%mm:%ss.%ms') & '] Sortiert.', 2)
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
_GUICtrlStatusBar_SetBkColor($hStatus, $CLR_DEFAULT)
GUISetCursor(2, 1, $hGui)
EndIf
Case $hLoad ; User hat auf 'Laden' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten...', 0)
Load()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
GUISetCursor(2, 1, $hGui)
Case $hSave ; User hat auf 'Speichern' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Speichere Daten...', 0)
Save()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
GUISetCursor(2, 1, $hGui)
Case $hDel
$aSelectedItems = _GUICtrlListView_GetSelectedIndices($hLVHandle, True)
If $aSelectedItems[0] > 0 Then
GUISetCursor(15, 1, $hGui)
For $i = $aSelectedItems[0] To 1 Step -1
_ArrayDelete($aListview, $aSelectedItems[$i])
Next
_GUICtrlListView_DeleteItemsSelected($hLVHandle)
$iLVCount -= $aSelectedItems[0]
_GUICtrlStatusBar_SetText($hStatus, $iLVCount, 1)
GUISetCursor(2, 1, $hGui)
EndIf
Case $hDelAll ; User hat auf 'Alle Einträge löschen' geklickt
If MsgBox(256 + 32 + 4, 'Einträge löschen', 'Wollen sie wirklich alle Einträge löschen?') = 6 Then
_GUICtrlListView_DeleteAllItems($hLVHandle)
ReDim $aListview[1][9]
$iLVCount = 0
_GUICtrlStatusBar_SetText($hStatus, $iLVCount, 1)
EndIf
Case $GUI_EVENT_CLOSE ; User hat auf das Schließen-Symbol geklickt (bzw. die ESC-Taste gedrückt)
If MsgBox(32 + 4, 'Beenden', 'Wollen sie das Programm wirklich beenden?') = 6 Then _End() ; wenn ja, dann End-Funktion aufrufen
EndSwitch
WEnd
Func _Stop()
$fStop = True
EndFunc ;==>_Stop
Func _End()
;~ Save() ; wenn der vordere Kommentar entfernt wird, dann werden vor dem beenden noch die Daten gespeichert
Exit ; Programm beenden
EndFunc ;==>End
Func _DriveSearch($sPath)
Local $aNewMP3, $aID3Tags, $sNewItem, $aItem
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
_GUICtrlStatusBar_SetText($hStatus, 'Bitte warten...', 2)
$aNewMP3 = _RecursiveFileListToArray($sPath, '\.mp3', 1) ; Alle MP3s auf der Festplatte auslesen
If Not @error And $aNewMP3[0] > 0 Then
_GUICtrlListView_SetItemCount($hListView, $iLVCount + $aNewMP3[0])
ReDim $aListview[$iLVCount + $aNewMP3[0] + 1][9]
_GUICtrlStatusBar_SetText($hStatus, 'Lese ID3-Tags... (' & $aNewMP3[0] & ')', 0)
For $j = 1 To $aNewMP3[0] ; die gefundenen MP3s durchgehen
_GUICtrlStatusBar_SetText($hStatus, $iLVCount, 1)
$aID3Tags = _ReadID3Tag($aNewMP3[$j]) ; die ID3-Tags auslesen
If Not @error Then
For $k = 0 To 10
$aID3Tags[$k][1] = StringReplace($aID3Tags[$k][1], '|', '') ; evtl. vorhandene "|" entfernen
Next
_GUICtrlStatusBar_SetText($hStatus, $aNewMP3[$j], 2)
$sNewItem = $aID3Tags[0][1] & '|' & $aID3Tags[1][1] & '|' & $aID3Tags[4][1] & '|' & $aID3Tags[2][1] & '|' & $aID3Tags[3][1]
$sNewItem &= '|' & $aID3Tags[8][1] & '|' & $aID3Tags[9][1] & '|' & $aID3Tags[10][1] & '|' & $aNewMP3[$j]
$aItem = StringSplit($sNewItem, '|')
For $k = 1 To $aItem[0]
$aListview[$iLVCount][$k - 1] = $aItem[$k]
Next
GUICtrlCreateListViewItem($sNewItem, $hListView)
$iLVCount += 1
EndIf
If $fStop Then ExitLoop
Next
ReDim $aListview[$iLVCount][9]
EndIf
EndFunc ;==>_DriveSearch
Func _WM_SIZE($hWnd, $msg, $wParam, $lParam)
Local $aGuiPos = WinGetPos($hGui)
If Not BitAND(WinGetState($hGui), 16) Then
IniWrite($sInifile, 'Config', 'Width', $aGuiPos[2])
IniWrite($sInifile, 'Config', 'Height', $aGuiPos[3])
EndIf
_GUICtrlStatusBar_Resize($hStatus)
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_SIZE
Func _WM_MOVE($hWnd, $msg, $wParam, $lParam)
Local $aGuiPos = WinGetPos($hGui)
If Not BitAND(WinGetState($hGui), 16) Then
IniWrite($sInifile, 'Config', 'Left', $aGuiPos[0])
IniWrite($sInifile, 'Config', 'Top', $aGuiPos[1])
EndIf
Return $GUI_RUNDEFMSG
EndFunc
Func _WM_GETMINMAXINFO($hWnd, $msg, $wParam, $lParam)
If $hWnd = $hGui Then
Local $minmaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam)
DllStructSetData($minmaxinfo, 7, 786) ; min X
DllStructSetData($minmaxinfo, 8, 444) ; min Y
;~ DllStructSetData($minmaxinfo, 9, 800) ; max X
;~ DllStructSetData($minmaxinfo, 10, 800) ; max Y
EndIf
EndFunc
Func Load() ; Datenbank-Datei laden
Local $hFile, $sContent, $aNewItems, $iTimer, $iCount, $aItem
$hFile = FileOpen($sDBFile, 0) ; Datei zum lesen öffnen
If $hFile <> -1 Then ; wenn das öffnen erfolgreich war, dann...
$sContent = FileRead($hFile) ; Datei komplett einlesen
FileClose($hFile) ; Datei schließen
$sContent = StringTrimRight($sContent, 2) ; das letzte @CRLF entfernen
$aNewItems = StringSplit($sContent, @CRLF, 1) ; Den Dateiinhalt am Zeilenende splitten
If Not IsArray($aNewItems) Then Return ; Wenn $aNewItems kein Array ist, dann Funktion verlassen
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlListView_SetItemCount($hLVHandle, $aNewItems[0])
Global $aListview[$aNewItems[0]][9]
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten... (' & $aNewItems[0] & ')', 0)
_GUICtrlListView_BeginUpdate($hLVHandle) ; Listview sperren
$iTimer = TimerInit()
For $i = 1 To $aNewItems[0] ; Alle Einträge des Arrays durchgehen
$iCount += 1
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
EndIf
$aItem = StringSplit($aNewItems[$i], '|')
For $j = 1 To $aItem[0]
$aListview[$i - 1][$j - 1] = $aItem[$j]
Next
GUICtrlCreateListViewItem($aNewItems[$i], $hListView) ; mit den eingelesenen Daten einen neuen Listview-Eintrag erstellen
Next
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
_GUICtrlListView_EndUpdate($hLVHandle) ; Listview wieder freigeben
$iLVCount = UBound($aListview)
EndIf
EndFunc ;==>Load
Func Save() ; Datenbank-Datei speichern
Local $sContent, $hFile, $iCount, $iTimer
$iCount = _GUICtrlListView_GetItemCount($hLVHandle); Anzahl der Listview-Einträge holen
If $iCount = 0 Then Return ; Wenn das Listview keine Einträge enthält, dann Funktion verlassen
$iTimer = TimerInit()
For $i = 0 To $iCount - 1 ; Schleife, um alle Listview-Einträge durchzugehen
$sContent &= _GUICtrlListView_GetItemTextString($hLVHandle, $i) & @CRLF
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $i + 1, 2)
EndIf
Next
$hFile = FileOpen($sDBFile, 2) ; Datei zum speichern (überschreiben) öffnen
If $hFile <> -1 Then ; wenn das öffnen erfolgreich war, dann...
FileWrite($hFile, $sContent)
FileClose($hFile) ; Datei schließen
EndIf
EndFunc ;==>Save
;===============================================================================
; Function Name: _RecursiveFileListToArray($sPath[, $sPattern][, $iFlag][, $iFormat][, $iRecursion][, $sDelim])
; Description:: gibt Verzeichnisse (rekursiv) und/oder Dateien zurück, die einem RegExp-Pattern entsprechen
; Parameter(s): $sPath = Startverzeichnis
; $sPattern = ein beliebiges RexExp-Pattern für die Auswahl
; $iFlag = Auswahl
; 0 = Dateien & Verzeichnisse
; 1 = nur Dateien
; 2 = nur Verzeichnisse
; $iFormat = Rückgabeformat
; 0 = String
; 1 = Array mit [0] = Anzahl
; 2 = Nullbasiertes Array
; $iRecursion = Verzeichnisse rekursiv durchsuchen
; 0 = Nein
; 1 = Ja
; $sDelim = Trennzeichen für die String-Rückgabe
; Requirement(s): AutoIt 3.3.0.0
; Return Value(s): Array/String mit den gefundenen Dateien/Verzeichnissen
; Author(s): Oscar (http://www.autoit.de)
; Anregungen von: bernd670 (http://www.autoit.de)
;===============================================================================
Func _RecursiveFileListToArray($sPath, $sPattern = '', $iFlag = 0, $iFormat = 1, $iRecursion = 1, $sDelim = @CRLF)
Local $hSearch, $sFile, $sReturn = ''
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
$hSearch = FileFindFirstFile($sPath & '*.*')
If @error Or $hSearch = -1 Then Return SetError(1, 0, $sReturn)
While Not $fStop
$sFile = FileFindNextFile($hSearch)
If @error Then ExitLoop
If @extended Then
If StringRegExp($sPath & $sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 2) Then $sReturn &= $sPath & $sFile & '\' & $sDelim
If $iRecursion Then $sReturn &= _RecursiveFileListToArray($sPath & $sFile & '\', $sPattern, $iFlag, 0)
ContinueLoop
EndIf
If StringRegExp($sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 1) Then $sReturn &= $sPath & $sFile & $sDelim
WEnd
FileClose($hSearch)
If $iFormat And $sReturn = '' Then Return StringSplit($sReturn, '', $iFormat)
If $iFormat Then Return StringSplit(StringTrimRight($sReturn, StringLen($sDelim)), $sDelim, $iFormat)
Return $sReturn
EndFunc ;==>_RecursiveFileListToArray
;===============================================================================
; Function Name: _ReadID3Tag($sPath)
; Description:: gibt ein Array mit den Daten aus den ID3-Tags zurück
; unterstützt werden die ID3-Tag-Versionen 1.0, 1.1, 2.3 und 2.4
; bei v2.4 müssen sich die ID3-Tags am Anfang der Datei befinden
; Parameter(s): $sPath = Pfad zu einer MP3-Datei
; Requirement(s): min. AutoIt v3.3.0.0
; Return Value(s): bei Erfolg: Array mit den ID3-Tagdaten (@error = 0)
; im Fehlerfall bekommt @error:
; 1 = Datei existiert nicht
; 2 = Datei konnte nicht zum lesen geöffnet werden
; 3 = falsche ID3 v2 Version
; 4 = Datei ist keine MP3-Datei
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _ReadID3Tag($sPath)
If Not FileExists($sPath) Then Return SetError(1, 0, 0)
Local $hFile, $sData, $sID3Header, $iID3HeaderSize = 0, $iOffset, $iSize, $tmp
Local $aID3v2Tags[8] = ['TIT2', 'TPE1', 'TALB', 'TYER', 'TLEN', 'TRCK', 'TCON', 'TENC']
Local $aID3[11][2] = [ _
['Title', ''],['Artist', ''],['Album', ''],['Year', ''], _
['Length', '0'],['Track', ''],['Genre', ''],['Encoder', ''], _
['MPEG-Version', ''],['Bitrate', '-'],['Sample-Freq.', '']]
Local $aMP3Version[4] = ['MPEG2.5', 'Reserved', 'MPEG2', 'MPEG1']
Local $aMP3Layer[4] = ['Reserved', 'Layer III', 'Layer II', 'Layer I']
Local $aMP3Bitrate[5][16] = [ _
[000, 032, 064, 096, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 384, 000], _
[000, 032, 040, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 144, 160, 176, 192, 224, 256, 000], _
[000, 008, 016, 024, 032, 040, 048, 056, 064, 080, 096, 112, 128, 144, 160, 000]]
Local $aSampleFreq[3][4] = [[44100, 48000, 32000, 0],[22050, 24000, 16000, 0],[11025, 12000, 8000, 0]]
Local $sMP3FrameHeader, $iMP3Version, $sMP3Version, $sMP3Layer, $iMP3Bitrate, $iMP3SampleFreq
Local $iVBRFrames = -1, $iVBRFilesize, $iVBRFlags
$hFile = FileOpen($sPath, 16)
If $hFile = -1 Then Return SetError(2, 0, 0)
$sData = Binary(FileRead($hFile, 4))
If BinaryMid($sData, 1, 3) = '0x494433' Then ; ID3 v2.x Kennung gefunden
If (BinaryMid($sData, 4, 1) = '0x03') Or (BinaryMid($sData, 4, 1) = '0x04') Then ; nur v2.3 und 2.4
FileRead($hFile, 2) ; 2 Bytes überspringen
For $i = 0 To 3 ; berechne ID3-Headergröße (4 Bytes, jedoch nur jeweils die unteren 7 Bit)
$iID3HeaderSize = BitShift($iID3HeaderSize, -7) + BitAND(Binary(FileRead($hFile, 1)), 0x7F)
Next
If $iID3HeaderSize > 0 Then
$sID3Header = Binary(FileRead($hFile, $iID3HeaderSize)) ; lese gesamten ID3-Header
For $i = 0 To 7
$iOffset = StringInStr(BinaryToString($sID3Header), $aID3v2Tags[$i]) ; Offset zu dem ID3-Tag
If $iOffset > 0 Then
$iSize = Hex(BinaryMid($sID3Header, $iOffset + 4, 4)) ; Größe des ID3-Frames
$tmp = BinaryMid($sID3Header, $iOffset + 11, Dec($iSize) - 1)
If BinaryMid($tmp, 1, 2) = '0xFFFE' Then
For $x = 3 To BinaryLen($tmp) Step 2
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 2), 2)
Next
Else
For $x = 1 To BinaryLen($tmp)
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 1))
Next
EndIf
$aID3[$i][1] = StringReplace($aID3[$i][1], Chr(0), '')
EndIf
Next
EndIf
Do
$sData = String(FileRead($hFile, 1))
If @error Then ExitLoop
If BitAND($sData, 0xff) = 0xff Then
FileSetPos($hFile, -1, 1)
$sData = String(FileRead($hFile, 4))
EndIf
Until BitAND($sData, 0xFFE00000) = 0xFFE00000
Else
FileClose($hFile)
Return SetError(3, 0, 0)
EndIf
Else ; ID3 v1.x
$iOffset = FileGetPos($hFile)
FileSetPos($hFile, -128, 2)
$sID3Header = BinaryToString(FileRead($hFile, 3))
If $sID3Header = 'TAG' Then
$aID3[0][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[1][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[2][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[3][1] = StringReplace(BinaryToString(FileRead($hFile, 4)), Chr(0), '')
EndIf
FileSetPos($hFile, $iOffset, 0)
EndIf
$sMP3FrameHeader = String($sData)
If BitAND($sMP3FrameHeader, 0xFFE00000) <> 0xFFE00000 Then
FileClose($hFile)
Return SetError(4, 0, 0) ; keine MP3-Datei, dann Return
EndIf
$iMP3Version = BitShift(BitXOR($sMP3FrameHeader, 0xFFE00000), 19) ; welche MP3-Version
$sMP3Version = $aMP3Version[$iMP3Version] ; in Textform
$sMP3Layer = $aMP3Layer[BitShift(BitAND($sMP3FrameHeader, 0x60000), 17)] ; welcher Layer
$aID3[8][1] = $sMP3Version & ' / ' & $sMP3Layer ; ins Ausgabe-Array
$iMP3Bitrate = BitShift(BitAND($sMP3FrameHeader, 0xF000), 12) ; Bitraten-Index auslesen
Switch $sMP3Version ; je nach MPEG-Version Bitrate aus der Tabelle holen
Case 'MPEG1'
$aID3[9][1] = $aMP3Bitrate[$iMP3Version - ($iMP3Version > 1)][$iMP3Bitrate]
Case 'MPEG2', 'MPEG2.5'
If $sMP3Layer = 'Layer I' Then
$aID3[9][1] = $aMP3Bitrate[3][$iMP3Bitrate]
Else
$aID3[9][1] = $aMP3Bitrate[4][$iMP3Bitrate]
EndIf
EndSwitch
$iMP3SampleFreq = BitShift(BitAND($sMP3FrameHeader, 0xC00), 10) ; Sample-Frequenz-Index auslesen
$aID3[10][1] = $aSampleFreq[2 - ($iMP3Version - ($iMP3Version > 1))][$iMP3SampleFreq] ; und Wert aus der Tabelle holen
Do ; evtl. Leerbytes überspringen
$tmp = FileRead($hFile, 1)
If @error Then ExitLoop
Until $tmp <> 0x00 Or @error
If $tmp = 0x58 And BinaryToString(FileRead($hFile, 3)) = 'ing' Then ; MP3 mit VBR (Xing-Header gefunden)?
$iVBRFlags = '0x' & Hex(FileRead($hFile, 4)) ; VBR-Flags auslesen
If BitAND($iVBRFlags, 0x3) Then ; wenn die Einträge vorhanden sind, dann...
$iVBRFrames = Dec(Hex(FileRead($hFile, 4))) ; Anzahl der VBR-Frames auslesen
$iVBRFilesize = Dec(Hex(FileRead($hFile, 4))) ; Dateigröße auslesen
$aID3[4][1] = $iVBRFrames * 1152 / $aID3[10][1] * 1000 ; VBR Laufzeit
$aID3[9][1] = 'VBR ~' & Int($iVBRFilesize * 8 / ($aID3[4][1] / 1000) / 1000) ; VBR durchschnittliche Bitrate
EndIf
Else
If $aID3[4][1] = 0 Then $aID3[4][1] = (FileGetSize($sPath) *
/ ($aID3[9][1] * 1000) * 1000 ; alternative CBR Laufzeit
$aID3[9][1] = 'CBR ' & $aID3[9][1]
EndIf
$aID3[4][1] = _TicksToTimeFormat($aID3[4][1]) ; Laufzeit (Ticks to hour:min:sec)
$aID3[9][1] &= ' kBit/s'
$aID3[10][1] &= ' Hz'
FileClose($hFile)
Return SetError(0, 0, $aID3)
EndFunc ;==>_ReadID3Tag
;===============================================================================
; Function Name: _TicksToTimeFormat($iTicks, $sFormat = '%hh:%mm:%ss')
; Description:: Diese Funktion wandelt Millisekunden in ein anzugebenes Zeitformat um
; Parameter(s): $iTicks = Zeit in Millisekunden
; $sFormat:
; %hh für Stunden
; %mm für Minuten
; %ss für Sekunden
; %ms für Millisekunden
; sonstige Zeichen, die dazwischen stehen, werden übernommen
; Requirement(s): -
; Return Value(s): Zeit im ausgewählten Format (String)
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _TicksToTimeFormat($iTicks, $sFormat = '%hh:%mm:%ss')
Local $aTime[4] = [0, 0, 0, 0], $sOut, $aTimeFormat[4] = ['hh', 'mm', 'ss', 'ms'], $aFormat
$aTime[2] = Int($iTicks / 1000)
$aTime[3] = $iTicks - $aTime[2] * 1000
$aTime[0] = Int($aTime[2] / 3600)
$aTime[2] = Mod($aTime[2], 3600)
$aTime[1] = Int($aTime[2] / 60)
$aTime[2] = Mod($aTime[2], 60)
$aFormat = StringRegExp($sFormat, '%([^%]+)', 3)
If Not IsArray($aFormat) Then Return SetError(1, 0, $iTicks)
For $i = 0 To UBound($aFormat) - 1
For $j = 0 To UBound($aTimeFormat) - 1
If StringLeft($aFormat[$i], 2) = $aTimeFormat[$j] Then $sOut &= StringFormat('%02i', $aTime[$j]) & StringMid($aFormat[$i], 3)
Next
Next
Return $sOut
EndFunc ;==>_TicksToTimeFormat
Also, die Sortierfunktion mit Hilfe von _GUICtrlListView_RegisterSortCallBack ausführen zu lassen dauert ewig: bei 42000 Einträgen = ca. 8 Minuten (!).
Jetzt habe ich das Skript dahingehend umgeschrieben, dass die Einträge auch in einem 2D-Array vorhanden sind. Dieses lasse ich dann per _ArraySort sortieren, lösche die Listview-Einträge und erstelle sie neu. Das verringert die Sortierung auf etwa 20-30 Sekunden (!). Das ist immer noch relativ lange, aber das kann man noch akzeptieren, IMHO.
Außerdem habe ich mal alle langwierigen Aktionen mit Rückmeldungen versehen, sodass man nicht den Eindruck hat, das Programm wäre abgestürzt. Das einlesen der Festplatten kann man mit [ESC] abbrechen.
Skript:
#include <Array.au3>
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiStatusBar.au3>
#include <ListViewConstants.au3>
Global $sHeader = 'Title|Artist|Album|Year|Length|MPEG-Version|Bitrate|Sample-Freq.|Path' ; Die Überschriften für das Listview
Global $sDBFile = @ScriptDir & '\MP3_Collection.txt' ; Pfad und Name der Datenbank-Datei
#region Hauptfenster
Global $iWidth = @DesktopWidth - 100
Global $hGui = GUICreate('MP3-Search', $iWidth, 500) ; Hauptfenster erstellen
GUISetBkColor(0xAAAAAA)
Global $hListView = GUICtrlCreateListView($sHeader, 5, 5, $iWidth - 10, 420, $LVS_SHOWSELALWAYS) ; Listview erstellen
Global $aListview[1][9]
Global $hLVHandle = GUICtrlGetHandle($hListView) ; das Handle vom Listview wird für die UDF-Listview-Funktionen benötigt
_GUICtrlListView_SetColumn($hLVHandle, 0, 'Title', 180, 0)
_GUICtrlListView_SetColumn($hLVHandle, 1, 'Artist', 180, 0)
_GUICtrlListView_SetColumn($hLVHandle, 2, 'Length', 60, 0)
_GUICtrlListView_SetColumn($hLVHandle, 3, 'Album', 120, 0)
_GUICtrlListView_SetColumn($hLVHandle, 4, 'Year', 60, 0)
_GUICtrlListView_SetColumn($hLVHandle, 5, 'MPEG-Version', 100, 0)
_GUICtrlListView_SetColumn($hLVHandle, 6, 'Bitrate', 100, 0)
_GUICtrlListView_SetColumn($hLVHandle, 7, 'Sample-Freq.', 90, 0)
_GUICtrlListView_SetColumn($hLVHandle, 8, 'Path', 800, 0)
Global $hSearch = GUICtrlCreateButton('Alle Festplatten durchsuchen', 10, 430, 160, 35, $BS_MULTILINE)
Global $hLoad = GUICtrlCreateButton('Laden', 230, 430, 70, 35)
Global $hSave = GUICtrlCreateButton('Speichern', 310, 430, 70, 35)
Global $hDel = GUICtrlCreateButton("Markierte Einträge löschen", 400, 430, 90, 35, $BS_MULTILINE)
Global $hDelAll = GUICtrlCreateButton('Alle Einträge löschen', 500, 430, 90, 35, $BS_MULTILINE)
Global $aParts[3] = [180, 240, -1], $aText[3] = ['Fertig.', '0', '']
Global $hStatus = _GUICtrlStatusBar_Create($hGui, $aParts, $aText)
#endregion Hauptfenster
GUISetState(@SW_SHOW, $hGui) ; Hauptfenster sichtbar machen
[/autoit] [autoit][/autoit] [autoit]Global $fStop = False, $iLVCount = 0
HotKeySet('{ESC}', '_Stop')
While 1
Switch GUIGetMsg() ; anhand der Control-ID das entsprechende Case aufrufen
Case $hSearch
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
$iLVCount = 0 ; Zähler auf Null setzen
$aDrives = DriveGetDrive('FIXED') ; Alle Festplatten-Buchstaben holen
;~ Dim $aDrives[2] = [1, 'c:']
If Not @error Then
GUISetCursor(15, 1, $hGui)
For $i = 1 To $aDrives[0] ; Alle Festplatten durchgehen
$aDrives[$i] = StringUpper($aDrives[$i]) & '\'
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Festplatte "' & $aDrives[$i] & '"', 0)
_GUICtrlStatusBar_SetText($hStatus, 'Bitte warten...', 2)
$aNewMP3 = _RecursiveFileListToArray($aDrives[$i], '\.mp3', 1) ; Alle MP3s auf der Festplatte auslesen
If Not @error Then
_GUICtrlListView_SetItemCount($hListView, $iLVCount + $aNewMP3[0])
ConsoleWrite('$iLVCount = ' & $iLVCount & @CR & '$aNewMP3[0] = ' & $aNewMP3[0] & @CR)
ReDim $aListview[$iLVCount + $aNewMP3[0] + 1][9]
_GUICtrlStatusBar_SetText($hStatus, 'Lese ID3-Tags... (' & UBound($aListview) & ')', 0)
For $j = 1 To $aNewMP3[0] ; die gefundenen MP3s durchgehen
_GUICtrlStatusBar_SetText($hStatus, $iLVCount, 1)
$aID3Tags = _ReadID3Tag($aNewMP3[$j]) ; die ID3-Tags auslesen
If Not @error Then
For $k = 0 To 10
$aID3Tags[$k][1] = StringReplace($aID3Tags[$k][1], '|', '') ; evtl. vorhandene "|" entfernen
Next
_GUICtrlStatusBar_SetText($hStatus, $aNewMP3[$j], 2)
$sNewItem = $aID3Tags[0][1] & '|' & $aID3Tags[1][1] & '|' & $aID3Tags[4][1] & '|' & $aID3Tags[2][1] & '|' & $aID3Tags[3][1]
$sNewItem &= '|' & $aID3Tags[8][1] & '|' & $aID3Tags[9][1] & '|' & $aID3Tags[10][1] & '|' & $aNewMP3[$j]
$aItem = StringSplit($sNewItem, '|')
For $k = 1 To $aItem[0]
$aListview[$iLVCount][$k - 1] = $aItem[$k]
Next
GUICtrlCreateListViewItem($sNewItem, $hListView)
$iLVCount += 1
EndIf
If $fStop Then ExitLoop 2 ; Wenn [ESC] gedrückt wurde, die Schleifen verlassen
Next
ReDim $aListview[$iLVCount][9]
EndIf
Next
GUISetCursor(2, 1, $hGui)
EndIf
_GUICtrlStatusBar_SetText($hStatus, $iLVCount, 1)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, 'Abgebrochen!', 0)
Else
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
EndIf
Case $hListView ; User hat auf eine Spaltenüberschrift geklickt
If $iLVCount > 0 Then
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Sortiere Daten...', 0)
$iSort = GUICtrlGetState($hListView)
$iTimer = TimerInit()
ConsoleWrite('Start Sort col: ' & $iSort & @CR)
_ArraySort($aListview, 0, 0, 0, $iSort)
ConsoleWrite('Sort: ' & Int(TimerDiff($iTimer)) & ' ms' & @CR)
_GUICtrlListView_DeleteAllItems($hLVHandle)
ConsoleWrite('Delete all: ' & Int(TimerDiff($iTimer)) & ' ms' & @CR)
_GUICtrlListView_BeginUpdate($hLVHandle) ; Listview sperren
_GUICtrlListView_AddArray($hLVHandle, $aListview)
_GUICtrlListView_EndUpdate($hLVHandle) ; Listview wieder freigeben
ConsoleWrite('Create new: ' & Int(TimerDiff($iTimer)) & ' ms' & @CR)
ConsoleWrite('End.' & @CR)
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
GUISetCursor(2, 1, $hGui)
EndIf
Case $hLoad ; User hat auf 'Laden' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten...', 0)
Load()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
GUISetCursor(2, 1, $hGui)
Case $hSave ; User hat auf 'Speichern' geklickt
GUISetCursor(15, 1, $hGui)
_GUICtrlStatusBar_SetText($hStatus, 'Speichere Daten...', 0)
Save()
_GUICtrlStatusBar_SetText($hStatus, 'Fertig.', 0)
_GUICtrlStatusBar_SetText($hStatus, '', 2)
GUISetCursor(2, 1, $hGui)
Case $hDel
$aSelectedItems = _GUICtrlListView_GetSelectedIndices($hLVHandle, True)
If $aSelectedItems[0] > 0 Then
GUISetCursor(15, 1, $hGui)
For $i = $aSelectedItems[0] To 1 Step - 1
_ArrayDelete($aListview, $aSelectedItems[$i])
Next
_GUICtrlListView_DeleteItemsSelected($hLVHandle)
$iLVCount -= $aSelectedItems[0]
_GUICtrlStatusBar_SetText($hStatus, $iLVCount, 1)
GUISetCursor(2, 1, $hGui)
EndIf
Case $hDelAll ; User hat auf 'Alle Einträge löschen' geklickt
If MsgBox(256 + 32 + 4, 'Einträge löschen', 'Wollen sie wirklich alle Einträge löschen?') = 6 Then
_GUICtrlListView_DeleteAllItems($hLVHandle)
ReDim $aListview[1][9]
$iLVCount = 0
_GUICtrlStatusBar_SetText($hStatus, $iLVCount, 1)
EndIf
Case $GUI_EVENT_CLOSE ; User hat auf das Schließen-Symbol geklickt (bzw. die ESC-Taste gedrückt)
If MsgBox(32 + 4, 'Beenden', 'Wollen sie das Programm wirklich beenden?') = 6 Then End() ; wenn ja, dann End-Funktion aufrufen
EndSwitch
WEnd
Func _Stop()
$fStop = True
EndFunc ;==>_Stop
Func End()
;~ Save() ; wenn der vordere Kommentar entfernt wird, dann werden vor dem beenden noch die Daten gespeichert
Exit ; Programm beenden
EndFunc ;==>End
Func Load() ; Datenbank-Datei laden
Local $hFile, $sContent, $aNewItems, $iTimer, $iCount, $aItem
$hFile = FileOpen($sDBFile, 0) ; Datei zum lesen öffnen
If $hFile <> -1 Then ; wenn das öffnen erfolgreich war, dann...
$sContent = FileRead($hFile) ; Datei komplett einlesen
FileClose($hFile) ; Datei schließen
$sContent = StringTrimRight($sContent, 2) ; das letzte @CRLF entfernen
$aNewItems = StringSplit($sContent, @CRLF, 1) ; Den Dateiinhalt am Zeilenende splitten
If Not IsArray($aNewItems) Then Return ; Wenn $aNewItems kein Array ist, dann Funktion verlassen
_GUICtrlListView_DeleteAllItems($hLVHandle)
_GUICtrlListView_SetItemCount($hLVHandle, $aNewItems[0])
Global $aListview[$aNewItems[0]][9]
_GUICtrlStatusBar_SetText($hStatus, 'Lade Daten... (' & $aNewItems[0] & ')', 0)
_GUICtrlListView_BeginUpdate($hLVHandle) ; Listview sperren
$iTimer = TimerInit()
For $i = 1 To $aNewItems[0] ; Alle Einträge des Arrays durchgehen
$iCount += 1
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
EndIf
$aItem = StringSplit($aNewItems[$i], '|')
For $j = 1 To $aItem[0]
$aListview[$i - 1][$j - 1] = $aItem[$j]
Next
GUICtrlCreateListViewItem($aNewItems[$i], $hListView) ; mit den eingelesenen Daten einen neuen Listview-Eintrag erstellen
Next
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
_GUICtrlListView_EndUpdate($hLVHandle) ; Listview wieder freigeben
$iLVCount = UBound($aListview)
EndIf
EndFunc ;==>Load
Func Save() ; Datenbank-Datei speichern
Local $sContent, $hFile, $iCount, $iTimer
$iCount = _GUICtrlListView_GetItemCount($hLVHandle); Anzahl der Listview-Einträge holen
If $iCount = 0 Then Return ; Wenn das Listview keine Einträge enthält, dann Funktion verlassen
$iTimer = TimerInit()
For $i = 0 To $iCount - 1 ; Schleife, um alle Listview-Einträge durchzugehen
$sContent &= _GUICtrlListView_GetItemTextString($hLVHandle, $i) & @CRLF
If TimerDiff($iTimer) > 100 Then
$iTimer = TimerInit()
_GUICtrlStatusBar_SetText($hStatus, $i + 1, 2)
EndIf
Next
$hFile = FileOpen($sDBFile, 2) ; Datei zum speichern (überschreiben) öffnen
If $hFile <> -1 Then ; wenn das öffnen erfolgreich war, dann...
FileWrite($hFile, $sContent)
FileClose($hFile) ; Datei schließen
EndIf
EndFunc ;==>Save
;===============================================================================
; Function Name: _RecursiveFileListToArray($sPath[, $sPattern][, $iFlag][, $iFormat][, $iRecursion][, $sDelim])
; Description:: gibt Verzeichnisse (rekursiv) und/oder Dateien zurück, die einem RegExp-Pattern entsprechen
; Parameter(s): $sPath = Startverzeichnis
; $sPattern = ein beliebiges RexExp-Pattern für die Auswahl
; $iFlag = Auswahl
; 0 = Dateien & Verzeichnisse
; 1 = nur Dateien
; 2 = nur Verzeichnisse
; $iFormat = Rückgabeformat
; 0 = String
; 1 = Array mit [0] = Anzahl
; 2 = Nullbasiertes Array
; $iRecursion = Verzeichnisse rekursiv durchsuchen
; 0 = Nein
; 1 = Ja
; $sDelim = Trennzeichen für die String-Rückgabe
; Requirement(s): AutoIt 3.3.0.0
; Return Value(s): Array/String mit den gefundenen Dateien/Verzeichnissen
; Author(s): Oscar (http://www.autoit.de)
; Anregungen von: bernd670 (http://www.autoit.de)
;===============================================================================
Func _RecursiveFileListToArray($sPath, $sPattern = '', $iFlag = 0, $iFormat = 1, $iRecursion = 1, $sDelim = @CRLF)
Local $hSearch, $sFile, $sReturn = ''
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
$hSearch = FileFindFirstFile($sPath & '*.*')
If @error Or $hSearch = -1 Then Return SetError(1, 0, $sReturn)
While Not $fStop
$sFile = FileFindNextFile($hSearch)
If @error Then ExitLoop
If @extended Then
If StringRegExp($sPath & $sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 2) Then $sReturn &= $sPath & $sFile & '\' & $sDelim
If $iRecursion Then $sReturn &= _RecursiveFileListToArray($sPath & $sFile & '\', $sPattern, $iFlag, 0)
ContinueLoop
EndIf
If StringRegExp($sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 1) Then $sReturn &= $sPath & $sFile & $sDelim
WEnd
FileClose($hSearch)
If $iFormat And $sReturn = '' Then Return StringSplit($sReturn, '', $iFormat)
If $iFormat Then Return StringSplit(StringTrimRight($sReturn, StringLen($sDelim)), $sDelim, $iFormat)
Return $sReturn
EndFunc ;==>_RecursiveFileListToArray
;===============================================================================
; Function Name: _ReadID3Tag($sPath)
; Description:: gibt ein Array mit den Daten aus den ID3-Tags zurück
; unterstützt werden die ID3-Tag-Versionen 1.0, 1.1, 2.3 und 2.4
; bei v2.4 müssen sich die ID3-Tags am Anfang der Datei befinden
; Parameter(s): $sPath = Pfad zu einer MP3-Datei
; Requirement(s): min. AutoIt v3.3.0.0
; Return Value(s): bei Erfolg: Array mit den ID3-Tagdaten (@error = 0)
; im Fehlerfall bekommt @error:
; 1 = Datei existiert nicht
; 2 = Datei konnte nicht zum lesen geöffnet werden
; 3 = falsche ID3 v2 Version
; 4 = Datei ist keine MP3-Datei
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _ReadID3Tag($sPath)
If Not FileExists($sPath) Then Return SetError(1, 0, 0)
Local $hFile, $sData, $sID3Header, $iID3HeaderSize = 0, $iOffset, $iSize, $tmp
Local $aID3v2Tags[8] = ['TIT2', 'TPE1', 'TALB', 'TYER', 'TLEN', 'TRCK', 'TCON', 'TENC']
Local $aID3[11][2] = [ _
['Title', ''],['Artist', ''],['Album', ''],['Year', ''], _
['Length', '0'],['Track', ''],['Genre', ''],['Encoder', ''], _
['MPEG-Version', ''],['Bitrate', '-'],['Sample-Freq.', '']]
Local $aMP3Version[4] = ['MPEG2.5', 'Reserved', 'MPEG2', 'MPEG1']
Local $aMP3Layer[4] = ['Reserved', 'Layer III', 'Layer II', 'Layer I']
Local $aMP3Bitrate[5][16] = [ _
[000, 032, 064, 096, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 384, 000], _
[000, 032, 040, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 144, 160, 176, 192, 224, 256, 000], _
[000, 008, 016, 024, 032, 040, 048, 056, 064, 080, 096, 112, 128, 144, 160, 000]]
Local $aSampleFreq[3][4] = [[44100, 48000, 32000, 0],[22050, 24000, 16000, 0],[11025, 12000, 8000, 0]]
Local $sMP3FrameHeader, $iMP3Version, $sMP3Version, $sMP3Layer, $iMP3Bitrate, $iMP3SampleFreq
Local $iVBRFrames = -1, $iVBRFilesize, $iVBRFlags
$hFile = FileOpen($sPath, 16)
If $hFile = -1 Then Return SetError(2, 0, 0)
$sData = Binary(FileRead($hFile, 4))
If BinaryMid($sData, 1, 3) = '0x494433' Then ; ID3 v2.x Kennung gefunden
If (BinaryMid($sData, 4, 1) = '0x03') Or (BinaryMid($sData, 4, 1) = '0x04') Then ; nur v2.3 und 2.4
FileRead($hFile, 2) ; 2 Bytes überspringen
For $i = 0 To 3 ; berechne ID3-Headergröße (4 Bytes, jedoch nur jeweils die unteren 7 Bit)
$iID3HeaderSize = BitShift($iID3HeaderSize, -7) + BitAND(Binary(FileRead($hFile, 1)), 0x7F)
Next
If $iID3HeaderSize > 0 Then
$sID3Header = Binary(FileRead($hFile, $iID3HeaderSize)) ; lese gesamten ID3-Header
For $i = 0 To 7
$iOffset = StringInStr(BinaryToString($sID3Header), $aID3v2Tags[$i]) ; Offset zu dem ID3-Tag
If $iOffset > 0 Then
$iSize = Hex(BinaryMid($sID3Header, $iOffset + 4, 4)) ; Größe des ID3-Frames
$tmp = BinaryMid($sID3Header, $iOffset + 11, Dec($iSize) - 1)
If BinaryMid($tmp, 1, 2) = '0xFFFE' Then
For $x = 3 To BinaryLen($tmp) Step 2
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 2), 2)
Next
Else
For $x = 1 To BinaryLen($tmp)
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 1))
Next
EndIf
$aID3[$i][1] = StringReplace($aID3[$i][1], Chr(0), '')
EndIf
Next
EndIf
Do
$sData = String(FileRead($hFile, 1))
If @error Then ExitLoop
If BitAND($sData, 0xff) = 0xff Then
FileSetPos($hFile, -1, 1)
$sData = String(FileRead($hFile, 4))
EndIf
Until BitAND($sData, 0xFFE00000) = 0xFFE00000
Else
FileClose($hFile)
Return SetError(3, 0, 0)
EndIf
Else ; ID3 v1.x
$iOffset = FileGetPos($hFile)
FileSetPos($hFile, -128, 2)
$sID3Header = BinaryToString(FileRead($hFile, 3))
If $sID3Header = 'TAG' Then
$aID3[0][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[1][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[2][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[3][1] = StringReplace(BinaryToString(FileRead($hFile, 4)), Chr(0), '')
EndIf
FileSetPos($hFile, $iOffset, 0)
EndIf
$sMP3FrameHeader = String($sData)
If BitAND($sMP3FrameHeader, 0xFFE00000) <> 0xFFE00000 Then
FileClose($hFile)
Return SetError(4, 0, 0) ; keine MP3-Datei, dann Return
EndIf
$iMP3Version = BitShift(BitXOR($sMP3FrameHeader, 0xFFE00000), 19) ; welche MP3-Version
$sMP3Version = $aMP3Version[$iMP3Version] ; in Textform
$sMP3Layer = $aMP3Layer[BitShift(BitAND($sMP3FrameHeader, 0x60000), 17)] ; welcher Layer
$aID3[8][1] = $sMP3Version & ' / ' & $sMP3Layer ; ins Ausgabe-Array
$iMP3Bitrate = BitShift(BitAND($sMP3FrameHeader, 0xF000), 12) ; Bitraten-Index auslesen
Switch $sMP3Version ; je nach MPEG-Version Bitrate aus der Tabelle holen
Case 'MPEG1'
$aID3[9][1] = $aMP3Bitrate[$iMP3Version - ($iMP3Version > 1)][$iMP3Bitrate]
Case 'MPEG2', 'MPEG2.5'
If $sMP3Layer = 'Layer I' Then
$aID3[9][1] = $aMP3Bitrate[3][$iMP3Bitrate]
Else
$aID3[9][1] = $aMP3Bitrate[4][$iMP3Bitrate]
EndIf
EndSwitch
$iMP3SampleFreq = BitShift(BitAND($sMP3FrameHeader, 0xC00), 10) ; Sample-Frequenz-Index auslesen
$aID3[10][1] = $aSampleFreq[2 - ($iMP3Version - ($iMP3Version > 1))][$iMP3SampleFreq] ; und Wert aus der Tabelle holen
Do ; evtl. Leerbytes überspringen
$tmp = FileRead($hFile, 1)
If @error Then ExitLoop
Until $tmp <> 0x00 Or @error
If $tmp = 0x58 And BinaryToString(FileRead($hFile, 3)) = 'ing' Then ; MP3 mit VBR (Xing-Header gefunden)?
$iVBRFlags = '0x' & Hex(FileRead($hFile, 4)) ; VBR-Flags auslesen
If BitAND($iVBRFlags, 0x3) Then ; wenn die Einträge vorhanden sind, dann...
$iVBRFrames = Dec(Hex(FileRead($hFile, 4))) ; Anzahl der VBR-Frames auslesen
$iVBRFilesize = Dec(Hex(FileRead($hFile, 4))) ; Dateigröße auslesen
$aID3[4][1] = $iVBRFrames * 1152 / $aID3[10][1] * 1000 ; VBR Laufzeit
$aID3[9][1] = 'VBR ~' & Int($iVBRFilesize * 8 / ($aID3[4][1] / 1000) / 1000) ; VBR durchschnittliche Bitrate
EndIf
Else
If $aID3[4][1] = 0 Then $aID3[4][1] = (FileGetSize($sPath) *
/ ($aID3[9][1] * 1000) * 1000 ; alternative CBR Laufzeit
$aID3[9][1] = 'CBR ' & $aID3[9][1]
EndIf
$aID3[4][1] = _MyTicksToTime($aID3[4][1]) ; Laufzeit (Ticks to hour:min:sec)
$aID3[9][1] &= ' kBit/s'
$aID3[10][1] &= ' Hz'
FileClose($hFile)
Return SetError(0, 0, $aID3)
EndFunc ;==>_ReadID3Tag
Func _MyTicksToTime($iTicks)
Local $iHour, $iMins, $iSecs
$iHour = Int($iTicks / 3600000)
$iTicks -= $iHour * 3600000
$iMins = Int($iTicks / 60000)
$iTicks -= $iMins * 60000
$iSecs = Int($iTicks / 1000)
Return StringFormat('%02i:%02i:%02i', $iHour, $iMins, $iSecs)
EndFunc ;==>_MyTicksToTime
Also zu der Sortierfunktion: Du brauchst vieeeeel Geduld, wenn Du >20000 Einträge im Listview hast! Das war der Grund, warum ich das im obigen Skript auskommentiert habe.
Und wenn man schon so lange braucht, um die Liste zu sortieren, ist das eigentlich schon der Todesstoss für das Projekt. Es sei denn, jemand kennt eine Möglichkeit (C-Routine oder so) wie man ein Listview mit so vielen Einträgen wirklich schnell sortieren kann...
Kopieren/verschieben der Dateien (inkl. erstellen evtl. Verzeichnisse) ist eher die einfache Aufgabe.
Es hatte mich mal interessiert, wie "schnell" AutoIt dabei ist und deshalb habe ich mal meine Skripte (Listview-Datenbank, _RecursiveFileListToArray und _ReadID3Tag) zusammengefasst und mit ein paar Statusmeldungen versehen (damit der User sieht, was passiert). Es wird jetzt ein Listview mit den ID3-Tags von allen MP3s von allen installierten Festplatten erstellt.
Nach dem erstellen, kann man das ganze Listview abspeichern, sodass man es beim nächsten Start des Programms wieder laden kann (ohne es neu erstellen zu müssen).
Hier das Skript:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiStatusBar.au3>
#include <ListViewConstants.au3>
Global $sHeader = "Title|Artist|Album|Year|Length|MPEG-Version|Bitrate|Sample-Freq.|Path" ; Die Überschriften für das Listview
Global $sDBFile = @ScriptDir & "\MP3_Collection.txt" ; Pfad und Name der Datenbank-Datei
#Region Hauptfenster
Global $hGui = GUICreate("MP3-Search", 800, 500) ; Hauptfenster erstellen
Global $hListView = GUICtrlCreateListView($sHeader, 0, 0, 800, 420, $LVS_SHOWSELALWAYS) ; Listview erstellen
Global $hLVHandle = GUICtrlGetHandle($hListView) ; das Handle vom Listview wird für die UDF-Listview-Funktionen benötigt
_GUICtrlListView_SetColumn($hLVHandle, 0, "Title", 180, 0)
_GUICtrlListView_SetColumn($hLVHandle, 1, "Artist", 180, 0)
_GUICtrlListView_SetColumn($hLVHandle, 2, "Length", 60, 0)
_GUICtrlListView_SetColumn($hLVHandle, 3, "Album", 120, 0)
_GUICtrlListView_SetColumn($hLVHandle, 4, "Year", 60, 0)
_GUICtrlListView_SetColumn($hLVHandle, 5, "MPEG-Version", 100, 0)
_GUICtrlListView_SetColumn($hLVHandle, 6, "Bitrate", 100, 0)
_GUICtrlListView_SetColumn($hLVHandle, 7, "Sample-Freq.", 90, 0)
_GUICtrlListView_SetColumn($hLVHandle, 8, "Path", 800, 0)
Global $hSearch = GUICtrlCreateButton("Alle Festplatten durchsuchen", 10, 430, 160, 35, $BS_MULTILINE)
Global $hLoad = GUICtrlCreateButton("Laden", 230, 430, 70, 35)
Global $hSave = GUICtrlCreateButton("Speichern", 310, 430, 70, 35)
Global $hDelAll = GUICtrlCreateButton("Alle Einträge löschen", 500, 430, 90, 35, $BS_MULTILINE)
Global $aParts[3] = [160, 220, -1], $aText[3] =["Fertig.", "0", ""]
Global $hStatus = _GUICtrlStatusBar_Create($hGui, $aParts, $aText)
#EndRegion Hauptfenster
;~ _GUICtrlListView_RegisterSortCallBack($hLVHandle) ; damit man das Listview (mit Klick auf die Spaltenüberschrift) sortieren kann
[/autoit] [autoit][/autoit] [autoit]GUISetState(@SW_SHOW, $hGui) ; Hauptfenster sichtbar machen
[/autoit] [autoit][/autoit] [autoit]Global $fStop = False, $iCount = 0
HotKeySet("{ESC}", "_Stop")
While 1
Switch GUIGetMsg() ; anhand der Control-ID das entsprechende Case aufrufen
Case $hSearch
_GUICtrlListView_DeleteAllItems($hLVHandle) ; Alle Listview-Einträge löschen
$iCount = 0 ; Zähler auf Null setzen
$aDrives = DriveGetDrive("FIXED") ; Alle Festplatten-Buchstaben holen
If Not @error Then
For $i = 1 To $aDrives[0] ; Alle Festplatten durchgehen
$aDrives[$i] = StringUpper($aDrives[$i]) & "\"
_GUICtrlStatusBar_SetText($hStatus, 'Durchsuche Festplatte "' & $aDrives[$i] & '"', 0)
_GUICtrlStatusBar_SetText($hStatus, "Bitte warten...", 2)
$aNewMP3 = _RecursiveFileListToArray($aDrives[$i], '\.mp3', 1) ; Alle MP3s auf der Festplatte auslesen
If Not @error Then
_GUICtrlStatusBar_SetText($hStatus, "Lese ID3-Tags...", 0)
_GUICtrlListView_SetItemCount($hListView, $iCount + $aNewMP3[0])
For $j = 1 To $aNewMP3[0] ; die gefundenen MP3s durchgehen
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
$aID3Tags = _ReadID3Tag($aNewMP3[$j]) ; die ID3-Tags auslesen
If Not @error Then
_GUICtrlStatusBar_SetText($hStatus, $aNewMP3[$j], 2)
$sNewItem = $aID3Tags[0][1] & "|" & $aID3Tags[1][1] & "|" & $aID3Tags[4][1] & "|" & $aID3Tags[2][1] & "|" & $aID3Tags[3][1]
$sNewItem &= "|" & $aID3Tags[8][1] & "|" & $aID3Tags[9][1] & "|" & $aID3Tags[10][1] & "|" & $aNewMP3[$j]
GUICtrlCreateListViewItem($sNewItem, $hListView)
$iCount += 1
EndIf
If $fStop Then ExitLoop 2 ; Wenn [ESC] gedrückt wurde, die Schleifen verlassen
Next
EndIf
Next
EndIf
_GUICtrlStatusBar_SetText($hStatus, "", 2)
If $fStop Then
$fStop = False
_GUICtrlStatusBar_SetText($hStatus, "Abgebrochen!", 0)
Else
_GUICtrlStatusBar_SetText($hStatus, "Fertig.", 0)
EndIf
;~ Case $hListView ; User hat auf eine Spaltenüberschrift geklickt
;~ _GUICtrlListView_SortItems($hLVHandle, GUICtrlGetState($hListView)) ; Einträge entsprechend sortieren
Case $hLoad ; User hat auf "Laden" geklickt
_GUICtrlStatusBar_SetText($hStatus, "Lade Daten...", 0)
Load()
_GUICtrlStatusBar_SetText($hStatus, "Fertig.", 0)
Case $hSave ; User hat auf "Speichern" geklickt
_GUICtrlStatusBar_SetText($hStatus, "Speichere Daten...", 0)
Save()
_GUICtrlStatusBar_SetText($hStatus, "Fertig.", 0)
_GUICtrlStatusBar_SetText($hStatus, "", 2)
Case $hDelAll ; User hat auf "Alle Einträge löschen" geklickt
If MsgBox(256 + 32 + 4, "Einträge löschen", "Wollen sie wirklich alle Einträge löschen?") = 6 Then
_GUICtrlListView_DeleteAllItems($hLVHandle)
$iCount = 0
EndIf
Case $GUI_EVENT_CLOSE ; User hat auf das Schließen-Symbol geklickt (bzw. die ESC-Taste gedrückt)
End()
;~ If MsgBox(32 + 4, "Beenden", "Wollen sie das Programm wirklich beenden?") = 6 Then End() ; wenn ja, dann End-Funktion aufrufen
EndSwitch
WEnd
Func _Stop()
$fStop = True
EndFunc
Func End()
;~ Save() ; wenn der vordere Kommentar entfernt wird, dann werden vor dem beenden noch die Daten gespeichert
_GUICtrlListView_UnRegisterSortCallBack($hLVHandle) ; Sortierroutine wieder de-registrieren
Exit ; Programm beenden
EndFunc
Func Load() ; Datenbank-Datei laden
Local $hFile, $sContent, $aNewItems
$hFile = FileOpen($sDBFile, 0) ; Datei zum lesen öffnen
If $hFile <> -1 Then ; wenn das öffnen erfolgreich war, dann...
$sContent = FileRead($hFile) ; Datei komplett einlesen
FileClose($hFile) ; Datei schließen
$sContent = StringTrimRight($sContent, 2) ; das letzte @CRLF entfernen
$aNewItems = StringSplit($sContent, @CRLF, 1) ; Den Dateiinhalt am Zeilenende splitten
If Not IsArray($aNewItems) Then Return ; Wenn $aNewItems kein Array ist, dann Funktion verlassen
_GUICtrlListView_SetItemCount($hListView, $aNewItems[0])
_GUICtrlListView_BeginUpdate($hLVHandle) ; Listview sperren
For $i = 1 To $aNewItems[0] ; Alle Einträge des Arrays durchgehen
$iCount += 1
_GUICtrlStatusBar_SetText($hStatus, $iCount, 1)
GUICtrlCreateListViewItem($aNewItems[$i], $hListView) ; mit den eingelesenen Daten einen neuen Listview-Eintrag erstellen
Next
_GUICtrlListView_EndUpdate($hLVHandle) ; Listview wieder freigeben
EndIf
EndFunc ;==>Load
Func Save() ; Datenbank-Datei speichern
Local $sContent, $hFile, $iCount
$iCount = _GUICtrlListView_GetItemCount($hLVHandle); Anzahl der Listview-Einträge holen
If $iCount = 0 Then Return ; Wenn das Listview keine Einträge enthält, dann Funktion verlassen
For $i = 0 To $iCount - 1 ; Schleife, um alle Listview-Einträge durchzugehen
$sContent &= _GUICtrlListView_GetItemTextString($hLVHandle, $i) & @CRLF
_GUICtrlStatusBar_SetText($hStatus, $i + 1, 2)
Next
$hFile = FileOpen($sDBFile, 2) ; Datei zum speichern (überschreiben) öffnen
If $hFile <> -1 Then ; wenn das öffnen erfolgreich war, dann...
FileWrite($hFile, $sContent)
FileClose($hFile) ; Datei schließen
EndIf
EndFunc ;==>Save
;===============================================================================
; Function Name: _RecursiveFileListToArray($sPath[, $sPattern][, $iFlag][, $iFormat][, $iRecursion][, $sDelim])
; Description:: gibt Verzeichnisse (rekursiv) und/oder Dateien zurück, die einem RegExp-Pattern entsprechen
; Parameter(s): $sPath = Startverzeichnis
; $sPattern = ein beliebiges RexExp-Pattern für die Auswahl
; $iFlag = Auswahl
; 0 = Dateien & Verzeichnisse
; 1 = nur Dateien
; 2 = nur Verzeichnisse
; $iFormat = Rückgabeformat
; 0 = String
; 1 = Array mit [0] = Anzahl
; 2 = Nullbasiertes Array
; $iRecursion = Verzeichnisse rekursiv durchsuchen
; 0 = Nein
; 1 = Ja
; $sDelim = Trennzeichen für die String-Rückgabe
; Requirement(s): AutoIt 3.3.0.0
; Return Value(s): Array/String mit den gefundenen Dateien/Verzeichnissen
; Author(s): Oscar (http://www.autoit.de)
; Anregungen von: bernd670 (http://www.autoit.de)
;===============================================================================
Func _RecursiveFileListToArray($sPath, $sPattern = '', $iFlag = 0, $iFormat = 1, $iRecursion = 1, $sDelim = @CRLF)
Local $hSearch, $sFile, $sReturn = ''
If StringRight($sPath, 1) <> '\' Then $sPath &= '\'
$hSearch = FileFindFirstFile($sPath & '*.*')
If @error Or $hSearch = -1 Then Return SetError(1, 0, $sReturn)
While True
$sFile = FileFindNextFile($hSearch)
If @error Then ExitLoop
If @extended Then
If StringRegExp($sPath & $sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 2) Then $sReturn &= $sPath & $sFile & '\' & $sDelim
If $iRecursion Then $sReturn &= _RecursiveFileListToArray($sPath & $sFile & '\', $sPattern, $iFlag, 0)
ContinueLoop
EndIf
If StringRegExp($sFile, $sPattern) And ($iFlag = 0 Or $iFlag = 1) Then $sReturn &= $sPath & $sFile & $sDelim
WEnd
FileClose($hSearch)
If $iFormat And $sReturn = '' Then Return StringSplit($sReturn, '', $iFormat)
If $iFormat Then Return StringSplit(StringTrimRight($sReturn, StringLen($sDelim)), $sDelim, $iFormat)
Return $sReturn
EndFunc
;===============================================================================
; Function Name: _ReadID3Tag($sPath)
; Description:: gibt ein Array mit den Daten aus den ID3-Tags zurück
; unterstützt werden die ID3-Tag-Versionen 1.0, 1.1, 2.3 und 2.4
; bei v2.4 müssen sich die ID3-Tags am Anfang der Datei befinden
; Parameter(s): $sPath = Pfad zu einer MP3-Datei
; Requirement(s): min. AutoIt v3.3.0.0
; Return Value(s): bei Erfolg: Array mit den ID3-Tagdaten (@error = 0)
; im Fehlerfall bekommt @error:
; 1 = Datei existiert nicht
; 2 = Datei konnte nicht zum lesen geöffnet werden
; 3 = falsche ID3 v2 Version
; 4 = Datei ist keine MP3-Datei
; Author(s): Oscar (http://www.autoit.de)
;===============================================================================
Func _ReadID3Tag($sPath)
If Not FileExists($sPath) Then Return SetError(1, 0, 0)
Local $hFile, $sData, $sID3Header, $iID3HeaderSize = 0, $iOffset, $iSize, $tmp
Local $aID3v2Tags[8] = ['TIT2', 'TPE1', 'TALB', 'TYER', 'TLEN', 'TRCK', 'TCON', 'TENC']
Local $aID3[11][2] = [ _
['Title', ''],['Artist', ''],['Album', ''],['Year', ''], _
['Length', '0'],['Track', ''],['Genre', ''],['Encoder', ''], _
['MPEG-Version', ''],['Bitrate', '-'],['Sample-Freq.', '']]
Local $aMP3Version[4] = ['MPEG2.5', 'Reserved', 'MPEG2', 'MPEG1']
Local $aMP3Layer[4] = ['Reserved', 'Layer III', 'Layer II', 'Layer I']
Local $aMP3Bitrate[5][16] = [ _
[000, 032, 064, 096, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 384, 000], _
[000, 032, 040, 048, 056, 064, 080, 096, 112, 128, 160, 192, 224, 256, 320, 000], _
[000, 032, 048, 056, 064, 080, 096, 112, 128, 144, 160, 176, 192, 224, 256, 000], _
[000, 008, 016, 024, 032, 040, 048, 056, 064, 080, 096, 112, 128, 144, 160, 000]]
Local $aSampleFreq[3][4] = [[44100, 48000, 32000, 0],[22050, 24000, 16000, 0],[11025, 12000, 8000, 0]]
Local $sMP3FrameHeader, $iMP3Version, $sMP3Version, $sMP3Layer, $iMP3Bitrate, $iMP3SampleFreq
Local $iVBRFrames = -1, $iVBRFilesize, $iVBRFlags
$hFile = FileOpen($sPath, 16)
If $hFile = -1 Then Return SetError(2, 0, 0)
$sData = Binary(FileRead($hFile, 4))
If BinaryMid($sData, 1, 3) = '0x494433' Then ; ID3 v2.x Kennung gefunden
If (BinaryMid($sData, 4, 1) = '0x03') Or (BinaryMid($sData, 4, 1) = '0x04') Then ; nur v2.3 und 2.4
FileRead($hFile, 2) ; 2 Bytes überspringen
For $i = 0 To 3 ; berechne ID3-Headergröße (4 Bytes, jedoch nur jeweils die unteren 7 Bit)
$iID3HeaderSize = BitShift($iID3HeaderSize, -7) + BitAND(Binary(FileRead($hFile, 1)), 0x7F)
Next
If $iID3HeaderSize > 0 Then
$sID3Header = Binary(FileRead($hFile, $iID3HeaderSize)) ; lese gesamten ID3-Header
For $i = 0 To 7
$iOffset = StringInStr(BinaryToString($sID3Header), $aID3v2Tags[$i]) ; Offset zu dem ID3-Tag
If $iOffset > 0 Then
$iSize = Hex(BinaryMid($sID3Header, $iOffset + 4, 4)) ; Größe des ID3-Frames
$tmp = BinaryMid($sID3Header, $iOffset + 11, Dec($iSize) - 1)
If BinaryMid($tmp, 1, 2) = '0xFFFE' Then
For $x = 3 To BinaryLen($tmp) Step 2
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 2), 2)
Next
Else
For $x = 1 To BinaryLen($tmp)
$aID3[$i][1] &= BinaryToString(BinaryMid($tmp, $x, 1))
Next
EndIf
$aID3[$i][1] = StringReplace($aID3[$i][1], Chr(0), '')
EndIf
Next
EndIf
Do
$sData = String(FileRead($hFile, 1))
If @error Then ExitLoop
If BitAND($sData, 0xff) = 0xff Then
FileSetPos($hFile, -1, 1)
$sData = String(FileRead($hFile, 4))
EndIf
Until BitAND($sData, 0xFFE00000) = 0xFFE00000
Else
FileClose($hFile)
Return SetError(3, 0, 0)
EndIf
Else ; ID3 v1.x
$iOffset = FileGetPos($hFile)
FileSetPos($hFile, -128, 2)
$sID3Header = BinaryToString(FileRead($hFile, 3))
If $sID3Header = 'TAG' Then
$aID3[0][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[1][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[2][1] = StringReplace(BinaryToString(FileRead($hFile, 30)), Chr(0), '')
$aID3[3][1] = StringReplace(BinaryToString(FileRead($hFile, 4)), Chr(0), '')
EndIf
FileSetPos($hFile, $iOffset, 0)
EndIf
$sMP3FrameHeader = String($sData)
If BitAND($sMP3FrameHeader, 0xFFE00000) <> 0xFFE00000 Then
FileClose($hFile)
Return SetError(4, 0, 0) ; keine MP3-Datei, dann Return
EndIf
$iMP3Version = BitShift(BitXOR($sMP3FrameHeader, 0xFFE00000), 19) ; welche MP3-Version
$sMP3Version = $aMP3Version[$iMP3Version] ; in Textform
$sMP3Layer = $aMP3Layer[BitShift(BitAND($sMP3FrameHeader, 0x60000), 17)] ; welcher Layer
$aID3[8][1] = $sMP3Version & ' / ' & $sMP3Layer ; ins Ausgabe-Array
$iMP3Bitrate = BitShift(BitAND($sMP3FrameHeader, 0xF000), 12) ; Bitraten-Index auslesen
Switch $sMP3Version ; je nach MPEG-Version Bitrate aus der Tabelle holen
Case 'MPEG1'
$aID3[9][1] = $aMP3Bitrate[$iMP3Version - ($iMP3Version > 1)][$iMP3Bitrate]
Case 'MPEG2', 'MPEG2.5'
If $sMP3Layer = 'Layer I' Then
$aID3[9][1] = $aMP3Bitrate[3][$iMP3Bitrate]
Else
$aID3[9][1] = $aMP3Bitrate[4][$iMP3Bitrate]
EndIf
EndSwitch
$iMP3SampleFreq = BitShift(BitAND($sMP3FrameHeader, 0xC00), 10) ; Sample-Frequenz-Index auslesen
$aID3[10][1] = $aSampleFreq[2 - ($iMP3Version - ($iMP3Version > 1))][$iMP3SampleFreq] ; und Wert aus der Tabelle holen
Do ; evtl. Leerbytes überspringen
$tmp = FileRead($hFile, 1)
If @error Then ExitLoop
Until $tmp <> 0x00 Or @error
If $tmp = 0x58 And BinaryToString(FileRead($hFile, 3)) = 'ing' Then ; MP3 mit VBR (Xing-Header gefunden)?
$iVBRFlags = '0x' & Hex(FileRead($hFile, 4)) ; VBR-Flags auslesen
If BitAND($iVBRFlags, 0x3) Then ; wenn die Einträge vorhanden sind, dann...
$iVBRFrames = Dec(Hex(FileRead($hFile, 4))) ; Anzahl der VBR-Frames auslesen
$iVBRFilesize = Dec(Hex(FileRead($hFile, 4))) ; Dateigröße auslesen
$aID3[4][1] = $iVBRFrames * 1152 / $aID3[10][1] * 1000 ; VBR Laufzeit
$aID3[9][1] = 'VBR ~' & Int($iVBRFilesize * 8 / ($aID3[4][1] / 1000) / 1000) ; VBR durchschnittliche Bitrate
EndIf
Else
If $aID3[4][1] = 0 Then $aID3[4][1] = (FileGetSize($sPath) *
/ ($aID3[9][1] * 1000) * 1000 ; alternative CBR Laufzeit
$aID3[9][1] = 'CBR ' & $aID3[9][1]
EndIf
$aID3[4][1] = _MyTicksToTime($aID3[4][1]) ; Laufzeit (Ticks to hour:min:sec)
$aID3[9][1] &= ' kBit/s'
$aID3[10][1] &= ' Hz'
FileClose($hFile)
Return SetError(0, 0, $aID3)
EndFunc ;==>_ReadID3Tag
Func _MyTicksToTime($iTicks)
Local $iHour, $iMins, $iSecs
$iHour = Int($iTicks / 3600000)
$iTicks -= $iHour * 3600000
$iMins = Int($iTicks / 60000)
$iTicks -= $iMins * 60000
$iSecs = Int($iTicks / 1000)
Return StringFormat('%02i:%02i:%02i', $iHour, $iMins, $iSecs)
EndFunc ;==>_MyTicksToTime
Naja, habe ich Dir schon eine Menge Arbeit abgenommen, aber wie gesagt, es war eigentlich nur das zusammensetzen von meinen bereits vorhandenen Skripten. ![]()
Welches Verhalten erwartest Du denn?
Soll sich das Tab-Control ebenfalls der Größe anpassen?
Dann so:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <TabConstants.au3>
#include <WindowsConstants.au3>
#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 413, 298, -1, -1, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_OVERLAPPEDWINDOW,$WS_TILEDWINDOW,$WS_POPUP,$WS_POPUPWINDOW,$WS_GROUP,$WS_TABSTOP,$WS_BORDER,$WS_CLIPSIBLINGS))
$Tab1 = GUICtrlCreateTab(8, 8, 401, 281)
GUICtrlSetResizing(-1, $GUI_DOCKBORDERS)
$TabSheet1 = GUICtrlCreateTabItem("TabSheet1")
$ListView1 = GUICtrlCreateListView("a|b|c|d", 32, 48, 250, 150)
GUICtrlSendMsg($ListView1, $LVM_SETCOLUMNWIDTH, 0, 50)
GUICtrlSendMsg($ListView1, $LVM_SETCOLUMNWIDTH, 1, 50)
GUICtrlSendMsg($ListView1, $LVM_SETCOLUMNWIDTH, 2, 50)
GUICtrlSendMsg($ListView1, $LVM_SETCOLUMNWIDTH, 3, 50)
$ListView1_0 = GUICtrlCreateListViewItem("Test1a|Test1b|Test1c|Test1d", $ListView1)
$ListView1_1 = GUICtrlCreateListViewItem("Test2a|Test2b|Test2c|Test2d", $ListView1)
$Button1 = GUICtrlCreateButton("Button1", 32, 232, 75, 25, 0)
$Button2 = GUICtrlCreateButton("Button2", 128, 232, 75, 25, 0)
GUICtrlCreateTabItem("")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
Da hast Du Dir ja einiges vorgenommen. Wobei ich zweifle, ob man das einfach so "by doing" lernen kann, aber ich lasse mich da gern eines Besseren belehren.
Ein Edit-Control-Element halte ich für so ein Projekt aber für falsch oder sagen wir: suboptimal. Ich würde Dir lieber zu einem Listview raten. Falls Dir da auch die Grundlagen fehlen, kannst Du Dir vielleicht mal mein Listview-Datenbank-Beispiel anschauen:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
Global $sHeader = "Artikelnummer|Art|Nummer|Baureihe|Name" ; Die Überschriften für das Listview und für das "Neuer Eintrag"-Fenster
Global $sDBFile = @ScriptDir & "\datenbank.txt" ; Pfad und Name der Datenbank-Datei
Global $iEdit = -1 ; Wert auf -1 setzen, weil _GUICtrlListView_GetSelectionMark() einen Nullbasierten Wert liefert
#Region Hauptfenster
Global $hGui = GUICreate("Listview-Datenbank-Beispiel", 600, 480) ; Hauptfenster erstellen
Global $hListView = GUICtrlCreateListView($sHeader, 0, 0, 600, 420, $LVS_SHOWSELALWAYS) ; Listview erstellen
Global $hLVHandle = GUICtrlGetHandle($hListView) ; das Handle vom Listview wird für die UDF-Listview-Funktionen benötigt
_GUICtrlListView_SetColumn($hLVHandle, 0, "Artikelnummer", 120, 1) ; 1. Spalte = 120 Px breit, rechts ausgerichtet
_GUICtrlListView_SetColumn($hLVHandle, 1, "Art", 60, 0) ; 2. Spalte = 60 Px breit, links ausgerichtet
_GUICtrlListView_SetColumn($hLVHandle, 2, "Nummer", 90, 0) ; 3. Spalte = 90 Px breit, links ausgerichtet
_GUICtrlListView_SetColumn($hLVHandle, 3, "Baureihe", 100, 0) ; 4. Spalte = 100 Px breit, links ausgerichtet
_GUICtrlListView_SetColumn($hLVHandle, 4, "Name", 120, 0) ; 5. Spalte = 120 Px breit, links ausgerichtet
Global $hNew = GUICtrlCreateButton("Neuer Eintrag", 5, 430, 80, 35, $BS_DEFPUSHBUTTON) ; Dieser Button ist der Default-Push-Button (wenn der User [Enter] drückt)
Global $hEdit = GUICtrlCreateButton("Markierten Eintrag bearbeiten", 95, 430, 110, 35, $BS_MULTILINE) ; $BS_Multiline für mehrzeiligen Button
Global $hLoad = GUICtrlCreateButton("Laden", 230, 430, 70, 35)
Global $hSave = GUICtrlCreateButton("Speichern", 310, 430, 70, 35)
Global $hDel = GUICtrlCreateButton("Markierte Einträge löschen", 400, 430, 90, 35, $BS_MULTILINE)
Global $hDelAll = GUICtrlCreateButton("Alle Einträge löschen", 500, 430, 90, 35, $BS_MULTILINE)
Global $hCM = GUICtrlCreateContextMenu($hListView) ; ein Kontextmenü für das Listview erstellen
Global $hCMNew = GUICtrlCreateMenuItem("Neuer Eintrag", $hCM) ; der 1. Kontextmenüeintrag
Global $hCMEdit = GUICtrlCreateMenuItem("Eintrag bearbeiten", $hCM) ; der 2. Kontextmenüeintrag
Global $hCMDel = GUICtrlCreateMenuItem("Markierte Einträge löschen", $hCM) ; der 3. Kontextmenüeintrag
#EndRegion Hauptfenster
#Region Fenster für neuen Eintrag
Global $hGuiNew = GUICreate("Neuer Eintrag", 632, 140, -1, -1, $WS_SYSMENU) ; das Fenster "Neuer Eintrag" erstellen
Global $aHeader = StringSplit($sHeader, '|') ; Überschriften-Array
Global $aNew[$aHeader[0]] ; Array für die Input-IDs
For $i = 1 To $aHeader[0]
GUICtrlCreateLabel($aHeader[$i], 4 + ($i - 1) * 125, 15, 110, 20) ; Überschriften-Label erstellen
GUICtrlSetFont(-1, 8, 400, 0, 'Verdana') ; Schriftgröße und -art der Überschriften festlegen
$aNew[$i - 1] = GUICtrlCreateInput("", 2 + ($i - 1) * 125, 30, 120, 20, Default, $WS_EX_STATICEDGE) ; Eingabefelder erstellen
GUICtrlSetFont(-1, 10, 600, 0, 'Verdana') ; Schriftgröße und -art der Eingabefelder festlegen
Next
Global $hCreate = GUICtrlCreateButton("Eintrag speichern", 254, 65, 120, 25, $BS_DEFPUSHBUTTON) ; Button zum speichern
#EndRegion Fenster für neuen Eintrag
_GUICtrlListView_RegisterSortCallBack($hLVHandle) ; damit man das Listview (mit Klick auf die Spaltenüberschrift) sortieren kann
[/autoit] [autoit][/autoit] [autoit]GUISetState(@SW_SHOW, $hGui) ; Hauptfenster sichtbar machen
[/autoit] [autoit][/autoit] [autoit]If FileExists($sDBFile) Then Load() ; wenn Datenbank-Datei existiert, dann Datenbank laden
[/autoit] [autoit][/autoit] [autoit]While 1
$nMsg = GUIGetMsg(1) ; Message-Event holen (1) = erweiterter Modus
Switch $nMsg[0] ; anhand der Control-ID das entsprechende Case aufrufen
Case $hListView ; User hat auf eine Spaltenüberschrift geklickt
_GUICtrlListView_SortItems($hLVHandle, GUICtrlGetState($hListView)) ; Einträge entsprechend sortieren
Case $hNew, $hCMNew ; User hat auf "Neuer Eintrag" geklickt
WinSetTitle($hGuiNew, "", "Neuer Eintrag") ; den Titel des Fenster anpassen
GUISetState(@SW_SHOW, $hGuiNew) ; das Fenster "Neuer Eintrag" anzeigen
GUISetState(@SW_DISABLE, $hGui) ; das Hauptfenster deaktivieren
Case $hEdit, $hCMEdit ; User hat auf "Eintrag bearbeiten" geklickt
WinSetTitle($hGuiNew, "", "Eintrag bearbeiten") ; den Titel des Fenster anpassen
GUISetState(@SW_SHOW, $hGuiNew) ; das Fenster "Neuer Eintrag" anzeigen
GUISetState(@SW_DISABLE, $hGui) ; das Hauptfenster deaktivieren
Edit()
Case $hLoad ; User hat auf "Laden" geklickt
Load()
Case $hSave ; User hat auf "Laden" geklickt
Save()
Case $hDel, $hCMDel ; User hat auf "Markierte Einträge löschen" geklickt
If MsgBox(256 + 32 + 4, "Einträge löschen", "Wollen sie die markierten Einträge wirklich löschen?") = 6 Then _GUICtrlListView_DeleteItemsSelected($hLVHandle)
Case $hDelAll ; User hat auf "Alle Einträge löschen" geklickt
If MsgBox(256 + 32 + 4, "Einträge löschen", "Wollen sie wirklich alle Einträge löschen?") = 6 Then _GUICtrlListView_DeleteAllItems($hLVHandle)
Case $hCreate ; User hat auf "Eintrag speichern" im Fenster "Neuer Eintrag" geklickt
NewItem()
Case $GUI_EVENT_CLOSE ; User hat auf das Schließen-Symbol geklickt (bzw. die ESC-Taste gedrückt)
Switch $nMsg[1] ; erweiterte Abfrage für welches Fenster
Case $hGui ; User will das Hauptfenster schließen
If MsgBox(32 + 4, "Beenden", "Wollen sie das Programm wirklich beenden?") = 6 Then End() ; wenn ja, dann End-Funktion aufrufen
Case $hGuiNew ; User will das "Neuer Eintrag"-Fenster schließen
$iEdit = -1
For $i = 0 To UBound($aNew) - 1
GUICtrlSetData($aNew[$i], "") ; Alle Eingabefelder leeren
Next
GUISetState(@SW_HIDE, $hGuiNew) ; "Neuer Eintrag"-Fenster verstecken
GUISetState(@SW_ENABLE, $hGui) ; Hauptfenster wieder aktivieren
WinActivate($hGui) ; und in den Vordergrund holen
EndSwitch
EndSwitch
WEnd
Func End()
;~ Save() ; wenn der vordere Kommentar entfernt wird, dann werden vor dem beenden noch die Daten gespeichert
_GUICtrlListView_UnRegisterSortCallBack($hLVHandle) ; Sortierroutine wieder de-registrieren
Exit ; Programm beenden
EndFunc
Func NewItem() ; Funktion zum auslesen der Eingabefelder (Neuer Eintrag bzw. Eintrag bearbeiten)
Local $sItem = ""
For $i = 0 To UBound($aNew) - 1 ; Schleife, um alle Eingabefelder durchzugehen
If $iEdit > -1 Then ; wenn $iEdit > -1 (Eintrag bearbeiten), dann...
_GUICtrlListView_SetItemText($hLVHandle, $iEdit, GUICtrlRead($aNew[$i]), $i) ; den Eintrag aus dem Eingabefeld ins Listview schreiben
Else ; sonst $iEdit = -1 (neuer Eintrag)
$sItem &= GUICtrlRead($aNew[$i]) & "|" ; den Eintrag aus dem Eingabefeld erstmal in einer Variablen ($sItem) speichern
EndIf
GUICtrlSetData($aNew[$i], "") ; das entsprechende Eingabefeld leeren
Next
If $iEdit > -1 Then ; wenn $iEdit > -1 (Eintrag bearbeiten), dann...
$iEdit = -1
GUISetState(@SW_HIDE, $hGuiNew) ; "Neuer Eintrag"-Fenster verstecken
GUISetState(@SW_ENABLE, $hGui) ; Hauptfenster wieder aktivieren
Sleep(300)
WinActivate($hGui) ; und in den Vordergrund holen
Else ; sonst $iEdit = -1 (neuer Eintrag)
GUICtrlSetState($aNew[0], $GUI_FOCUS) ; den Focus wieder auf das erste Eingabefeld setzen, für weitere Eingaben
GUICtrlCreateListViewItem(StringTrimRight($sItem, 1), $hListView) ; mit den Werten aus $sItem einen neuen Listview-Eintrag hinzufügen
EndIf
EndFunc ;==>NewItem
Func Edit() ; Funktion zum bearbeiten eines Listview-Eintrags im "Eintrag bearbeiten"-Fenster
$iEdit = _GUICtrlListView_GetSelectionMark($hLVHandle) ; auslesen, welcher Listview-Eintrag markiert (bei mehreren, den obersten) ist
If $iEdit > -1 Then
Local $aItem = _GUICtrlListView_GetItemTextArray($hLVHandle, $iEdit) ; die Einträge aus dem Listview in ein Array holen
For $i = 1 To $aItem[0]
GUICtrlSetData($aNew[$i - 1], $aItem[$i]) ; und in die entsprechenden Eingabefelder schreiben
Next
EndIf
EndFunc ;==>Edit
Func Load() ; Datenbank-Datei laden
Local $hFile, $sContent, $aNewItems
$hFile = FileOpen($sDBFile, 0) ; Datei zum lesen öffnen
If $hFile <> -1 Then ; wenn das öffnen erfolgreich war, dann...
$sContent = FileRead($hFile) ; Datei komplett einlesen
FileClose($hFile) ; Datei schließen
$sContent = StringTrimRight($sContent, 2) ; das letzte @CRLF entfernen
$aNewItems = StringSplit($sContent, @CRLF, 1) ; Den Dateiinhalt am Zeilenende splitten
If Not IsArray($aNewItems) Then Return ; Wenn $aNewItems kein Array ist, dann Funktion verlassen
_GUICtrlListView_BeginUpdate($hLVHandle) ; Listview sperren
For $i = 1 To $aNewItems[0] ; Alle Einträge des Arrays durchgehen
GUICtrlCreateListViewItem($aNewItems[$i], $hListView) ; mit den eingelesenen Daten einen neuen Listview-Eintrag erstellen
Next
_GUICtrlListView_EndUpdate($hLVHandle) ; Listview wieder freigeben
EndIf
EndFunc ;==>Load
Func Save() ; Datenbank-Datei speichern
Local $sItem, $hFile, $iCount
$iCount = _GUICtrlListView_GetItemCount($hLVHandle) - 1 ; Anzahl der Listview-Einträge holen
If $iCount = -1 Then Return ; Wenn das Listview keine Einträge enthält, dann Funktion verlassen
$hFile = FileOpen($sDBFile, 2) ; Datei zum speichern (überschreiben) öffnen
If $hFile <> -1 Then ; wenn das öffnen erfolgreich war, dann...
For $i = 0 To $iCount ; Schleife, um alle Listview-Einträge durchzugehen
$sItem = _GUICtrlListView_GetItemTextString($hLVHandle, $i) ; die Werte aus dem Listview-Eintrag holen
FileWriteLine($hFile, $sItem) ; und in die Datei schreiben
Next
FileClose($hFile) ; Datei schließen
EndIf
EndFunc ;==>Save
Ein Listview bietet halt einfach eine bessere Übersicht (Spalten-Zeilenorientiert) und man kann nach einzelnen Spalten sortieren lassen.
Naja, Möglichkeiten gibt es viele, die Daten weiter zu verwenden. Ich verwende gerne ListViews, da könnte man die ID3-Tags auslesen und dann in jeweils eine Spalte einfügen (zusätzlich zum Dateipfad).
Entscheidend ist aber, was willst Du damit erreichen, also: Was soll am Ende dabei rauskommen?
Einfach eine Auflistung aller MP3s ist ja ganz schön, aber was soll man damit anfangen? Nicht falsch verstehen, ich will Dein Projekt nicht runtermachen, nur voranbringen. ![]()
Wenn Du noch nicht viel mit Arrays anfangen kannst, dann wäre es vielleicht angebracht, dieses Projekt erstmal aufzuschieben und sich mit Grundlagen (Arrays) zu befassen.
Oder anders ausgedrückt: Bevor Du anfängst zu rennen, lerne erst das gehen. ![]()
Windows ab Vista unterstützt das auslesen der Hardware-Seriennummer aller eingebauten Festplatten. Die werden vom jeweiligen Hersteller vergeben und sind einmalig (sollten sie jedenfalls).
Auslesen kann man sie so:
#include <Array.au3>
$aDisks = _CI_GetHarddrives()
_ArrayDisplay($aDisks)
Func _CI_GetHarddrives($strComputer = '.')
Local $aReturn[1][8] = [[ _
'Bezeichnung:', 'Größe:', 'Anschluss:', 'Bytes/Sektor:', 'Anzahl der Sektoren:', _
'PNPDeviceID:', 'Status:', 'Seriennr. (Hardware):']]
Local $x = 0, $objWMIService, $colItems
$objWMIService = ObjGet('winmgmts:\\' & $strComputer & '\root\cimv2')
If Not IsObj($objWMIService) Then Return SetError(1, 0, 0)
$colItems = $objWMIService.ExecQuery('SELECT * FROM Win32_DiskDrive', 'WQL', 0x30)
If IsObj($colItems) Then
For $objItem In $colItems
$x += 1
ReDim $aReturn[$x + 1][8]
$aReturn[$x][0] = $objItem.Model
$aReturn[$x][1] = $objItem.Size
$aReturn[$x][2] = $objItem.InterfaceType
$aReturn[$x][3] = $objItem.BytesPerSector
$aReturn[$x][4] = $objItem.TotalSectors
$aReturn[$x][5] = $objItem.PNPDeviceID
$aReturn[$x][6] = $objItem.Status
Switch @OSVersion
Case 'WIN_VISTA', 'WIN_7'
If Number($objItem.SerialNumber) > 0 Then
$aReturn[$x][7] = $objItem.SerialNumber & ' ("' & _CI_SerialToString($objItem.SerialNumber) & '")'
Else
$aReturn[$x][7] = 'nicht vorhanden'
EndIf
Case Else
$aReturn[$x][7] = 'Wird von ' & @OSVersion & ' nicht unterstützt!'
EndSwitch
Next
EndIf
Return $aReturn
EndFunc ;==>_CI_GetHarddrives
Func _CI_SerialToString($sSerial)
Local $sOut = ''
For $i = 1 To StringLen($sSerial) Step 2
$sOut &= Chr(Dec(StringMid($sSerial, $i, 2)))
Next
Return $sOut
EndFunc ;==>_CI_SerialToString
Schade, dass Du uns verlässt. Aber viel Glück und Erfolg in Deiner neuen Heimat.
Und vielleicht findet sich ja irgendwo ein Internet-Cafe. ![]()
WinWaitActive wartet bis zum Sanktnimmerleinstag (ohne Timeout), wenn das Updatefenster nicht auftaucht.
Mit anderen Worten: das Skript wird an dieser Stelle pausiert, bis das Fenster auftaucht (die While-Schleife wird nicht weiter durchlaufen).
Teste lieber innerhalb der While-Schleife mit "If WinExists("update", "OK") Then...", ob das Fenster existiert.
Danke für den Hinweis auf _BASS_ChannelSlideAttribute und das Beispiel! Das erleichtert das crossfading ungemein. ![]()
Es gibt jetzt auch gleich eine neue Version (Post #1).