Mathematisches Problem IParam-Speicherung

    • Offizieller Beitrag

    Hi,
    irgendwie habe ich schon 'nen Knoten im Hirn - aber ich komme einfach auf keine Lösung.

    Für die Formatierung von Listview-SubItem nutze ich als Informationsträger, ob ein SubItem benutzerdefiniert formatiert wurde, den IParam des Item. IParam erlaubt mir einen Integerwert zu speichern.
    Um also Infos zu mehreren Spalten (SubItem) des Items zu hinterlegen speichere ich in IParam die Summe von 2^SpaltenIndex für jede betroffene Spalte.
    Den Wert von IParam muß ich dann allerdings noch verschieben, damit es keine Kollisionen mit niedrigen Control-ID gibt. Dazu addiere ich einfach ein Shift von 9999.
    Somit kann ich die Informationen für max. 30 Spalten (Index 0-29) hinterlegen - dann falle ich aus dem Integerbereich raus.
    Und hier setzt nun meine Überlegung an: Wie kann ich mir den negativen Zahlenbereich mit 'einverleiben'?
    Ich brauche irgendeine Möglichkeit um zu definieren:
    Wenn IParam negativ ist, berechne mit Algorithmus X den Wert der für SpaltenIndex 0-29 zuständig ist. Als zweiter Wert ergibt sich ein 'Zeiger' auf 2 hoch 30 und höher. Denn intern kann ich ja mit größeren Zahlen rechnen, nur Speichern in IParam geht nicht.
    Versucht habe ich schon einige Sachen, aber ich bekomme nichts eineindeutiges gebacken. Den Wert reinrechnen ist das Eine, ich muß ihn natürlich mit einer Umkehrmethode auch wieder zurückrechnen können.
    Ziel ist immer die Abfragevariante (nach ermitteln des tatsächlichen IParam):

    [autoit]

    If BitAND($IParam, 2^$SpaltenIndex) Then

    [/autoit]

    Hier mal noch ein kleines Skriptbsp. zum Durchspielen der Werte:

    [autoit]

    #include <GuiListView.au3>
    $gui = GUICreate('')
    $lv = GUICtrlCreateListView('a|b|c', 10, 10, 200, 150)
    $hLV = GUICtrlGetHandle($lv)
    GUICtrlCreateListViewItem(' | | ', $lv) ; Anzahl Spalten z. Test unwichtig

    [/autoit][autoit][/autoit][autoit]

    $IParam = 0
    $shift = 9999 ; IParam muß größer 9999 sein
    For $i = 0 To 30 ; letzter gültiger Spalten-Index ist 29
    ConsoleWrite('2 hoch ' & $i & @TAB & 2^$i & @CRLF)
    $IParam += 2^$i
    ; für negativen Bereich wäre das dann
    ;~ $IParam -= 2^$i ; <== das funktioniert dann bis 30 und Shift wäre nich nötig
    ConsoleWrite('set Summe $IParam: ' & $IParam & @CRLF)
    _GUICtrlListView_SetItemParam($hLV, 0, $IParam+$shift)
    ConsoleWrite('get Summe $IParam: ' & _GUICtrlListView_GetItemParam($hLV, 0)-$shift & @CRLF & @CRLF)
    Next

    [/autoit]
  • Hi,
    ich hab zwar auch grade einen Knoten im Hirn, aber ggf geht das

    Spoiler anzeigen
    [autoit]

    #include <GuiListView.au3>
    $gui = GUICreate('')
    $lv = GUICtrlCreateListView('a|b|c', 10, 10, 200, 150)
    $hLV = GUICtrlGetHandle($lv)
    GUICtrlCreateListViewItem(' | | ', $lv) ; Anzahl Spalten z. Test unwichtig

    [/autoit] [autoit][/autoit] [autoit]

    $IParam = 0
    $shift = 9999 ; IParam muß größer 9999 sein
    For $i = -30 To 30 ; letzter gültiger Spalten-Index ist 29
    if $i<0 then
    $t=-1
    Else
    $t=1
    endif

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite('2 hoch ' & $i & @TAB & $t*(2^($t*$i)) & @CRLF)
    $IParam += $t*(2^($t*$i))
    ; für negativen Bereich wäre das dann
    ;~ $IParam -= 2^$i ; <== das funktioniert dann bis 30 und Shift wäre nich nötig
    ConsoleWrite('set Summe $IParam: ' & $IParam & @CRLF)
    _GUICtrlListView_SetItemParam($hLV, 0, $IParam+$shift)
    ConsoleWrite('get Summe $IParam: ' & _GUICtrlListView_GetItemParam($hLV, 0)-$shift & @CRLF & @CRLF)
    Next

    [/autoit]

    wenigstens in die Richtung...

    nuts, im Prinzip möchter er 60 verschiedene "Zustände" in einer Integer-Zahl speichern. 30 ist einfach, das sind die "gesetzten" Bits, mit negativem Vorzeichen wären es 60^...

    • Offizieller Beitrag

    Hallo,

    benutze doch einfach das höchste Bit als Vorzeichen-Bit ist es 0 ist die Zahl positiv und bei 1 ist sie negativ.

    • Offizieller Beitrag

    im Prinzip möchter er 60 verschiedene "Zustände" in einer Integer-Zahl speichern.


    Wenn es das wäre, wär es nicht so schwierig. Das ließe sich mit Bernds Empfehlung regeln.
    Es sind aber bei 30 Werten schon wesentlich mehr Zustände: alle Kombinationen von 0 bis 29. (Dürfte 30! sein ?). Leider läßt sich in IParam ausschließlich ein Integerwert speichern. Sonst hätte ich den Zustand einfach in einem '01'-String abgelegt.

    Mein Problem ist also, dass ich die Information des positiven Integerwertes auch brauche, wenn ich einen negativen Wert verwende. Das war ja meine Überlegung, den Zahlenbereich zu strecken.
    Grundsätzlich könnte ich mir die IParam-Geschichte sparen und gleich auf das Array mit den Format-Infos zugreifen. Aber das wollte ich vermeiden, weil bei großer Elementanzahl jeder Schreib- oder Lesezugriff sich in der Performance bemerkbar macht.

  • was ist mit so was?

    Spoiler anzeigen
    [autoit]

    ; http://support.microsoft.com/kb/189323
    ; Gibt Die Zahl mit Vorzeichen zurück.
    ; Bei Fehler ( kleiner 0 oder größer MAXINT_4) wird der übergebene Wert zurückgegeben und @error auf 1 gesetzt.

    [/autoit] [autoit][/autoit] [autoit]

    ; in AutoIt this is long, int and uint,ulong,dword
    Func UnsignedToLong($Value)
    Local Const $OFFSET_4 = 4294967296
    Local Const $MAXINT_4 = 2147483647
    If $Value < 0 Or $Value >= $OFFSET_4 Then Return SetError(1,0,$Value) ;' Overflow
    If $Value <= $MAXINT_4 Then
    Return $Value
    Else
    Return $Value - $OFFSET_4
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; in AutoIt this is long, int and uint,ulong,dword
    Func LongToUnsigned($Value)
    Local Const $OFFSET_4 = 4294967296
    If $Value < 0 Then
    Return $Value + $OFFSET_4
    Else
    Return $Value
    EndIf
    EndFunc

    [/autoit]
    • Offizieller Beitrag

    Danke progandy, für den Beitrag. Leider bringt die Funktion keinen Gewinn (na OK - eine Spalte mehr). Denn der Offset ist 2^32 und danach bricht die Funktion mit Overflow ab.
    OK, gibts wohl keinen Weg. Trotzdem Danke, dass ihr euch Gedanken gemacht habt.

  • Mal ganz doof gefragt, würde es helfen, Iparam als Zeiger (Pointer) auf einen wie auch immer großen Speicherbereich zu behandeln? Die "Zustände" würden dann nicht in IParam "gespeichert", sondern an der Position auf die der Pointer zeigt. Also gewissermaßen doch ein Array^^

  • Mal ganz doof gefragt, würde es helfen, Iparam als Zeiger (Pointer) auf einen wie auch immer großen Speicherbereich zu behandeln? Die "Zustände" würden dann nicht in IParam "gespeichert", sondern an der Position auf die der Pointer zeigt. Also gewissermaßen doch ein Array^^


    Das ist auch die normale Vorgehensweise ... ;)


    Gruß
    Greenhorn


    • Offizieller Beitrag

    Das ist auch die normale Vorgehensweise ... ;)


    ...die nicht angewendet werden kann, da IParam ausschließlich ein Integerwert sein muß. Und ein Pointer ist nun mal ein Pointer und kein Integerwert. Das war übrigens mein erster Gedanke und aufgrund der Bedingungen auch entsprechend der Mißerfolg. :(


  • ...die nicht angewendet werden kann, da IParam ausschließlich ein Integerwert sein muß. Und ein Pointer ist nun mal ein Pointer und kein Integerwert. Das war übrigens mein erster Gedanke und aufgrund der Bedingungen auch entsprechend der Mißerfolg. :(


    warum nicht? es sollte so definiert sein: (MSDN)

    [autoit]

    $tagLVITEM= ...
    LPARAM lParam;
    ...

    [/autoit]


    AutoIt hat leider --> int Param --> Da musst du nen Bug melden, denn das ist ein anderer Datentyp ;)

    Zitat

    lparam/int_ptr/long_ptr an integer big enough to hold a pointer when running on x86 or x64 versions of AutoIt.


    im Gegensatz zu "int a 32 bit integer" (nur auf 32bit groß genug für einen Pointer)

  • Nur auf x64 wird das nicht funktionieren, aber da muss man einfach mal alle Structs kontrollieren und umstellen ;)

    • Offizieller Beitrag

    Ja Danke. Mit 'int_ptr' funktioniert es nun. :)
    Nun muß ich nur noch testen ob (bzw. wie sehr) mich das zusätzliche Auslesen aus der Struktur bremst.
    So habe ich es jetzt gelöst:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    #include <GuiListView.au3>
    Global $aItemParam[1]
    Local $col = ''
    For $i = 1 To 120
    $col &= $i & '|'
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $gui = GUICreate('')
    $lv = GUICtrlCreateListView(StringTrimRight($col,1), 10, 10, 200, 150)
    $hLV = GUICtrlGetHandle($lv)

    [/autoit] [autoit][/autoit] [autoit]

    _createNewItem($hLV, 'Test', $aItemParam)

    [/autoit] [autoit][/autoit] [autoit]

    _markSubItem($aItemParam, $hLV, 0, 1)
    _markSubItem($aItemParam, $hLV, 0, 119)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To _GUICtrlListView_GetColumnCount($hLV)-1
    ConsoleWrite($i & ' - ' & _getMarked($hLV, 0, $i) & @CRLF)
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _createNewItem($hWnd, $sText, ByRef $aIParam, $iItem=-1) ; if $iItem=-1 append
    If $iItem < -1 Then $iItem = 0
    If $iItem > UBound($aIParam)-1 Then $iItem = -1
    Local $cntCOL = _GUICtrlListView_GetColumnCount($hWnd)
    Local $tagITEMPARAM = "int_ptr;char[" & $cntCOL & "]"
    Local $tITEMPARAM = DllStructCreate($tagITEMPARAM)
    DllStructSetData($tITEMPARAM, 1, DllStructGetPtr($tITEMPARAM, 2))
    For $i = 1 To $cntCOL
    DllStructSetData($tITEMPARAM, 2, '0', $i)
    Next
    If $iItem = -1 Then
    _GUICtrlListView_AddItem($hWnd, $sText)
    If $aIParam[UBound($aIParam)-1] Then ReDim $aIParam[UBound($aIParam)+1]
    $aIParam[UBound($aIParam)-1] = $tITEMPARAM
    _GUICtrlListView_SetItemParam($hWnd, 0, DllStructGetData($tITEMPARAM, 1))
    Else
    _GUICtrlListView_InsertItem($hWnd, $sText, $iItem)
    _ArrayInsert($aIParam, $iItem, $tITEMPARAM)
    _GUICtrlListView_SetItemParam($hWnd, $iItem, DllStructGetData($tITEMPARAM, 1))
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _markSubItem(ByRef $aIParam, $hWnd, $iItem, $iSubItem, $mark='1')
    If $mark <> '1' Then $mark = '0'
    If $iItem < 0 Or $iItem > _GUICtrlListView_GetItemCount($hWnd)-1 Then Return SetError(1,0,0)
    If $iSubItem < 0 Or $iSubItem > _GUICtrlListView_GetColumnCount($hWnd)-1 Then Return SetError(2,0,0)
    DllStructSetData($aIParam[$iItem], 2, $mark, $iSubItem+1)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _getMarked($hWnd, $iItem, $iSubItem)
    Local $ptr = _GUICtrlListView_GetItemParam($hWnd, $iItem)
    Local $struct = DllStructCreate("char[" & _GUICtrlListView_GetColumnCount($hWnd) & "]", $ptr)
    Return DllStructGetData($struct, 1, $iSubItem+1)
    EndFunc

    [/autoit]