Blockly集合积木开发

Blockly集合积木开发

今天出一期关于Blockly集合积木开发的教程,废话不多说,上代码

集合积木

集合积木借鉴mixly,python代码可以参考菜鸟教程www.runoob.com/python/pyth...

构建积木

1,涉及要修改得文件(blocks,set这个是要自己创建) 2,blocks文件引入set文件,并在export导出积木

javascript 复制代码
set文件代码

/**
 * @license
 * Copyright 2012 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

// Former goog.module ID: Blockly.libraryBlocks.set
import type {Block} from '../core/block.js';
import type {BlockSvg} from '../core/block_svg.js';
import type {Workspace} from '../core/workspace.js';
import type {Connection} from '../core/connection.js';
import {Msg} from '../core/msg.js';
import {Align} from '../core/inputs/align.js';
import {MutatorIcon} from '../core/icons/mutator_icon.js';
import {
  createBlockDefinitionsFromJsonArray,
  defineBlocks,
} from '../core/common.js';
import * as xmlUtils from '../core/utils/xml.js';

/**
 * A dictionary of the block definitions provided by this module.
 */
export const blocks = createBlockDefinitionsFromJsonArray([
  {
    type: "set_len",
    style: "set_blocks",
    helpUrl: "",
    tooltip: "",
    output: "Number",
    message0: "%{BKY_SET_LEN}",
    args0: [{ type: "input_value", name: "VALUE", check: "Set" }],
  },
  {
    type: "set_pop",
    style: "set_blocks",
    helpUrl: "",
    tooltip: "",
    output: null,
    message0: "%{BKY_SET_POP}",
    args0: [{ type: "input_value", name: "VALUE", check: "Set" }],
  },
  {
    type: "set_operate",
    style: "set_blocks",
    helpUrl: "",
    tooltip: "",
    output: "Set",
    message0: "%{BKY_SET_OPERATE}",
    args0: [
      { type: "input_value", name: "VALUE1", check: "Set" },
      { type: "input_value", name: "VALUE2", check: "Set" },
      {
        type: "field_dropdown",
        name: "SELECT",
        options: [
          ["并集", "union"],
          ["交集", "intersection"],
          ["差集", "difference"],
        ],
      },
    ],
  },
  {
    type: "set_operate_update",
    style: "set_blocks",
    helpUrl: "",
    tooltip: "",
    previousStatement: null,
    nextStatement: null,
    message0: "%{BKY_SET_OPERATE_UPDATE}",
    args0: [
      { type: "input_value", name: "VALUE1", check: "Set" },
      { type: "input_value", name: "VALUE2", check: "Set" },
      {
        type: "field_dropdown",
        name: "SELECT",
        options: [
          ["并集", "update"],
          ["交集", "intersection_update"],
          ["差集", "difference_update"],
        ],
      },
    ],
  },
  {
    type: "set_add_discard",
    style: "set_blocks",
    helpUrl: "",
    tooltip: "",
    inputsInline: true,
    previousStatement: null,
    nextStatement: null,
    message0: "%{BKY_SET_ADD_DISCARD}",
    args0: [
      { type: "input_value", name: "VALUE1", check: "Set" },
      {
        type: "field_dropdown",
        name: "SELECT",
        options: [
          ["添加", "add"],
          ["移除", "discard"],
        ],
      },
      { type: "input_value", name: "VALUE2", check: ["Number", "String"] },
    ],
  },
  {
    type: "set_update",
    style: "set_blocks",
    helpUrl: "",
    tooltip: "",
    inputsInline: true,
    previousStatement: null,
    nextStatement: null,
    message0: "%{BKY_SET_UPDATE}",
    args0: [
      { type: "input_value", name: "VALUE1", check: "Set" },
      { type: "input_value", name: "VALUE2", check: ["List", "String"] },
    ],
  },
  {
    type: "set_sub",
    style: "set_blocks",
    helpUrl: "",
    tooltip: "",
    output: "Boolean",
    message0: "%{BKY_SET_SUB}",
    args0: [
      { type: "input_value", name: "VALUE1", check: "Set" },
      { type: "input_value", name: "VALUE2", check: "Set" },
      {
        type: "field_dropdown",
        name: "SELECT",
        options: [
          ["子集", "issubset"],
          ["超集", "issuperset"],
        ],
      },
    ],
  },
  {
    type: "set_toset",
    style: "set_blocks",
    helpUrl: "",
    tooltip: "",
    output: "Set",
    message0: "%{BKY_SET_TOSET}",
    args0: [{ type: "input_value", name: "VALUE" }],
  },
])

/**
 * Type of a 'set_create_with' block.
 */
export type CreateWithBlock = Block & SetCreateWithMixin;
interface SetCreateWithMixin extends SetCreateWithMixinType {
  itemCount_: number;
};
type SetCreateWithMixinType = typeof SET_CREATE_WITH;
const SET_CREATE_WITH = {
  /**
   * Block for creating a set with any number of elements of any type.
   */
  init: function(this: CreateWithBlock) {
    this.setHelpUrl('');
    this.setStyle('set_blocks');
    this.itemCount_ = 3;
    this.updateShape_();
    this.setOutput(true, 'Set');
    this.setInputsInline(true);
    this.setMutator(
      new MutatorIcon(['set_create_with_item'], this as unknown as BlockSvg)
    )
    this.setTooltip('');
  },
  /**
   * Create XML to represent set inputs.
   * Backwards compatible serialization implementation.
   */
  mutationToDom: function(this: CreateWithBlock): Element {
    const container = xmlUtils.createElement('mutation');
    container.setAttribute('items', String(this.itemCount_));
    return container;
  },
  /**
   * Parse XML to restore the set inputs.
   * Backwards compatible serialization implementation.
   *
   * @param xmlElement XML storage element.
   */
  domToMutation: function(this: CreateWithBlock, xmlElement: Element) {
    const items = xmlElement.getAttribute('items');
    if (!items) throw new TypeError('element did not have items');
    this.itemCount_ = parseInt(items, 10)
    this.updateShape_();
  },
  /**
   * Returns the state of this block as a JSON serializable object.
   *
   * @returns The state of this block, ie the item count.
   */
  saveExtraState: function (this: CreateWithBlock): {itemCount: number} {
    return {
      'itemCount': this.itemCount_,
    };
  },
  /**
   * Applies the given state to this block.
   *
   * @param state The state to apply to this block, ie the item count.
   */
  loadExtraState: function (this: CreateWithBlock, state: AnyDuringMigration) {
    this.itemCount_ = state['itemCount'];
    this.updateShape_();
  },
  /**
   * Populate the mutator's dialog with this block's components.
   * 
   * @param workspace Mutator's workspace.
   * @returns Root block in mutator.
   */
  decompose: function(
    this: CreateWithBlock,
    workspace: Workspace,
  ): ContainerBlock {
    const containerBlock = workspace.newBlock(
      'set_create_with_container'
    ) as ContainerBlock;
    (containerBlock as BlockSvg).initSvg();
    let connection = containerBlock.getInput('STACK')!.connection;
    for (let i = 0; i < this.itemCount_; i++) {
      const itemBlock = workspace.newBlock(
        'set_create_with_item'
      ) as ItemBlock;
      (itemBlock as BlockSvg).initSvg();
      if (!itemBlock.previousConnection) {
        throw new Error('itemBlock has no previousConnection')
      }
      connection!.connect(itemBlock.previousConnection)
      connection = itemBlock.nextConnection;
    }
    return containerBlock;
  },
  /**
   * Reconfigure this block based on the mutator dialog's components.
   * 
   * @param containerBlock Root block in mutator.
   */
  compose: function(this: CreateWithBlock, containerBlock: Block) {
    let itemBlock: ItemBlock | null = containerBlock.getInputTargetBlock(
      'STACK'
    ) as ItemBlock;
    // Count number of inputs.
    const connections: Connection[] = [];
    while (itemBlock) {
      if (itemBlock.isInsertionMarker()) {
        itemBlock = itemBlock.getNextBlock() as ItemBlock | null;
        continue;
      }
      connections.push(itemBlock.valueConnection_ as Connection);
      itemBlock = itemBlock.getNextBlock() as ItemBlock | null;
    }
    // Disconnect any children that don't belong.
    for (let i = 0; i < this.itemCount_; i++) {
      const connection = this.getInput('ADD' + i)!.connection!.targetConnection;
      if (connection && !connections.includes(connection)) {
        connection.disconnect();
      }
    }
    this.itemCount_ = connections.length;
    this.updateShape_();
    // Reconnect any child blocks.
    for (let i = 0; i < this.itemCount_; i++) {
      connections[i]?.reconnect(this, 'ADD' + i)
    }
  },
  /**
   * Store pointers to any connected child blocks.
   *
   * @param containerBlock Root block in mutator.
   */
  saveConnections: function(this: CreateWithBlock, containerBlock: Block) {
    let itemBlock: ItemBlock | null = containerBlock.getInputTargetBlock(
      'STACK',
    ) as ItemBlock;
    let i = 0;
    while(itemBlock) {
      if (itemBlock.isInsertionMarker()) {
        itemBlock = itemBlock.getNextBlock() as ItemBlock | null;
        continue;
      }
      const input = this.getInput('ADD' + i);
      itemBlock.valueConnection_ = input?.connection!.targetConnection as Connection;
      itemBlock = itemBlock.getNextBlock() as ItemBlock | null;
      i++;
    }
  },
  /**
   * Modify this block to have the correct number of inputs.
   */
  updateShape_: function(this: CreateWithBlock) {
    if (this.itemCount_ && this.getInput('EMPTY')) {
      this.removeInput('EMPTY');
    } else if (!this.itemCount_ && ! this.getInput('EMPTY')) {
      this.appendDummyInput('EMPTY')
        .appendField(
          Msg['SET_CREATE_EMPTY_TITLE']
        );
    }
    // Add new inputs.
    for (let i = 0; i < this.itemCount_; i++) {
      if (!this.getInput('ADD' + i)) {
        const input = this.appendValueInput('ADD' + i).setAlign(Align.RIGHT);
        if (i === 0) {
          input.appendField(Msg['SET_CREATE_WITH_INPUT_WITH'])
        }
      }
    }
    // Remove deleted inputs.
    for (let i = this.itemCount_; this.getInput('ADD' + i); i++) {
      this.removeInput('ADD' + i);
    }
  }
};
blocks['set_create_with'] = SET_CREATE_WITH;

/** type for a 'set_creat_with_item' block. */
type ItemBlock = Block & ItemMutator
interface ItemMutator extends ItemMutatorType {
  valueConnection_?: Connection;
}
type ItemMutatorType = typeof SET_CREATE_WITH_ITEM
const SET_CREATE_WITH_ITEM = {
  /**
   * Mutator block for adding items.
   */
  init: function(this: ItemBlock) {
    this.setStyle('set_blocks');
    this.appendDummyInput()
      .appendField(Msg['SET_ELEMENT']);
    this.setPreviousStatement(true);
    this.setNextStatement(true);
    this.setTooltip('');
    this.contextMenu = false;
  }
}
blocks['set_create_with_item'] = SET_CREATE_WITH_ITEM;

/** Type for a 'set_create_with_container' block. */
type ContainerBlock = Block & ContainerMutator
interface ContainerMutator extends ContainerMutatorType {}
type ContainerMutatorType = typeof SET_CREATE_WITH_CONTAINER
const SET_CREATE_WITH_CONTAINER = {
  /**
   * Mutator block from set container.
   */
  init: function(this: ContainerBlock) {
    this.setStyle('set_blocks');
    this.appendDummyInput()
      .appendField(Msg['SET_CREATE_WITH_CONTAINER']);
    this.appendStatementInput('STACK');
    this.setTooltip('');
    this.contextMenu = false;
  }
}
blocks['set_create_with_container'] = SET_CREATE_WITH_CONTAINER;

defineBlocks(blocks);

至此集合积木已经完成,看一下效果图

三,构建python

1,涉及要修改得文件(python,set这个是要自己创建) 2,python文件引入set文件,并在export导出python代码

javascript 复制代码
set文件代码

/**
 * @license
 * Copyright 2012 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file Generating Python for set blocks.
 */

// Former goog.module ID: Blockly.Python.set
import type {Block} from '../../core/block.js';
import type {CreateWithBlock} from '../../blocks/set.js';
import type {PythonGenerator} from './python_generator.js';
import {Order} from './python_generator.js';

export function set_create_with(
  block: Block,
  generator: PythonGenerator,
): [string, Order] {
  // Create a set with any number of elements of any type.
  const createWithBlock = block as CreateWithBlock;
  const elements = new Array(createWithBlock.itemCount_);
  for (let i = 0; i < createWithBlock.itemCount_; i++) {
    elements[i] = generator.valueToCode(block, 'ADD' + i, Order.NONE) || '0';
  }
  let code = '{' + elements.join(', ') + '}'
  if (createWithBlock.itemCount_ == 0) code = 'set()'
  return [code, Order.COLLECTION]
}

export function set_len(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';

  let code = `len(${VALUE})`
  return [code, Order.ATOMIC]
}

export function set_pop(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';

  let code = `${VALUE}.pop()`
  return [code, Order.ATOMIC]
}

export function set_operate(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE1 = generator.valueToCode(block, 'VALUE1', Order.NONE) || '0';
  let VALUE2 = generator.valueToCode(block, 'VALUE2', Order.NONE) || '0';
  let SELECT = block.getFieldValue('SELECT')

  let code = `${VALUE1}.${SELECT}(${VALUE2})`
  return [code, Order.ATOMIC]
}

export function set_operate_update(block: Block, generator: PythonGenerator)  {
  let VALUE1 = generator.valueToCode(block, 'VALUE1', Order.NONE) || '0';
  let VALUE2 = generator.valueToCode(block, 'VALUE2', Order.NONE) || '0';
  let SELECT = block.getFieldValue('SELECT')

  let code = `${VALUE1}.${SELECT}(${VALUE2})\n`
  return code
}

export function set_add_discard(block: Block, generator: PythonGenerator)  {
  let VALUE1 = generator.valueToCode(block, 'VALUE1', Order.NONE) || '0';
  let SELECT = block.getFieldValue('SELECT')
  let VALUE2 = generator.valueToCode(block, 'VALUE2', Order.NONE) || '0';

  let code = `${VALUE1}.${SELECT}(${VALUE2})\n`
  return code
}

export function set_update(block: Block, generator: PythonGenerator)  {
  let VALUE1 = generator.valueToCode(block, 'VALUE1', Order.NONE) || '0';
  let VALUE2 = generator.valueToCode(block, 'VALUE2', Order.NONE) || '0';

  let code = `${VALUE1}.update(${VALUE2})\n`
  return code
}

export function set_sub(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE1 = generator.valueToCode(block, 'VALUE1', Order.NONE) || '0';
  let VALUE2 = generator.valueToCode(block, 'VALUE2', Order.NONE) || '0';
  let SELECT = block.getFieldValue('SELECT')

  let code = `${VALUE1}.${SELECT}(${VALUE2})`
  return [code, Order.ATOMIC]
}

export function set_toset(block: Block, generator: PythonGenerator) : [string, Order] {
  let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';

  return [`set(${VALUE})`, Order.ATOMIC]
}

至此元组python已经完成,看一下效果图 总结:开发blockly积木,最基本还是要对技术文档了解,这样开发起来会简单很多

相关推荐
小羊没烦恼!18 分钟前
T-SQL查询高级—SQL Server索引中的碎片和填充因子
开发语言·前端·javascript·数据库·后端·python·web安全
定栓1 小时前
Webpack迁到Vite第一节:模块系统迁移:require → import
运维·前端·webpack
小熊在忙fpga1 小时前
N32G430芯片的flash表示
前端·javascript·html
Data analyse4561 小时前
App埋点版本兼容的字段迁移校验
大数据·运维·服务器·前端·数据库·数据分析
todoitbo1 小时前
本来只想给内网开个口子,Natapp 却多给了一道防护
前端·javascript·vue.js·内网穿透·网络防护·natapp
会灭火的程序员1 小时前
SuperMap AgentX Server智能体接入WEB应用技术文档
前端·supermap·agentx·agentx server
CRMEB1 小时前
商品 SKU 设计,从简单规格到多规格踩过什么
java·前端·数据库·开源
Chloe.Zz1 小时前
一篇入门Agent
开发语言·前端·javascript
java1234_小锋1 小时前
【技术专题】HTML5 网页技术 - HTML5 表格标签
前端·html·html5
雪芽蓝域zzs2 小时前
JS 项目转 TS 项目(Vue3 + 若依这类后台项目)完整改造清单
前端·vue.js