当前位置: 首页 > news >正文

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

一、背景 

由于自带的下拉图标是给水平布局的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;// 重建domthis.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 propertiescontentDiv.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

相关文章:

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

一、背景 由于自带的下拉图标是给水平布局的block使用&#xff0c;放在垂直布局下显得别扭&#xff0c;而且下拉选择后回修改image字段的图片&#xff0c;这让我很不爽&#xff0c;所以在原来的基础上稍作修改&#xff0c;效果如下&#xff1a; 二、使用说明 &#xff08;1&am…...

Robot Framweork之UI自动化测试---分层设计

Robot Framework 的分层思想是一种测试设计和代码组织的模式&#xff0c;它将测试用例的实现和测试执行逻辑分离&#xff0c;以提高测试的可维护性、可读性和可扩展性。 一、分层思想 在实际项目中&#xff0c;一般分为三层&#xff1a;元素层&#xff0c;流程层&#xff0c;用…...

MySQL8.0/8.x更新用户密码命令

authentication_string 这是Mysql8.0新做出的修改&#xff0c;在旧版本中使用的是password()函数。 2&#xff0c;在网上找到的mysql忘记密码的解决方案中&#xff0c;大多会使用 UPDATE user SET authentication_string12345 WHERE userroot; 来直接将密码改成12345&#xff0…...

【MySQL】下载安装以及SQL介绍

1&#xff0c;数据库相关概念 以前我们做系统&#xff0c;数据持久化的存储采用的是文件存储。存储到文件中可以达到系统关闭数据不会丢失的效果&#xff0c;当然文件存储也有它的弊端。 假设在文件中存储以下的数据&#xff1a; 姓名 年龄 性别 住址 张三 23 男 北京…...

算法题--二叉树(二叉树的最近公共祖先、重建二叉树、二叉搜索树的后序遍历序列)

目录 二叉树 题目 二叉树的最近公共祖先 原题链接 解析 二叉搜索树的最近公共节点 核心思想 答案 重建二叉树 题目链接 解析 核心思想 答案 二叉搜索树的后序遍历序列 原题链接 解析 核心思想 答案 二叉树 该类题目的解决一般是通过节点的遍历去实现&#x…...

mysql的基础面经-索引、事务

1 聚簇索引 1 和主键索引的关系 2 和非聚簇索引的关系&#xff0c;其叶子节点存储的是聚簇索引中的主键 3 索引覆盖机制使得非聚簇索引不用回表二次查询 2 举一个使用索引覆盖的例子 我的项目中没有使用到覆盖索引&#xff0c;但是可以举一个例子&#xff0c;比如我直接为年…...

Windows下双网卡配置静态路由,实现内外网同时使用

怎么样设置双网卡&#xff1f;内网外网两个网络这么同时连接&#xff1f; 接下来听好了&#xff0c;赶紧动手 情况描述&#xff1a; 我使用的Windows10电脑&#xff0c;支持双网卡工作 目前我工作需要使用的使用内网&#xff0c;但是又需要使用外网&#xff0c;需要同时使用&a…...

Spring整合Mybatis、Spring整合JUnit

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaweb 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Spring整合 一、Spring整合Mybatis1.1 整合Mybatis&#x…...

Devops系统中jira平台迁移

需求:把aws中的devops系统迁移到华为云中,其中主要是jira系统中的数据迁移,主要方法为在华为云中建立一套 与aws相同的devops平台,再把数据库和文件系统中的数据迁移,最后进行测试。 主要涉及到的服务集群CCE、数据库mysql、弹性文件服务SFS、数据复制DRS、弹性负载均衡ELB。 迁…...

【雕爷学编程】MicroPython动手做(29)——物联网之SIoT

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…...

LAXCUS分布式操作系统引领科技潮流,进入百度首页

信息源自某家网络平台&#xff0c;以下原样摘抄贴出。 随着科技的飞速发展&#xff0c;分布式操作系统做为通用基础平台&#xff0c;为大数据、高性能计算、人工智能提供了强大的数据和算力支持&#xff0c;已经成为了当今计算机领域的研究热点。近日&#xff0c;一款名为LAXCU…...

Linux--按行读取数据:fgets

函数定义&#xff1a; char *fgets(char *s,int size,FILE *stream); S是指接受数据缓冲区&#xff0c;用于存放stream里读取的数据 size是指缓冲区的大小 返回值为NULL表明读取失败&#xff0c;反之读取成功...

express学习笔记5 - 自定义路由异常处理中间件

修改router/index.js&#xff0c;添加异常处理中间件 *** 自定义路由异常处理中间件* 注意两点&#xff1a;* 第一&#xff0c;方法的参数不能减少* 第二&#xff0c;方法的必须放在路由最后*/ router.use((err, req, res, next) > {console.log(err);const msg (err &…...

filebeat介绍

1、filebeat概述 Filebeat是用于转发和集中日志数据的轻量级传送工具。Filebeat监视您指定的日志文件或位置&#xff0c;收集日志事件&#xff0c;并将它们转发到Elasticsearch或 Logstash或kafka进行索引 1.1 Filebeat两个主要组件 prospector 和 harvester。 prospector&a…...

使用SSM框架实现个人博客管理平台以及实现Web自动化测试

文章目录 前言1. 项目概述2. 项目需求2.1功能需求2.2 其他需求2.3 系统功能模块图 3. 开发环境4. 项目结构5. 部分功能介绍5.1 数据库密码密文存储5.2 统一数据格式返回5.3 登录拦截器 6. 项目展示7. 项目测试7.1 测试用例7.2 执行部分自动化测试用例 前言 在几个月前实现了一…...

【深度学习】MAT: Mask-Aware Transformer for Large Hole Image Inpainting

论文&#xff1a;https://arxiv.org/abs/2203.15270 代码&#xff1a;https://github.com/fenglinglwb/MAT 文章目录 AbstractIntroductionRelated WorkMethod总体架构卷积头Transformer主体Adjusted Transformer Block Multi-Head Contextual Attention Style Manipulation Mo…...

PyTorch BatchNorm2d详解

通常和卷积层&#xff0c;激活函数一起使用...

慕课网Go-4.package、单元测试、并发编程

package 1_1_User.go package usertype User struct {Name string }1_1_UserGet.go package userfunc GetCourse(c User) string {return c.Name }1_1_UserMain.go package mainimport ("fmt"Userch03 "goproj/IMOOC/ch03/user"//别名&#xff0c;防止同名…...

[JavaWeb]SQL介绍-DDL-DML

SQL介绍-DDL-DML 一.SQL简介1.简介2.SQL通用语法3.SQL语言的分类 二.DDL-操作数据库与表1.DDL操作数据库2.DDL操作表①.查询表(Retrieve)②.创建表(Create)③.修改表(Update)④.删除表(Delete) 三.Navicat的安装与使用四.DML-操作表数据1.添加(Insert)2.修改(Update)3.删除(Del…...

git源码安装(无sudo权限)

git源码安装&#xff08;无sudo权限&#xff09; 下载源码解压安装添加到环境变量 下载源码 去https://mirrors.edge.kernel.org/pub/software/scm/git/下载需要的版本。我下载的是2.41.0版本 wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.41.0.tar.gz解…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别

UnsatisfiedLinkError 在对接硬件设备中&#xff0c;我们会遇到使用 java 调用 dll文件 的情况&#xff0c;此时大概率出现UnsatisfiedLinkError链接错误&#xff0c;原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用&#xff0c;结果 dll 未实现 JNI 协…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...