- Offizieller Beitrag
Ich habe mir eine Art dynamische MsgBox erstellt (InfoBox). Dient in erster Linie dazu, Key-Value Paare anzuzeigen. Man kann z.B. die Datensätze einer CSV Datei Satz für Satz anzeigen und die Feldnamen und -Inhalte werden anhand ihrer Länge sauber positioniert. Dazu werden die Label, die die Werte anzeigen, in ihrer Höhe verändert um Multilinefähig zu sein.
Dabei ist mir übrigens aufgefallen, dass bei Verwendung von GuiCtrlSetData() der neue Inhalt das Label nicht beeinflusst. D.h. man muss es immer wieder löschen und neu erstellen um Werte in dynamischer Größe anzeigen zu können.
Nun die entsprechenden Berechnungen funktionieren auch wie erwartet. Das einzige Problem: Wenn ich aufgrund veränderter Labelpositionen auch das Fenster in der Größe ändern muss, werden die Multiline-Label geschrottet und die ganze Anzeige fliegt mir um die Ohren. Die Problemfunktion ist tatsächlich WinMove. Kommentiere ich den Aufruf aus, wird alles korrekt positioniert (z.T. dann ausserhalb des sichtbaren Bereiches).
Das Verhalten kann ich in keiner anderen Konstellation rekonstruieren. Einfache GUI mit mehrzeiligem Label - WinMove - alles ist gut.
Ich habe im Moment keine Idee. Vielleicht seht ihr mehr als ich.
Hier das Skript, der betreffende Bereich ist markiert:
[EDIT] Lösung: GUICtrlSetPos statt ControlMove verwenden
;-- TIME_STAMP 2020-03-28 14:07:26
Local $oAdressBox = _InfoBoxCreate('Meine Adressen', 'Name;Vorname;Strasse Nr;PLZ;Ort;Geburtstag', -1, -1, -1, -1, -1, ';')
Local $csv = _
'Meier;Johannes;Grubenweg 18;12345;Münchhausenhofen;01.04.1985' & @LF & _
'Name der so lang ist, dass er breiter ist, als die zur Verfügung stehende ValueLabel-Breite;Kurt;Am Hänschenhof 33;89553;Burghausenhofen;12.12.1991' & @LF & _
'Müller;Irma;Am Alten Forstweg 125;33778;Musterwertshausen;23.12.1956'
Local $aCSV = StringSplit($csv, @LF, 1)
For $i = 1 To $aCSV[0]
_InfoBoxShow($oAdressBox, $aCSV[$i], -1, ';')
Next
Func _InfoBoxCreate($_sTitle, $_sKeyNames, $_xPos=-1, $_yPos=-1, $_wSize=400, $_hSize=200, _
$_iMargin=15, $_sDelim=Opt("GUIDataSeparatorChar"))
If $_wSize = -1 Then $_wSize = 400
If $_hSize = -1 Then $_hSize = 200
If $_iMargin = -1 Then $_iMargin = 15
Local $oInfoBox = ObjCreate("Scripting.Dictionary")
Local $aSplit = StringSplit($_sKeyNames, $_sDelim, 1)
$oInfoBox.Add('__Title__', $_sTitle)
$oInfoBox.Add('__iMargin__', $_iMargin)
$oInfoBox.Add('__maxLenKey__', Int(($_wSize-$_iMargin)/4)) ; 25% von Fensterbreite abzgl. 1*Rand
$oInfoBox.Add('__maxLenVal__', $_wSize-$oInfoBox.Item('__maxLenKey__')-$_iMargin-10) ; Platz rechts von Key, abzgl. Abstand zu Key(10) und 1*Rand
$oInfoBox.Add('__hWnd__', GUICreate('', $_wSize, $_hSize, $_xPos, $_yPos, BitOR(0x00800000,0x80000000))) ; WS_BORDER,WS_POPUP
GUISetFont(10, 400, Default, 'Courier New', HWnd($oInfoBox.Item('__hWnd__')))
GUISetBkColor(0xFFFFFF)
Local $sTitle = GUICtrlCreateLabel($_sTitle, 10, 10, $_wSize-20) ; Titelposition fix mit Abstand 10 zu Fensterrändern
GUICtrlSetColor(-1, 0x000080)
GUICtrlSetFont(-1, 11, 600, Default, 'Consolas')
Local $yKey, $yNew = 35, $aNewY, $aKeyID[$aSplit[0]][6] ; [[ID-Key, maxY-Key, ID-Val, maxY-Val, iHeightKey, iHeightVal]]
For $i = 1 To $aSplit[0]
$oInfoBox.Add($aSplit[$i], '')
$aKeyID[$i-1][0] = GUICtrlCreateLabel($aSplit[$i], 15, $yNew, $oInfoBox.Item('__maxLenKey__'))
GUICtrlSetColor(-1, 0x8181C0)
$aNewY = __InfoBox_NewY(HWnd($oInfoBox.Item('__hWnd__')), $aKeyID[$i-1][0], $yNew, $oInfoBox.Item('__maxLenKey__'))
ControlMove(HWnd($oInfoBox.Item('__hWnd__')), '', $aKeyID[$i-1][0], $aNewY[1], $aNewY[2], _
$oInfoBox.Item('__maxLenKey__'), $yNew+$aNewY[0])
$aKeyID[$i-1][1] = $yNew+$aNewY[0] ; maxPosY Label
$aKeyID[$i-1][4] = $aNewY[0] ; Höhe Label
$yNew += $aNewY[0] +10
Next
$oInfoBox.Add('__aKeyID__', $aKeyID)
$oInfoBox.Add('__cClose__', GUICtrlCreateButton('OK', $_wSize-75, $yNew, 60, 22, 0x0001)) ; $BS_DEFPUSHBUTTON
$yNew += 32 ; Buttonhöhe + Diff 10
; Resizen Window
Local $aWin = WinGetPos(HWnd($oInfoBox.Item('__hWnd__')))
WinMove(HWnd($oInfoBox.Item('__hWnd__')), '', $aWin[0], $aWin[1], $aWin[2], $yNew )
Return $oInfoBox
EndFunc
Func _InfoBoxShow(ByRef $_oBox, $_sText, $_sTitle=-1, $_sDelim=Opt("GUIDataSeparatorChar"))
Local $hWnd = HWnd($_oBox.Item('__hWnd__'))
Local $hLast = GUISwitch($hWnd)
If $_sTitle <> -1 Then
$_oBox.Item('__Title__') = $_sTitle
GUICtrlSetData($_oBox.Item('__Title__'), $_sTitle)
EndIf
Local $aID = $_oBox.Item('__aKeyID__')
Local $aVal = StringSplit($_sText, $_sDelim, 1)
Local $yNew = 35, $aNewY, $aPos
; alle Val-Label erstellen
For $i = 1 To $aVal[0]
; Val setzen, dazu muss Ctrl neu erstellt werden um korrekte Größe zu ermitteln
; GUICtrlSetData() verändert nicht die Ctrl-Größe!
GUICtrlDelete($aID[$i-1][2])
$aID[$i-1][2] = GUICtrlCreateLabel($aVal[$i], ($_oBox.Item('__iMargin__')+ _
$_oBox.Item('__maxLenKey__')+10), $yNew)
GUICtrlSetColor(-1, 0x000080)
; Platzbedarf ermitteln
$aNewY = __InfoBox_NewY($hWnd, $aID[$i-1][2], $yNew, $_oBox.Item('__maxLenVal__'))
$aID[$i-1][3] = $yNew +$aNewY[0] ; maxPosY Label
$aID[$i-1][5] = $aNewY[0] ; Höhe Label
If $aNewY[0] > 25 Then ; mehr als 1 Zeile
ControlMove($hWnd, '', $aID[$i-1][2], $aNewY[1], $aNewY[2], _
$_oBox.Item('__maxLenVal__'), $yNew+$aNewY[0])
EndIf
$yNew += $aNewY[0] +10
Next
Local $yLastKey, $yLastVal, $bChanged = False
For $i = 1 To UBound($aID) -1 ; erstes Ctrl überspringen, da keine untersch. y-Pos möglich
$yLastKey = $aID[$i-1][1]
$yLastVal = $aID[$i-1][3]
If $yLastKey = $yLastVal Then
$yNew = $yLastKey +10
ElseIf $yLastKey < $yLastVal Then ; Value vertikal Size > Key vertikal Size
$yNew = $yLastVal +10
Else ; Value vertikal Size < Key vertikal Size
$yNew = $yLastKey +10
EndIf
If $yNew <> $aID[$i][4] - $aID[$i][1] Then ; Key muss verschoben werden
$aPos = ControlGetPos($hWnd, '', $aID[$i][0])
$aID[$i][1] = $yNew+$aID[$i][4]
ControlMove($hWnd, '', $aID[$i][0], $aPos[0], $yNew, $aPos[2], $aID[$i][1])
$bChanged = True
EndIf
If $yNew <> $aID[$i][5] - $aID[$i][3] Then ; Val muss verschoben werden
$aPos = ControlGetPos($hWnd, '', $aID[$i][2])
$aID[$i][3] = $yNew+$aID[$i][5]
ControlMove($hWnd, '', $aID[$i][2], $aPos[0], $yNew, $aPos[2], $aID[$i][3])
$bChanged = True
EndIf
Next
; OK-Button verschieben und Fenster Resizen
If $bChanged Then
$yNew = $aID[UBound($aID)-1][3] +10
$aPos = ControlGetPos($hWnd, '', $_oBox.Item('__cClose__'))
ControlMove($hWnd, '', $_oBox.Item('__cClose__'), $aPos[0], $yNew)
Local $aWin = WinGetPos($hWnd)
;###################################################################################################
; WinMove zerschießt die Labelgröße, aber nur hier im Skript. Wird es auskommentiert, bleiben die
; Label in richtiger Größe erhalten. Wenn Button 'OK' nicht sichtbar ist - mit <Enter> bestätigen.
WinMove($hWnd, '', $aWin[0], $aWin[1], $aWin[2], $yNew+10)
;###################################################################################################
EndIf
$_oBox.Item('__aKeyID__') = $aID
GUISetState(@SW_SHOW, $hWnd)
Local $opt = Opt('GUIOnEventMode', 0)
Do
Until GUIGetMsg() = $_oBox.Item('__cClose__')
GUISetState(@SW_HIDE, $hWnd)
Opt('GUIOnEventMode', $opt)
GUISwitch($hLast)
EndFunc
Func __InfoBox_NewY($_hGui, $_cCtrl, $_yLast, $_maxLenCtrl)
Local $aSize = ControlGetPos($_hGui, '', $_cCtrl)
Local $lenText = $aSize[2]
Local $factorLines = Ceiling($lenText / $_maxLenCtrl) ; Anzahl Zeilen für vorhandene Labelbreite
Local Const $rowHeight = 17
Local $hSizeLabel = $rowHeight*$factorLines
Local $aRet[] = [$hSizeLabel, $aSize[0], $aSize[1]]
Return $aRet
EndFunc
Alles anzeigen