Scratch Blocks自定义组件之「下拉图标」

news2024/12/23 20:08:59

一、背景 

由于自带的下拉图标是给水平布局的block使用,放在垂直布局下显得别扭,而且下拉选择后回修改image字段的图片,这让我很不爽,所以在原来的基础上稍作修改,效果如下:

 二、使用说明

(1)引入field_icon_dropdown.js到core文件夹中,代码在下文

(2)将field_icon_dropdown注册到Blockly中,这样在任意地方都可以使用,如果不想注入,直接用script标签引入也行,代码如下

goog.require('Blockly.FieldIconDropDown');

(3)block定义代码如下,下面代码是直接集成到一个完整block中,以设置彩灯块为例:

// ZE3P LED
Blockly.Blocks['ZE3P_led'] = {
  init: function () {
    this.jsonInit({
      "message0": "%1",
      "args0": [
        {
          "type": "field_icon_dropdown",
          "name": "COLOR",
          "options": [
            {
              src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_coral.svg',
              width: 48,
              height: 48,
              value: 'Red'
            },
            {
              src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_green.svg',
              width: 48,
              height: 48,
              value: 'Green'
            },
            {
              src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_blue.svg',
              width: 48,
              height: 48,
              value: 'Blue'
            },
            {
              src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_orange.svg',
              width: 48,
              height: 48,
              value: 'Orange'
            },
            {
              src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_yellow.svg',
              width: 48,
              height: 48,
              value: 'Yellow'
            },
            {
              src: Blockly.mainWorkspace.options.pathToMedia + 'icons/set-led_white.svg',
              width: 48,
              height: 48,
              value: 'White'
            },
          ],
        }
      ],
      "outputShape": Blockly.OUTPUT_SHAPE_ROUND,
      "output": "String",
      "extensions": ["colours_looks"]
    });
  }
}
// ZE3P LED显示颜色
Blockly.Blocks['ZE3P_led_set_color'] = {
  init: function () {
    this.jsonInit({
      "message0": "%1%2",
      "args0": [
        {
          "type": "field_image",
          "src": Blockly.mainWorkspace.options.pathToMedia + "/extensions/ZE3P.png",
          "width": 24,
          "height": 24
        },
        {
          "type": "field_vertical_separator"
        }
      ],
      "message1": "设置彩灯 %1 显示 %2 ",
      "args1": [
        {
          "type": "field_pin_dropdown",
          "name": "INTERFACE",
          "options": Blockly.Blocks.ZE3PInterfaceOptions,
        },
        {
          "type": "input_value",
          "name": "COLOR",
        }
      ],
      "category": Blockly.Categories.looks,
      "extensions": ["colours_looks", "shape_statement"]
    });
  }
};

 (4)添加toolbox配置,代码如下:

<block type="ZE3P_led_set_color" id="ZE3P_led_set_color">
    <value name="COLOR">
        <shadow type="ZE3P_led">
            <field name="COLOR">Red</field>
        </shadow>
    </value>
</block>

(5)转码实现以python为例,代码如霞 

// LED颜色
Blockly.Python['ZE3P_led'] = function (block) {
  let color = block.getFieldValue('COLOR') || 0;
  const code = "LedColor." + color;
  return [code, Blockly.Python.ORDER_ATOMIC];
};
// LED显示颜色
Blockly.Python['ZE3P_led_set_color'] = function (block) {
  const pin = block.getFieldValue('INTERFACE') || "";
  const color = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_ATOMIC) || "";
  return `led.set_color(Interface.${pin}, ${color})\n`;
};

提示:如果采用注册方法,最好本地编译一下,使用javascript引入则不需要 

三、效果展示

 四、完整代码

完整field_icon_dropdown.js代码如下:

'use strict';

goog.provide('Blockly.FieldIconDropDown');
goog.require('Blockly.DropDownDiv');


/**
 * 构造器
 * @param icons
 * @constructor
 */
Blockly.FieldIconDropDown = function (icons) {
  this.icons_ = icons;
  // Example:
  // [{src: '...', width: 20, height: 20, value: 'machine_value'}, ...]
  // 选择第一个为默认值
  const defaultValue = icons[0].value;
  Blockly.FieldIconDropDown.superClass_.constructor.call(this, defaultValue);
  this.addArgType('icon_dropdown');
};
goog.inherits(Blockly.FieldIconDropDown, Blockly.Field);

/**
 * Json配置
 */
Blockly.FieldIconDropDown.fromJson = function (element) {
  return new Blockly.FieldIconDropDown(element['options']);
};

/**
 * 下拉面板宽度(不需要修改,3个图标宽度)
 * @type {number}
 * @const
 */
Blockly.FieldIconDropDown.DROPDOWN_WIDTH = 168;

/**
 * 颜色记录
 */
Blockly.FieldIconDropDown.savedPrimary_ = null;

/**
 * 初始化
 */
Blockly.FieldIconDropDown.prototype.init = function (block) {
  if (this.fieldGroup_) {
    return;
  }
  // 下拉箭头大小
  const arrowSize = 12;

  // 重建dom
  this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null);
  this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);

  // 字段宽度
  this.size_.width = 44;

  // 图标
  this.imageElement_ = Blockly.utils.createSvgElement('image', {
    'height': 24 + 'px',
    'width': 24 + 'px',
    'x': 4 + "px",
    'y': 4 + "px",
  }, this.fieldGroup_);
  this.setParentFieldImage(this.getSrcForValue(this.value_));

  // 下拉箭头位置
  this.arrowX_ = 32;
  this.arrowY_ = 10;
  if (block.RTL) {
    this.arrowX_ = -this.arrowX_ - arrowSize;
  }

  // 下拉图标
  this.arrowIcon_ = Blockly.utils.createSvgElement('image', {
    'height': arrowSize + 'px',
    'width': arrowSize + 'px',
    'transform': 'translate(' + this.arrowX_ + ',' + this.arrowY_ + ')'
  }, this.fieldGroup_);
  this.arrowIcon_.setAttributeNS('http://www.w3.org/1999/xlink',
    'xlink:href', Blockly.mainWorkspace.options.pathToMedia + 'dropdown-arrow.svg');

  this.mouseDownWrapper_ = Blockly.bindEventWithChecks_(
    this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
};

/**
 * 鼠标放置样式
 */
Blockly.FieldIconDropDown.prototype.CURSOR = 'default';

/**
 * 设置值
 */
Blockly.FieldIconDropDown.prototype.setValue = function (newValue) {
  if (newValue === null || newValue === this.value_) {
    return;  // No change
  }
  if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
    Blockly.Events.fire(new Blockly.Events.Change(
      this.sourceBlock_, 'field', this.name, this.value_, newValue));
  }
  this.value_ = newValue;
  this.setParentFieldImage(this.getSrcForValue(this.value_));
};

/**
 * 设置当前选择图片
 */
Blockly.FieldIconDropDown.prototype.setParentFieldImage = function (src) {
  if (this.imageElement_ && src) {
    this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', src || '');
  }
};

/**
 * 获取值
 */
Blockly.FieldIconDropDown.prototype.getValue = function () {
  return this.value_;
};

/**
 * 根据src获取值
 * @param value
 * @returns {*}
 */
Blockly.FieldIconDropDown.prototype.getSrcForValue = function (value) {
  for (var i = 0, icon; icon = this.icons_[i]; i++) {
    if (icon.value === value) {
      return icon.src;
    }
  }
};

/**
 * 下拉选择
 */
Blockly.FieldIconDropDown.prototype.showEditor_ = function () {
  if (Blockly.DropDownDiv.hideIfOwner(this)) {
    return;
  }
  Blockly.DropDownDiv.hideWithoutAnimation();
  Blockly.DropDownDiv.clearContent();
  // 构建下拉内容
  const contentDiv = Blockly.DropDownDiv.getContentDiv();
  // Accessibility properties
  contentDiv.setAttribute('role', 'menu');
  contentDiv.setAttribute('aria-haspopup', 'true');
  for (let i = 0, icon; icon = this.icons_[i]; i++) {

    // 按钮
    const button = document.createElement('button');
    button.setAttribute('id', ':' + i);
    button.setAttribute('role', 'menuitem');
    button.setAttribute('class', 'blocklyDropDownButton');
    button.title = icon.alt;
    button.style.width = icon.width + 'px';
    button.style.height = icon.height + 'px';
    let backgroundColor = this.sourceBlock_.getColour();
    if (icon.value === this.getValue()) {
      backgroundColor = this.sourceBlock_.getColourTertiary();
      button.setAttribute('aria-selected', 'true');
    }
    button.style.backgroundColor = backgroundColor;
    button.style.borderColor = this.sourceBlock_.getColourTertiary();

    // 事件
    Blockly.bindEvent_(button, 'click', this, this.buttonClick_);
    Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_);
    Blockly.bindEvent_(button, 'mousedown', button, function (e) {
      this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
      e.preventDefault();
    });
    Blockly.bindEvent_(button, 'mouseover', button, function () {
      this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
      contentDiv.setAttribute('aria-activedescendant', this.id);
    });
    Blockly.bindEvent_(button, 'mouseout', button, function () {
      this.setAttribute('class', 'blocklyDropDownButton');
      contentDiv.removeAttribute('aria-activedescendant');
    });

    // 图标
    const buttonImg = document.createElement('img');
    buttonImg.src = icon.src;
    button.setAttribute('data-value', icon.value);
    buttonImg.setAttribute('data-value', icon.value);
    button.appendChild(buttonImg);
    contentDiv.appendChild(button);
  }
  contentDiv.style.width = Blockly.FieldIconDropDown.DROPDOWN_WIDTH + 'px';

  // 设置颜色
  Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary());
  Blockly.DropDownDiv.setCategory(this.sourceBlock_.parentBlock_.getCategory());
  this.savedPrimary_ = this.sourceBlock_.getColour();
  this.sourceBlock_.setColour(this.sourceBlock_.getColourSecondary(),
    this.sourceBlock_.getColourSecondary(),
    this.sourceBlock_.getColourTertiary());

  const scale = this.sourceBlock_.workspace.scale;
  const secondaryYOffset = (
    -(Blockly.BlockSvg.MIN_BLOCK_Y * scale) - (Blockly.BlockSvg.FIELD_Y_OFFSET * scale)
  );
  const renderedPrimary = Blockly.DropDownDiv.showPositionedByBlock(this, this.sourceBlock_, this.onHide_.bind(this), secondaryYOffset);
  if (!renderedPrimary) {
    const arrowX = this.arrowX_ + Blockly.DropDownDiv.ARROW_SIZE / 1.5 + 1;
    const arrowY = this.arrowY_ + Blockly.DropDownDiv.ARROW_SIZE / 1.5;
    this.arrowIcon_.setAttribute('transform', 'translate(' + arrowX + ',' + arrowY + ') rotate(180)');
  }
};

/**
 * 点击按钮
 */
Blockly.FieldIconDropDown.prototype.buttonClick_ = function (e) {
  const value = e.target.getAttribute('data-value');
  this.setValue(value);
  Blockly.DropDownDiv.hide();
};

/**
 * 关闭下拉面板时回掉
 */
Blockly.FieldIconDropDown.prototype.onHide_ = function () {
  if (this.sourceBlock_) {
    this.sourceBlock_.setColour(this.savedPrimary_,
      this.sourceBlock_.getColourSecondary(),
      this.sourceBlock_.getColourTertiary());
  }
  Blockly.DropDownDiv.content_.removeAttribute('role');
  Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
  Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
  this.arrowIcon_.setAttribute('transform', 'translate(' + this.arrowX_ + ',' + this.arrowY_ + ')');
};

Blockly.Field.register('field_icon_dropdown', Blockly.FieldIconDropDown);

五、关于我

作者:陆志敏

联系:761324428@qq.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/825230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

转机来了,国内全新芯片技术取得突破,关键驱动引擎开始提速

芯片技术转机来了 我们都知道&#xff0c;芯片技术是现代信息技术的基石&#xff0c;它驱动着计算机、智能手机、物联网设备等各类电子设备的运行。 科技的不断进步&#xff0c;芯片技术也在不断演进。 从传统的集成电路到现代的微处理器和系统芯片&#xff0c;其计算能力和能…

Total Variation loss

Total Variation loss 适合任务 图像复原、去噪等 处理的问题 图像上的一点点噪声可能就会对复原的结果产生非常大的影响&#xff0c;很多复原算法都会放大噪声。因此需要在最优化问题的模型中添加一些正则项来保持图像的光滑性&#xff0c;图片中相邻像素值的差异可以通过…

Pytorch深度学习框架入门

1.pytorch加载数据 唤醒指定的python运行环境的命令&#xff1a; conda activate 环境的名称 from torch.utils.data import Dataset #Dataset数据处理的包 from PIL import Image import os#定义数据处理的类 class MyData(Dataset):#数据地址处理方法def __init__(self,ro…

从《信息技术服务数据中心业务连续性等级评价准则》看数据备份

​​​​​​​ 5月23日&#xff0c;国家标准化管理委员会与国家市场监督管理总局发布了《信息技术服务数据中心业务连续性等级评价准则》&#xff0c;旨在适应各行各业逐步深入的数字化转型&#xff0c;提升全社会对数据中心服务中断风险的重视。 信息技术服务数据中心业务连续…

KL15 是什么?ACC,crank,on等

KL含义 KL is the abbreviation for klemme which is the German term for connector / connection.KL是“ klemme”的缩写&#xff0c;这是德语中连接器或连接的术语。 KL30 &#xff0c;通常表示电瓶的正极。positive KL31&#xff0c;通常表示电瓶的负极。negative KL15, 通…

【NLP概念源和流】 04-过度到RNN(第 4/20 部分)

接上文 【NLP概念源和流】 03-基于计数的嵌入,GloVe(第 3/20 部分) 一、说明 词嵌入使许多NLP任务有了显著的改进。它对单词原理图的理解以及将不同长度的文本表示为固定向量的能力使其在许多复杂的NLP任务中非常受欢迎。大多数机器学习算法可以直接应用于分类和回归任务的…

go初识iris框架(三) - 路由功能处理方式

继了解get,post后 package mainimport "github.com/kataras/iris/v12"func main(){app : iris.New()//app.Handle(请求方式,url,请求方法)app.Handle("GET","/userinfo",func(ctx iris.Context){path : ctx.Path()app.Logger().Info(path) //获…

MTS性能监控你知道多少

前言 说到MySQL的MTS&#xff0c;相信很多同学都不陌生&#xff0c;从5.6开始基于schema的并行回放&#xff0c;到5.7的LOGICAL_CLOCK支持基于事务的并行回放&#xff0c;这些内容都有文章讲解&#xff0c;在本篇文章不再赘述。今天要讲的是&#xff0c;你知道如何查看并行回放…

最新AI系统ChatGPT网站源码/支持GPT4.0/GPT联网功能/支持ai绘画/mj以图生图/支持思维导图生成

使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到系统&#xff01; 同步mj图片重新生成指令 同步 Vary 指令 单张图片对比加强 Vary(Strong) | Vary(Subtle) 同步 Zoom 指令 单张图片无限缩放 Zoom out 2x | Zoom out 1.5x 新增GPT联网提问功能、签到功能 一、功能演示 …

基于springboot生鲜物流系统-计算机毕设 附源码13339

springboot生鲜物流系统 摘要 生鲜产品易于腐烂、难贮存、不易长时间运输&#xff0c;生产者所面临的市场风险很大&#xff0c;很多生鲜产品无法实现“货畅其流”和“物尽其值”&#xff0c;适宜的生鲜产品物流体系就显得尤为重要。本文将广东省生鲜产品物流体系的构建作为一个…

删除链表中等于给定值 val 的所有节点

203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 给出链表 1->2->3->3->4->5->3, 和 val 3, 你需要返回删除3之后的链表&#xff1a;1->2->4->5。 分析思路&#xff1a;这道题的思路&#xff0c;与之前删除链表中重复的结点相似。 因…

腾讯云从业者认证考试考点——云网络产品

文章目录 腾讯云网络产品功能网络产品概述负载均衡&#xff08;Cloud Load Balancer&#xff09;私有网络&#xff08;Virtual Private Cloud&#xff0c;VPC&#xff09;专线接入弹性网卡&#xff08;多网卡热插拔服务&#xff09;NAT网关&#xff08;NAT Gateway&#xff09;…

了解 spring MVC + 使用spring MVC - springboot

前言 本篇介绍什么是spring MVC &#xff0c;如何使用spring MVC&#xff0c;了解如何连接客户端与后端&#xff0c;如何从前端获取各种参数&#xff1b;如有错误&#xff0c;请在评论区指正&#xff0c;让我们一起交流&#xff0c;共同进步&#xff01; 文章目录 前言1. 什么…

RD算法(四)登堂入室 —— 成像完成

SAR成像专栏目录_lightninghenry的博客-CSDN博客https://lightning.blog.csdn.net/article/details/122393577?spm=1001.2014.3001.5502先放RD算法最终的成像结果: 经简单的地距投影后为(地距投影的内容在后面的几何校正章节中讲解): 温哥华这地形还真像是一张怪兽的巨嘴呀…

商城-学习整理-基础-商品服务API-三级分类(五)

目录 一、启动之前创建的环境1、启动虚拟机2、启动mysql3、启动redis4、启动nacos5、导入三级分类测试数据 二、开发商品服务三级分类列表1、后台模块1&#xff09;书写商品三级分类表后台业务逻辑 2、前端模块1&#xff09;启动renren-fast前后端项目2&#xff09;在系统管理-…

js逆向 - X-Zse-96分析(JsRPC实战)

本文仅供学习交流&#xff0c;只提供关键思路不会给出完整代码&#xff0c;严禁用于非法用途&#xff0c;若有侵权请联系我删除&#xff01; 目标网站&#xff1a;aHR0cHM6Ly93d3cuemhpaHUuY29tLw 目标接口&#xff1a;aHR0cHM6Ly93d3cuemhpaHUuY29tL2FwaS92NC9zZWFyY2hfdjM …

卸载 Postman!一款 IDEA 神级插件,更便捷、高效...

Restful Fast Request 是 IDEA 版 Postman&#xff0c;它是一个强大的 restful api 工具包插件&#xff0c;可以根据已有的方法帮助您快速生成 url 和 params。 Restful Fast Request API 调试工具 API 管理工具 API 搜索工具。 它有一个漂亮的界面来完成请求、检查服务器…

Django智能养殖场管理系统

目 录 摘要 1 绪论 1.1研究背景与意义 1.2研究内容 1.3论文结构与章节安排 2 智能养殖场管理系统分析 2.1 可行性分析 2.2 系统业务流程分析 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章小结 3 智能养殖场管理系统总体设计 …

数据分析 VS 数据可视化:决战时刻

数据分析和数据可视化是数据科学领域中两个重要的组成部分&#xff0c;很多人不明白两者之间的关系&#xff0c;会误认为是一个东西&#xff0c;其实不然。本文就带大家简单了解一下它们的区别与联系吧&#xff01; 数据分析是指通过收集、处理和解释数据来获取有关特定问题或…

深度学习入门 ---- 张量(Tensor)

文章目录 张量张量在深度学习领域的定义张量的基本属性使用PyTorch安装PyTorch查看安装版本 创建张量常用函数四种创建张量的方式和区别 四则运算 张量 张量在深度学习领域的定义 张量&#xff08;tensor&#xff09;是多维数组&#xff0c;目的是把向量、矩阵推向更高的维度。…