Bei der Window-Prozedur muss man doch nur zur bisherigen Prozedur springen, dann ist auch eine Verkettung möglich.
Klar, so geht's ja. ![]()
Sollte man dann aber auch immer auf dem Schirm haben, dass das der Weg ist.
Bei der Window-Prozedur muss man doch nur zur bisherigen Prozedur springen, dann ist auch eine Verkettung möglich.
Klar, so geht's ja. ![]()
Sollte man dann aber auch immer auf dem Schirm haben, dass das der Weg ist.
Es gibt ein Problem:
Es eignet sich für eine vernünftige Performance eigentlich nur ein Hook (bzw. 2: Key- und WM). Was zum Problem führt, dass der User später keinen eigenen (gleichartigen) Hook in seinem Code einbauen kann, da dieser in der UDF bereits registriert ist. Vielleicht ist es schonmal jemandem gelungen, das in einen anderen Prozess oder Thread auszulagern und ggf. über IPC zu kommunizieren.
Die Auswertung von Shift, Capslock, etc. ist auf den ersten Blick etwas schwierig, bis man es dann mal gemacht hat. Ich hatte mal eine derartige Auswertesoftware geschrieben zum Aufspüren von Benutzerfehlern an neuer Software. Wobei hier die erfassten Zeichen parallel in der Statusleiste angezeigt wurden, damit die Kontrolle nicht "heimlich" lief.
Wenn ich am WE wieder daheim bin, kann ich das gern mal vorsuchen.
Was du noch vergessen hast an Eigenschaften:
Bewegen des Cursor im Ctrl mit
- Pfeil li/re/auf/ab
- Home/End
- Kombinationen mit Shift/Ctrl und daraus resultierende Textmarkierung
Diese Eigenschaften waren mein allererstes Programm - geschrieben in Turbopascal zur Ausführung in der Konsole (Nachbildung des Userinput von dbase) ![]()
Ist es eigentlich möglich, mehrere Variablen in eine Variable zu packen
Ja, dazu gibt es den Variablentyp Array.
Mit der Funktion _GetColorWithBrightness erhaltet ihr zu einer RGB-Farbe den um n-Helligkeitschritte (+/-) oder auf eine fixe Helligkeit geänderten Farbwert.
Bei den reinen Farben (R, G, B) sind recht große Schritte erforderlich (ca. 10), bei Mischfarben reichen meist Schrittweiten von 2-3. Könnt ihr im Bsp.-Skript testen.
;-- TIME_STAMP 2022-09-30 12:10:37
_TestBrightness(0xF5F5DC, 2)
_TestBrightness(0x0000FF, 10)
_TestBrightness(0xE9967A, 4)
Func _TestBrightness($_RGB, $_step)
Local $hGui = GUICreate('Test Brightness', 400, 200)
Local $RGB2 = $_RGB, $aL1[6], $aL2[6], $y
GUICtrlCreateLabel('AUFHELLEN', 10, 10)
GUICtrlCreateLabel('ABDUNKELN', 200, 10)
For $i = 0 To UBound($aL1) -1
$y = 30 + $i*21
$aL1[$i] = GUICtrlCreateLabel('', 10, $y, 180, 20)
$aL2[$i] = GUICtrlCreateLabel('', 200, $y, 180, 20)
Next
GUICtrlSetBkColor($aL1[0], $_RGB)
GUICtrlSetBkColor($aL2[0], $RGB2)
For $i = 1 To UBound($aL1) -1
$_RGB = _GetColorWithBrightness($_RGB, $_step)
GUICtrlSetBkColor($aL1[$i], $_RGB)
$RGB2 = _GetColorWithBrightness($RGB2, (-1)*$_step)
GUICtrlSetBkColor($aL2[$i], $RGB2)
Next
GUISetState()
Do
Until GUIGetMsg() = -3
GUIDelete($hGui)
EndFunc
; #FUNCTION# =======================================================================================
; Name ..........: _GetColorWithBrightness
; Description ...: Gibt zu einer Farbe die auf einen Helligkeitswert geänderte Farbe zurück
; Parameter(s)...: $_RGB
; ....[optional].: $_iStep Zur Änderung der Helligkeit um einzelne Schritte (+/-), (Default: 0)
; ...............: Nur wirksam, wenn "$_iBrightness=Null".
; ....[optional].: $_iBrightness Zur Änderung der Helligkeit auf einen fixen Wert (Default: Null)
; Return values .: Success Der neue Farbwert
; ...............: Failure Der Farbwert, wie übergeben ($_iStep/$_iBrightness nicht angegeben)
; Author ........: BugFix
; ==================================================================================================
Func _GetColorWithBrightness($_RGB, $_iStep=0, $_iBrightness=Null)
Local $R = BitAND(BitShift($_RGB, 16), 0xFF)
Local $G = BitAND(BitShift($_RGB, 8), 0xFF)
Local $B = BitAND($_RGB, 0xFF)
Local $R1 = $R, $G1 = $G, $B1 = $B
Local $Brightness = Int(Sqrt($R^2*0.299 + $G^2*0.587 + $B^2*0.114))
If $_iBrightness = Null Then ; Schrittweite wird verwendet
$_iBrightness = $Brightness + ($_iStep)
EndIf
$_iBrightness = $_iBrightness < 0 ? 0 : ($_iBrightness > 255 ? 255 : $_iBrightness)
If $_iBrightness > $Brightness Then
While $Brightness < $_iBrightness
$R1 = $R1 +1 > 255 ? 255 : $R1 +1
$G1 = $G1 +1 > 255 ? 255 : $G1 +1
$B1 = $B1 +1 > 255 ? 255 : $B1 +1
$Brightness = Int(Sqrt($R1^2*0.299 + $G1^2*0.587 + $B1^2*0.114))
WEnd
ElseIf $_iBrightness < $Brightness Then
While $Brightness > $_iBrightness
$R1 = $R1 -1 < 0 ? 0 : $R1 -1
$G1 = $G1 -1 < 0 ? 0 : $G1 -1
$B1 = $B1 -1 < 0 ? 0 : $B1 -1
$Brightness = Int(Sqrt($R1^2*0.299 + $G1^2*0.587 + $B1^2*0.114))
WEnd
EndIf
Return '0x' & Hex($R1,2) & Hex($G1,2) & Hex($B1,2)
EndFunc
Alles anzeigen
ListCtrl mit AlternateColors
import wNim/[wApp, wWindow, wFrame, wPanel, wListCtrl]
import winim/[inc\commctrl]
# ------------------------------------------------------------------------------
type
ListHead = tuple[text: string, format: int, width: int]
ListText = seq[string]
proc setListColumns(list: wListCtrl, head: openArray[ListHead]) =
for i in 0..<head.len:
list.appendColumn(text=head[i][0], width=head[i][2])
list.setColumnFormat(i, head[i][1])
proc setListText(list: wListCtrl, stuff: openArray[ListText]) =
var item: int
for i in 0..<stuff.len:
item = list.appendItem(stuff[i][0])
for j in 1..<stuff[i].len:
list.setItem(item, j, stuff[i][j])
# ------------------------------------------------------------------------------
let
app = App()
frame = Frame(title="Test Alternate Color",size=(500,250))
panel = frame.Panel()
lc1 = panel.ListCtrl(style=wLcReport or wBorderDouble or wLcSingleSel or wLcNoSortHeader)
lc2 = panel.ListCtrl(style=wLcReport or wBorderDouble or wLcSingleSel or wLcNoSortHeader)
lc1.setExtendedStyle(LVS_EX_GRIDLINES)
lc1.setListColumns([
("Column 1",wListFormatLeft,110),
("Column 2",wListFormatLeft,110)])
lc1.setListText([@["1111","2222"], @["3333","4444"], @["5555","6666"]])
lc2.setExtendedStyle(LVS_EX_GRIDLINES)
lc2.setListColumns([
("Column 1",wListFormatLeft,110),
("Column 2",wListFormatLeft,110)])
lc2.setListText([@["7777","8888"], @["9999","0000"], @["1122","3344"]])
# Listview 1: even / odd color setzen (ARGB konvertieren zu wColor)
lc1.setBackgroundColor(0x00B0E0E6.wColor)
lc1.setAlternateRowColor(wLightBlue)
# Listview 2: even color setzen, odd color berechnet
lc2.setBackgroundColor(0x00B0E0E6.wColor)
lc2.enableAlternateRowColors()
proc layout() =
panel.autolayout """
|-[lc1(==lc2)]-[lc2]-|
V:|-[lc1]-|
V:|-[lc2]-|
"""
frame.wIdExit do ():
frame.delete()
layout()
frame.center()
frame.show()
app.mainLoop()
Alles anzeigen
Um im Listview die Zeilen abwechselnd zu färben werden mit GuiCtrlSetBkColor($Listview, COLOR_ODD) die Farbe für die ungeraden Zeilen bestimmt und das Setzen des Flag GUICtrlSetBkColor($Listview, $GUI_BKCOLOR_LV_ALTERNATE) ermöglicht dann bei der Erstellung der ListviewItem mit GuiCtrlSetBkColor($Listview, COLOR_EVEN) die Färbung der geraden Zeilen zu definieren.
Optisch gefällt mir an der Variante nicht, dass der gesamte Listviewhintergrund (auch ohne Dateninhalt) eingefärbt wird.
Zum anderen wäre es doch praktisch, die alternative Farbe automatisch zu bestimmen, wenn man keinen speziellen Wunsch hat. (Diese Möglichkeit habe ich in Nim entdeckt)
Ich habe das noch kombiniert mit der Berechnung der Farbe für den Text (Farbe für hellen oder dunklen Hintergrund), damit ein ausreichender Kontrast zum Lesen vorhanden ist. Gefärbt werden nun ausschließlich die mit Daten befüllten Item.
Vielleicht könnt ihr es brauchen.
EDIT: Da war noch ein Fehler drin. Durch die Berechnung entstanden Floatzahlen, die durch die Funktion Hex nicht verarbeitet werden können.
Zusätzlich wird jetzt ohne Angabe von Farben weiß/grau verwendet.
;-- TIME_STAMP 2022-09-29 16:01:46
#include <GUIConstantsEx.au3>
_AlternateColors_ByFlag()
_AlternateColors_EvenByUser()
_AlternateColors_EvenCalculated(0xEFE4B0)
_AlternateColors_EvenCalculated(0xFFD700)
_AlternateColors_EvenCalculated(0xDC143C)
_AlternateColors_EvenCalculated(0x00FF00)
_AlternateColors_EvenCalculated(0xA0A0A0)
_AlternateColors_EvenCalculated() ; ohne Angabe: weiß / grau
Func _AlternateColors_ByFlag()
Local $hGui = GUICreate('AlternateColors by Flag')
Local $LV = GUICtrlCreateListView("Col 1|Col 2", 15, 15, 300, 250)
GUICtrlSetBkColor(-1, 0xEFE4B0) ; Color odd row
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_LV_ALTERNATE)
For $i = 1 To 30
GUICtrlCreateListViewItem(Random(10000, 1000000, 1) & '|' & Random(10000, 1000000, 1), $LV)
GUICtrlSetBkColor(-1, 0xC8BFE7) ; Color even row
Next
GUISetState()
Do
Until GUIGetMsg() = -3
GUIDelete($hGui)
EndFunc
Func _AlternateColors_EvenByUser()
Local $hGui = GUICreate('AlternateColors by User')
Local $LV = GUICtrlCreateListView("Col 1|Col 2", 15, 15, 300, 250)
For $i = 1 To 30
GUICtrlCreateListViewItem(Random(10000, 1000000, 1) & '|' & Random(10000, 1000000, 1), $LV)
_LV_SetAlternateBkColor($i-1, 0xC8BFE7, 0xEFE4B0) ; color even, color odd - by user
Next
GUISetState()
Do
Until GUIGetMsg() = -3
GUIDelete($hGui)
EndFunc
Func _AlternateColors_EvenCalculated($_colorOdd=-1)
Local $hGui = GUICreate('AlternateColors Calculated')
Local $LV = GUICtrlCreateListView("Col 1|Col 2", 15, 15, 300, 250)
For $i = 1 To 30
GUICtrlCreateListViewItem(Random(10000, 1000000, 1) & '|' & Random(10000, 1000000, 1), $LV)
_LV_SetAlternateBkColor($i-1, $_colorOdd) ; color odd, color even - calculated
Next
GUISetState()
Do
Until GUIGetMsg() = -3
GUIDelete($hGui)
EndFunc
Func _LV_SetAlternateBkColor($_Index, $_RGBodd=-1, $_RGBeven=-1, $_ColOnDark=-1, $_ColOnBright=-1)
$_RGBodd = $_RGBodd = -1 ? 0xFFFFFF : $_RGBodd
$_ColOnDark = $_ColOnDark = -1 ? 0xFAFAFA : $_ColOnDark
$_ColOnBright = $_ColOnBright = -1 ? 0x000088 : $_ColOnBright
Local $R, $G, $B
If Mod($_Index, 2) <> 0 Then
GUICtrlSetBkColor(-1, $_RGBodd)
Else
If $_RGBeven = -1 Then
$R = Int(0.8*BitAND(BitShift($_RGBodd, 16), 0xFF))
$G = Int(0.8*BitAND(BitShift($_RGBodd, 8), 0xFF))
$B = Int(0.8*BitAND($_RGBodd, 0xFF))
$_RGBeven = '0x' & Hex($R, 2) & Hex($G, 2) & Hex($B, 2)
EndIf
GUICtrlSetBkColor(-1, $_RGBeven)
EndIf
GUICtrlSetColor(-1, _RGB_GetContrast((Mod($_Index, 2) <> 0 ? $_RGBodd : $_RGBeven), $_ColOnDark, $_ColOnBright))
EndFunc
Func _RGB_GetContrast($_RGB, $_ColOnDark=0xFAFAFA, $_colOnBright=0x000088)
; get brightness
Local $R = BitAND(BitShift($_RGB, 16), 0xFF)
Local $G = BitAND(BitShift($_RGB, 8), 0xFF)
Local $B = BitAND($_RGB, 0xFF)
Local $Brightness = Sqrt($R^2*0.299 + $G^2*0.587 + $B^2*0.114)
If $Brightness < 140 Then ; dark
Return $_ColOnDark ; contrast text color if background is dark
Else
Return $_colOnBright ; contrast text color if background is bright
EndIf
EndFunc
Alles anzeigen
Standard:
[_LV_SetAlternateBkColor] User setzt Farbe für odd und even:
[_LV_SetAlternateBkColor] User setzt nur Farbe für odd:
Da finde ich jede Menge...
Klassischer Fall von Eigentor.
Mir war zwar klar, dass die Ctrl als Fenster behandelt werden - nach der setFocus Prozedur hatte ich aber in den Ctrl-Dokus gesucht. Es gibt ja aber das übergeordnete wWindow, dem die Ctrl angehören. Und somit sind die dort dokumentierten Prozeduren auch für die Ctrl gültig.
Kannst Du bitte kurz beschreiben, wofür Du einen Impressumgrabber brauchst
Hab ich mich auch schon gefragt.
Ich befürchte um Firmen mit ungewollter Werbung zuzuschei... Im Gegensatz zu Privatpersonen können sich Firmen leider nicht dagegen wehren. (Außer DNS-Attacke als Antwort
)
allerdings meckert VSCodium:
"message": 'setFocus' is declared but not used [XDeclaredButNotUsed]
Das hat mich auch gewundert.
Ich will grundsätzlich nichts ausschließen und halte es deshalb für möglich, dass diese proceure in den Tiefen der Includes doch schon existiert (aber dokumentiert habe ich es nicht gefunden). Somit wäre sie doppelt - und deshalb "nicht genutzt" ?
Die Funktion hatte ich schmerzlich vermisst. Deshalb habe ich sie mir erstellt.
Ich war auf Irrwegen
- s. Post #5
Um Zugriff auf die fenstertypischen Prozeduren zu bekommen muss nur wWindow importiert werden:
# compile: nim c --app:gui testfocus.nim
include winim/[inc\winuser]
import wNim/[wApp, wFrame, wPanel, wListBox, wTextCtrl]
# sets the focus to passed handle
# required: include winim/[inc\winuser]
proc setFocus(hwnd: HWND): WINBOOL {.discardable, stdcall, dynlib: "user32", importc: "SetFocus".}
let
app = App()
frame = Frame(title="Test Focus",size=(400,250))
panel = frame.Panel()
lb = panel.ListBox(style=wLbNeededScroll or wLbNoSel)
tc = panel.TextCtrl(style=wBorderSunken)
for e in @["Eintrag A","Eintrag B","Eintrag C","Eintrag D"]:
lb.append(e)
# Fokus liegt jetzt auf: lb
# setzen auf: tc
tc.setFocus()
proc layout() =
panel.layout:
lb:
left = 10
top = 30
width = 120
height = 100
tc:
left = 20
top = lb.bottom + 20
width = 80
height = 20
frame.wIdExit do ():
frame.delete()
layout()
frame.center()
frame.show()
app.mainLoop()
Alles anzeigen
GELÖST
So, bin nun auf kleinem Umweg zum Ziel (Objekt) gelangt. Wobei ich hier nur die Fehlerinfos in das Objekt lade, die anderen Nodes sind ja direkt abfragbar.
import json
type
oErrCode = object
code: string
device: seq[JsonNode]
name: string
description: string
reason: seq[JsonNode]
disposal: seq[JsonNode]
remark: string
let str_json =
"""
{
"title": "Test",
"author": "BugFix",
"articles": [
{"number": "a123", "storage_location": "D-75"},
{"number": "b456", "storage_location": "C-145"},
{"number": "c789", "storage_location": "H-63"}
],
"error_list": [
{
"code": "101",
"device": ["dev A","dev B","dev C"],
"name": "SensorErrBla",
"description": "Sensorfehler",
"reason": ["Mainboard defekt"],
"disposal": ["Mainboard ersetzen"],
"remark": ""
},
{
"code": "101",
"device": ["dev D","dev E","dev F"],
"name": "SensorErrBlub",
"description": "Sensorfehler",
"reason": ["Mainboard defekt"],
"disposal": ["Mainboard ersetzen"],
"remark": ""
},
{
"code": "102",
"device": ["dev A","dev B","dev C"],
"name": "BatteryErrBla",
"description": "Akkufehler",
"reason": ["Akku defekt","Controllerboard defekt"],
"disposal": ["Akku erstzen","Controllerboard ersetzen"],
"remark": ""
},
{
"code": "102",
"device": ["dev D","dev E","dev F"],
"name": "BatteryErrBlub",
"description": "Akkufehler",
"reason": ["Akku defekt","Controllerboard defekt","Mainboard defekt"],
"disposal": ["Akku erstzen","Controllerboard ersetzen","Mainboard ersetzen"],
"remark": "Bei Akkutausch: Reset Nutzung im Wartungsmenü"
}
]
}
"""
let parsed_json = parseJson(str_json)
proc getErrCodes(jn: JsonNode, errcode = ""): seq[oErrCode] =
var
s_errors = newSeq[oErrCode]()
oErr: oErrCode
let a_errlist = jn["error_list"].getElems()
for err in a_errlist:
if errcode == "" or (errcode != "" and errcode == err["code"].getStr()):
oErr.code = err["code"].getStr()
oErr.device = @(err["device"].getElems())
oErr.name = err["name"].getStr()
oErr.description = err["description"].getStr()
oErr.reason = @(err["reason"].getElems())
oErr.disposal = @(err["disposal"].getElems())
oErr.remark = err["remark"].getStr()
s_errors.add(oErr)
result = s_errors
let sError102 = getErrCodes(parsed_json, "102")
for oE in sError102:
echo oE.code & ", " & oE.name
echo oE.device
echo "----------------------------------------"
Alles anzeigen
Ich meinte hier:
Das ist keine JSON-Datei, sondern nur die Struktur mit Kommentaren (die in JSON-Dateien ja nicht möglich sind).
OK, ich löse das Problem nun anders. Die Verschachtelung der error_list konnte von der json Funktion nicht geparst werden, ich bekam ein Objekt mit einem leeren Array.
Somit habe ich das um eine Stufe "entschachtelt" und führe den Error-Code in jedem Error-List Objekt mit.
import json
let str_json =
"""
{
"title": "Test",
"author": "BugFix",
"articles": [
{"number": "a123", "storage_location": "D-75"},
{"number": "b456", "storage_location": "C-145"},
{"number": "c789", "storage_location": "H-63"}
],
"error_list": [
{
"code": "101",
"device": ["dev A","dev B","dev C"],
"name": "SensorErrBla",
"description": "Sensorfehler",
"reason": ["Mainboard defekt"],
"disposal": ["Mainboard ersetzen"],
"remark": ""
},
{
"code": "101",
"device": ["dev D","dev E","dev F"],
"name": "SensorErrBlub",
"description": "Sensorfehler",
"reason": ["Mainboard defekt"],
"disposal": ["Mainboard ersetzen"],
"remark": ""
},
{
"code": "102",
"device": ["dev A","dev B","dev C"],
"name": "BatteryErrBla",
"description": "Akkufehler",
"reason": ["Akku defekt","Controllerboard defekt"],
"disposal": ["Akku erstzen","Controllerboard ersetzen"],
"remark": ""
},
{
"code": "102",
"device": ["dev D","dev E","dev F"],
"name": "BatteryErrBlub",
"description": "Akkufehler",
"reason": ["Akku defekt","Controllerboard defekt","Mainboard defekt"],
"disposal": ["Akku erstzen","Controllerboard ersetzen","Mainboard ersetzen"],
"remark": "Bei Akkutausch: Reset Nutzung im Wartungsmenü"
}
]
}
"""
let
parse_json = parseJson(str_json)
a_errlist = parse_json["error_list"].getElems()
for e in a_errlist:
if e["code"].getStr() == "102": echo e["name"].getStr(), ": ", e["device"].getElems()
Alles anzeigen
ZitatAlles anzeigenFunction _WinAPI_FileInUse
Tests whether the specified file in use by another application
#include <WinAPIFiles.au3>
_WinAPI_FileInUse ( $sFilePath )
Success: 1 - File in use by another application.
Failure: 0.
Fehlt dir in Zeile 18 deines Json strings nicht ein ","? Wobei das natürlich ein Copy/Paste Fehler sein kann, da du ja sicher mit anderen Daten arbeitest.
Kann sein, dass ich den Wald vor lauter Bäumen nicht sehe.
Zeile #18 des JSON ist doch Code-Zeile #43
43 ],
44 "error_list": {
45 "101": [
Da ist doch ein Komma. Oder wo meinst Du? Gib mal die Codezeile an oder kopiere die Zeile hier rein.
EDIT #3: Lösung mit geänderter JSON-Struktur hier: Post #4
Lösung mit Überführung in Objekt hier: Post #7
Ich hatte hier auf meine JSON-Datei verwiesen.
Die Umsetzung in mein Projekt soll in Nim erfolgen.
Ich habe die Struktur der JSON-Datei mal heruntergebrochen auf ein Minimum:
{
"KEY": "Value-String", "# Version"
"KEY": "Value-String", "# Creator"
"KEY": [ "# Source: ARRAY OBJEKTE - keine fixe Anzahl"
{
"KEY": "Value-String", "# product-number"
"KEY": "Value-String" "# title"
}
],
"KEY": { "# error-list: OBJEKT"
"KEY": [ "# error-code: ARRAY OBJEKTE - keine fixe Anzahl"
{
"KEY": ["Array Strings - keine fixe Anzahl"], "# device"
"KEY": "Value-String", "# name"
"KEY": "Value-String", "# description"
"KEY": ["Array Strings - keine fixe Anzahl"], "# reason"
"KEY": ["Array Strings - keine fixe Anzahl"], "# disposal"
"KEY": "Value-String" "# remark"
}
]
}
}
Alles anzeigen
Die Nim JSON Library bietet die Möglichkeit, die geparsten JSON-Daten in ein Objekt zu überführen.
Somit habe ich auf obiger Struktur aufbauend meine Datentypen erstellt.
Hier mal meine Testdatei mit minimalem JSON-Musterdatensatz:
import json
type
oSource = object
product_number: string
product_title: string
oErrCode = object
device: openArray[string]
name: string
description: string
reason: openArray[string]
disposal: openArray[string]
remark: string
oErrListItem = object
code_number: string
code_item: openArray[oErrCode]
oErrList = object
errors: openArray[oErrListItem]
oError = object
version: string
craetor: string
source: openArray[oSource]
error_list: oErrList
let err_json =
"""
{
"version": "2022-09",
"creator": "BugFix",
"source": [
{
"product_number": "XYZ 123ab",
"product_title": "Servicemanual für Geräte des Typs A / B"
},
{
"product_number": "XYZ 123c",
"product_title": "Servicemanual für Geräte des Typs C"
},
{
"product_number": "XYZ 123def",
"product_title": "Servicemanual für Geräte des Typs D / E / F"
}
],
"error_list": {
"101": [
{
"device": ["dev A","dev B","dev C"],
"name": "SensorErrBla",
"description": "Sensorfehler",
"reason": ["Mainboard defekt"],
"disposal": ["Mainboard ersetzen"],
"remark": ""
},
{
"device": ["dev D","dev E","dev F"],
"name": "SensorErrBlub",
"description": "Sensorfehler",
"reason": ["Mainboard defekt"],
"disposal": ["Mainboard ersetzen"],
"remark": ""
}
],
"102": [
{
"device": ["dev A","dev B"],
"name": "BatteryErrBla",
"description": "Akkufehler",
"reason": ["Akku defekt","Controllerboard defekt"],
"disposal": ["Akku erstzen","Controllerboard ersetzen"],
"remark": "Bei Akkutausch: Reset Nutzung im Wartungsmenü"
},
{
"device": ["dev C"],
"name": "BatteryErrBlub",
"description": "Akkuladefehler",
"reason": ["Controllerboard defekt"],
"disposal": ["Controllerboard ersetzen"],
"remark": ""
},
{
"device": ["dev D","dev D],
"name": "BatteryErrBlaBlub",
"description": "Akkufehler",
"reason": ["Akku defekt","Akku nicht vorhanden"],
"disposal": ["Akku ersetzen","Akku einsetzen"],
"remark": "Bei Akkutausch: Reset Nutzung im Wartungsmenü"
}
]
}
}
"""
let
obj_json = parseJson(err_json) # JSON String parsen
oErrorsJSON = to(obj_json, oError) # JSON String in mein Objekt überführen
echo oErrorsJSON.creator
Alles anzeigen
Grundsätzlich ist die Überführung verschachtelteter Strukturen in ein Objekt möglich: Nim: How to parse nested JSON into objects
Im dortigen Bsp. sind jedoch alle Daten fix.
Ich habe jedoch in allen Arrays eine veränderliche Anzahl von Einträgen, deshalb die Nutzung von "openArray". Und hier liegt das Problem. Gleich beim ersten Auftauchen fliegt es mir um die Ohren:
Error: type mismatch: got <openArray[oSource], JsonNode, string>
but expected one of:
proc initFromJson(dst: var JsonNode; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var JsonNode
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson(dst: var bool; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var bool
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson(dst: var string; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var string
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[S, T](dst: var array[S, T]; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var array[S, T]
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var T: SomeFloat
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var T: SomeInteger
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var T: distinct
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T: enum](dst: var T; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var T: enum
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T: object | tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var T: object or tuple
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var Option[initFromJson.T]
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T](dst: var OrderedTable[string, T]; jsonNode: JsonNode;
jsonPath: var string)
first type mismatch at position: 1
required type for dst: var OrderedTable[system.string, initFromJson.T]
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T](dst: var Table[string, T]; jsonNode: JsonNode;
jsonPath: var string)
first type mismatch at position: 1
required type for dst: var Table[system.string, initFromJson.T]
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var ref T
but expression 'dst.source' is of type: openArray[oSource]
proc initFromJson[T](dst: var seq[T]; jsonNode: JsonNode; jsonPath: var string)
first type mismatch at position: 1
required type for dst: var seq[T]
but expression 'dst.source' is of type: openArray[oSource]
Alles anzeigen
In einem ersten Versuch hatte ich statt "openArray[string]" mit Sequences gearbeitet. Nur schlägt auch das fehl, weil der JSON-Parser wohl erkennt, wenn Daten in einem Array vorliegen und die Übernahme in eine Sequenz ablehnt. - Fehlermeldung (Compile) war in etwa: "Type is seq[string] but array found".
Wie komme ich nun am besten aus der Situation raus?
Momentan fiele mir nur ein: Statt "openArray" mit "array[string,FIXE-ZAHL]" zu arbeiten und alle Einträge in der JSON-Datei entsprechend mit Leerwerten auffüllen.
Also wenn ihr Ideen habt: Gern her damit.
EDIT:
OK, in der Beschreibung zur Funktion to steht es auch
ZitatKnown limitations:
Heterogeneous arrays are not supported.
Dann muss ich mich wohl doch von Node zu Node hangeln.
EDIT #2:
Hmm, ein weiteres Problem
Mit dem JSON-String aus obigem Code
Führt zum Fehler bei der Ausführung:
C:\Users\BugFix\scoop\apps\nim\1.2.0\lib\pure\json.nim(931) parseJson
C:\Users\BugFix\scoop\apps\nim\1.2.0\lib\pure\json.nim(847) parseJson
C:\Users\BugFix\scoop\apps\nim\1.2.0\lib\pure\json.nim(806) parseJson
C:\Users\BugFix\scoop\apps\nim\1.2.0\lib\pure\json.nim(806) parseJson
C:\Users\BugFix\scoop\apps\nim\1.2.0\lib\pure\json.nim(815) parseJson
C:\Users\BugFix\scoop\apps\nim\1.2.0\lib\pure\json.nim(806) parseJson
C:\Users\BugFix\scoop\apps\nim\1.2.0\lib\pure\json.nim(818) parseJson
C:\Users\BugFix\scoop\apps\nim\1.2.0\lib\pure\parsejson.nim(526) eat
C:\Users\BugFix\scoop\apps\nim\1.2.0\lib\pure\parsejson.nim(522) raiseParseErr
Error: unhandled exception: input(36, 15) Error: ] expected [JsonParsingError]
Die Zeile, bevor der Error geworfen wird ist: eat(p, tkBracketRi)
Nach meinem Verständnis ein Fehler: Schließende Klammer nicht gefunden. Aber die Klammerzuordnung ist korrekt im JSON-String.
Großes ![]()
Es kommt zwar drauf an, wie viele Geräte du generell verwerwaltest,... Aber ich würde in Erwägung ziehen, die Infos nach Gerät zu speichern und dann ggf. alle durchiterieren, um die Geräte zu finden, die die Fehlermeldung haben.
Selbst wenn du 10000 Geräte hast dürfte das durchlaufen nicht lange dauern.
Der Hinweis ist grundsätzlich richtig. Ich hatte aber nicht erwähnt, dass es hier nur um Gerätetypen allgemein geht. Also nicht für jedes (mit Seriennnummer identifizierbare) Gerät werden Fehlercodes gespeichert, sondern nur über den Artikel als solchen. Und diese Anzahl ist bei uns überschaubar, so etwa 50-60 Artikel sind betroffen. Die Anzahl der relevanten Fehler ist bei etwa 30 - 40 pro Gerätetyp.
"error-list": {
"207": [
{
"device": ["prisma SMART/SOFT","prisma SMART/SOFT plus/max"],
"name": "TempSensorError",
"description": "Sensorfehler",
"reason": ["Temperatursensor defekt oder nicht angeschlossen","Mainboard defekt"],
"disposal": ["Temperatursensor ersetzen","Mainboard ersetzen"],
"remark": ""
},
{
"device": ["prisma VENT30/40/50","prisma VENT30-C/40-C/50-C"],
"name": "",
"description": "Modulfehler",
"reason": ["Verbindungskabel defekt","Mainboard defekt","PSG-Modul defekt","prisma CHECK defekt"],
"disposal": ["Verbindungskabel ersetzen","Mainboard ersetzen","PSG-Modul ersetzen","prisma CHECK ersetzen"],
"remark": ""
}
],
...
}
Alles anzeigen
Ich habe bei einigen Fehlercodes 2 max. 3 unterschiedliche Bedeutungen. Somit ist der Aufwand (s. Bsp.) auf 2 oder 3 Einträge begrenzt.
Eine Speicherung mit PrimärKey=Gerätetyp würde für jeden Eintrag aus dem Array "device" einen Eintrag erfordern mit allen anderen Angaben. Der obige Eintrag wäre dann doppelt so umfangreich und voll unnötiger Redundanzen.
Meiner Meinung nach ist die bisherige Variante für meinen Anwendungsfall passend.
Trotzdem Danke für die Investition deines Gehirnschmalzes. ![]()
Ich rate daher einfach mal und schlage folgenden Aufbau vor:
Danke, du hast schon richtig erahnt wohin ich wollte. Ich hatte keine Vorstellung, wie ich die Codes platziere, da sie mehrfach auftreten können aber eigentlich ja als Key fungieren sollen.
![]()
Ich möchte die Fehlerkataloge verschiedener Geräte in eine JSON-Datei überführen und damit eine Software füttern, mit der auch unsere Innendienstmitarbeiter telefonisch eine erste Diagnostik vornehmen können.
Meine Idee ist, dass der User den Fehlercode eingibt, Geräte die diesen Code verwenden angezeigt bekommt und dann für die weiteren Informationen das korrekte Gerät auswählt (bzw. dies im Dialog mit dem Kunden tut - das für den Fall, dass gerade kein Zugriff auf die Kundendaten möglich ist - z.B. tel. Notdienst).
Hier mal zwei fiktive Codes, die aber z.T. unterschiedliche Bedeutung haben können (je nach Gerät):
Fehlercode: 108
Geräte: Device_A, Device_B, Device_C
Bezeichnung: ClockTimeError
Beschreibung: Fehler Echtzeituhr
Ursachen: Uhrzeit nicht gestellt, Batterie auf Mainboard leer, Mainboard defekt
Beseitigung: Uhrzeit stellen, Batterie auf Mainboard ersetzen, Mainboard ersetzen
Fehlercode: 108
Geräte: Device_D, Device_E
Bezeichnung: TemperatureError
Beschreibung: Fehler Temperatursensor
Ursachen: Sensor defekt oder nicht angeschlossen
Beseitigung: Sensor anschliessen oder ersetzen
Fehlercode: 333
Geräte: Device_A, Device_B, Device_C, Device_D, Device_E
Bezeichnung: LogBatteryError
Beschreibung: Fehler Log-Speicherbatterie
Ursachen: Spannung auf kritischen Wert gefallen
Beseitigung: Batterie ersetzen
Alles anzeigen
In JSON würde ich das jetzt so anlegen:
{
"errorcode version": "0.0.1",
"error list": [
{
"code": 108 [
{
"device": ["Device_A", "Device_B", "Device_C"],
"name": "ClockTimeError",
"description": "Fehler Echtzeituhr",
"reason": ["Uhrzeit nicht gestellt", "Batterie auf Mainboard leer", "Mainboard defekt"],
"disposal": ["Uhrzeit stellen", "Batterie auf Mainboard ersetzen", "Mainboard ersetzen"]
},
{
"device": ["Device_D", "Device_E"],
"name": "TemperatureError",
"description": "Fehler Temperatursensor",
"reason": "Sensor defekt oder nicht angeschlossen",
"disposal": "Sensor anschliessen oder ersetzen"
}
],
"code": 333
{
"device": ["Device_A", "Device_B", "Device_C", "Device_D", "Device_E"],
"name": "LogBatteryError",
"description": "Fehler Log-Speicherbatterie",
"reason": "Spannung auf kritischen Wert gefallen",
"disposal": "Batterie ersetzen"
}
}
]
}
Alles anzeigen
Ist das in der Form korrekt?
Vom Ablauf her sieht das ja soweit OK aus (ich weiß nur nicht, warum die Sleep darin sind).
Ich würde es etwas anders gestalten:
$sCmd = "C:\Program Files (x86)\Sage\Sage 100\8.1\Shared\OLStart.exe /APP ABF /EXCL /DB ACCDE /VER 8.1"
$sClasshWnd = "[CLASS:OFormPopup]"
$sClassInstCtrl = "[CLASS:OFormSub; INSTANCE:2]"
; Run OLStart.exe
$PID = Run($sCmd )
$hWnd = WinWait($sClasshWnd)
WinActivate($hWnd)
If WinWaitActive($hWnd, 30) Then ; Timeout 30 s
; Wait for 30 seconds. <<< bezieht sich dein warten auf "WinWaitActive"? - s. TimeOut-Parameter
;~ Sleep(30000)
ControlSend($hWnd, "", $sClassInstCtrl, "{Enter}")
EndIf
Alles anzeigen
Wegen der Remote-Verbindung beachte das Edit in Post #4.