<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />Vor ein paar Jahren arbeitete ich an der Erstellung eines Skripts zur automatischen Generierung eines Stichprobenplans für eine attributive Messsystemanalyse. Alles lief reibungslos, bis ich auf ein großes Problem stieß: Wie könnte ich das Skript dazu bringen, ein Fenster aufzurufen, um die Master-„Gut/Schlecht“-Liste der verwendeten Teile zu erstellen, wenn die Anzahl der Teile zur Laufzeit ausgewählt wurde? Jetzt denken Sie vielleicht schon über eine einfache Möglichkeit nach, dies zu tun. Ich bin jedoch immer noch stolz auf die Methode, die ich entwickelt habe, und das werde ich in diesem Blogbeitrag teilen.
Im Programmierteil des JSL-Skriptindex sind zwei scheinbar harmlose Einträge versteckt: Eval und Parse. Diese Funktionen ermöglichen es einem geschickten Skriptersteller, einen String so auszuführen, als wäre er ein Codestück. Die Fähigkeit, dies zu tun, hat erstaunliche Auswirkungen. Dadurch kann auch mein Problem von früher gelöst werden.
Lassen Sie uns einsteigen, indem wir ein einfaches Skript erstellen:
//Abschnitt 1:
//Bestanden/Nicht bestanden-Kriterien für einen Teil abrufen
//Einige Variablen initialisieren
ich = 1 ;
listParts = {} ;
// Modales Fenster erstellen, um Kriterien abzurufen
Neues Fenster ( „Gut/Nicht bestanden-Liste abrufen“ ,
<< Modal ,
H-Listenfeld (
V-Listenfeld (
Aufstellungsbox ( 2 ,
Textfeld ( verkohlen ( ich )) , listParts [ ich ] = Textbearbeitungsfeld ( "Passieren" ) ,
Button-Box ( "OK" , listParts [ ich ] = listParts [ ich ] << Text abrufen ; ) , Button-Box ( "Stornieren" )
)
)
)
) ;
//Liste ansehen
zeigen ( listParts [ ich ]) ;
Stellen Sie sicher, dass das Protokoll angezeigt wird, und führen Sie dann dieses Skript aus. Das Skript selbst zeigt ein Fenster an und fragt nur für einen Teil, ob der Teil „Bestanden“ oder „Nicht bestanden“ ist. Wenn die Schaltfläche „OK“ gedrückt wird, wird der Text im Fenster an das i übergeben Th Position in der listParts-Liste, und listParts wird im Protokoll angezeigt. Das Speichern der Ergebnisse in einer Liste mit nur einem Element erscheint im Moment etwas albern, macht aber Sinn, wenn wir mehr als einen Teil haben, für den wir Pass/Fail-Kriterien speichern müssen. Im folgenden Beispiel sehen Sie, wie das Skript für drei Teile aussieht:
//Sektion 2:
//Wiederholung des obigen Skripts, aber mit Kriterien für 3 Teile
ich = 1 ;
listParts = {} ;
Neues Fenster ( „Gut/Nicht bestanden-Liste abrufen“ ,
<< Modal ,
H-Listenfeld (
V-Listenfeld (
Aufstellungsbox ( 2 ,
Textfeld ( verkohlen ( 1 )) , listParts [ 1 ] = Textbearbeitungsfeld ( "Passieren" ) ,
Textfeld ( verkohlen ( 2 )) , listParts [ 2 ] = Textbearbeitungsfeld ( "Passieren" ) ,
Textfeld ( verkohlen ( 3 )) , listParts [ 3 ] = Textbearbeitungsfeld ( "Passieren" ) ,
Button-Box ( "OK" , für ( ich = 1 , ich <= 3 , ich ++, listParts [ ich ] = listParts [ ich ] << Text abrufen ; )) , Button-Box ( "Stornieren" )
)
)
)
) ;
zeigen ( listParts ) ;
Aber wir haben das Problem noch nicht gelöst. Wie können wir dafür sorgen, dass dieses Skript eine dynamische Anzahl von Textfeldern anzeigt, die auf einer beliebigen Anzahl von Teilen basiert, die erst nach Beginn der Ausführung des Skripts bekannt ist und bei jeder Ausführung des Skripts unterschiedlich sein kann? Zur Rettung kommen Eval und Parse, die oben genannten Wunderkinder. Schauen Sie sich den folgenden Code an:
//Sektion 3:
//Anzahl der Teile bestimmen
Neues Fenster ( „Wie viele Teile?“ ,
<< Modal ,
neb = Nummernbearbeitungsfeld ( 10 ) ,
Button-Box ( "OK" , numParts = neb << Erhalten ; )
) ;
zeigen ( numParts ) ;
listParts = {} ;
//Ersten Teil des Skripts für das modale Fenster erstellen
//Escape-Zeichenfolge für „ is \!“
A = "
Neues Fenster(\!"Gut/Schlecht-Liste abrufen\!",
<
H-Listenfeld(
V-Listenfeld(
Aufstellungsbox( 2,
" ;
//for-Schleife erstellt zweiten Teil, der so viele Eingabefelder erstellt, wie es Teile gibt
// || ist die Abkürzung für verketten
B = „“ ;
für ( ich = 1 , ich <= numParts , ich ++,
b1 = verkohlen ( "Textfeld(char(" || verkohlen ( ich ) || ")), listParts[" || verkohlen ( ich ) || "] = Textbearbeitungsfeld(\!"Pass\!")," ) ;
B = B || b1 ;
) ;
//den letzten Teil des Skripts für das modale Fenster erstellen
C = "
Button Box(\!"OK\!", for (i = 1, i <=numParts, i++, listParts = listParts << Text abrufen;)), Button Box(\!"Abbrechen\!")
)
)
)
)
" ;
// Teile des Skripts kombinieren und ausführen
D = A || B || C ;
evalu ( analysieren ( D )) ;
//Schau dir an, was geschaffen wurde
zeigen ( D ) ;
zeigen ( listParts ) ;
Zunächst gibt es einen Abschnitt, in dem der Benutzer gefragt werden kann, wie viele Teile in „numParts“ gespeichert sind. Als Nächstes erstellt das Skript drei separate Zeichenfolgen, die JSL verdächtig ähneln, nur dass sie alle lila sind. Die erste Zeichenfolge ist lediglich eine exakte Kopie (mit einem speziellen Code, damit die Anführungszeichen die Zeichenfolge nicht beenden) des vorherigen Skripts bis zu dem Teil, in dem Textfelder eingefügt werden. Der zweite Teil ist eine for-Schleife zum Erstellen einer Zeichenfolge, die aus den zuvor eingegebenen Teilen (numParts) und Wiederholungen von Textfeldern besteht. Der dritte Abschnitt enthält die letzten Teile des vorherigen Skripts.
Sobald diese Zeichenfolge erstellt ist, kombinieren wir sie ( D = A || B || C ; ), dann verwenden Sie die evalu ( analysieren ( D )) ; Befehl, um auszuwerten, was passiert, wenn JMP die Zeichenfolge d (unsere dynamisch erstellte Zeichenfolge mit einer einstellbaren Anzahl von Textfeldern) so analysiert, als wäre die Zeichenfolge d ein JSL-Skript und nicht nur eine Zeichenfolge. Sehen Sie sich das Protokoll an, um sowohl den superlangen Befehl zum Anzeigen zahlreicher Textfelder als auch die Liste der generierten Pass/Fail-Werte zu sehen (siehe unten, wenn Sie nur die Standardeinstellungen akzeptieren):
d = "
Neues Fenster(\!"Gut/Schlecht-Liste abrufen\!",
<
H-Listenfeld(
V-Listenfeld(
Aufstellungsbox( 2,
Text Box(char(1)), listParts[1] = Textbearbeitungsfeld(\!"Pass\!"),Text Box(char(2)), listParts[2] = Textbearbeitungsfeld(\!"Pass\ !"),Text Box(char(3)), listParts[3] = Textbearbeitungsfeld(\!"Pass\!"),Text Box(char(4)), listParts[4] = Textbearbeitungsfeld(\ !"Pass\!"),Text Box(char(5)), listParts[5] = Text Edit Box(\!"Pass\!"),Text Box(char(6)), listParts[6] = Text Edit Box(\!"Pass\!"),Text Box(char(7)), listParts[7] = Text Edit Box(\!"Pass\!"),Text Box(char(8)), listParts[ 8] = Textbearbeitungsfeld(\!"Pass\!"),Textfeld(char(9)), listParts[9] = Textbearbeitungsfeld(\!"Pass\!"),Textfeld(char(10) ), listParts[10] = Textbearbeitungsfeld(\!"Pass\!"),
Button Box(\!"OK\!", for (i = 1, i <=numParts, i++, listParts = listParts << Text abrufen;)), Schaltflächenfeld(\!"Abbrechen\!")
)
)
)
)
";
listParts = {"Bestanden", "Bestanden", "Bestanden", "Bestanden", "Bestanden", "Bestanden", "Bestanden", "Bestanden", "Bestanden", "Bestanden"};
Nehmen Sie sich einen Moment Zeit, um über die Auswirkungen nachzudenken. Mit diesen Konzepten können Sie Code erstellen, der sich selbst anpasst und dann selbst ausführt. Dynamische, selbstreferenzielle, rekursive und verrückte Skripte könnten nur der Anfang sein. Mit genügend Zeit und Geduld könnten Sie dieses Konzept wahrscheinlich für die Erstellung von Skynet nutzen. Wenn ich genauer darüber nachdenke, ist das vielleicht keine so gute Idee ...
Zusätzlich zu dem, was Erin zu sagen hat, kann ich dies auch auf eine gewisse Dummheit meinerseits zurückführen, da ich in diesem Beispiel nicht immer die richtigen Namen verwende. Was meiner Meinung nach passiert, ist, dass beim Erstellen des Fensters eine Reihe von Textfeldern erstellt werden. Textfelder sind Objekte, was bedeutet, dass es möglich sein sollte, ihnen die Nachricht << Get Text() zu senden. Wo die Dummheit (Glück?) ins Spiel kommt, ist, dass jedem Textfeld der Name ListParts zugewiesen wird, wenn ich also wirklich Glück habe Wenn Wenn ich ListParts[x] die Get Text()-Nachricht sende, erhalte ich tatsächlich Text. Im Nachhinein hätte ich die Textfelder „listParts[x]“ anders benennen sollen (z. B. im Beispiel unten „ListParts[1]“ durch „tb[1]“ ersetzen sollen).
Text Box(char(1)), listParts[1] = Text Edit Box("Pass"),
Ich denke, das ist ein Beispiel für einen dieser seltenen Fälle, in denen ein Drehbuch etwas tut, was der Autor wollte, obwohl es eigentlich falsch ist, was irgendwie aufregend ist!
Das Problem hierbei ist, dass <
Sie können keine Nachrichten an Dinge senden, die keine Objekte sind, und Listen sind keine Objekte im gleichen Sinne wie beispielsweise Datentabellen. Ich habe kürzlich einen seit langem bestehenden Fehler in den Add-Ins eines meiner Kunden behoben, als mir klar wurde, dass ich es versucht hatte
list<<INSERT item=""></INSERT>
anstatt
insert item(list, item)
Ich denke, was viele von uns verwirrt, ist, dass assoziative Arrays Objekte SIND, die <
map=associative array(:Name, :Weight);
map<<INSERT item=""></INSERT>
Zurück zur vorliegenden Frage: Ich bin mir jedoch nicht wirklich sicher, warum das Beispiel überhaupt listparts[i]<Betreff: Eval (), Parse () und Rekursion, ein Abenteuer in der Metaprogrammierung
Tolles Beispiel, danke @Jed_Campbell .Ich habe ein Problem, das ich scheinbar nicht lösen kann.Ich erhalte eine Fehlermeldung: Send Expects Scriptable Object in access or equalty of 'List' , {/*###*/"Pass", "Fail"}
Ich denke, dass dieser Sendebefehl das Problem verursacht.Ich erhalte die Fehlermeldung nur, wenn ich mehr als eine Zahl wähle.Irgendwelche Gedanken?
listParts = listParts << Get Text;