Blog Of Zhang Xu

07 Aug 2020

Blockly学习——定义块(define blocks)

定义块是blockly开发最重要的环节,可以利用官方工具:Blockly Developer Tools ,也可以自己定义,本文记录整理通过代码定义方法,原网址为:

https://developers.google.com/blockly/guides/create-custom-blocks/define-blocks


JSON vs JavaScript

var mathChangeJson = {
  "message0": "change %1 by %2",
  "args0": [
    {"type": "field_variable", "name": "VAR", "variable": "item", "variableTypes": [""]},
    {"type": "input_value", "name": "DELTA", "check": "Number"}
  ],
  "previousStatement": null,
  "nextStatement": null,
  "colour": 230
};

Blockly.Blocks['math_change'] = {
  init: function() {
    this.jsonInit(mathChangeJson);
    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      return 'Add a number to variable "%1".'.replace('%1',
          thisBlock.getFieldValue('VAR'));
    });
  }
};

Block 颜色

主题颜色通过 JSON colour 属性或者block.setColour(..) 来设置。

连接状态

// Untyped:
{
    ...,
    "nextStatement": null,
}
// Typed:
{
  "nextStatement": "Action",
  ...
}
// Untyped:
this.setNextStatement(true);  // false implies no next connector, the default

// Typed:
this.setNextStatement(true, 'Action');
// Untyped:
{
  ...,
  "previousStatement": null,
}
// Typed:
{
  "previousStatement": "Action",
  ...
}
// Untyped:
this.setPreviousStatement(true);  // false implies no previous connector, the default

// Typed:
this.setPreviousStatement(true, 'Action');

块的输出

// Untyped:
{
  ...,
  "output": null,
}
// Typed:
{
  "output": "Number",
  ...
}
//Untyped:
init: function() {
  // ...
  this.setOutput(true);
}

//Typed:
init: function() {
  // ...
  this.setOutput(true, 'Number');
}

块的输入

存在三种类型的输入:

JSON通过带插值(1%, 2%)的消息字符串(message0, message1,…)来定义输入。

{
  "message0": "set %1 to %2",
  "args0": [
    {
      "type": "field_variable",
      "name": "VAR",
      "variable": "item",
      "variableTypes": [""]
    },
    {
      "type": "input_value",
      "name": "VALUE"
    }
  ]
}

插值的顺序和声明的type 会决定块最终的结构,比如将set %1 to %2 改为 put %2 in %1 。块会变成:

每一个对象都有一个type 属性,剩下的参数取决于type :

每一个对象还有一个alt 属性,比如说有一个新的field ,使用这个field 的块就可以用alt 定义field input fallback。

{
  "message0": "sound alarm at %1",
  "args0": [
    {
      "type": "field_time",
      "name": "TEMPO",
      "hour": 9,
      "minutes": 0,
      "alt":
        {
          "type": "field_input",
          "name": "TEMPOTEXT",
          "text": "9:00"
        }
    }
  ]
}

dummy input 可以不用在argsN里声明。

多行可以用多个message

{
  "type": "controls_repeat_ext",
  "message0": "repeat %1 times",
  "args0": [
    {"type": "input_value", "name": "TIMES", "check": "Number"}
  ],
  "message1": "do %1",
  "args1": [
    {"type": "input_statement", "name": "DO"}
  ],
  "previousStatement": null,
  "nextStatement": null,
  "colour": 120
}
js格式inputfields

JS为每一个输入类型提供append 方法

this.appendDummyInput()
    .appendField('for each')
    .appendField('item')
    .appendField(new Blockly.FieldVariable());
this.appendValueInput('LIST')
    .setCheck('Array')
    .setAlign(Blockly.ALIGN_RIGHT)
    .appendField('in list');
this.appendStatementInput('DO')
    .appendField('do');

每个方法带有一个identifier stringcode generators 使用,Dummy inputs 不需要。

setCheck 用于检查输入类型,没有的话可以连接任何块。

input.setCheck('Number');

setAlign 用于设置fields 对齐,参数有:Blockly.ALIGN_LEFT Blockly.ALIGN_RIGHT Blockly.ALIGN_CENTRE 默认左对齐。

appendField ,一个block被用appendInput 赋予输入时,可以被赋予多个fileds,fields经常用作描述input的标签。

最简单的filed元素是text。

input.appendField('hello');

需要指定fileds类名,通过CSS 定义风格时用

appendField(new Blockly.FieldLabel('hello'))

input.appendField('hello')
     .appendField(new Blockly.FieldLabel('Neil', 'person'));

Fields

Fileds 定义块的UI,包括字符串标签,图像和输入文本数值。最简单的math_number 块,用field_input 让用户输入一个数。

Blockly提供很多内建fields(text inputs, color pickers, images)。也可以创建自己的fields。

Tooltips

帮助提示,可以是静态的字符串,

init: function() {
  this.setTooltip("Tooltip text.");
}

也可以是动态的,根据下拉框选项选择。

Blockly.Blocks['math_arithmetic'] = {
  init: function() {
    // ...

    // Assign 'this' to a variable for use in the tooltip closure below.
    var thisBlock = this;
    this.setTooltip(function() {
      var mode = thisBlock.getFieldValue('OP');
      var TOOLTIPS = {
        'ADD': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
        'MINUS': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
        'MULTIPLY': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
        'DIVIDE': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
        'POWER': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER
      };
      return TOOLTIPS[mode];
    });
  }
};

Change Listeners and Validators

主要用来设置block的⚠警告,或者用户通知。通过setOnChange

Mutator

mutator可以通过JSON同mutator key添加

{
  // ...,
  "mutator":"if_else_mutator"
}

下面基本用不到

Per-block configuration

一些其他特性:

Deletable State

有这一条语句的表示不可删除:

block.setDeletable(false);
Editable State
block.setEditable(false);  // Web or Android
Movable State

Context Menus