1. Dashboard
  2. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team
    4. Mitgliedersuche
  3. Forenregeln
  4. Forum
    1. Unerledigte Themen
  • Anmelden
  • Registrieren
  • Suche
Alles
  • Alles
  • Artikel
  • Seiten
  • Forum
  • Erweiterte Suche
  1. AutoIt.de - Das deutschsprachige Forum.
  2. Mitglieder
  3. Kanashius

Beiträge von Kanashius

  • Problem mit einer For-To-Next-Schleife. (Verstaendisprobleme)

    • Kanashius
    • 17. April 2025 um 14:45

    Hey, bakesbusters,

    Das Ergebnis ist richtig (Die Verwendung von For $z = 0 To UBound($nummern2, 2) - 1 ), das warum ist aber komplett falsch.
    Es hat garnichts mit 3D-Arrays zu tun, es wird auch nichts deklariert.
    UBound ist einfach eine Funktion, die die Anzahl der Elemente im Array ausgibt.
    Bei einem 1D-Array ist das wie eine Liste, wo UBound($arData) die Anzahl der Elemente in der Liste zurückgibt:

    Code
    Local $arData = ["Erstes Element", "Zweites Element", "Drittes Element"]
    1. Erstes Element	=> $arData[0]
    2. Zweites Element	=> $arData[1]
    3. Drittes Element	=> $arData[2]
    Ubound($arData) gibt also 3 zurück

    Ein 2D-Array ist dagegen wie eine Tabelle, wo Ubound($arData) die Anzahl der Zeilen zurückgibt und Ubound($arData, 2) die Anzahl der Spalten.

    Code
    Local $arData[3][2] = [["Zeile 1 Spalte 1", "Zeile 1 Spalte 2"], ["Zeile 2 Spalte 1", "Zeile 2 Spalte 2"], ["Zeile 3 Spalte 1", "Zeile 3 Spalte 2"]]
    +-----------------------------------+----------------------------------+
    |  Zeile 1 Spalte 1 ($arData[0][0]) | Zeile 1 Spalte 2 ($arData[0][1]) |
    +-----------------------------------+----------------------------------+
    |  Zeile 2 Spalte 1 ($arData[1][0]) | Zeile 2 Spalte 2 ($arData[1][1]) |
    +-----------------------------------+----------------------------------+
    |  Zeile 3 Spalte 1 ($arData[2][0]) | Zeile 3 Spalte 2 ($arData[2][1]) |
    +-----------------------------------+----------------------------------+
    Ubound($arData) gibt also 3 zurück, weil es 3 Zeilen gibt
    Ubound($arData) gibt also 2 zurück, weil es 2 Spalten gibt

    Als "Deklaration" bezeichnet man übrigens nur die Angabe ("Deklaration") der Variable. Also z.B.:

    Code
    Local $sData
    Local $arData[2][3]

    Dabei wird nur festgelegt, dass es die Variable gibt (und in den meisten Sprachen auch welchen Typ sie hat, also wie viel Arbeitsspeicher sie benötigt). Dabei wird auch die Größe des Arrays angegeben.

    Als "Definition" oder "Zuweisung" wird es bezeichnet, wenn man einer Variable dabei einen Wert zuweist:

    Code
    Local $sData = "Ein schöner String"
    Local $arData = ["Ein", "schönes", "Array"]

    Dabei kann man z.B. die Größen-Angabe des Arrays weglassen, weil der Compiler sich die Größe durch die Zuweisung direkt selbst ableiten kann.

    Ubound verändert das Array also überhaupt nicht. Es liest nur die Größe aus und gibt sie zurück, damit man damit weiterarbeiten kann.

  • Problem mit einer For-To-Next-Schleife. (Verstaendisprobleme)

    • Kanashius
    • 16. April 2025 um 16:17

    Hier einmal eine Ausführliche Erklärung der For-Schleife und deiner Schwierigkeiten:

    AutoIt
    ; Wenn du das Array direkt zuweist musst du die Größe nicht angeben, die leitet sich aus der Zuweisung automatisch ab
    Local $arNumbers = [[72,87,84], [69,79,79], [76,82,68], [76,76,65], [79,68,89]]
    
    ; Die Größe kann mit Ubound abgefragt werden. Der erste Parameter ist das Array und der zweite die Dimension (Standard, wenn nicht angegeben ist 1)
    ConsoleWrite("2D-Array size: $arNumbers["&UBound($arNumbers)&"]["&UBound($arNumbers, 2)&"]"&@crlf)
    
    ; Eine For-Schleife definiert eine Variable, die mit jedem durchlauf verändert wird (normal um 1 erhöht) und das solange, bis die Variable einen Wert erreicht.
    ; Dabei wird der Start und das Ende angegeben (Hier ist 0 der Start und 10 das Ende).
    ConsoleWrite("-----------"&"For Loop 1"&"-----------"&@crlf)
    For $i=0 To 10
    	ConsoleWrite("Iteration: "&$i&@crlf)
    Next
    
    ; Durch das angeben von Step kann auch festgelegt werden, um wie viel sich die Variable verändern soll.
    ConsoleWrite("-----------"&"For Loop 2"&"-----------"&@crlf)
    For $i=2 To 10 Step 2
    	ConsoleWrite("Iteration: "&$i&@crlf)
    Next
    
    ; Die Werte können dabei auch negativ sein.
    ConsoleWrite("-----------"&"For Loop 3"&"-----------"&@crlf)
    For $i=10 To -10 Step -2
    	ConsoleWrite("Iteration: "&$i&@crlf)
    Next
    
    ; Das kann man dann auch nutzen, um über ein Array zu iterieren.
    ; Da der Index (das zwischen den []) für den Zugriff auf ein Array bei 0 anfängt ist der letzte Index dementsprechend die Größe des Arrays-1
    ; Hier starten wir also bei 0 und wollen bis 3 gehen um alle 4 Werte im Array auszugeben. 0 ist der Anfang und die Größe des Arrays ist 4 ( Ubound($ar1DExample) ).
    ; Es soll aber nicht von 0 bis 4, sondern nur von 0 bis 3 iteriert werden, weil der Index 4 nicht existiert (Array variable has incorrect number of subscripts...).
    ; Also nehmen wir die Größe und ziehen 1 ab: Ubound($ar1DExample)-1, was deshalb das Ziel der For-Schleife ist.
    ConsoleWrite("-----------"&"Iterate Array 1"&"-----------"&@crlf)
    Local $ar1DExample = [11,22,33,44]
    For $i=0 To UBound($ar1DExample)-1 Step 1
    	ConsoleWrite("Access $ar1DExample["&$i&"]: "&$ar1DExample[$i]&@crlf)
    Next
    
    ; Wollen wir jetzt das 2D-Array von oben ($arNumbers) iterieren, müssen wir also erst eine For-Schleife für den ersten Index schreiben und dann für den zweiten Index.
    ; Also bleibt die äußere For-Schleife genauso wie vorher, aber bei der zweiten (inneren) For-Schleife brauchen wir eine andere Variable und das Ziel ist auch nicht mehr
    ; die Größe der ersten Dimension ( UBound($arNumbers) ), sondern die Größe der zweiten Dimension ( UBound($arNumbers, 2) ).
    ; Das war übrigens auch der Fehler, der dir bei deinem Beispiel passiert ist.
    ; Du bist sowohl bei der ersten loop, als auch bei der zweiten von 0 bis 4 iteriert, statt bei der inneren Schleife von 0 bis 2 zu iterieren.
    ; Deshalb kam dann auch die Fehlermeldung, dass du auf Werte außerhalb des Arrays zugreifen willst.
    ; Das Problem bei dem anderen Beispiel aus deinem Post ist, dass du auf $nummern2[$y] zugreifen willst.
    ; Die Variable $nummern2 ist aber ein 2D-Array, du MUSST also den zweiten Index angeben ( $nummern2[$y][$z] ), ansonsten bekommst du die Fehlermeldung:
    ; Array variable ... subscript dimension range exceeded.
    ConsoleWrite("-----------"&"Iterate Array 2"&"-----------"&@crlf)
    ; Local $arNumbers = [[72,87,84], [69,79,79], [76,82,68], [76,76,65], [79,68,89]]
    For $i=0 To UBound($arNumbers)-1 Step 1
    	For $j=0 To UBound($arNumbers, 2)-1 Step 1
    		ConsoleWrite("Access $arNumbers["&$i&"]["&$j&"]: "&$arNumbers[$i][$j]&@crlf)
    	Next
    Next
    
    ; Das gleiche gilt auch für 3D-Arrays. Einfach eine Weitere For-Schleife, die über die dritte Dimension iteriert.
    ConsoleWrite("-----------"&"Iterate Array 3"&"-----------"&@crlf)
    Local $ar3DExample = [[[1, 2, 3], [7, 8, 9]], [[10, 20, 30], [70, 80, 90]]]
    For $i=0 To UBound($ar3DExample)-1 Step 1
    	For $j=0 To UBound($ar3DExample, 2)-1 Step 1
    		For $k=0 To UBound($ar3DExample, 3)-1 Step 1
    			ConsoleWrite("Access $ar3DExample["&$i&"]["&$j&"]["&$k&"]: "&$ar3DExample[$i][$j][$k]&@crlf)
    		Next
    	Next
    Next
    
    ; Ich bin mir auch nicht sicher, warum du in deinem Beispiel das ganze als String umschreiben und dann mit Execute ausführen willst.
    ; Das sorgt nur für unnötig viele Operationen.
    ; Du kannst einfach iterieren und die Funktion für jede Variable aufrufen.
    ConsoleWrite("-----------"&"Array - Int to Char"&"-----------"&@crlf)
    Local $arChars[UBound($arNumbers)][UBound($arNumbers, 2)]
    Local $arWords[UBound($arNumbers)]
    Local $sSentence = ""
    For $i=0 To UBound($arNumbers)-1 Step 1
    
    	Local $sWord = ""
    
    	; Iteriere Buchstaben
    	For $j=0 To UBound($arNumbers, 2)-1 Step 1
    		$arChars[$i][$j] = Chr($arNumbers[$i][$j])
    		ConsoleWrite("Access ["&$i&"]["&$j&"]: "&$arNumbers[$i][$j]&" >> "&$arChars[$i][$j]&@crlf)
    		$sWord &= $arChars[$i][$j]
    	Next
    
    	$arWords[$i] = $sWord
    	ConsoleWrite("Access $arWords["&$i&"]: "&$arWords[$i]&@crlf)
    
    	$sSentence &= $arWords[$i]
    	; Füge Leerzeichen hinzu, wenn es nicht das letzte Wort ist
    	If $i<UBound($arNumbers)-1 Then $sSentence &= " "
    Next
    ConsoleWrite("Sentence: "&$sSentence&@crlf)
    
    
    ; Kommen wir zum wichtigsten, wenn du solche Probleme selbst lösen möchtest:
    ; Lass dir alle Infos ausgeben.
    ; Ein paar ConsoleWrite ausgaben der Variablen würden dir das Problem zeigen
    ConsoleWrite("-----------"&"Problemsolving"&"-----------"&@crlf)
    Global $nummern2[5][3] = [[72,87,84],[69,79,79],[76,82,68],[76,76,65],[79,68,89]]
    Global $pre = "Chr("
    Global $back =")"
    For $y = 0 To UBound($nummern2) - 1
        For $z = 0 To UBound($nummern2) - 1
    		ConsoleWrite("Access: $nummern2["&$y&"]["&$z&"]: ")
    		ConsoleWrite($nummern2[$y][$z]&@CRLF)
    		$nummern2[$y][$z] = $pre & $nummern2[$y][$z] & $back
    		$nummern2[$y][$z] = Execute($nummern2[$y][$z])
        Next
    Next
    ; Die Fehlermeldung folgt auf der Ausgabe => Access: $nummern2[0][3]
    ; Dabei ist 3 größer als $nummern2[5][3] die Größe-1 der zweiten Dimension (3-1=2)
    Alles anzeigen

    Ich hoffe, das hilft dir weiter :)

  • daten aus einer ini datei in ein array[x][x] nach vorgaben umwandeln? möglich? wie?

    • Kanashius
    • 13. April 2025 um 15:13

    Und zum Wiederverwenden als Funktion könnte man es so machen:

    AutoIt
    ConsoleWrite("-------------Array-------------"&@crlf)
    Local $arData = _iniSectionToArray("shortlist.ini", "Data")
    ; Display data
    For $i=0 To UBound($arData)-1 Step 1
    	ConsoleWrite(StringFormat("%-10s %-9s %-8s\r\n", $arData[$i][0], $arData[$i][1], $arData[$i][2]))
    Next
    
    ConsoleWrite("--------------Map--------------"&@crlf)
    Local $mData = _iniToMap("shortlist.ini")
    ; Display data
    For $sKey In MapKeys($mData)
    	ConsoleWrite("-----Section "&$sKey&"-----"&@crlf)
    	Local $mSection = $mData[$sKey]
    	For $sSecKey In MapKeys($mSection)
    		ConsoleWrite($sSecKey&": "&$mSection[$sSecKey]&@crlf)
    	Next
    Next
    
    ConsoleWrite("---------Map Processed---------"&@crlf)
    Local $mDataProc = _iniToMap("shortlist.ini", "_processValueData")
    ; Display data
    For $sKey In MapKeys($mDataProc)
    	ConsoleWrite("-----Section "&$sKey&"-----"&@crlf)
    	Local $mSection = $mDataProc[$sKey]
    	For $sSecKey In MapKeys($mSection)
    		Local $arValue = $mSection[$sSecKey]
    		ConsoleWrite(StringFormat("%-5s: %-10s %-9s %-8s\r\n", $sSecKey, $arValue[0], $arValue[1], $arValue[2]))
    	Next
    Next
    
    Func _iniSectionToArray($sFile, $sSection)
    	Local $arData = IniReadSection($sFile, $sSection)
    	Local $arResult[UBound($arData)-1][3]
    	For $i=1 To UBound($arData)-1 Step 1
    		Local $arLine = StringSplit($arData[$i][1], "|", BitOR(1, 2))
    		If UBound($arLine)<3 Then Return SetError(1, 0, -1)
    		$arResult[$i-1][0] = $arLine[0]
    		$arResult[$i-1][1] = $arLine[1]
    		$arResult[$i-1][2] = $arLine[2]
    	Next
    	Return $arResult
    EndFunc
    
    Func _iniToMap($sFile, $sProcessDataCallback = Default)
    	Local $mResult[]
    	Local $arSections = IniReadSectionNames($sFile)
    	For $i=1 To UBound($arSections)-1 Step 1
    		Local $mSection[]
    		Local $arData = IniReadSection($sFile, $arSections[$i])
    		For $j=1 To UBound($arData)-1 Step 1
    			If $sProcessDataCallback<>Default Then
    				$mSection[$arData[$j][0]] = Call($sProcessDataCallback, $arData[$j][1])
    			Else
    				$mSection[$arData[$j][0]] = $arData[$j][1]
    			EndIf
    		Next
    		$mResult[$arSections[$i]] = $mSection
    	Next
    	Return $mResult
    EndFunc
    
    Func _processValueData($sValue)
    	Return StringSplit($sValue, "|", BitOR(1, 2))
    EndFunc
    Alles anzeigen

    Ich hab noch eine Funktion hinzugefügt, die alls Sections der Ini einliest und in eine Map speichert. Dabei kann auch eine Funktion angegeben werden (z.B. "_ProcessValueData") um die Value weiter zu verarbeiten (hier z.B. in ein Array umzuwandeln).
    Die Ausgabe hab ich extra manuell gemacht, um ein Beispiel zu geben, wie man das benutzen kann.

  • AutoIt Hackathon #1 Mitarbeiter-ID abgeschlossen

    • Kanashius
    • 30. März 2025 um 21:30
    AutoIt
    Func _CreateID($aUserdata)
    	Local $Return
    	Local $Return = StringLeft(StringReplace($aUserdata[2], "-", ""), 5)
    	While StringLen($Return)<5
    		$Return &= "9"
    	WEnd
    	Local $arBirthDate = StringRegExp($aUserdata[3], "(\d+).(\d+).\d{2}(\d)(\d)", 1)
    	$Return &= $arBirthDate[2]
    	If $aUserdata[4]="M" Then
    		$Return &= $arBirthDate[1]
    	Else
    		$Return &= Int($arBirthDate[1])+50
    	EndIf
    	$Return &= $arBirthDate[0]
    	$Return &= $arBirthDate[3]
    	$Return &= StringLeft($aUserdata[0], 2)
    	Local $sVName2 = StringLeft($aUserdata[1], 2)
    	While StringLen($sVName2)<2
    		$sVName2 &= "9"
    	WEnd
    	$Return &= $sVName2
    	Local $iChecksum = 0
    	Local $arChars = StringSplit($Return, "", 1+2)
    	For $i=0 To UBound($arChars)-1 Step 1
    		$iChecksum += Asc($arChars[$i])
    	Next
    	While StringLen($iChecksum)>1
    		Local $arLetters = StringSplit($iChecksum, "", 1+2)
    		Local $iNewSum = 0
    		For $i=0 To UBound($arLetters)-1 Step 1
    			$iNewSum += Int($arLetters[$i])
    		Next
    		$iChecksum = $iNewSum
    	WEnd
    	$Return &= $iChecksum
    	Return $Return
    EndFunc   ;==>_CreateID
    Alles anzeigen
  • Was ist eure Präferenz: "light mode" oder "dark mode" bei Software (egal ob Web oder Desktop)?

    • Kanashius
    • 14. März 2025 um 21:05
    Zitat

    Ich persönlich kann auch nichts mit einem Darkmode anfangen...kein einziges Printmedium/Buch ist lesbarer im Darkmode, mir zumindest ist auch nicht ein einziges relevantes bekannt!

    Ich lese fast ausschließlich ebooks und diese auch nur im darkmode. Ich lese meistens Abends vorm schlafen und wenn mir da der Helle (Smatphone-)Bildschirm ins Gesicht leuchten würde, wäre es mit der eventuellen Müdigkeit aber schwer.

    Und auch was Andy sonst so ausführt sind halt alles helle Umgebungen. Wenn es eh schon hell ist brauch ich keinen Darkmode. Wenn ich aber am PC sitze bin ich normal in einer dunkleren Umgebung und will halt nicht angestrahlt werden. Da dürfte Schnuffels beobachtung also vermutlich zutreffen. Lightmode nutzer machen sich im Zweifel lieber die ganze Umgebung hell, damit die hellen Bildschirme nicht stören.

    Ich bin froh, dass es sich langsam durchsetzt, dass light und darkmode unterstützt wird. (Auch wenn viele Webseiten das leider noch nicht haben.). Ich hoffe ja, dass auch bei PDFs langsam mal der Darkmode auftaucht (wär cool, wenn per Standard die Usereinstellung gilt, diese aber vom PDF "überschrieben" werden kann, wenn die Darstellung im darkmode nicht funktioniert)

  • Was ist eure Präferenz: "light mode" oder "dark mode" bei Software (egal ob Web oder Desktop)?

    • Kanashius
    • 13. März 2025 um 23:14
    Zitat

    Das Problem beim Dark Mode ist nur, dass der Kontrast fehlt und man die Ränder der Fenster nicht anhieb sieht, wenn sie übereinander liegen.

    Naja, das Problem liegt aber meiner Meinung nach aber daran, dass Windows lange keinen Darkmode hatte und es meines Wissens auch jetzt noch nicht so einfach möglich ist. Dazu kommt, dass GUIs in Win10/11 keine Rahmen mehr haben, sondern nurnoch einen leichten Schatten, der halt im Darkmode nicht ins Gewicht fällt.
    Viele nutzen deshalb schon lange nicht mehr die Standard Windows Fenster, sondern eigene (Firefox, Discord,...), die alle auch keinen Rahmen haben und wenn ich mich nicht täusche nichtmal einen Schatten.

    Es ist etwas schade, aber ich denke das ist einfach dem geschuldet, dass dark mode am Anfang nicht bedacht wurde (gab es noch nicht wirklich) und die Umsetzung immernoch nicht ausgereift und schon garnicht einheitlich ist. Deshalb entstehen dann solche Probleme.

    Beispiel:

    Spoiler anzeigen

    Wobei das im Explorer tatsächlich interessant gelöst wurde, indem die Titlebar oben nur beim aktiven Fenster dunkel ist und sonst grau. Das macht die Unterscheidung deutlich leichter. Außerdem haben die Explorer-Fenster auch einen sehr hellen Pixel drumherum, was deutlich beim erkennen hilft, wenn man mehrere übereinander hat. Das fehlt bei den "custom" Fenstern.

    Funfact: Ich hab gerade 3 (normal 4) Bildschirme. Ich schiebe extra leere Firefox Fenster auf die extra Bildschirme, wenn ich sie ne Zeit lang nicht benutze und dort was helles (ohne darkmode) angezeigt wird, damit es micht nicht so blendet :D (Ich mach sie nicht aus, weil ich oft "mal kurz" dann trotzdem was drüberschiebe oder so)

  • GUIRegisterMsg($WM_DRAWITEM, ...) Problem mit Map

    • Kanashius
    • 2. März 2025 um 23:21

    Ja, weil in seinem Beispiel die ComboBox (für alle Einträge) ausgelesen wird.

    Zitat

    Eigentlich könnte ich statt GUICtrlRead($cCombo) auf das funktionsintern gelesene $sText zugreifen. Hatte das aber mal testweise geändert, um es als Fehlerquelle auszuschließen.

    Wenn man das also mit $sText ersetzt sieht es so aus:

    AutoIt
    If MapExists($mUnit, $sText) And $mUnit[$sText]['access'] = 0 Then $clrForeground = 0x0000FF

    Und das funktioniert bei mir einwandfrei. Es sind Einträge in der Liste Rot und wenn man die auswählt ist auch die Farbe in dem ComboFeld richtig.

    Wenn ich mir $sText ausgeben lasse ist es halt manchmal ein leerer String und in so einem Fall existiert $mUnit[$sText] nunmal nicht und wenn man dann damit auf etwas zugreifen will schlägt das mit der Fehlermeldung fehl.
    Ich hab mir mit _ToStringC($mUnit) (_toString für alle (AutoIt-) Objekte (und mehr) sowie eine Methode zum Errorhandling) das ganze auch ausgeben lassen und die Map war immer komplett definiert.

    Win10, AutoIt 3.3.16.1

  • GUIRegisterMsg($WM_DRAWITEM, ...) Problem mit Map

    • Kanashius
    • 2. März 2025 um 19:50

    Beim auslesen der Combobox kommt bei mir am Anfang ein leerer String (wenn noch nicht ausgewählt wurde). Dabei crasht es dann.

    Wenn ich das Prüfe crasht es nicht mehr:

    AutoIt
    Local $sComboContent = GUICtrlRead($cCombo)
    If MapExists($mUnit, $sComboContent) And $mUnit[$sComboContent].access = 0 Then $clrForeground = 0x0000FF
  • FileExplorer List and TreeView

    • Kanashius
    • 2. März 2025 um 19:41

    Es gibt ein komplettes Rework dieser UDF. Ich würde empfehlen, diese zu nutzen: TreeListExplorer

    Diese Version hat einige Bugs, its langsamer beim Laden der Ordner/Dateien und benötigt zusätzliche UDFs (AutoIt-Object), die die neue Version nicht mehr benötigt.

    PS: Ich kann den original Post leider nicht bearbeiten.

  • TreeListExplorer UDF um eine TreeView/ListView zum navigieren von Ordnern/Dateien zu nutzen

    • Kanashius
    • 2. März 2025 um 19:38

    Die TreeListExplorer UDF kann genutzt werden um eine TreeView/ListView zum navigieren von Ordnern/Dateien zu nutzen.

    Sie erlaubt es, ein TLE System zu erstellen, welches beliebig viele TreeViews und ListViews synchronisiert. Bei dem System kann auch ein Root Ordner gesetzt werden. Jede View kann dabei Ordner und/oder Dateien anzeigen.

    Die folgenen Funktionen sind verfügbar:

    Code
    ; #CURRENT# =====================================================================================================================
    ; __TreeListExplorer_StartUp
    ; __TreeListExplorer_FreeIconCache
    ; __TreeListExplorer_Shutdown
    ; __TreeListExplorer_CreateSystem
    ; __TreeListExplorer_DeleteSystem
    ; __TreeListExplorer_AddView
    ; __TreeListExplorer_RemoveView
    ; __TreeListExplorer_OpenPath
    ; __TreeListExplorer_Reload
    ; __TreeListExplorer_GetPath
    ; __TreeListExplorer_GetRoot
    ; __TreeListExplorer_GetSelected
    ; __TreeListExplorer_SetRoot
    ; ===============================================================================================================================
    Alles anzeigen

    Wenn ein System erstellt wird, kann eine callback Funktion übergeben werden, die aufgerufen wird, wenn der Root Ordner oder der aktuelle Ordner sich wechselt.
    Wenn eine View zu einem System hinzugefügt wird, können Callbacks für den Klick/Doppelklick auf ein Item hinzugefügt werden. Es gibt auch einen Callback zum behandeln des Anfangs/Ende eines Ladevorgangs (Befüllen einer Tree-/ListView).

    Beispiel Oberfläche:

    Spoiler anzeigen

    Der Code für das Beispiel:

    AutoIt
    ; #AutoIt3Wrapper_UseX64=Y
    #include "TreeListExplorer.au3"
    #include <GuiTreeView.au3>
    
    Global $iWidth = 1600, $iHeight = 1000, $iSpace = 5
    
    ; StartUp of the TreeListExplorer UDF (required)
    __TreeListExplorer_StartUp()
    If @error Then ConsoleWrite("__TreeListExplorer_StartUp failed: "&@error&":"&@extended&@crlf)
    
    ; create gui
    Local $hGui = GUICreate("TreeListExplorer Example", $iWidth, $iHeight)
    Local $iTopLine = 100
    Local $iCtrlHeight = ($iHeight - $iTopLine)/2 - $iSpace*3, $iCtrlWidth = $iWidth/2 - $iSpace*3
    ; create left gui
    Local $iTop = $iSpace*2+$iTopLine, $iLeft = $iSpace
    Local $idInputPathRight = GUICtrlCreateInput("", $iLeft, $iTop-$iSpace-20, $iCtrlWidth, 20)
    ; _GUICtrlEdit_SetReadOnly($idInputPathRight, True) ; If the Input should be readonly
    Local $idTreeViewLeft = GUICtrlCreateTreeView($iLeft, $iTop, $iCtrlWidth, $iCtrlHeight)
    $iTop+=$iCtrlHeight+$iSpace
    Local $idListViewLeft = GUICtrlCreateListView("", $iLeft, $iTop, $iCtrlWidth, $iCtrlHeight)
    ; create right gui
    Local $iLeft = $iSpace*2 + $iCtrlWidth
    Local $iTop = $iSpace
    GUICtrlCreateLabel("Current Folder:", $iLeft, $iTop, 75, 20)
    Local $idLabelCurrentFolderRight = GUICtrlCreateLabel("", $iLeft+75, $iTop, $iCtrlWidth-75, 20)
    GUICtrlCreateLabel("Selected Folder:", $iLeft, $iTop+20+$iSpace, 80, 20)
    Local $idLabelSelectRight = GUICtrlCreateLabel("", $iLeft+80, $iTop+20+$iSpace, $iCtrlWidth-80, 20)
    Local $idProgressRight = GUICtrlCreateProgress($iLeft, $iTop+40+$iSpace*2, $iCtrlWidth, 20)
    Local $iTop = $iSpace*2+$iTopLine
    Local $idTreeViewRight = GUICtrlCreateTreeView($iLeft, $iTop, $iCtrlWidth, $iCtrlHeight)
    $iTop+=$iCtrlHeight+$iSpace
    Global $idListViewRight = GUICtrlCreateListView("", $iLeft, $iTop, $iCtrlWidth, $iCtrlHeight, $LVS_SHOWSELALWAYS)
    
    ; Create TLE system for the left side
    Local $hTLESystemLeft = __TreeListExplorer_CreateSystem($hGui);, "", Default, Default, 0)
    If @error Then ConsoleWrite("__TreeListExplorer_CreateSystem left failed: "&@error&":"&@extended&@crlf)
    ; Add Views to TLE system
    __TreeListExplorer_AddView($hTLESystemLeft, $idInputPathRight)
    If @error Then ConsoleWrite("__TreeListExplorer_AddView $idInputPathRight failed: "&@error&":"&@extended&@crlf)
    __TreeListExplorer_AddView($hTLESystemLeft, $idTreeViewLeft)
    If @error Then ConsoleWrite("__TreeListExplorer_AddView $idTreeViewLeft failed: "&@error&":"&@extended&@crlf)
    __TreeListExplorer_AddView($hTLESystemLeft, $idListViewLeft)
    If @error Then ConsoleWrite("__TreeListExplorer_AddView $idListViewLeft failed: "&@error&":"&@extended&@crlf)
    
    ; Create TLE system for the right side
    Local $hTLESystemRight = __TreeListExplorer_CreateSystem($hGui, "", "_currentFolderRight", "_selectCallback")
    If @error Then ConsoleWrite("__TreeListExplorer_CreateSystem right failed: "&@error&":"&@extended&@crlf)
    ; Add Views to TLE system: ShowFolders=True, ShowFiles=True
    __TreeListExplorer_AddView($hTLESystemRight, $idTreeViewRight, True, True, "_clickCallback", "_doubleClickCallback", "_loadingCallback")
    If @error Then ConsoleWrite("__TreeListExplorer_AddView $idTreeViewRight failed 2: "&@error&":"&@extended&@crlf)
    __TreeListExplorer_AddView($hTLESystemRight, $idListViewRight, True, True, "_clickCallback", "_doubleClickCallback", "_loadingCallback", "_filterCallback", False)
    If @error Then ConsoleWrite("__TreeListExplorer_AddView $idListViewRight failed: "&@error&":"&@extended&@crlf)
    
    ; Set the root directory for the right side to the users directory
    __TreeListExplorer_SetRoot($hTLESystemRight, "C:\Users")
    If @error Then ConsoleWrite("__TreeListExplorer_SetRoot failed: "&@error&":"&@extended&@crlf)
    ; Open the User profile on the right side
    __TreeListExplorer_OpenPath($hTLESystemRight, @DesktopDir)
    ;__TreeListExplorer_OpenPath($hTLESystemRight, @UserProfileDir)
    If @error Then ConsoleWrite("__TreeListExplorer_OpenPath failed: "&@error&":"&@extended&@crlf)
    
    Local $idButtonTest = GUICtrlCreateButton("Test", $iSpace, $iSpace)
    
    GUISetState(@SW_SHOW)
    
    ConsoleWrite("Left root: "&__TreeListExplorer_GetRoot($hTLESystemLeft)&" Left folder: "&__TreeListExplorer_GetPath($hTLESystemLeft)&@crlf)
    ConsoleWrite("Right root: "&__TreeListExplorer_GetRoot($hTLESystemRight)&" Right folder: "&__TreeListExplorer_GetPath($hTLESystemRight)&@crlf)
    
    ; Removes the TLE system and clears the Tree/Listview
    ; __TreeListExplorer_DeleteSystem($hTLESystemLeft)
    ; __TreeListExplorer_RemoveView($idTreeViewRight)
    
    while True
    	Local $iMsg = GUIGetMsg()
    	If $iMsg=-3 Then
    		__TreeListExplorer_Shutdown()
    		Exit
    	EndIf
    	If $iMsg=$idButtonTest Then
    		__TreeListExplorer_Reload($hTLESystemRight, True) ; reload all folders in the right system
    		__TreeListExplorer_Reload($hTLESystemLeft, True) ; reload folder in the right system
    	EndIf
    WEnd
    
    Func _currentFolderRight($hSystem, $sRoot, $sFolder, $sSelected)
    	GUICtrlSetData($idLabelCurrentFolderRight, $sRoot&$sFolder&"["&$sSelected&"]")
    	; ConsoleWrite("Folder "&$hSystem&": "&$sRoot&$sFolder&"["&$sSelected&"]"&@CRLF)
    EndFunc
    
    Func _selectCallback($hSystem, $sRoot, $sFolder, $sSelected)
    	GUICtrlSetData($idLabelSelectRight, $sRoot&$sFolder&"["&$sSelected&"]")
    	__TreeListExplorer__FileGetIconIndex($sRoot&$sFolder&$sSelected)
    	; ConsoleWrite("Select "&$hSystem&": "&$sRoot&$sFolder&"["&$sSelected&"]"&@CRLF)
    EndFunc
    
    Func _clickCallback($hSystem, $hView, $sRoot, $sFolder, $sSelected, $item)
    	ConsoleWrite("Click at "&$hView&": "&$sRoot&$sFolder&"["&$sSelected&"] :"&$item&@CRLF)
    	If $hView=GUICtrlGetHandle($idListViewRight) Then
    		Local $sSel = _GUICtrlListView_GetSelectedIndices($hView)
    		If StringInStr($sSel, "|") Then ConsoleWrite("Multiple selected items: "&$sSel&@CRLF)
    	EndIf
    EndFunc
    
    Func _doubleClickCallback($hSystem, $hView, $sRoot, $sFolder, $sSelected, $item)
    	ConsoleWrite("Double click at "&$hView&": "&$sRoot&$sFolder&"["&$sSelected&"] :"&$item&@CRLF)
    EndFunc
    
    Func _filterCallback($hSystem, $hView, $bIsFolder, $sPath, $sName, $sExt)
    	; ConsoleWrite("Filter: "&$hSystem&" > "&$hView&" -- Folder: "&$bIsFolder&" Path: "&$sPath&" Filename: "&$sName&" Ext: "&$sExt&@crlf)
    	Return $bIsFolder Or $sExt=".au3"
    EndFunc
    
    Func _loadingCallback($hSystem, $hView, $sRoot, $sFolder, $sSelected, $sPath, $bLoading)
    	; ConsoleWrite("Loading "&$hSystem&": Status: "&$bLoading&" View: "&$hView&" >> "&$sRoot&$sFolder&"["&$sSelected&"] >> "&$sPath&@CRLF)
    	If $bLoading Then
    		Switch $hView
    			Case GUICtrlGetHandle($idTreeViewLeft)
    				ToolTip("Load TreeView: "&$sPath)
    				;ConsoleWrite("Load: "&$hView&" >> "&$sPath&@crlf)
    			Case GUICtrlGetHandle($idListViewLeft)
    				ToolTip("Load ListView: "&$sPath)
    				;ConsoleWrite("Load: "&$hView&" >> "&$sPath&@crlf)
    			Case GUICtrlGetHandle($idListViewRight), GUICtrlGetHandle($idTreeViewRight)
    				GUICtrlSetData($idProgressRight, 50)
    		EndSwitch
    	Else
    		Switch $hView
    			Case GUICtrlGetHandle($idListViewRight), GUICtrlGetHandle($idTreeViewRight)
    				GUICtrlSetData($idProgressRight, 0)
    		EndSwitch
    		ToolTip("")
    		;ConsoleWrite("Done: "&$hView&" >> "&$sPath&@crlf)
    	EndIf
    EndFunc
    Alles anzeigen


    Code
    Changelog:
    Version 2.0.0 (New Version after rework)
    Version 2.1.0
    - Rename $sCallbackOnSelect to $sCallbackOnClick
    - Add an additional callback $sCallbackOnSelectionChange, that is called whenever the Tree-/ListView item selection changes
    Version 2.2.0
    - Improve loading speed for TreeView folders when expanding
    Version 2.3.0
    - Fix some bugs where folders did not correctly expand/collapse when clicking them (when the root folder is not "" => shows all drives)
    - Fix some documentation
    - Add a method for reloading (__TreeListExplorer_Reload) the current folder (ListView/TreeView) or all folders (TreeView)
    - Remove the reload parameter from the __TreeListExplorer_OpenPath method (Replaced with __TreeListExplorer_Reload).
    - Other small internal changes
    Version 2.4.0
    - Add the possibility to handle file/folder selections better
    - Files/Folders keep selected when reloading
    - The currently selected File/Folder can be checked with __TreeListExplorer_GetSelected
    - File selection is synchronized between all Tree-/Listviews, Folder selection only between ListViews (TreeView folder selection changes the current folder and expands it)
    - fixed minor issues
    Version 2.5.0
    - Disabled TreeList expand with a single click and changed it to a double click
    - Selection is now synchronized for all files/folders between all views (Tree-/ListView)
    - The Selection callback is now moved from __TreeListExplorer_AddView to __TreeListExplorer_CreateSystem and only fires ones per change for the system and not for every view (as it was before)
    - All callbacks were changed to pass the selected folder and some additional information is now provided (clicked index/item, the loading path,...)
    - Small performance improvements
    - Some internal restructuring
    Version 2.5.1
    - Fixed: selection not working for drives
    Version 2.6.0
    - Added support for icons of all file extensions for TreeViews and ListViews.
    Version 2.7.0
    - Input controls are now possible as a view. They show the current folder and when pressing {ENTER} inside, the system tries to open the path show in the input.
    - Changed the behavior of the treeview when clicking items. They now change the current folder, but are not expanded. This changes the folder in the ListView, when clicking a folder in the TreeView.
    Version 2.7.1
    - Clicking on the Bitmap of a TreeView item is now registered as a click (not just the text like before)
    - Fixed a missing selection update when clicking on a TreeView item
    Version 2.8.0
    - TreeView selection is now triggering the select event and the $sSelect corresponds to the selected folder/file. NOTE: __TreeViewExplorer_GetSelected will be empty, if the selection is a folder in a treeview
    - Selection handling was improved, especially the synchronization between TreeView and ListView
    - Add keyboard navigation to the listview
    - Fixed a bug, where the icon index was sent as event (GuIGetMsg), when an item was clicked (happens without the udf message handling, so it needed a workaround: suppress the default autoit handler for mouseclicks)
    Version 2.9.0
    - Fixed bug for TreeViews, where folders were shown as expandable, when having only files but no folders, even if showing files was turned of
    - rework how treeviews are filled/updated/expanded (folders that are expanded will stay expanded on reload)
    - add the possibility to set a depth limit for the treeview (Example: Drive selection with $sRoot="" and $iMaxDepth=0)
    - Fixed bug for Arrow selection in the ListView to not trigger a click event anymore
    - When the open folder or the selection changed, the TreeView checks, if it still exists (=> treeview updates, if a folder was deleted)
    Version 2.9.1
    - Workaround for a Bug in the GuiTreeView UDF (until it is fixed), causing random control deletions instead of TreeView item deletions
    Version 2.9.2
    - Improved fileicon support. Should support pretty much any file.
    Version 2.9.3
    - Fixed custom icon size when extracting icons
    Version 2.9.4
    - Improved display quality for some icons (Thanks WildByDesign for the work on that)
    - Fixed an issue, where cached file icons for individual files were shown as a folder
    Version 2.9.5
    - Improved display quality for some icons (When resource files are defined in the registry, the one with the size greater or equal to the required icon size will be choosen)
    Version 2.10.0
    - Added the possibility to filter ListViews/TreeViews with a callback function. This callbackfunction is called for every file/folder and only if it returns True, will they be added to the view.
    - Added the possibility to set $bNavigate for ListViews when adding them. This enables or disables the possibility to navigate through folders with doubleclicks in a ListView (and add/removes the ".." folder at the top, which enables the user to navigate to the parent folder)
    Version 2.10.1
    - Added the WinAPIConstants.au3 include to fix missing constants due to changes with the new AutoIt-Version (v3.3.18.0)
    Version 2.10.2
    - Fixed a bug using _GUICtrlListView_AddItem ($iParam)
    Version 2.10.3
    - Fixed missed _GUICtrlListView_AddItem call in v2.10.2
    Version 2.11.0
    - Allow multiselect with CTRL+Click, SHIFT+Click and CTRL+A
    - Allow the removal of the ".." go to parent folder listviewitem without disabling navigation
    - Fix a bug, where the doubleclick on a folder does not open it, when that requires another view to be changed first (which surpresses the $NM_DBLCLICK event in _winProc)
    - Enable the usage of custom columns. The first column must be the file/folder/drive name, all others can be adjusted (and filled with a callback function)
    - Smaller fixes
    Version 2.11.1
    - Fix $arDoubleClickTime not being a local variable
    Alles anzeigen


    Ich hoffe euch gefällt die UDF und meldet euch gerne bei Verbesserungsvorschlägen/Bugs.

    Ihr könnt die TreeListExplorer UDF auch auf Github finden.


    PS:
    Diese UDF ist ein rework (bzw. komplettes neuschreiben) einer alten UDF von mir (FileExplorere List and TiewView), ich kann den Post aber nicht mehr bearbeiten, ist vmtl. zu alt :D

    Dateien

    TreeListExplorer-Example.au3 7,62 kB – 202 Downloads TreeListExplorer.au3 118,54 kB – 207 Downloads
  • Ordnernamen in Variable schicken

    • Kanashius
    • 20. Februar 2025 um 17:01
    Zitat von Peter S. Taler

    Ja, nur das deine erstbeste Lösung keine Steinzeitlösung ist. Ich habe auch an stringright gedacht als ich die Frage des TE-Erstellers sah. Und ja die Antwort von Moobas ist schwer verständlich, als ich sie gelesen habe, dachte ich zuerst, der spricht chinesisch. Nach Ausprobieren, und anständig Drüberschauen, war mir klar was Moobas vorgeschlagen hatte. Es funktioniert reibungslos.

    Und genau darum geht es... Das die Lösung funktioniert hat niemand abgestritten. Ich hab wegen Schnuffels Verwirrung geantwortet und dabei eine Übersichtlichere Lösung angeboten, die zusätzlich noch performanter ist... Außer dir hat das niemand kritisiert.

    Zitat von Peter S. Taler

    Klar je länger man über etwas spricht, desto mehr Lösungen tauchen auf, nur eine Lösung zu "diskreditieren" weil sie, unbewiesen, angeblich etwas langsamer ist --> macht das Sinn?

    Je mehr Lösungen, desto besser ist das meiner Meinung nach für den Thread ersteller. Und auch andere, die nach dem Problem suchen, können sich das dann anschauen und sehen, was für Möglichkeiten es gibt => können noch Ansätze,... lernen. Das ist doch gerade für Anfänger interessant. Warum also bei der ersten Lösung aufhören, wenn man lust hat weiter darüber nachzudenken.
    Und ich denke nicht, dass ich hier die erste Lösung "diskreditieren". Ich hab sie mir angeschaut, war auch ne Sekunde verwirrt, bis ichs mir angeschaut habe um es zu verstehen... Wenn man als Softwareentwickler schon ne Sekunde braucht (mit Hintergrundwissen, was in dem ersten Array-Index steht,...) wie soll das dann ein Anfänger verstehen? Also ist es doch nur sinnvoll, eine weitere Lösung anzubieten.
    Dabei gehe ich natürlich auch auf die jeweiligen Vor-/Nachteile ein, so wie ich sie als Softwareentwickler einschätze. Das ist kein "diskreditieren" und auch nicht "unbewiesen/angeblich", sondern basiert auf der eigenen Erfahrung, was im Hintergrund abläuft und wie lange das ggf. dauert. Da ich es nicht gemessen und damit bewiesen habe, habe ich extra ein "vermutlich" dazugeschrieben.

    Und weil ichs jetzt genau wissen wollte habe ich jetzt ein Programm zum nachmessen geschrieben:

    AutoIt
    #include <Array.au3>
    Local $arFuncs = ["_FolderWithStringSplitShort", "_FolderWithStringSplit", "_FolderWithStringSplitDataOnly", "_FolderWithStringRight", "_FolderWithStringTrimLeft", "_FolderWithRegExp", "_FolderWithRegExpExt", "_FolderWithRegExpExtSecond"]
    Local $sTestPath = "C:\Users\User\Desktop\SomeFolder\Folder"
    Local $iCalls = 1000000
    
    Local $iMaxLength = 0
    For $i=0 To UBound($arFuncs)-1 Step 1
    	If $iMaxLength<StringLen($arFuncs[$i]) Then
    		$iMaxLength = StringLen($arFuncs[$i])
    	EndIf
    Next
    
    Local $arResult[UBound($arFuncs)][2]
    For $i=0 To UBound($arFuncs)-1 Step 1
    	Local $iInit = TimerInit()
    	For $j=0 To $iCalls Step 1
    		Call($arFuncs[$i], $sTestPath)
    	Next
    	Local $iDiff = TimerDiff($iInit)
    	$arResult[$i][0] = $arFuncs[$i]
    	$arResult[$i][1] = $iDiff
    Next
    
    _ArraySort($arResult, 0, 0, 0, 1)
    
    Local $sFormat = "%"&$iMaxLength&"s: % 10.2f ms >> 1 Call: % 10f ms"
    For $i=0 To UBound($arResult)-1 Step 1
    	ConsoleWrite(StringFormat($sFormat, $arResult[$i][0], $arResult[$i][1], $arResult[$i][1]/$iCalls)&@crlf)
    Next
    
    
    Func _FolderWithStringSplitShort($sPath)
    	Return Stringsplit($sPath, '\')[Stringsplit($sPath, '\')[0]]
    EndFunc
    
    Func _FolderWithStringSplit($sPath)
    	Local $arPath = Stringsplit($sPath, '\')
    	Return $arPath[$arPath[0]]
    EndFunc
    
    Func _FolderWithStringSplitDataOnly($sPath)
    	Local $arPath = Stringsplit($sPath, '\', BitOR(1,2))
    	return $arPath[UBound($arPath)-1]
    EndFunc
    
    Func _FolderWithStringRight($sPath)
    	Return StringRight($sPath, StringLen($sPath)-StringInStr($sPath, "\", 0, -1))
    EndFunc
    
    Func _FolderWithStringTrimLeft($sPath)
    	Return StringTrimLeft($sPath, StringInStr($sPath, "\", 1, -1))
    EndFunc
    
    Func _FolderWithRegExp($sPath)
    	Return StringRegExp($sPath, '.*\\(.*)', 2)[1]
    EndFunc
    
    Func _FolderWithRegExpExt($sPath)
    	Local $sFolder = StringRegExp($sPath, '([[:alpha:]]:.*\\|\\{2}.*\\)(.*)\b', 1)
    	If $sFolder = 0 Then Return SetError(1,0,"")
    	Return $sFolder[1]
    EndFunc
    
    Func _FolderWithRegExpExtSecond($sPath)
    	If StringLen($sPath) <= 3 Then
    		Return StringLeft($sPath, 1) & ':\'
    	Else
    		$sFolder = StringRegExp($sPath, '([[:alpha:]]:.*\\|\\{2}.*\\)(.*)\b', 1)
    		If $sFolder = 0 Then Return SetError(1,0,"")
    		Return $sFolder[1]
    	Endif
    EndFunc
    Alles anzeigen

    Ergebnis:

    Code
         _FolderWithStringTrimLeft:    7475.89 ms >> 1 Call:   0.007476 ms
            _FolderWithStringRight:    8337.42 ms >> 1 Call:   0.008337 ms
                 _FolderWithRegExp:    8436.82 ms >> 1 Call:   0.008437 ms
              _FolderWithRegExpExt:    9146.73 ms >> 1 Call:   0.009147 ms
            _FolderWithStringSplit:    9954.14 ms >> 1 Call:   0.009954 ms
        _FolderWithRegExpExtSecond:    9990.07 ms >> 1 Call:   0.009990 ms
    _FolderWithStringSplitDataOnly:   10245.97 ms >> 1 Call:   0.010246 ms
       _FolderWithStringSplitShort:   12759.48 ms >> 1 Call:   0.012759 ms

    Wie erwartet:
    - Die Mehrfachaufrufe von StringSplit sind langsamer.
    - Interessanterweise ist die Methode "StringSplitDataOnly" langsamer als das normale "StringSplit", das extra Ubound scheint also durchaus einen unterschied zu machen. Performanter ist es also, mit dem ersten Index im Array zu arbeiten. (Hatte ich auch vermuted, deshalb wird es in C auch gemacht, ich finde es trotzdem vom Programmierstandpunkt schlechter, weil es in AutoIt inkonsistent ist. Manche Funktionen machen es, manche nicht, deshalb hatte ich es schon öfter, dass mir das auf die Füße gefallen ist. Deshalb stört es mich auch.)
    - Die extra checks auf die Länge des Strings sorgen bei der letzten Regexp Lösung dafür, dass diese auch etwas langsamer ist.
    - Ansonsten ist RegExp schneller als StringSplit, vmtl. weil es weniger im Speicher arbeitet um die ganzen Pfadteile abzuspeichern.
    - Die String Methoden sind am schnellsten, weil sie den String nur einmal durchlaufen um das \ zu suchen und dann einmal durchgehen und abtrennen. Dabei ist StringTrimLeft schneller, weil es einmal weniger über den String iteriert, als StringRight mit, wo die Länge nochmal extra aufgerufen wird.

    Ist das für den Threadersteller relevant? Nein.
    Kann es für andere interessant sein, wo es ggf. einen Unterschied macht? Auch ja. Es kann ja jemand auf diesen Thread stoßen, der eine Excel-Datei mit millionen Einträgen durchgehen und verarbeiten will. Da kann es durchaus relevant sein.


    Generell ist es sinnvoll, sich zumindest hin und wieder damit auseinander zu setzen, was denn Performanter ist und warum. Es wird bei anderen Fällen einen großen Unterschied machen.
    Um zu wissen warum muss man sich nur mal die aktuelle Softwarewelt anschauen. Die Hardware wird immer Leistungsfähiger, die Programme laufen oft aber immernoch super langsam. Warum? Weil genau auf solche Dinge nicht geachtet wird... es ist ja schnell genug/genug Speicher da.
    Ich will nicht wissen, wie viel aufgrund von nicht optimierter Software an Resourcen verbraten wird, oft auch nur, weil es (am Anfang) schneller/günstiger ist und sich das dann niemand wieder anschaut.

    Es kommt immer aufs gleichgewicht zwischen Komplexität/Aufwand und der Performance an. Sollte man schnelle/kleine Dinge machen, die die Performance steigern: Klar. Sollte man riesen Aufwand betreiben um die letzte millisekunde herauszukitzeln? Nur wenn es wichtig ist.
    Hier ist aber keine Lösung enorm Komplex/Aufwändig. Warum also nicht auch ein wenig auf die Performance schauen, man lernt etwas und es schadet niemandem.

  • Ordnernamen in Variable schicken

    • Kanashius
    • 18. Februar 2025 um 18:41

    Schnuffel Es ist nur Zweimal der gleiche Befehl (StringSplit). Beim ersten StringSplit wird auf den Index zugegriffen, der bei dem zweiten StringSplit im ersten Feld steht.
    Bei StringSplit wird (, meiner Meinung nach nervigerweise, ) die Anzahl der Elemente im Array in den ersten Index geschrieben, was hier genutzt wird.

    Ich würde sagen: Es tut was es soll, sorgt aber für schlechtere Performance, nur um alles in eine Zeile zu bekommen. Der String wird 2x in alle Teile zerlegt, nur um beim 2ten mal die Anzahl der Teile zu nehmen und den Rest wegzuwerfen...

    AutoIt
    Local $sPath = "C:\Some\Cool\Folder"
    
    Local $sFolder = Stringsplit($sPath, '\')[Stringsplit($sPath, '\')[0]]
    ConsoleWrite("1: "&$sFolder&@crlf)
    
    ; ist das gleiche wie
    Local $arPath = Stringsplit($sPath, '\')
    Local $sFolder = $arPath[$arPath[0]]
    ConsoleWrite("2: "&$sFolder&@crlf)
    
    ; oder besser (Ich mag es nicht, dass am ersten Arrayindex die Anzahl der Ergebnisse sind... Daten zur Verarbeitung und Programmierinfos sollten getrennt sein)
    Local $arPath = Stringsplit($sPath, '\', BitOR(1,2))
    Local $sFolder = $arPath[UBound($arPath)-1]
    ConsoleWrite("3: "&$sFolder&@crlf)
    
    ; Andere Möglichkeit, ohne extra Arrays zu erzeugen (vmtl. Performanter):
    Local $sParent = StringLeft($sPath, StringInStr($sPath, "\", 0, -1))
    Local $sFolder = StringRight($sPath, StringLen($sPath)-StringInStr($sPath, "\", 0, -1))
    ConsoleWrite("4: "&$sFolder&@crlf)
    ConsoleWrite("4 path: "&$sParent&@crlf)
    Alles anzeigen
  • Passwort anzeigen

    • Kanashius
    • 2. Februar 2025 um 17:02

    Ich hab mich mal daran versucht:

    Ich hab es hinbekommen den Style zu ändern, es hat aber nichts geändert. Deshalb geh ich mal davon aus, dass dieser Satz aus der Hilfe zu GuiCtrlSetStyle für $ES_PASSWORD gilt:
    "Some styles cannot be changed dynamically, check MSDN documentation. $CBS_UPPERCASE combo style is one example."

    Von daher bleibt vermutlich nur der Workaround, zwei Controls zu erstellen und miteinander auszutauschen:

    AutoIt
    #include <WinAPI.au3>
    #include <EditConstants.au3>
    #include <GUIConstantsEx.au3>
    
    Global $iWidth = 800, $iHeight = 600, $iSpace = 10
    Local $hGui = GUICreate("Test", $iWidth, $iHeight)
    Local $iInputWidth = $iWidth-$iSpace*3-100
    Local $hInputPW = GUICtrlCreateInput("", $iSpace, $iSpace,$iInputWidth, 25, $ES_PASSWORD)
    Local $hInputPWShow = GUICtrlCreateInput("", $iSpace, $iSpace,$iInputWidth, 25)
    GUICtrlSetState($hInputPWShow, $GUI_HIDE)
    Local $hButton = GUICtrlCreateButton("SHOW", $iSpace*2+($iInputWidth), $iSpace, 100, 25)
    GUISetState(@SW_SHOW, $hGui)
    
    While True
    	Local $iMsg = GUIGetMsg()
    	If $iMsg=-3 Then Exit
    	If $iMsg=$hButton Then _switchInput($hInputPW, $hInputPWShow)
    WEnd
    
    Func _switchInput($hInput, $hInputShow)
    	If BitAND(GUICtrlGetState($hInput), $GUI_SHOW) Then
    		GUICtrlSetData($hInputShow, GUICtrlRead($hInput))
    		GUICtrlSetState($hInput, $GUI_HIDE)
    		GUICtrlSetState($hInputShow, $GUI_SHOW)
    	Else
    		GUICtrlSetData($hInput, GUICtrlRead($hInputShow))
    		GUICtrlSetState($hInputShow, $GUI_HIDE)
    		GUICtrlSetState($hInput, $GUI_SHOW)
    	EndIf
    EndFunc
    
    #cs
    Func _switchInput($hInput)
    	Local $iStyle = GUICtrlGetStyle($hInput)[0]
    	ConsoleWrite("Res: "&$ES_PASSWORD&" >> "&BitAND($iStyle, $ES_PASSWORD)&@crlf)
    	If BitAND($iStyle, $ES_PASSWORD) Then
    		ConsoleWrite("ON: "&BitXOR($iStyle, $ES_PASSWORD)&@crlf)
    		GUICtrlSetStyle($hInput, BitXOR($iStyle, $ES_PASSWORD))
    	Else
    		ConsoleWrite("OFF: "&BitOr($iStyle, $ES_PASSWORD)&@crlf)
    		GUICtrlSetStyle($hInput, BitOr($iStyle, $ES_PASSWORD))
    	EndIf
    EndFunc
    
    ; #FUNCTION# ====================================================================================================================
    ; Name ..........: GUICtrlGetStyle
    ; Description ...: Retrieves the Styles/ExStyles value(s) of a control.
    ; Syntax ........: GUICtrlGetStyle($hWnd)
    ; Parameters ....: $hWnd                - Control ID/Handle to the control
    ; Return values .: $aArray[2] = [Style, ExStyle]
    ; Author ........: guinness
    ; Example .......: Yes
    ; ===============================================================================================================================
    Func GUICtrlGetStyle($hWnd)
        If Not IsHWnd($hWnd) Then
            $hWnd = GUICtrlGetHandle($hWnd)
        EndIf
        Local $aReturn = [_WinAPI_GetWindowLong($hWnd, $GWL_STYLE), _WinAPI_GetWindowLong($hWnd, $GWL_EXSTYLE)]
        Return $aReturn
    EndFunc   ;==>GUICtrlGetStyle
    #ce
    Alles anzeigen

    Ich hab meine Versuch, den Style dynamisch zu wechseln mal drin gelassen. Vielleicht kann den mal jemand bei anderen Styles gebrauchen.

    Ich hoffe das hilft dir weiter :)

  • Datumsformat ändern

    • Kanashius
    • 1. Februar 2025 um 23:47

    Hi :)

    Ich muss zugeben, ich finde das Format sehr seltsam. Sowohl das verwenden der DOS-Time (Schaut ziemlich veraltet aus (jeder bit zählt ;) )... Wer nutzt das heute noch???) als auch des Ziel-Formates... Keine Ahnung, wer damit etwas anfangen kann/will :D

    Hier aber trotzdem eine Implementierung:

    AutoIt
    #include <Date.au3>
    Global $iDateFormatOne = 1, $iDateFormatTwo = 2, $iDateFormatThree = 3, $iDateFormatFour = 4, $iDateFormatFive = 5
    
    ConsoleWrite(">> "&_dateTimeConvert(0x3621, 0x944a)&@crlf)
    ConsoleWrite(">> "&_dateTimeConvert(0x3621, 0x944a, $iDateFormatOne)&@crlf)
    ConsoleWrite(">> "&_dateTimeConvert(0x3621, 0x944a, $iDateFormatTwo)&@crlf)
    ConsoleWrite(">> "&_dateTimeConvert(0x3621, 0x944a, $iDateFormatThree)&@crlf)
    ConsoleWrite(">> "&_dateTimeConvert(0x3621, 0x944a, $iDateFormatFour)&@crlf)
    ConsoleWrite(">> "&_dateTimeConvert(0x3621, 0x944a, $iDateFormatFive)&@crlf)
    ConsoleWrite(">> "&_dateTimeConvert(0x3621, 0x944a, $iDateFormatFive, 1)&@crlf)
    
    ConsoleWrite(@crlf)
    
    Local $sDateConverted = _dateTimeConvert(0x3a24, 0x944a, $iDateFormatFive)
    If @error Then ConsoleWrite("Error formatting date: "&@error&":"&@extended)
    ConsoleWrite("Formatted Date: "&$sDateConverted&@crlf)
    
    ; #FUNCTION# =======================================================================================
    ; Name ..........: _dateTimeConvert
    ; Description ...: Converts the given DosDate and DosTime to another format.
    ; Syntax ........: _dateTimeConvert($iDosDate=Default, $iDosTime=Default, $iWantedFormat = $iDateFormatOne, $iTimeZone=Default)
    ; Parameters ....: $iDosDate              - The DosDate (See _Date_Time_DOSDateTimeToArray($iDosDate, $iDosTime)) for details
    ;                  $iDosTime              - The DosTime (See _Date_Time_DOSDateTimeToArray($iDosDate, $iDosTime)) for details
    ;                  $iWantedFormat         - One of $iDateFormatOne (Default), $iDateFormatTwo, $iDateFormatThree, $iDateFormatFour, $iDateFormatFive
    ;                                           $iDateFormatOne = DDMMYYYY
    ;                                           $iDateFormatTwo = YYYYMMDD
    ;                                           $iDateFormatThree = MMDDYYYY
    ;                                           $iDateFormatFour = MMDDYYYY
    ;                                           $iDateFormatFive = DDHHMMZmmmYYd (with Z=TimeZone, mmm=Short name for month e.g. feb and d=day of the year)
    ;                                           TimeZone: A=UTC+1, B=UTC+2,... ,I=UTC+9, K=UTC+10, L=UTC+11, M=UTC+12, N=UTC-12, O=UTC-11,... , Y=UTC-12, Z=UTC-0
    ;                  $iTimeZone             - The TimeZone bias (hour) as an integer, e.g. 0=UTC, 1=UTC+1, 2=UTC+2, -1=UTC-1 (Default: Systems current timezone)
    ; Return values .: The formatted date/time
    ; Errors ........: 1 - Error calling _Date_Time_DOSDateTimeToArray. @extended contains the error code thrown by _QRCode_DrawQRCode.
    ;                  2 - Error formatting: Required parameter $iDosDate and/or $iDosTime was not set (e.g. Default).
    ;                  3 - Parameter $iWantedFormat does not match any possible target format.
    ; Author ........: Kanashius
    ; ==================================================================================================
    Func _dateTimeConvert($iDosDate=Default, $iDosTime=Default, $iWantedFormat = $iDateFormatOne, $iTimeZone=Default)
    	Local Static $arTimeZoneLetters = StringSplit("YXWVUTSRQPONZABCDEFGHIKLM", "", BitOR(1,2))
    	Local Static $arMonth = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"]
    	If $iTimeZone=Default Then $iTimeZone = _Date_Time_GetTimeZoneInformation()[1]/60*-1
    	Local $arDate = _Date_Time_DOSDateTimeToArray($iDosDate, $iDosTime)
    	If @error Then Return SetError(1, @error, -1)
    	Switch $iWantedFormat
    		Case $iDateFormatOne
    			If $iDosDate=Default Then Return SetError(2, 1, -1)
    			Return StringFormat("%02u%02u%04u", $arDate[1], $arDate[0], $arDate[2])
    		Case $iDateFormatTwo
    			If $iDosDate=Default Then Return SetError(2, 2, -1)
    			Return StringFormat("%04u%02u%02u", $arDate[2], $arDate[0], $arDate[1])
    		Case $iDateFormatThree, $iDateFormatFour
    			If $iDosDate=Default Then Return SetError(2, 3, -1)
    			Return StringFormat("%02u%02u%04u", $arDate[0], $arDate[1], $arDate[2])
    		Case $iDateFormatFive
    			If $iDosDate=Default Then Return SetError(2, 4, -1)
    			If $iDosTime=Default Then Return SetError(2, 5, -1)
    			Local $sTimeZoneLetter = $arTimeZoneLetters[12+$iTimeZone]
    			Local $iYDay = 0
    			For $i=1 To $arDate[0]-1 Step 1
    				$iYDay+=_DateDaysInMonth($arDate[2], $i)
    			Next
    			$iYDay+=$arDate[1]
    			Return StringFormat("%02u%02u%02u%s%s%02u%03u", $arDate[1], $arDate[3], $arDate[4], $sTimeZoneLetter, $arMonth[$arDate[0]-1], Mod($arDate[2], 100), $iYDay)
    		Case Else
    			Return SetError(3, 0, -1)
    	EndSwitch
    EndFunc
    Alles anzeigen

    Output:

    Code
    >> 01012007
    >> 01012007
    >> 20070101
    >> 01012007
    >> 01012007
    >> 011834Ajan07001
    >> 011834Ajan07001
    
    Formatted Date: 011834Aapr09091

    Ich hoffe das hilft dir weiter :)

    PS: Falls du die Wahl hast würde ich aktuelle Standardformate nutzen. Z.B. ISO8601: 20250201T234550+0100

  • Worm Fehler in Windows

    • Kanashius
    • 16. Januar 2025 um 18:58

    Das klingt fast so, als ob der Controller im USB-Stick einen Cache o.ä. nutzt und deshalb die Datei dort löscht (wie es ein USB-Stick nunmal kann) und dann erst den Löschbefehl an die SD-Karte weitergibt, die den vermutlich einfach ignoriert.
    Da entsteht also vmtl. der Unterschied zwischen USB-Stick Cache und SD-Karte.
    Wenn du im rechtsklick menü den Explorer aktualisiert könnte es sein, dass es aktualisiert wird, vllt. aber auch nicht. Musst du ausprobieren. Wenn es nicht hilft würde ich auf einen Cache im USB-Stick tippen, was du nicht wirklich ändern kannst.

  • Aufruf des Eventviewers funktioniert nicht mehr

    • Kanashius
    • 15. Januar 2025 um 15:24
    Zitat von hipfzwirgel


    Der Vorschlag von Moombas mit Stringsplit macht ja im Grunde nichts anderes als den String des Indexes in 2 Teile zu zerlegen und diese dann zum gleichen Shellexecutebefehl wie oben zusammenzusetzen...

    Nein, da ist ein großer Unterschied.

    ShellExecute ist eine Funktion, die mehrere Parameter nimmt: 1. Den Dateinamen der auszuführenden Datei, 2. Parameter die übergeben werden sollen, 3. Das Arbeitsverzeichnis (der Ordner, von dem alle relativen Pfade im ausgeführten Programm ausgehen),...
    Wenn du im Code ShellExecute("eventvwr.exe", "/v:""C:\ProgramData\Microsoft\Event Viewer\Views\View_1.xml""") ausführst ist der 1. Parameter: "eventvwr.exe" und der 2. Parameter: "/v:""C:\ProgramData\Microsoft\Event Viewer\Views\View_1.xml"""
    Es wird also die Executable "eventvwr.exe" ausgeführt.
    Wenn du aber Shellexecute($aArray[9]) mit $aArray[9]="eventvwr.exe", "/v:""C:\ProgramData\Microsoft\Event Viewer\Views\View_1.xml""" ausführst, entspricht der 1. Parameter: "eventvwr.exe", "/v:""C:\ProgramData\Microsoft\Event Viewer\Views\View_1.xml"""
    Es wird also versucht, die Executable "eventvwr.exe", "/v:""C:\ProgramData\Microsoft\Event Viewer\Views\View_1.xml""" auszuführen, aber es gibt natürlich keine Datei mit dem Namen, kann es auch garnicht, weil bestimmte Zeichen gar nicht erlaubt wären.

    Nur weil du die Ausgabe als String genauso aussehen lässt, heißt das noch lange nicht, dass der Code auch genauso aussieht und es das Gleiche ist.

    Du musst also irgendwie aus deinem $aArray[9] zwei Variablen bekommen, damit du eine als executable für Parameter 1 nehmen kannst und die andere für Parameter 2.
    Das ist es, was Moombas mit dem StringSplit versucht hat. Wobei das vermutlich nicht funktioniert hat, weil bei "eventvwr.exe" die Anführungszeichen mit geschickt werden.
    Aber dafür könnte man sich ja mal mit _ArrayDisplay(StringSplit($aArray[9], ', ', BitOr(1,2))) (benötigt #include <Array.au3>) anschauen, was in dem StringSplit genau rauskommt und ggf. noch die Anführungszeichen entfernen (StringLeft/StringRight/StringMid).

  • Hilfe benötigt bei der Automatisierung des Dateiumbenennungsskripts in AutoIt

    • Kanashius
    • 24. Dezember 2024 um 01:21

    Auch wenn reguläre Ausdrücke gerade für Anfänger schwerer sind, würde ich sie hier verwenden. Sie sind meiner Meinung nach die beste/einfachste Möglichkeit, sicherzustellen, dass ein Input genauso aussieht, wie man das will und im Zweifel ein Fehler geworfen wird.

    AutoIt
    ; #include <Array.au3>
    
    Local $arData = ["report_2023_final.txt", "log_2023_backup.zip", "log_2023_final_backup.zip", "log_2023_unknown.zip", "log_2023.zip", "log.zip", "log", "final", "other.txt"]
    Local $mData[]
    
    For $i=0 to UBound($arData)-1 Step 1
    	; Array => 0: Full match, 1: type (report/log) (required), 2: year (or empty), 3+: other additions (e.g. final/backup), last: file extension
    	Local $arSplit = StringRegExp($arData[$i], "(?|(report)|(log))(?:_(\d{4}))?(?:_)?((?:(?:_)?[a-zA-Z0-9]+)*)?\.(\S+)", 2)
    	If @error Then
    		ConsoleWrite("Error matching: "&$arData[$i]&@crlf)
    		ContinueLoop
    	EndIf
    	; _ArrayDisplay($arSplit)
    	Local $mEntry[]
    	$mEntry["path"] = $arSplit[0]
    	$mEntry["type"] = $arSplit[1]
    	If $arSplit[2]<>"" Then $mEntry["year"] = $arSplit[2]
    	If $arSplit[3]<>"" Then
    		Local $arAddSplit = StringSplit($arSplit[3], "_", 1+2)
    		For $j=0 to UBound($arAddSplit)-1 Step 1
    			Switch $arAddSplit[$j]
    				Case "final"
    					$mEntry["final"] = True
    				Case "backup"
    					$mEntry["backup"] = True
    				Case Else
    					ConsoleWrite("Error with addition: "&$arAddSplit[$j]&" >> found in "&$arData[$i]&@crlf)
    					ContinueLoop 2
    			EndSwitch
    		Next
    	EndIf
    	$mEntry["ext"] = $arSplit[UBound($arSplit)-1]
    	MapAppend($mData, $mEntry)
    Next
    
    #cs
    ; Output for debugging
    For $sKey in MapKeys($mData)
    	Local $mTmp = $mData[$sKey]
    	ConsoleWrite($sKey&": "&$mTmp.path&@crlf)
    	ConsoleWrite(@TAB&"Type: "&$mTmp.type&@crlf)
    	If MapExists($mTmp, "year") Then ConsoleWrite(@TAB&"Year: "&$mTmp.year&@crlf)
    	If MapExists($mTmp, "final") Then ConsoleWrite(@TAB&"Final: "&$mTmp.final&@crlf)
    	If MapExists($mTmp, "backup") Then ConsoleWrite(@TAB&"Backup: "&$mTmp.backup&@crlf)
    	If MapExists($mTmp, "ext") Then ConsoleWrite(@TAB&"Extension: "&$mTmp.ext&@crlf)
    Next
    #ce
    
    For $sKey in MapKeys($mData)
    	Local $mEntry = $mData[$sKey]
    	Local $sFilenameNew = ""
    	If MapExists($mEntry, "backup") Then $sFilenameNew &= "backup_"
    	$sFilenameNew &= $mEntry.type
    	If MapExists($mEntry, "final") Then $sFilenameNew &= "_final"
    	If MapExists($mEntry, "year") Then $sFilenameNew &= "_"&$mEntry.year
    	$sFilenameNew &= "."&$mEntry.ext
    	ConsoleWrite("Copy: "&$mEntry.path&" >> "&$sFilenameNew&@crlf)
    	; FileMove($mEntry.path, $sFilenameNew, BitOR(0,8))
    	; If @error Then ConsoleWrite("Copy failed: "&$mEntry.path&" >> "&$sFilenameNew&" >> "&@error&":"&@extended&@crlf)
    Next
    Alles anzeigen

    Hier bin ich bei dem Ausdruck (?|(report)|(log))(?:_(\d{4}))?(?:_)?((?:(?:_)?[a-zA-Z0-9]+)*)?\.(\S+) davon ausgegangen, dass am Anfang immer der Typ der Datei steht (report/log/...); (optional) gefolgt von einem Jahr; (optional) gefolgt von Zusätzen, wie backup/final/... (mit _ getrennt) und am Ende der Dateiendung.
    Wenn irgendetwas anderes auftaucht, wird ein Fehler ausgegeben und die Datei ignoriert (nicht kopiert/verschoben/gelöscht/...).

    Gerade bei wichtigen Dateien würde ich aber immer auf einer Kopie arbeiten. Sind es zu viele Dateien um alle zu kopieren würde ich erst mit Teilen davon arbeiten und Testen und sicherstellen, dass alle Möglichkeiten abgedeckt sind.

    Falls du noch Fragen hast, stell sie gerne :)

  • Hilfe bei der Automatisierung: Wie greife ich auf Felder in einer Herstellersoftware zu?

    • Kanashius
    • 23. Dezember 2024 um 17:37

    Ich hab es so verstanden, dass die "Speichern" Funktion in seinem eigenen Programm angestoßen werden soll und nicht die in dem automatisierten Fenster.

    Also wäre "CTRL+ALT+y":

    AutoIt
    HotKeySet("^!y", "_test")
    
    While Sleep(10)
    WEnd
    
    Func _test()
    	msgbox(48,"","Pressed")
    EndFunc

    Vorsicht mit Großbuchstaben: "^!Y" wäre equivalent zu "CTRL+ALT+SHIFT+Y".

  • Wiederholung eines Scripts

    • Kanashius
    • 6. Dezember 2024 um 15:11

    Da alles "Offline" ist, ist es ja bereits auf deinem PC, du musst nur schauen, wo.

    Auf die schnelle konnte ich zum EM Client folgendes finden:
    In "C:\Users\<USERNAME>\AppData\Roaming\eM Client" ist eine SQLite Database Datei, die alle Daten beinhaltet. (Ich hab nicht weiter geschaut, aber die Dateien sind dort als BLOB drin, oder vmtl. als extra Dateien irgendwo in dem gleichen Ordner). Ggf. musst du die Dateinamen aus der SQLite Database bekommen. Aber das gibt dir auch die Möglichkeit die PDFs z.B. nach Kontakt,... zu sortieren.
    (Während des Zugriff auf die SQLite Database sollte EM Client geschlossen sein)

    Alternativ: Menu > Tools > Settings > General > Backup
    Dort müsste ja vermutlich auch alles drin sein (weiß nicht, wie es mit Anhängen,... aussieht). Kannst ja mal in die dabei generierten Daten schauen.

    Das dürfte beides deutlich einfacher/schneller/zuverlässiger funktionieren, als die GUI zu automatisieren.

  • Smart TV Tips erbeten // erledigt

    • Kanashius
    • 26. Oktober 2024 um 23:20

    Naja... basierend auf diesem Artikel von gestern würde ich sagen: Lass den SmartTV garnicht ans Internet und nutze nur HDMI zuspieler...

    Moderne Datenkraken: Smart-TVs tracken sogar HDMI-Inhalte
    Smart-TVs werten sogar dann Bildinhalte aus, wenn ein HDMI-Zuspieler genutzt wird. Die Analysen dienen gezielter Werbung.
    www.heise.de

    Echt ne Frechheit, was mittlerweile alles gemacht/überwacht/ausspioniert wird (oft für Werbung),...

Spenden

Jeder Euro hilft uns, Euch zu helfen.

Download

AutoIt Tutorial
AutoIt Buch
Onlinehilfe
AutoIt Entwickler
  1. Datenschutzerklärung
  2. Impressum
  3. Shoutbox-Archiv
Community-Software: WoltLab Suite™