Blockly元组积木开发
今天出一期关于Blockly元组积木开发的教程,废话不多说,上代码
一:元组积木
元组积木借鉴mixly,python代码可以参考菜鸟教程www.runoob.com/python/pyth...
二:构建积木
1,涉及要修改得文件(blocks,tuple这个是要自己创建) 2,blocks文件引入tuple文件,并在export导出要积木
javascript
tuple文件代码
/**
* @license
* Copyright 2012 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
// Former goog.module ID: Blockly.libraryBlocks.tuple
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: "tuple_indexOf",
helpUrl: "",
tooltip: "",
style: 'tuple_blocks',
output: null,
message0: "%{BKY_TUPLE_INDEXOF}",
args0: [
{
type: "input_value",
name: "VALUE",
check: "Tuple",
},
{ type: "input_value", name: "INDEX", check: "Number" },
],
},
{
type: "tuple_slice",
helpUrl: "",
tooltip: "",
style: "tuple_blocks",
output: "Tuple",
message0: "%{BKY_TUPLE_SLICE}",
args0: [
{
type: "input_value",
name: "VALUE",
check: "Tuple",
},
{ type: "input_value", name: "START", check: "Number" },
{ type: "input_value", name: "END", check: "Number" },
],
},
{
type: "tuple_random_item",
style: "tuple_blocks",
helpUrl: "",
tooltip: "",
output: null,
message0: "%{BKY_TUPLE_RANDOM_ITEM}",
args0: [
{
type: "input_value",
name: "VALUE",
check: "Tuple",
},
],
},
{
type: "tuple_length",
style: "tuple_blocks",
helpUrl: "",
tooltip: "",
output: "Number",
message0: "%{BKY_TUPLE_LENGTH}",
args0: [
{
type: "input_value",
name: "VALUE",
check: "Tuple",
},
],
},
{
type: "tuple_max_value",
style: "tuple_blocks",
helpUrl: "",
tooltip: "",
output: null,
message0: "%{BKY_TUPLE_MAX_VALUE}",
args0: [
{
type: "input_value",
name: "VALUE",
check: "Tuple",
},
{
type: "field_dropdown",
name: "TYPE",
options: [
["最大值", "max"],
["最小值", "min"],
["总和", "sum"],
],
},
],
},
{
type: "tuple_serach_value",
style: "tuple_blocks",
helpUrl: "",
tooltip: "",
output: "Number",
message0: "%{BKY_TUPLE_SERACH_VALUE}",
args0: [
{
type: "input_value",
name: "VALUE",
check: "Tuple",
},
{
type: "input_value",
name: "SEARCH",
},
{
type: "field_dropdown",
name: "TYPE",
options: [
["位置", "index"],
["个数", "count"],
],
},
],
},
{
type: "tuple_delete",
style: "tuple_blocks",
helpUrl: "",
tooltip: "",
previousStatement: null,
nextStatement: null,
message0: "%{BKY_TUPLE_DELETE}",
args0: [
{
type: "input_value",
name: "VALUE",
check: "Tuple",
},
],
},
{
type: "tuple_concat",
style: "tuple_blocks",
helpUrl: "",
tooltip: "",
output: "Tuple",
inputsInline: true,
message0: "%{BKY_TUPLE_CONCAT}",
args0: [
{
type: "input_value",
name: "VALUE1",
check: "Tuple",
},
{
type: "input_value",
name: "VALUE2",
check: "Tuple",
},
],
},
{
type: "tuple_to_tuple",
style: "tuple_blocks",
helpUrl: "",
tooltip: "",
output: "Tuple",
message0: "%{BKY_TUPLE_TO_TUPLE}",
args0: [
{
type: "input_value",
name: "VALUE"
},
],
},
]);
/**
* Type of a 'tuple_create_with' block.
*/
export type CreateWithBlock = Block & TupleCreateWithMixin;
interface TupleCreateWithMixin extends TupleCreateWithMixinType {
itemCount_: number;
};
type TupleCreateWithMixinType = typeof TUPLE_CREATE_WITH;
const TUPLE_CREATE_WITH = {
/**
* Block for creating a tuple with any number of elements of any type.
*/
init: function(this: CreateWithBlock) {
this.setHelpUrl('');
this.setStyle('tuple_blocks');
this.itemCount_ = 3;
this.updateShape_();
this.setOutput(true, 'Tuple');
this.setMutator(
new MutatorIcon(['tuple_create_with_item'], this as unknown as BlockSvg)
)
this.setTooltip('');
},
/**
* Create XML to represent tuple 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 tuple 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(
'tuple_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(
'tuple_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['TUPLE_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['TUPLE_CREATE_WITH_INPUT_WITH'])
}
}
}
// Remove deleted inputs.
for (let i = this.itemCount_; this.getInput('ADD' + i); i++) {
this.removeInput('ADD' + i);
}
}
};
blocks['tuple_create_with'] = TUPLE_CREATE_WITH;
/** type for a 'tuple_creat_with_item' block. */
type ItemBlock = Block & ItemMutator
interface ItemMutator extends ItemMutatorType {
valueConnection_?: Connection;
}
type ItemMutatorType = typeof TUPLE_CREATE_WITH_ITEM
const TUPLE_CREATE_WITH_ITEM = {
/**
* Mutator block for adding items.
*/
init: function(this: ItemBlock) {
this.setStyle('tuple_blocks');
this.appendDummyInput()
.appendField(Msg['ELEMENT']);
this.setPreviousStatement(true);
this.setNextStatement(true);
this.setTooltip('');
this.contextMenu = false;
}
}
blocks['tuple_create_with_item'] = TUPLE_CREATE_WITH_ITEM;
/** Type for a 'tuple_create_with_container' block. */
type ContainerBlock = Block & ContainerMutator
interface ContainerMutator extends ContainerMutatorType {}
type ContainerMutatorType = typeof TUPLE_CREATE_WITH_CONTAINER
const TUPLE_CREATE_WITH_CONTAINER = {
/**
* Mutator block from tuple container.
*/
init: function(this: ContainerBlock) {
this.setStyle('tuple_blocks');
this.appendDummyInput()
.appendField(Msg['TUPLE_CREATE_WITH_CONTAINER']);
this.appendStatementInput('STACK');
this.setTooltip('');
this.contextMenu = false;
}
}
blocks['tuple_create_with_container'] = TUPLE_CREATE_WITH_CONTAINER;
defineBlocks(blocks);
至此元组积木已经完成,看一下效果图
三:构建python
1,涉及要修改得文件(python,tuple这个是要自己创建) 2,python文件引入tuple文件,并在export导出python代码
javascript
tuple文件
/**
* @license
* Copyright 2012 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file Generating Python for tuple blocks.
*/
// Former goog.module ID: Blockly.Python.tuple
import type {Block} from '../../core/block.js';
import type {CreateWithBlock} from '../../blocks/tuple.js';
import type {PythonGenerator} from './python_generator.js';
import {Order} from './python_generator.js';
export function tuple_create_with(
block: Block,
generator: PythonGenerator,
): [string, Order] {
// Create a tuple 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) || 'None';
}
let code = ''
if (elements.length === 1) {
code = '(' + elements.join(', ') + ',)';
} else {
code = '(' + elements.join(', ') + ')';
}
return [code, Order.FUNCTION_CALL];
}
export function tuple_indexOf(block: Block, generator: PythonGenerator) : [string, Order] {
let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
let INDEX = generator.valueToCode(block, 'INDEX', Order.NONE) || '0';
let code = `${VALUE}[${INDEX}]`
return [code, Order.ATOMIC]
}
export function tuple_slice(block: Block, generator: PythonGenerator) : [string, Order] {
let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
let START = generator.valueToCode(block, 'START', Order.NONE) || '0';
let END = generator.valueToCode(block, 'END', Order.NONE) || '0';
let code = `${VALUE}[${START} : ${END}]`
return [code, Order.MEMBER]
}
export function tuple_random_item(block: Block, generator: PythonGenerator) : [string, Order] {
(generator as AnyDuringMigration).definitions_['import_random'] = 'import random'
let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
let code = `random.choice(${VALUE})`
return [code, Order.ATOMIC]
}
export function tuple_length(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 tuple_max_value(block: Block, generator: PythonGenerator) : [string, Order] {
let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
let TYPE = block.getFieldValue('TYPE')
let code = `${TYPE}(${VALUE})`
return [code, Order.ATOMIC]
}
export function tuple_serach_value(block: Block, generator: PythonGenerator) : [string, Order] {
let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
let SEARCH = generator.valueToCode(block, 'SEARCH', Order.NONE) || '0';
let TYPE = block.getFieldValue('TYPE')
let code = `${VALUE}.${TYPE}(${SEARCH})`
return [code, Order.ATOMIC]
}
export function tuple_delete(block: Block, generator: PythonGenerator) {
let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
let code = `del ${VALUE}\n`
return code
}
export function tuple_concat(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 code = `${VALUE1} + ${VALUE2}`
return [code, Order.ATOMIC]
}
export function tuple_to_tuple(block: Block, generator: PythonGenerator) : [string, Order] {
let VALUE = generator.valueToCode(block, 'VALUE', Order.NONE) || '0';
let code = `tuple(${VALUE})`
return [code, Order.ATOMIC]
}
至此元组python已经完成,看一下效果图 总结:由于我的blockly项目是typescript的,有些开发人员项目和我并不相同,特别是引入的一些库文件有所不同,在用的时候要留一下,避免陷入太深,具体代码更具自己的项目改动一下就可以使用