Benutzerdefinierte Blöcke: Blockparadigmen

Beim Entwerfen einer Anwendung, die Blockly verwendet, stehen mehrere Paradigmen zur Auswahl. Diese Entscheidungen sollten frühzeitig getroffen werden, da sie sich auf die Blockierungen auswirken, die der Nutzer benötigt.

Konfiguration

Viele Blockly-Anwendungen werden zum Beschreiben von Konfigurationen anstelle von ausführbaren Programmen verwendet. Konfigurationsanwendungen beginnen in der Regel mit der Initialisierung eines Blocks auf Stammebene im Arbeitsbereich. Ein gutes Beispiel ist der Tab Block Factory der Blockly Developer Tools:

Blockly.Blocks['factory_base'] = {
  init: function() {
    this.setDeletable(false);
    this.setMovable(false);
    this.setEditable(false);
    // etc...
  }
}

Blockly.serialization.blocks.append({'type': 'factory_base'}, workspace);

Dadurch wird ein nicht löschbarer, nicht verschiebbarer Block erstellt, der die gesamte Konfiguration des Nutzers enthält. Der Arbeitsbereich kann jederzeit serialisiert werden, um die aktuelle Konfiguration zu ermitteln.

Bei solchen Anwendungen kann es sinnvoll sein, alle Blöcke, die nicht mit dem Stammblock verbunden sind, automatisch zu deaktivieren. Dies kann mit einer Zeile erreicht werden:

workspace.addChangeListener(Blockly.Events.disableOrphans);

Serienprogramm

Die meisten Blockly-Anwendungen wurden zum Erstellen serieller Programme entwickelt. Die Nutzer stapeln Blöcke, die der Reihe nach ausgeführt werden.

Jeder (nicht deaktivierte) Block im Arbeitsbereich ist Teil des Programms. Wenn mehrere Stapel von Blöcken vorhanden sind, werden zuerst die höheren ausgeführt. Wenn zwei Stapel ungefähr die gleiche Höhe haben, erhalten die Stapel links (rechts im RTL-Modus) Priorität.

Der Arbeitsbereich kann jederzeit in ausführbaren Code exportiert werden. Dieser Code kann clientseitig in JavaScript (mit eval oder dem JS-Interpreter) oder serverseitig in einer beliebigen Sprache ausgeführt werden.

import {javascriptGenerator} from 'blockly/javascript';

var code = javascriptGenerator.workspaceToCode(workspace);

Paralleles Programm

Einige Blockly-Anwendungen führen alle Blockstapel parallel und nicht seriell aus. Ein Beispiel wäre eine Musikanwendung, in der ein Drum-Loop gleichzeitig mit einer Melodie läuft.

Eine Möglichkeit zur Implementierung der parallelen Ausführung besteht darin, den Code für jeden Block einzeln zu generieren:

import {javascriptGenerator} from 'blockly/javascript';

var json = Blockly.serialization.workspaces.save(workspace);

// Store top blocks separately, and remove them from the JSON.
var blocks = json['blocks']['blocks'];
var topBlocks = blocks.slice();  // Create shallow copy.
blocks.length = 0;

// Load each block into the workspace individually and generate code.
var allCode = [];
var headless = new Blockly.Workspace();
for (var i = 0; block < topBlocks.length; i++) {
  var block = topBlocks[i];
  blocks.push(block);
  Blockly.serialization.workspaces.load(json, headless);
  allCode.push(javascriptGenerator.workspaceToCode(headless));
  blocks.length = 0;
}

Wenn die Zielsprache JavaScript ist, können dann mithilfe des Arrays allCode mehrere JS-Interpreter für die gleichzeitige Ausführung erstellt werden. Wenn die Zielsprache in etwa Python ist, kann das Array allCode zu einem einzelnen Programm zusammengestellt werden, das ein Threading-Modul verwendet.

Wie bei jedem parallelen Programm müssen sorgfältige Entscheidungen in Bezug auf alle gemeinsam genutzten Ressourcen wie Variablen und Funktionen getroffen werden.

Ereignisgesteuertes Programm

Event-Handler sind nur Funktionen, die vom System und nicht vom Programm aufgerufen werden. Diese Blöcke können entweder den Stapel der auszuführenden Blöcke umschließen oder Header sein, die auf einem Stapel von Blöcken angeordnet sind.

Einige Entwickler fügen den Ereignisblöcken gerne einen Hut hinzu, damit sie sich von anderen Blöcken unterscheiden. Dies ist nicht der Standard-Look für Blockly. Sie können ihn aber hinzufügen, indem Sie entweder die Renderer-Konstante ADD_START_HATS in true überschreiben (Codelab für benutzerdefinierte Renderer – Konstanten überschreiben) oder ein Design hinzufügen und die Hutoption für den Blockstil festlegen. Weitere Informationen zum Festlegen von Hüten für Blöcke als Teil von Designs finden Sie hier.

Innerhalb eines ereignisgesteuerten Modells kann es sinnvoll sein, auch einen Handler für den Programmstart zu erstellen. Bei diesem Modell wird jeder Block im Arbeitsbereich, der nicht mit einem Event-Handler verbunden ist, ignoriert und nicht ausgeführt.

Überlegen Sie beim Entwerfen eines Systems, das Ereignisse verwendet, ob es möglich oder wünschenswert ist, mehrere Instanzen desselben Event-Handlers zu unterstützen.