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. Oscar

Beiträge von Oscar

  • ooMPEG

    • Oscar
    • 18. August 2020 um 16:37

    Es gibt eine neue Version (in Post#1).

    Einige Eigenarten der MP3-Dateien entdeckt man erst, wenn man die Funktionen ausgiebig testet (mit diversen MP3-Varianten).

    Ich programmiere ja gerade einen MP3-Player in Nim und da sind mir einige "Fehler" in dem Modul hier aufgefallen.

  • Gibt es eine "Tag"-Eigenschaft für Controls?

    • Oscar
    • 18. August 2020 um 16:04

    Im Prinzip kann man bei jedem Fenster (die Control-Elemente sind auch Fenster) mit "_WinAPI_SetWindowLong" den Wert von "$GWL_USERDATA" verändern.

    Das Problem bei AutoIt ist bloß, dass dort die Control-ID abgespeichert ist und ich weiß nicht, wie AutoIt reagiert, wenn man dort andere Sachen speichert.

    Aber warum willst Du die zusätzlichen Marker nicht in einem Array (oder Dictionary) speichern?

  • ​Sammlung: Nim Snippets / Procedures

    • Oscar
    • 15. August 2020 um 13:32

    Um zwei Strings nach ihrer Ähnlichkeit zu untersuchen, wird oft die Levenshtein-Distance verwendet.

    Hier im AutoIt-Forum hatten wir eine recht kurze Variante von "Lutz Müller, FH Köln Campus Gummersbach".

    Die habe ich mal nach Nim konvertiert:

    Code
    import sequtils
    
    # Basiert auf der Berechnung der Levenshtein-Distanz
    # von Lutz Müller, FH Köln Campus Gummersbach
    
    # Levenshtein-Distanz berechnen
    proc lsDistance*(s, t: string): int =
      let
        n = s.len
        m = t.len
      if s == t: return 0
      if s == "": return m
      if t == "": return n
      var
        d = newSeqWith(n + 1, newSeq[int](m + 1))
        cost: int
      for i in 0..n: d[i][0] = i
      for i in 0..m: d[0][i] = i
      for i in 1..n:
        for j in 1..m:
          cost = if s[i-1] == t[j-1]: 0 else: 1
          d[i][j] = min([d[i-1][j] + 1, d[i][j-1] + 1, d[i-1][j-1] + cost])
      return d[n][m]
    
    # Levenshtein-Distanz in Prozent berechnen
    proc lsDistancePercent*(s, t: string): int =
      let n = max(s.len, t.len)
      if n == 0 or s == t: return 100
      return int(100 / n * float(n - lsDistance(s, t)))
    
    # Beispiel
    let
      s1 = "Zuckerkuchen"
      s2 = "Butterkuchen"
    
    echo "Levenshtein-Distanz: ", lsDistance(s1, s2)
    echo "Levenshtein-Distanz: ", lsDistancePercent(s1, s2), "%"
    Alles anzeigen
  • Suche einfach erweiterbaren Einstellungen-Dialog (Program Settings)

    • Oscar
    • 12. August 2020 um 13:24
    Zitat von Professor Bernd

    Nun kann ich weiter überlegen, wie ich die visuelle Handhabung mit Koda und die besonderen Ansprüche mit Child-GUIs unter einen Hut bekomme. Ideen sind willkommen!

    Hmm...Du brauchst das also nicht für ein eigenes Projekt, sondern Du willst ein Programm erstellen, um visuell einen Settings-Dialog zu erstellen?

    Nun, ich kann natürlich nur für mich sprechen, aber wer braucht sowas?

    Ich gebe zu Bedenken, dass einer, der ein Programm erstellt, dass seitenweise Einstellungen erfordert und dementsprechend umfangreich ist, wohl nicht unbedingt ein Hilfsprogramm braucht, um die paar Zeilen Code für den Einstellungsdialog zu schreiben.

    Vor allem, weil Du schon eine "eierlegende Wollmilchsau" schreiben müsstest, um sowas individuelles, wie einen Einstellungsdialog, für jedes erdenkliche Programm zu schreiben.

    Ich habe in meiner gesamten AutoIt-Zeit nicht ein einziges Mal Koda zum erstellen einer GUI verwendet und ich denke, dass das bei sehr vielen so ist (wohl auch der Grund, warum das nicht mehr weiterentwickelt wird).

    Und ein Programm zum erstellen eines Einstellungsdialogs halte ich für ähnlich überflüssig. Entschuldige, wenn ich Dir damit "auf die Füsse trete". Das ist nicht böse gemeint.

    Ich wollte nur anregen, dass Du vielleicht mal eine Umfrage starten solltest, wer sowas gebrauchen kann, bevor Du allzuviel Arbeit da rein steckst.

  • Suche einfach erweiterbaren Einstellungen-Dialog (Program Settings)

    • Oscar
    • 11. August 2020 um 10:03

    Ich habe mal eine GUI erstellt, die so wie Deine Vorgabe aussieht.

    Auf der rechten Seite befinden sich Child-Fenster, die mit einem Klick auf eines der Treeview-Items ein-/ausgeblendet werden.

    AutoIt
    #include <GUIConstantsEx.au3>
    #include <GuiTreeView.au3>
    #include <TreeViewConstants.au3>
    #include <WindowsConstants.au3>
    
    Global $hMainGui = GUICreate('Test', 600, 380)
    GUISetBkColor(0xAAAAAA)
    
    GUICtrlCreateLabel('', -2, 50, 604, 4, -1, $WS_EX_CLIENTEDGE)
    GUICtrlCreateLabel('', -2, 350, 604, 4, -1, $WS_EX_CLIENTEDGE)
    GUICtrlCreateLabel('', 170, 54, 4, 300, -1, $WS_EX_CLIENTEDGE)
    
    Global $idHeaderIcon = GUICtrlCreateIcon('shell32.dll', -131, 5, 5, 40, 40)
    Global $idHeaderText = GUICtrlCreateLabel('Sample GUI', 50, 10, 200, 28)
    GUICtrlSetFont(-1, 16, 600, 0, 'Arial', 4)
    
    Global $idTreeview = GUICtrlCreateTreeView(10, 60, 160, 200, BitOR($TVS_DISABLEDRAGDROP, $TVS_SHOWSELALWAYS))
    GUICtrlSetBkColor(-1, 0xAAAAAA)
    GUICtrlSetFont(-1, 12, 600, 0, 'Arial', 4)
    
    Global $idLink1 = GUICtrlCreateTreeViewItem('Link 1', $idTreeview)
    _GUICtrlTreeView_SetIcon($idTreeview, $idLink1, 'shell32.dll', 43)
    Global $idLink2 = GUICtrlCreateTreeViewItem('Link 2', $idTreeview)
    _GUICtrlTreeView_SetIcon($idTreeview, $idLink2, 'shell32.dll', 166)
    Global $idLink3 = GUICtrlCreateTreeViewItem('Link 3', $idTreeview)
    _GUICtrlTreeView_SetIcon($idTreeview, $idLink3, 'shell32.dll', 221)
    Global $idLink4 = GUICtrlCreateTreeViewItem('Link 4', $idTreeview)
    _GUICtrlTreeView_SetIcon($idTreeview, $idLink4, 'shell32.dll', 21)
    
    Global $hLink1Gui = GUICreate('', 415, 285, 180, 60, $WS_CHILD, -1, $hMainGui)
    GUISetBkColor(0xAAAAFF)
    GUICtrlCreateLabel('Title for the panel 1', 50, 10, 200, 28)
    GUICtrlSetFont(-1, 14, 600, 0, 'Arial', 4)
    GUICtrlCreateLabel('Label1', 10, 44, 80, 28)
    GUICtrlSetFont(-1, 12, 400, 0, 'Arial', 4)
    Global $idInput1 = GUICtrlCreateInput('', 90, 40, 200, 28)
    Global $idButton1 = GUICtrlCreateButton('Button1', 320, 40, 80, 28)
    
    Global $hLink2Gui = GUICreate('', 415, 285, 180, 60, $WS_CHILD, -1, $hMainGui)
    GUISetBkColor(0xAAFFFF)
    GUICtrlCreateLabel('Title for the panel 2', 50, 10, 200, 28)
    GUICtrlSetFont(-1, 14, 600, 0, 'Arial', 4)
    GUICtrlCreateLabel('Label2', 10, 44, 80, 28)
    GUICtrlSetFont(-1, 12, 400, 0, 'Arial', 4)
    Global $idInput2 = GUICtrlCreateInput('', 90, 40, 200, 28)
    Global $idButton2 = GUICtrlCreateButton('Button2', 320, 40, 80, 28)
    
    Global $hLink3Gui = GUICreate('', 415, 285, 180, 60, $WS_CHILD, -1, $hMainGui)
    GUISetBkColor(0xFFAAAA)
    GUICtrlCreateLabel('Title for the panel 3', 50, 10, 200, 28)
    GUICtrlSetFont(-1, 14, 600, 0, 'Arial', 4)
    GUICtrlCreateLabel('Label3', 10, 44, 80, 28)
    GUICtrlSetFont(-1, 12, 400, 0, 'Arial', 4)
    Global $idInput3 = GUICtrlCreateInput('', 90, 40, 200, 28)
    Global $idButton3 = GUICtrlCreateButton('Button3', 320, 40, 80, 28)
    
    Global $hLink4Gui = GUICreate('', 415, 285, 180, 60, $WS_CHILD, -1, $hMainGui)
    GUISetBkColor(0xAAFFAA)
    GUICtrlCreateLabel('Title for the panel 4', 50, 10, 200, 28)
    GUICtrlSetFont(-1, 14, 600, 0, 'Arial', 4)
    GUICtrlCreateLabel('Label4', 10, 44, 80, 28)
    GUICtrlSetFont(-1, 12, 400, 0, 'Arial', 4)
    Global $idInput4 = GUICtrlCreateInput('', 90, 40, 200, 28)
    Global $idButton4 = GUICtrlCreateButton('Button4', 320, 40, 80, 28)
    
    Global $hLastGui = 0
    GUISetState(@SW_SHOW, $hMainGui)
    While True
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                Exit
            Case $idLink1
                If $hLastGui <> 0 Then GUISetState(@SW_HIDE, $hLastGui)
                GUISetState(@SW_SHOW, $hLink1Gui)
                $hLastGui = $hLink1Gui
            Case $idLink2
                If $hLastGui <> 0 Then GUISetState(@SW_HIDE, $hLastGui)
                GUISetState(@SW_SHOW, $hLink2Gui)
                $hLastGui = $hLink2Gui
            Case $idLink3
                If $hLastGui <> 0 Then GUISetState(@SW_HIDE, $hLastGui)
                GUISetState(@SW_SHOW, $hLink3Gui)
                $hLastGui = $hLink3Gui
            Case $idLink4
                If $hLastGui <> 0 Then GUISetState(@SW_HIDE, $hLastGui)
                GUISetState(@SW_SHOW, $hLink4Gui)
                $hLastGui = $hLink4Gui
        EndSwitch
    WEnd
    Alles anzeigen
  • Files and Folder

    • Oscar
    • 10. August 2020 um 05:12

    Vorweg: Ja, ich weiß, dass es in wNim einen Filedialog gibt! :)

    Es ging mir darum, etwas zu lernen. Und zwar über Treeviews, Listviews, ImageList und das einlesen von Verzeichnissen/Dateien.

    Beim darstellen der Verzeichnisstruktur in einem Treeview gibt es ja immer das Problem, dass man alle Verzeichnisse rekursiv durchsuchen muss, was entsprechend lange dauert, weil Festplatten und Co. dafür nunmal einige Zeit brauchen.

    Diese Zeit kann man erheblich verkürzen, indem man immer nur 2 Rekursionen ausführt und diese darstellt. Erst beim anklicken/aufklappen eines Zweiges/Items vom Treeview liest man die nächste Rekursionsstufe ein.

    Das habe ich hier auch so umgesetzt.

    Außerdem habe ich bei Dateien/Verzeichnissen mit den Dateiattributen "s" = System, "h" = Hidden, und "p" = Reparsepoint/Link die Icons als Overlay-Icons erstellt. Bei den "System"-Dateien wird ein Ausrufezeichen eingeblendet. Die "Hidden"-Dateien sind "gedimmt" dargestellt und die "Reparsepoints" haben unten links den kleinen Pfeil.

    Den Code habe ich wieder ausführlich kommentiert:

    Code
    import wNim, winim, strutils, os, math, tables
    
    let iconSize: wSize = (32, 32)
    
    # Prozedur, um die System-ImageList zu initialisieren
    proc FileIconInit*(restoreCache: WINBOOL): WINBOOL {.discardable.} =
      type fii = proc(fRestoreCache: WINBOOL): WINBOOL {.gcsafe, stdcall.}
      let
        shell32 = LoadLibrary("shell32.dll")
        pAddr = GetProcAddress(shell32, cast[LPCSTR](660))
      if IsBadCodePtr(pAddr):
        return FALSE
      else:
        let procFii = cast[fii](pAddr)
        return procFii(restoreCache)
    
    # Prozedur, um die System-ImageList auszulesen.
    # Im Gegensatz zu "Shell_GetImageLists" (nur 16x16 und 32x32 Icons) bietet
    # "SHGetImageList" Icon-Groessen bis 256x256 an (siehe unten).
    proc getSystemImageList*(iImageList: int32): HIMAGELIST =
      var riid = IID_IImageList
      if SHGetImageList(iImageList, riid, cast[ptr pointer](result.addr)) != S_OK:
        MessageDialog(nil, "Die System-Image-List konnte nicht geladen werden.\r\n" &
          "Das Programm wird beendet.", "Fehler!", wOk or wIconStop).display()
        quit()
    
    FileIconInit(TRUE) # System-ImageList initialisieren
    var hAppIml = ImageList(iconSize) # ImageList fuer die App erstellen
    
    # "SHGetImageList" stellt verschiedene Icongroessen zur Verfuegung:
    # SHIL_SYSSMALL = SM_CXSMICON x SM_CYSMICON (GetSystemMetrics)
    # SHIL_SMALL = 16x16
    # SHIL_LARGE = 32x32
    # SHIL_EXTRALARGE = 48x48
    # SHIL_JUMBO = 256x256
    hAppIml.mHandle = getSystemImageList(SHIL_LARGE) # System-ImageList an die App-ImageList uebergeben
    
    # Die Laufwerk-Icons der App-ImageList hinzufuegen
    var
      imlRoot = hAppIml.add(Icon("imageres.dll,104", size=iconSize))
      imlUnknown = hAppIml.add(Icon("imageres.dll,70", size=iconSize))
      imlFloppy = hAppIml.add(Icon("imageres.dll,23", size=iconSize))
      imlCrMedia = hAppIml.add(Icon("imageres.dll,37", size=iconSize))
      imlCrNoMedia = hAppIml.add(Icon("imageres.dll,158", size=iconSize))
      imlHarddiskSys = hAppIml.add(Icon("imageres.dll,31", size=iconSize))
      imlHarddisk = hAppIml.add(Icon("imageres.dll,27", size=iconSize))
      imlNetwork = hAppIml.add(Icon("imageres.dll,28", size=iconSize))
      imlCDromMedia = hAppIml.add(Icon("imageres.dll,56", size=iconSize))
      imlCDromNoMedia = hAppIml.add(Icon("imageres.dll,25", size=iconSize))
      imlRamDisk = hAppIml.add(Icon("imageres.dll,29", size=iconSize))
    
    # Ermittelt den DriveType und gibt anhand dessen den
    # Icon-Index aus der App-ImageList zurueck
    proc getDriveTypeIdx(path: string): int =
      let
        sFile = newWideCString(path)
        pFile = cast[LPCWSTR](sFile[0].addr)
        iDrive = GetDriveTypeW(pFile)
      case iDrive
      of DRIVE_UNKNOWN, DRIVE_NO_ROOT_DIR: # Typ unbekannt oder kein Volume
        result = imlUnknown
      of DRIVE_REMOVABLE: # Bei einem Wechselmedium-Laufwerk
        case (path.toLower)[0]
        of 'a', 'b':
          result = imlFloppy # Floppy
        else:
          try: # Cardreader
            let fi = getFileInfo(path)
            result = imlCrMedia # Medium eingelegt
          except OSError:
            result = imlCrNoMedia # kein Medium
      of DRIVE_FIXED: # Harddisk
        if (path.toLower)[0] == 'c':
          result = imlHarddiskSys # Systemlaufwerk
        else:
          result = imlHarddisk # Normales Laufwerk
      of DRIVE_REMOTE:
        result = imlNetwork # Netzwerklaufwerk
      of DRIVE_CDROM: # CD/DVD
        try:
          let fi = getFileInfo(path)
          result = imlCDromMedia # Medium eingelegt
        except OSError:
          result = imlCDromNoMedia # kein Medium
      of DRIVE_RAMDISK:
        result = imlRamDisk # Ram-Disk
      else: discard
    
    # Holt den Icon-Index fuer die Verzeichnisse/Dateien aus der App-ImageList
    proc getSystemIconIndex(path: string): int =
      let
        sFile = newWideCString(path)
        pFile = cast[LPCWSTR](sFile[0].addr)
      var shfi: SHFILEINFOW
      if SHGetFileInfoW(pFile, 0x00000080'i32, shfi.addr, UINT sizeof(shfi), 
          SHGFI_SYSICONINDEX) != 0: result = shfi.iIcon
    
    # Gibt einen String zurueck mit fuenf wichtigen Dateiattributen oder "error"
    proc getFileAttrStr(path: string): string =
      let
        sFile = newWideCString(path)
        pFile = cast[LPCWSTR](sFile[0].addr)
      let iAttr = GetFileAttributesW(pFile)
      if iAttr == INVALID_FILE_ATTRIBUTES: return "error"
      result.add(if iAttr and 0x00000001'i32: 'r' else: '-') # r = readonly
      result.add(if iAttr and 0x00000020'i32: 'a' else: '-') # a = archive
      result.add(if iAttr and 0x00000004'i32: 's' else: '-') # s = system
      result.add(if iAttr and 0x00000002'i32: 'h' else: '-') # h = hidden
      result.add(if iAttr and 0x00000400'i32: 'p' else: '-') # p = reparse point
    
    # Geaenderte Version von getIcon, wegen Bug in der originalen Version.
    # In der Original-Version wird immer Index 0 zurueckgegeben!
    proc newGetIcon*(self: wImageList, index: int): wIcon =
      if index <= self.getImageCount():
        var hIcon = ImageList_GetIcon(self.mHandle, cast[int32](index), ILD_TRANSPARENT)
        result = Icon(hIcon, copy=false)
    
    # Eine OrderedTable, zum speichern von Pfad und Icon-Index bei den Overlay-Icons
    var IconIndexTable = initOrderedTable[string, int]()
    
    # Prozedur, zum holen des Icon-Indexes fuer das Treeview bzw. das Listview.
    # Bei den Attributen 's', 'h', 'p' wird ein entsprechendes Overlay-Icon erstellt
    # und der App-ImageList hinzugefuegt. Damit das nicht bei jedem Aufruf passiert
    # wird der Pfad und der neue Icon-Index in einer OrderedTable gespeichert und
    # im Wiederholungsfall daraus geholt.
    proc getIconIndex(path: string, attr: string): int =
      # Wenn fuer den Pfad bereits ein Icon-Index existiert, diesen zurueckgeben
      if IconIndexTable.hasKey(path): return IconIndexTable[path]
      result = getSystemIconIndex(path)
      if attr.find({'s', 'h', 'p'}) != -1:
        var
          hIcon = hAppIml.newGetIcon(result)
          hImage = Image(hIcon)
          hLink = Image(Icon("imageres.dll,154", size=iconSize))
          hSystem = Image(Icon("mmcndmgr.dll,7", size=iconSize))
        if attr.find('p') != -1:
          hImage.paste(hLink, 0, 0)
        if attr.find('s') != -1:
          hImage.paste(hSystem, 0, 0)
        if attr.find('h') != -1:
          hImage.brightnessContrast(brightness = 100, contrast = -60)
        result = hAppIml.add(Icon(hImage))
        hSystem.delete
        hLink.delete
        hImage.delete
        hIcon.delete
        IconIndexTable[path] = result # Pfad und Icon-Index merken
    
    # Zum suchen, nach einem SubItem (Unterverzeichnis)
    proc findItemText(tvItem: wTreeItem, text: string): bool =
      for tvChild in tvItem.getChildren:
        if tvChild.getText == text: return true
      return false
    
    # Erstellt die SubItems (Verzeichnisse) beim Treeview
    proc addSubItems(tree: wTreeCtrl, parent: wTreeItem, sDir: string) =
      var sFolder: string = sDir
      sFolder.normalizePathEnd(true) # sicherstellen, dass ein Backslash am Ende steht
      for kind, path in walkDir(sFolder):
        var attr = getFileAttrStr(path)
        case kind
        of pcDir, pcLinkToDir:
          if not findItemText(parent, lastPathPart(path)): # wenn Unterverzeichnis noch nicht vorhanden,
            tree.appendItem(parent, lastPathPart(path), getIconIndex(path, attr), data=1) # dann erstellen
        else: discard
    
    # Zum auslesen des Pfads (excl. Root)
    proc getTree(self: wTreeItem, sepChar: char = chr(92)): string =
      let tvRoot = self.getTreeCtrl.getRootItem
      var tvItem = self
      while tvItem != tvRoot:
        result = tvItem.getText & sepChar & result
        tvItem = tvItem.getParent
    
    # Erstellt im Listview die Items fuer die Verzeichnisse/Dateien.
    # Fuer die Dateiendungen kann ein Filter uebergeben werden. Dazu werden
    # einfach die erlaubten Dateiendungen als String uebergeben.
    # Zum Beispiel: readFolder(list, "c:\", "exe", "au3", "mp3", "pdf", ...)
    # Beim uebergeben von einem Leerstring werden alle Dateien angezeigt. 
    proc readFolder(list: wListCtrl, sDir: string, sFileExt: varargs[string]) =
      var
        sFolder: string = sDir
        lvIndex: int
      sFolder.normalizePathEnd(true) # sicherstellen, dass ein Backslash am Ende steht
      list.deleteAllItems() # alle Eintraege aus dem Listview entfernen
      SendMessage(list.getHandle, WM_SETREDRAW, FALSE, 0) # Listview-Refresh verbieten
      for kind, path in walkDir(sFolder): # zuerst alle Verzeichnisse einlesen
        case kind
        of pcDir, pcLinkToDir:
          var attr = getFileAttrStr(path)
          lvIndex = list.appendItem( # und ins Listview einfuegen
            [lastPathPart(path), "", (if kind == pcLinkToDir: "<LNK>" else: "<DIR>"), attr],
            image = getIconIndex(path & r"\", attr)
            )
        else: discard 
      for kind, path in walkDir(sFolder): # danach die Dateien
        case kind
        of pcFile, pcLinkToFile:
          for extension in sFileExt: # anhand des Dateiendungs-Filter
            if path.toLower.endsWith(extension.toLower): # nur die erlaubten Endungen zulassen
              var
                (dir, name, ext) = path.splitFile
                attr: string = getFileAttrStr(path)
              lvIndex = list.appendItem( # und ins Listview einfuegen
                [name, ext.substr(1), insertSep($getFileSize(path), '.'), attr],
                image = getIconIndex(path, attr)
                )
        else: discard 
      SendMessage(list.getHandle, WM_SETREDRAW, TRUE, 0) # Listview-Refresh wieder erlauben
    
    
    let app = App()
    let frame = Frame(title="Files and Folder", size=(1000, 640))
    let panel = Panel(frame)
    panel.setBackgroundColor(0x00DDDDDD)
    
    let idPath = TextCtrl(panel, pos=(10, 5), size=(960, 30), style=wBorderSimple or wTeReadOnly)
    idPath.font = Font(14, faceName="Tahoma", weight=wFontWeightNormal)
    idPath.setBackgroundColor(0x00F4F4F4)
    
    let idTreeview = TreeCtrl(panel, pos=(10, 40), size=(350, 540), style=wBorderSimple or wTrHasButtons or wTrHasLines or wClipChildren)
    idTreeview.font = Font(12, faceName="Tahoma", weight=wFontWeightNormal)
    idTreeview.setBackgroundColor(0x00F4F4F4)
    idTreeview.setImageList(hAppIml, wImageListNormal)
    
    let idListview = ListCtrl(panel, pos=(370, 40), size=(600, 540), style=wLcReport or wBorderSimple or wClipChildren)
    idListview.font = Font(12, faceName="Arial", weight=wFontWeightNormal)
    idListview.appendColumn("Dateiname", width=290, format=wListFormatLeft)
    idListview.appendColumn("Ext", width=80, format=wListFormatRight)
    idListview.appendColumn("Größe", width=120, format=wListFormatRight)
    idListview.appendColumn("Attr.", width=85, format=wListFormatRight)
    idListview.setBackgroundColor(0x00F4F4F4)
    idListview.setImageList(hAppIml, wImageListSmall)
    
    let root = idTreeview.addRoot("PC", imlRoot) # idTreeview-Root-Item erstellen
    let iDrive = GetLogicalDrives() # die Laufwerke auslesen
    var
      iIcon: int
      tvItem: wTreeItem
    for i in 0..25: # Alle Laufwerksbuchstaben testen
      if (iDrive and 2^i) == 2^i: # Laufwerke (Bit 0 = A:, Bit 1 = B:, Bit 2 = C:, usw.)
        iIcon = getDriveTypeIdx($chr(97 + i) & r":\") # Icon-Index vom Laufwerk holen
        tvItem = idTreeview.appendItem(root, $chr(65 + i) & $chr(58), iIcon) # Laufwerk-Item erstellen
        idTreeview.addSubItems(tvItem, $chr(97 + i) & $chr(58)) # und die SubItems erstellen
    
    root.expand() # Root-Item ausklappen
    
    # Workaround, weil es "getItem" in wNim v0.11.2 nicht mehr gibt
    proc myGetItem*(event: wEvent): wTreeItem =
      let pnmtv = cast[LPNMTREEVIEW](event.lParam)
      result.mHandle = pnmtv.itemNew.hItem
      result.mTreeCtrl = event.getEventObject.wTreeCtrl
    
    # Wenn ein Item im Treeview angeklickt wird
    idTreeview.wEvent_TreeSelChanged do (event: wEvent):
      let tvItem = event.myGetItem
      if tvItem == root: return
      frame.setCursor(Cursor(wCursorWait))
      let path = tvItem.getTree
      idPath.label = path
      idListview.readFolder(path, "")
      frame.setCursor(wNilCursor)
    
    # Beim aufklappen eines Treeview-Item
    idTreeview.wEvent_TreeItemExpanded do (event: wEvent):
      let tvItem = event.myGetItem
      if tvItem == root: return
      frame.setCursor(Cursor(wCursorWait))
      for tvChild in tvItem.getChildren:
        if tvChild.getData == 1:
          let path = tvChild.getTree
          idTreeview.addSubItems(tvChild, path)
      frame.setCursor(wNilCursor)
    
    frame.center()
    frame.show()
    app.mainLoop()
    Alles anzeigen
  • wNim Version 0.11.2 und Treeview

    • Oscar
    • 9. August 2020 um 14:29
    Zitat von BugFix

    Hmm, hab mal nachgesehen, die Methode gibt es in den Events nicht mehr.

    Ich habe mich auch gerade mal durchgewühlt. Die beiden Methoden sind auskommentiert (in wTreeEvent.nim):

    Code
    # method getItem*(self: wTreeEvent): wTreeItem {.property, inline.} =
    #   ## Returns the item.
    #   result.mTreeCtrl = self.mTreeCtrl
    #   result.mHandle = self.mHandle
    
    # method getOldItem*(self: wTreeEvent): wTreeItem {.property, inline.} =
    #   ## Returns the old item (valid for wEvent_TreeSelChanging, wEvent_TreeSelChanged,
    #   ## and wEvent_TreeEndDrag events).
    #   result.mTreeCtrl = self.mTreeCtrl
    #   result.mHandle = self.mOldHandle

    Und nachdem ich mich etwas in wTreeCtrl.nim eingelesen habe, konnte ich zumindest ein Workaround erstellen:

    Code
    import wNim, winim
    
    let app = App()
    let frame = Frame(title="Treeview-Example", size=(480, 640))
    let panel = Panel(frame)
    let idTreeview = TreeCtrl(panel, pos=(10, 40), size=(440, 540), style=wBorderSimple or wTrHasButtons or wTrHasLines or wClipChildren)
    idTreeview.font = Font(16, faceName="Tahoma", weight=wFontWeightNormal)
    
    # Beispieldaten eintragen
    let root = idTreeview.addRoot("Root")
    let ItemA = idTreeview.appendItem(root, "A:")
    idTreeview.appendItem(ItemA, "A1")
    idTreeview.appendItem(ItemA, "A2")
    idTreeview.appendItem(ItemA, "A3")
    let ItemB = idTreeview.appendItem(root, "B:")
    idTreeview.appendItem(ItemB, "B1")
    idTreeview.appendItem(ItemB, "B2")
    idTreeview.appendItem(ItemB, "B3")
    let ItemC = idTreeview.appendItem(root, "C:")
    idTreeview.appendItem(ItemC, "C1")
    idTreeview.appendItem(ItemC, "C2")
    idTreeview.appendItem(ItemC, "C3")
    
    root.expand() # Root-Item aufklappen
    
    # Zum auslesen des Pfads (excl. Root)
    proc getTree(self: wTreeItem, sepChar: char = chr(92)): string =
      let tvRoot = self.getTreeCtrl.getRootItem
      var tvItem = self
      while tvItem != tvRoot:
        result = tvItem.getText & sepChar & result
        tvItem = tvItem.getParent
    
    proc myGetItem*(event: wEvent): wTreeItem =
      let pnmtv = cast[LPNMTREEVIEW](event.lParam)
      result.mHandle = pnmtv.itemNew.hItem
      result.mTreeCtrl = event.getEventObject.wTreeCtrl
    
    idTreeview.wEvent_TreeSelChanged do (event: wEvent):
      let tvItem = event.myGetItem
      echo "Angeklickt, Tree: ", tvItem.getTree
    
    idTreeview.wEvent_TreeItemExpanded do (event: wEvent):
      let tvItem = event.myGetItem
      echo "Aufgeklappt, Tree: ", tvItem.getTree
    
    frame.center()
    frame.show()
    app.mainLoop()
    Alles anzeigen

    So funktioniert zumindest wieder das auslesen des Items.

  • wNim Version 0.11.2 und Treeview

    • Oscar
    • 9. August 2020 um 13:34
    Zitat von BugFix

    EDIT:

    Verursacher ist: tree. Beim Aufruf von tree.getRootItem crasht die Funktion, weil tree nil ist.

    Demzufolge ist bereits der Aufruf von tvItem.getTreeCtrl innerhalb der Events nicht erfolgreich. Deshalb sah es auch so aus, als seien diese die Schuldigen.

    Ja, insofern gebe ich Dir recht. Mein getTree crasht, wegen dem nil.

    Das Problem liegt aber an "event.getItem". Die Prozedur "getItem" liefert nicht mehr das Item zurück, sondern immer nil.

    Mit der Version 0.11.0 funktionierte das einwandfrei. Dort wurde das angeklickte Item zuruückgegeben.

    Meine Frage ist also, wie komme ich in der neuen Version an das Item?

  • wNim Version 0.11.2 und Treeview

    • Oscar
    • 9. August 2020 um 09:55
    Zitat von BugFix

    Im Bsp. wHyperlink.nim ist das recht gut gezeigt.

    Irgendwie will das bei mir nicht funktionieren oder ich bin zu blöd dafür.

    Wenn ich das so ändere, passiert beim anklicken der Items gar nichts:

    Code
    import wNim
    
    type
      wMyLinkEvent = ref object of wCommandEvent
    
    # Use wEventRegister macro to define the event message
    wEventRegister(wMyLinkEvent):
      wEvent_TreeSelChanged
    
    let app = App()
    let frame = Frame(title="Treeview-Example", size=(480, 640))
    let panel = Panel(frame)
    let idTreeview = TreeCtrl(panel, pos=(10, 40), size=(440, 540), style=wBorderSimple or wTrHasButtons or wTrHasLines or wClipChildren)
    idTreeview.font = Font(16, faceName="Tahoma", weight=wFontWeightNormal)
    
    # Beispieldaten eintragen
    let root = idTreeview.addRoot("Root")
    let ItemA = idTreeview.appendItem(root, "A:")
    idTreeview.appendItem(ItemA, "A1")
    idTreeview.appendItem(ItemA, "A2")
    idTreeview.appendItem(ItemA, "A3")
    let ItemB = idTreeview.appendItem(root, "B:")
    idTreeview.appendItem(ItemB, "B1")
    idTreeview.appendItem(ItemB, "B2")
    idTreeview.appendItem(ItemB, "B3")
    let ItemC = idTreeview.appendItem(root, "C:")
    idTreeview.appendItem(ItemC, "C1")
    idTreeview.appendItem(ItemC, "C2")
    idTreeview.appendItem(ItemC, "C3")
    
    root.expand() # Root-Item aufklappen
    
    # Zum auslesen des Pfads
    proc getTree(tree: wTreeCtrl, item: wTreeItem, sepChar: char = chr(92)): string =
      var tvItem = item
      while tvItem != tree.getRootItem:
        result = tvItem.getText & sepChar & result
        tvItem = tvItem.getParent
    
    idTreeview.wEvent_TreeSelChanged do (event: wEvent):
      let 
        tvItem = event.getItem # Item
      echo "Klick", tvItem
    
    frame.center()
    frame.show()
    app.mainLoop()
    Alles anzeigen
  • ​Sammlung: Nim Snippets / Procedures

    • Oscar
    • 8. August 2020 um 11:58

    Wenn man in einer ComboBox dem Benutzer eine Auswahl der verfügbaren Laufwerksbuchstaben zur Verfügung stellen will, so braucht man eine Sequenz von Strings.

    Diese kleine Prozedur ermittelt die angemeldeten Laufwerke und generiert die String-Sequenz:

    Code
    import winim
    
    # Diese Prozedur liefert eine Sequenz von Strings mit den vorhandenen Laufwerksbuchstaben.
    # Man kann diese eingrenzen, indem man den/die gewuenschten DriveType(n) uebergibt.
    # DRIVE_REMOVABLE = Wechselmedium
    # DRIVE_FIXED = Harddisk
    # DRIVE_REMOTE = Netzwerk
    # DRIVE_CDROM = CD/DVD
    # DRIVE_RAMDISK = RamDisk
    # DRIVE_ALL = alle Laufwerke
    const DRIVE_ALL* = 7
    proc getDrives*(reqType: varargs[UINT]): seq[string] =
      let iDrive = GetLogicalDrives() # die Laufwerke auslesen
      var path: string
      for i in 0..25: # Alle Laufwerksbuchstaben testen
        if ((iDrive shr i) and 1): # Laufwerke (Bit 0 = A:, Bit 1 = B:, Bit 2 = C:, usw.)
          path = $chr(65 + i) & $chr(58) & $chr(92)
          if DRIVE_ALL in reqType:
            result.add(path)
          else:
            if GetDriveTypeA(path) in reqType: result.add(path)
    
    # Zum Beispiel:
    echo getDrives(DRIVE_FIXED, DRIVE_REMOVABLE, DRIVE_CDROM)
    Alles anzeigen
  • wNim Version 0.11.2 und Treeview

    • Oscar
    • 6. August 2020 um 18:31

    Ich habe da ein Problem mit der neuen Version (0.11.2) von wNim.

    Mit der alten Version (0.11.0) funktioniert das folgende Beispiel einwandfrei:

    Code
    import wNim
    
    let app = App()
    let frame = Frame(title="Treeview-Example", size=(480, 640))
    let panel = Panel(frame)
    let idTreeview = TreeCtrl(panel, pos=(10, 40), size=(440, 540), style=wBorderSimple or wTrHasButtons or wTrHasLines or wClipChildren)
    idTreeview.font = Font(16, faceName="Tahoma", weight=wFontWeightNormal)
    
    # Beispieldaten eintragen
    let root = idTreeview.addRoot("Root")
    let ItemA = idTreeview.appendItem(root, "A:")
    idTreeview.appendItem(ItemA, "A1")
    idTreeview.appendItem(ItemA, "A2")
    idTreeview.appendItem(ItemA, "A3")
    let ItemB = idTreeview.appendItem(root, "B:")
    idTreeview.appendItem(ItemB, "B1")
    idTreeview.appendItem(ItemB, "B2")
    idTreeview.appendItem(ItemB, "B3")
    let ItemC = idTreeview.appendItem(root, "C:")
    idTreeview.appendItem(ItemC, "C1")
    idTreeview.appendItem(ItemC, "C2")
    idTreeview.appendItem(ItemC, "C3")
    
    root.expand() # Root-Item aufklappen
    
    # Zum auslesen des Pfads
    proc getTree(tree: wTreeCtrl, item: wTreeItem, sepChar: char = chr(92)): string =
      var tvItem = item
      while tvItem != tree.getRootItem:
        result = tvItem.getText & sepChar & result
        tvItem = tvItem.getParent
    
    # Wenn ein Item im Treeview angeklickt wird
    idTreeview.wEvent_TreeSelChanged do (event: wEvent):
      let 
        tvItem = event.getItem # Item
        tvCtrl = tvItem.getTreeCtrl # Treeview
      echo "Angeklickt = ", tvItem.getText, ", Pfad = ", tvCtrl.getTree(tvItem)
    
    # Beim aufklappen eines Treeview-Item wechselt *nicht* der Focus.
    # Man benoetigt also das Item vom Aufklappen, nicht das selektierte!
    idTreeview.wEvent_TreeItemExpanded do (event: wEvent):
      let 
        tvItem = event.getItem # Item
        tvCtrl = tvItem.getTreeCtrl # Treeview
      echo "Aufgeklappt = ", tvItem.getText, ", Pfad = ", tvCtrl.getTree(tvItem)
    
    frame.center()
    frame.show()
    app.mainLoop()
    Alles anzeigen

    Wenn ich jetzt aber die Version 0.11.2 installiere und das Programm compiliere und starte (soweit funktioniert das noch)

    und dann ein Item anklicke oder eines aufklappen will, dann erscheint das hier:

    tv_error.png

    Im changelog zur neuen Version schreibt der Autor, dass er das Event-System geändert hat:

    Zitat

    Slightly modify the event system. wNim now uses the new wEventRegister() macro to define all the event.
    A newly-defined event don't need to use const wEvent_MyNewEvent = wEvent_App + 1 anymore.
    The constructor of wEvent Event() can return the corresponding object of the subclass that registered
    by wEventRegister. All of this means that the GUI controls and their event can be designd as plugin
    module more easily (Breaking Change).

    Aber ich verstehe nicht, wie ich das jetzt auf das neue System umstellen soll.

    Hat jemand eine Idee?

  • Achtung! Bug in wNim/wImageList

    • Oscar
    • 5. August 2020 um 14:05
    Zitat von BugFix

    Hast du auch auf GitHub beim Autor ein Issue gemeldet?

    Nein, mein englisch ist zu schlecht dafür.

  • Achtung! Bug in wNim/wImageList

    • Oscar
    • 5. August 2020 um 09:29

    Nachdem ich gestern wie blöd einen Fehler in meinem Programm gesucht habe, entdeckte ich den Fehler in "wNim/wImageList".

    Sowohl "getBitmap" als auch "getIcon" sind fehlerhaft!

    In beiden Fällen wird der übergebene Index nicht beachtet, sondern stattdessen immer mit "Index 0" gearbeitet.

    Die Original-Prozedur sieht so aus:

    Code
    proc getIcon*(self: wImageList, index: int): wIcon {.validate, property.} =
      ## Create the icon from specified index.
      if index <= self.getImageCount():
        var hIcon = ImageList_GetIcon(self.mHandle, 0, ILD_TRANSPARENT)
        result = Icon(hIcon, copy=false)

    Der zweite Parameter von "ImageList_GetIcon" muss eigentlich der Index sein, stattdessen steht da "0".

    Und in der Prozedur "getBitmap" das Gleiche:

    Code
    proc getBitmap*(self: wImageList, index: int): wBitmap {.validate, property.} =
      ## Create the bitmap from specified index.
      var
        width, height: int32
        info: IMAGEINFO
        bm: winimx.BITMAP
    
      # need to create new bitmap, don't just warp info.hbmImage
      if index <= self.getImageCount() and
          ImageList_GetIconSize(self.mHandle, &width, &height) != 0 and
          ImageList_GetImageInfo(self.mHandle, 0, &info) != 0 and
          GetObject(info.hbmImage, sizeof(winimx.BITMAP), &bm) != 0:
    
        result = Bitmap(width, height, int bm.bmBitsPixel)
        let
          hdc = CreateCompatibleDC(0)
          prev = SelectObject(hdc, result.mHandle)
    
        defer:
          SelectObject(hdc, prev)
          DeleteDC(hdc)
    
        discard ImageList_Draw(self.mHandle, index, hdc, 0, 0, 0)
    Alles anzeigen

    Der zweite Parameter von "ImageList_GetImageInfo" muss ebenfalls den Index enthalten, stattdessen "0".

    Ich habe die "getIcon"-Prozedur jetzt so geändert:

    Code
    proc newGetIcon*(self: wImageList, index: int): wIcon =
      if index <= self.getImageCount():
        var hIcon = ImageList_GetIcon(self.mHandle, cast[int32](index), ILD_TRANSPARENT)
        result = Icon(hIcon, copy=false)

    So arbeitet sie einwandfrei!

    Analog dazu kann man auch die "getBitmap"-Prozedur anpassen.

  • Wie FileIconInit aufrufen?

    • Oscar
    • 2. August 2020 um 19:32
    Zitat von BugFix

    Vielleicht praktischerweise gleich "einpacken" in eine Funktion

    Ja, stimmt!

    Aber dann als "FileIconInit()":

    Code
    import winim/lean
    
    proc FileIconInit(restoreCache: WINBOOL): WINBOOL {.discardable.} =
      type fii = proc(fRestoreCache: WINBOOL): WINBOOL {.gcsafe, stdcall.}
      let
        shell32 = LoadLibrary("shell32.dll")
        pAddr = GetProcAddress(shell32, cast[LPCSTR](660))
      if IsBadCodePtr(pAddr):
        return FALSE
      else:
        let procFii = cast[fii](pAddr)
        return procFii(restoreCache)
    
    echo "FileIconInit: ", FileIconInit(TRUE)
    Alles anzeigen
  • Wie FileIconInit aufrufen?

    • Oscar
    • 2. August 2020 um 18:31

    Danke für den Stupser in die Richtung!

    So scheint es jetzt zu funktionieren:

    Code
    import winim
    type fii = proc(fRestoreCache: WINBOOL): WINBOOL {.gcsafe, stdcall.}
    let
      shell32 = LoadLibrary("shell32.dll")
      pAddr = GetProcAddress(shell32, cast[LPCSTR](660))
    if IsBadCodePtr(pAddr):
      echo "Error!"
    else:
      let FileIconInit = cast[fii](pAddr)
      echo "FileIconInit: ", FileIconInit(TRUE)
  • Wie FileIconInit aufrufen?

    • Oscar
    • 2. August 2020 um 14:09

    Ich muss von Nim aus FileIconInit aufrufen. Nur leider gibt es die Funktion nicht in winim.

    Laut MSDN:

    Zitat

    FileIconInit is not included in a header file. You must call it directly from Shell32.dll, using ordinal 660.

    In AutoIt wird das so gelöst:

    AutoIt
    DllCall('shell32.dll', 'int', 660, 'int', True)

    Aber wie geht das in Nim?

  • ​Sammlung: Nim Snippets / Procedures

    • Oscar
    • 1. August 2020 um 06:35

    Weil es mich interessierte, wie das mit den Icons aus der System-ImageList im Listview funktioniert, habe ich mich mal reingekniet und ein Beispiel erarbeitet.

    Damit werden die Icons zu den Dateien/Verzeichnissen im Listview (funktioniert auch beim Treeview) wie im Explorer dargestellt, also mit den passenden Icons.

    Erklärungen gibt es noch bei den Kommentaren:

    Code
    import wNim, os, strutils, winim
    
    var 
      hAppIml = ImageList(32, 32)
      hSystemIml: HIMAGELIST
    
    # System-ImageList holen (Big oder Small Icons)
    Shell_GetImageLists(hSystemIml.addr, NULL) # Big Icons (32 x 32)
    # Shell_GetImageLists(NULL, hSystemIml.addr) # Small Icons (16 x 16)
    
    # Um nicht die Original System-ImageList zu veraendern, ein Duplikat erstellen
    hAppIml.mHandle = ImageList_Duplicate(hSystemIml)
    let upIdx = hAppIml.add(Icon("shell32.dll,307")) # "Pfeil nach oben"-Icon einfuegen
    
    # Gibt einen String zurueck mit vier wichtigen Dateiattributen oder "----"
    proc getFileAttrStr(path: string): string =
      let
        sFile = newWideCString(path)
        pFile = cast[LPCWSTR](sFile[0].addr)
      let iAttr = GetFileAttributesW(pFile)
      result.add(if iAttr and 0x00000001'i32: 'r' else: '-') # r = readonly
      result.add(if iAttr and 0x00000020'i32: 'a' else: '-') # a = archive
      result.add(if iAttr and 0x00000004'i32: 's' else: '-') # s = system
      result.add(if iAttr and 0x00000002'i32: 'h' else: '-') # h = hidden
    
    # Holt den Icon-Index aus der System-ImageList
    proc getSystemIconIndex(path: string): int =
      let
        sFile = newWideCString(path)
        pFile = cast[LPCWSTR](sFile[0].addr)
      var shfi: SHFILEINFOW
      if SHGetFileInfoW(pFile, 0x00000080'i32, shfi.addr, UINT sizeof(shfi), 
          SHGFI_SYSICONINDEX) != 0: result = shfi.iIcon
    
    # Erstellt im Listview die Items fuer die Verzeichnisse/Dateien.
    # Fuer die Dateiendungen kann ein Filter uebergeben werden. Dazu werden
    # einfach die erlaubten Dateiendungen als String uebergeben.
    # Zum Beispiel: readFolder(list, "c:\", "exe", "au3", "mp3", "pdf", ...)
    # Beim uebergeben von einem Leerstring werden alle Dateien angezeigt. 
    proc readFolder(list: wListCtrl, sDir: string, sFileExt: varargs[string]) =
      var sFolder: string = sDir
      sFolder.normalizePathEnd(true) # sicherstellen, dass ein Backslash am Ende steht
      SendMessage(list.getHandle, WM_SETREDRAW, FALSE, 0) # Listview-Refresh verbieten
      list.deleteAllItems() # alle Eintraege aus dem Listview entfernen
      if not sFolder.isRootDir(): # wenn nicht RootDir, dann "Pfeil nach oben" einfuegen
        list.appendItem(["..", "", "<DIR>", ""], image = upIdx)
      for path in walkDirs(sFolder & "*"): # zuerst alle Verzeichnisse einlesen
        list.appendItem( # und ins Listview einfuegen
          [lastPathPart(path), "", "<DIR>", getFileAttrStr(path)],
          image = getSystemIconIndex(path)
          )
      for kind, path in walkDir(sFolder): # danach die Dateien
        if kind == pcFile:
          for extension in sFileExt: # anhand des Dateiendungs-Filter
            if path.toLower.endsWith(extension.toLower): # nur die erlaubten Endungen zulassen
              var (dir, name, ext) = path.splitFile
              list.appendItem( # und ins Listview einfuegen
                [name, ext.substr(1), insertSep($getFileSize(path), '.'), getFileAttrStr(path)],
                image = getSystemIconIndex(path)
                )
      SendMessage(list.getHandle, WM_SETREDRAW, TRUE, 0) # Listview-Refresh wieder erlauben
    
    
    let app = App()
    let frame = Frame(title="System-ImageList", size=(900, 800))
    let panel = Panel(frame)
    let idListview = ListCtrl(panel, style=wLcReport or wBorderSimple, pos=(10, 10), size=(862, 700))
    idListview.font = Font(14, faceName="Arial", weight=wFontWeightNormal)
    idListview.appendColumn("Dateiname", width=470, format=wListFormatLeft)
    idListview.appendColumn("Ext", width=90, format=wListFormatRight)
    idListview.appendColumn("Größe", width=180, format=wListFormatRight)
    idListview.appendColumn("Attr.", width=90, format=wListFormatRight)
    idListview.setBackgroundColor(0x00EEEEEE)
    idListview.setImageList(hAppIml)
    
    let sAllowedExt = @["exe", "au3", "mp3", "pdf"] # eine Sequenz mit Strings geht auch
    idListview.readFolder(r"d:\downloads", sAllowedExt)
    # idListview.readFolder(r"d:\downloads", "") # Leerstring = alle Dateien anzeigen
    frame.center()
    frame.show()
    app.mainLoop()
    Alles anzeigen
  • ​Sammlung: Nim Snippets / Procedures

    • Oscar
    • 27. Juli 2020 um 18:59

    Ich habe auch mal wieder ein Snippet!

    Das sind alles so Nebenprodukte vom meinem MP3-Player. :)

    Und wenn ich dafür sonst kein Beispiel ergoogeln konnte, muss ich halt selbst eines erstellen.

    Dieses Mal geht es um das Sortieren von einem Listview (bei wNim List-Ctrl):

    Code
    import wNim
    
    let app = App()
    let frame = Frame(title="ListviewSort", size=(640, 480))
    let panel = Panel(frame)
    
    let idPlaylist = ListCtrl(panel, style=wLcReport or wBorderSimple, pos=(10, 10), size=(600, 400))
    idPlaylist.font = Font(14, faceName="Arial", weight=wFontWeightNormal)
    idPlaylist.setBackgroundColor(0x00DDDDDD)
    idPlaylist.appendColumn("Interpret", width=200)
    idPlaylist.appendColumn("Titel", width=200, format=wListFormatLeft)
    idPlaylist.appendColumn("Laufzeit", width=110, format=wListFormatRight)
    
    # Ein paar Beispieldaten in das Listview eintragen
    idPlaylist.appendItem(["ZZ Down", "Gimme All", "03:53"])
    idPlaylist.appendItem(["Johnson Twins", "Bla bla", "04:16"])
    idPlaylist.appendItem(["Kniff Richard", "Yeah", "05:11"])
    idPlaylist.appendItem(["Roller Stones", "Gimme Shelter", "04:03"])
    idPlaylist.appendItem(["Ralph a Ville", "Moin", "03:46"])
    
    let hImgList = ImageList(16, 16) # Imagelist erstellen
    hImgList.add(Icon("shell32.dll,246")) # up-Icon
    hImgList.add(Icon("shell32.dll,247")) # down-Icon
    idPlaylist.setImageList(hImgList) # die Imagelist dem Listview zuordnen
    
    var
      iSortCol, iOldCol: int = -1
      bSortDir: bool = false
    
    # Callback-Funktion zum sortieren der Eintraege
    proc sortCmp(item1: int; item2: int; data: int): int =
      result = cmp(idPlaylist.getItemText(item1, iSortCol), idPlaylist.getItemText(item2, iSortCol))
      if bSortDir: result *= -1
    
    # Beim Klick auf ein Spalten-Header
    idPlaylist.wEvent_ListColClick do (event: wEvent):
      iSortCol = event.getColumn() # die Spalte ermitteln
      if iSortCol == iOldCol: # wenn die gleiche Spalte wie vorher
        bSortDir = not bSortDir # dann Sortier-Richtung umdrehen
      else: # ansonsten
        bSortDir = false # Sortier-Richtung auf aufsteigend setzen
        idPlaylist.setColumnImage(iOldCol, -1) # und das vorherige Sortier-Image entfernen
      iOldCol = iSortCol # die Spalte merken
      idPlaylist.setColumnImage(iSortCol, if bSortDir: 1 else: 0) # Sortier-Image entsprechend der Richtung setzen
      idPlaylist.sortItemsByIndex(sortCmp) # und das Listview sortieren (Callback fuer den Vergleich)
    
    frame.center()
    frame.show()
    app.mainLoop()
    Alles anzeigen
  • GUI ohne Close-Button?

    • Oscar
    • 26. Juli 2020 um 17:47
    Zitat von BugFix

    Aber dann sind die Min/Max-Button etwas "verloren" positioniert. Dann schon lieber disabled.

    Ist das denn so schlimm, dass der Close-Button zwar vorhanden ist, aber halt disabled?

    Ich denke, das ist doch einfach der "Look an feel" von Windows. Ein Fenster ohne Close-Button wirkt IMHO eher wie ein Exot (zumindest wenn es sich nicht um ein Fenster komplett ohne Systemmenü handelt).

  • ​Sammlung: Nim Snippets / Procedures

    • Oscar
    • 25. Juli 2020 um 11:17

    Um mit meinem MP3-Player voranzukommen, brauchte ich eine Möglichkeit die Reihenfolge der Einträge in der Playlist (ListView) mit der Maus zu verändern (nach oben/unten ziehen).

    Dazu habe ich bei Google nichts finden können. Mit AutoIt hatte ich das bereits umgesetzt. Vom Prinzip her wusste ich also, wie es geht, aber das Ganze mit Nim hinzukriegen war dann doch eine stundenlange Tortur, mit Suchen im AutoIt-Script und den UDFs, auf MSDN und bei C-Sourcecodes.

    Naja, lange Rede, kurzer Sinn: Ich hab's dann doch geschafft. :)

    Man kann jetzt also Dateien vom Explorer auf die Playlist ziehen (das war der einfache Teil) und innerhalb der Playlist die Einträge verschieben (der aufwendige Teil).

    Hier also das Beispielprogramm (ListView Drag and Drop):

    Code
    import wNim, winim, os
    
    let app = App()
    let frame = Frame(title="Drag and Drop Test", size=(1000, 630), style=wDefaultFrameStyle or wStayOnTop)
    let panel = Panel(frame)
    panel.setBackgroundColor(0x00A0A0A0)
    
    let idPlaylist = ListCtrl(panel, style=wLcReport or wBorderSimple, pos=(10, 10), size=(960, 530))
    idPlaylist.font = Font(14, faceName="Arial", weight=wFontWeightNormal)
    idPlaylist.setBackgroundColor(0x00202020)
    idPlaylist.setForegroundColor(0x00EEEEEE)
    idPlaylist.appendColumn("File", width=700)
    idPlaylist.appendColumn("Size", width=220, format=wListFormatRight)
    idPlaylist.setDropTarget() # <- damit man Dateien vom Explorer auf die Playlist ziehen kann
    
    # Die Farbe der Einfuege-Markierung aendern
    SendMessage(idPlaylist.getHandle, LVM_SETINSERTMARKCOLOR, 0, cast[LPARAM](0x00EE8844))
    
    # Globale Variablen fuer das Drag and Drop innerhalb der Playlist
    var
      bDrag: bool = false
      oldPos: wPoint
      iDragStart, iDragEnd: int
      tItem: tuple[index, col, flag: int]
      lvMark: LVINSERTMARK # Struktur: cbSize, dwFlags, iItem, dwReserved
      plvMark: LPLVINSERTMARK = lvMark.addr
    
    lvMark.cbSize = UINT(sizeof(lvMark)) # die Groesse in die Struktur eintragen
    
    # Drag and Drop beginnt (Item wurde mit der linken Maustaste gezogen)
    idPlaylist.wEvent_ListBeginDrag do (event: wEvent):
      bDrag = true
      tItem[0] = -1
      iDragStart = event.getIndex()
      idPlaylist.setItemState(iDragStart, 0, LVIS_SELECTED or LVIS_FOCUSED, false)
    
    # Waehrend des Drag-Vorgangs die Einfuege-Markierung anpassen
    idPlaylist.wEvent_MouseMove do (event: wEvent):
      if bDrag:
        let pos = event.getMousePos() # Mausposition (Client-Koordinaten)
        if pos.y > oldPos.y + 2: lvMark.dwFlags = LVIM_AFTER # Markierung unter dem Item
        if pos.y < oldPos.y - 2: lvMark.dwFlags = 0          # Markierung ueber dem Item
        oldPos = pos
        tItem = idPlaylist.hitTest(pos) # tItem = tuple(index, col, flag)
        lvMark.iItem = int32(tItem[0])
        ListView_SetInsertMark(idPlaylist.getHandle, plvMark) # Einfuege-Markierung anzeigen
    
    # Drag and Drop beendet (Maustaste losgelassen)
    idPlaylist.wEvent_LeftUp do (event: wEvent):
      if bDrag:
        bDrag = false
        iDragEnd = tItem[0] # momentanen Index als EndIndex setzen
        if lvMark.dwFlags == LVIM_AFTER: iDragEnd += 1 # wenn Markierung unterhalb, dann 1 addieren
        lvMark.iItem = int32(-1)
        ListView_SetInsertMark(idPlaylist.getHandle, plvMark) # Einfuege-Markierung verstecken
        if iDragEnd != -1 and iDragStart != iDragEnd:
          let iCol = getColumnCount(idPlaylist) # Anzahl der Spalten ermitteln
          var sDragItemText: seq[string]
          for i in 0..iCol - 1: # den gezogenen Eintrag auslesen (alle Spalten)
            sDragItemText.add(idPlaylist.getItemText(iDragStart, i))
          if iDragStart < iDragEnd: # wenn StartIndex kleiner als EndIndex (nach unten gezogen)
            idPlaylist.insertItem(iDragEnd, sDragItemText) # dann erst einfuegen
            idPlaylist.deleteItem(iDragStart) # und danach loeschen
          else:                     # wenn StartIndex groesser als EndIndex (nach oben gezogen)
            idPlaylist.deleteItem(iDragStart) # dann erst loeschen
            idPlaylist.insertItem(iDragEnd, sDragItemText) # und danach einfuegen
    
    # Die beiden folgenden Events bearbeiten das Drag and Drop von Dateien
    # vom Explorer auf die Playlist.
    
    # Wenn die Maus den Bereich der Playlist erreicht (Files dragged)
    idPlaylist.wEvent_DragEnter do (event: wEvent):
      var dataObject = event.getDataObject()
      if dataObject.isFiles():
        event.setEffect(wDragCopy)
      else:
        event.setEffect(wDragNone)
    
    # Wenn die linke Maustaste ueber der Playlist losgelassen wird (Files dropped)
    idPlaylist.wEvent_Drop do (event: wEvent):
      var
        oData = event.getDataObject()
      if oData.isFiles():
        for file in oData.getFiles():
          let size = getFileSize(file)
          idPlaylist.appendItem([file, $size])
      else:
        event.setEffect(wDragNone)
    
    frame.center()
    frame.show()
    app.mainLoop()
    Alles anzeigen

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™