VcnStudio 概述

欢迎使用 VcnStudio 开发平台,VcnStudio 提供了开发:安卓APP、跨平台视窗、国产操作系统桌面软件、网站、微信小程序、服务器接口、数据库后端、基于ESP32单片机 等应用程序的最迅速、最简捷的方法。不论是专业开发人员还是编程初学者,VcnStudio 都提供了整套工具,以方便不同需求的用户开发相应的应用程序。

何谓 VcnStudio ?

VcnStudio 的全称为 Visual Chinese Studio,其中:

Visual 一词表示:可视的、可视化的,在编程中通常指的是开发图形用户界面 (GUI) 的方法、不需要编写大量代码去描述界面元素的外观和位置,只需要通过可视化的方式将指定可以在屏幕中呈现出来的组件(例如:按钮、标签)添加到设计器窗口中即可快速完成软件界面的设计。

Chinese 一词表示:中文的、中文语言的,而 VcnStudio 采用了以中文作为源代码组成字符的自研编程语言:轻语言(Q)。在所有使用 轻语言 编写的程序中的源代码都可以使用中文编写、源代码文件都可以由中文汉字组成。

Studio 一词表示工作站、工作环境。

因此 VcnStudio 是一款支持可视化设计程序界面、且采用中文编写程序源代码的一个集成式 IDE 开发工具。

这里需要注意一个编程概念,VcnStudio 只是一款开发工具,并不是编程语言,VcnStudio 搭载的编程语言为 轻语言 ,而轻语言程序是纯粹的源代码文件,也就是说使用系统自带的记事本程序也可以编写轻语言程序。而 VcnStudio 集成了代码编辑器、智能提示、编译器等等,支持更多的编辑功能、更方便编写程序。

VcnStudio 适用于

  • 对不懂英文、没有时间学习专业编程知识的、但对编程有兴趣的普通人

  • 长期定制软件、支出成本较高且成品不理想、想自己做软件的个人创业团队或中小型企业、商家

  • 需要可以自己控制的软件开发;不想让创意或想法被别人抄袭

  • 老师、学生、党政机关、社区工作者制作方便自己生活使用的等各种场景APP

无论是开发个人或日常生活中使用的小工具,还是编写企业运营级系统项目,都可以在 VcnStudio 中完成。

相关资源

VcnStudio官网

VcnStudio开发者交流社区

VcnStudio开发者中心

VcnStudio类库市场

采购合作 购买VcnStudioUSB加密锁

公开课程:https://space.bilibili.com/330302804

实战课程:http://bbs.vcnstudio.com/?c=course&a=index

支持开发的应用

VcnStudio 支持开发以下平台或系统的应用程序:

  • 原生安卓(Android)APP 手机应用程序
  • 国产麒麟、统信、深度、红旗等操作系统桌面视窗软件
  • Linux 命令行程序
  • Linux 桌面应用程序
  • 微软 Windows 视窗应用程序
  • 苹果电脑 MAC 应用程序
  • 微信小程序(可视化)
  • 网站(H5 + WEB桌面端)、服务器接口
  • 单片机程序(ESP32)

价格

请关注官网发布的价格信息:合作与采购

安装 VcnStudio

在安装 VcnStudio 之前、必须确认计算机满足最低的安装要求。

检查硬件和系统需求

为稳定运行 VcnSudio ,计算机相关配置及系统需满足下列条件:

  • Microsoft Windows 7 及以上操作系统

  • X86 或 64 位架构的CPU

  • 系统内存大于或等于4G

  • 系统硬盘或目标安装目录不少于2G

安装

VcnStudio 安装包为纯绿色集成开发环境,当下载安装包之后、安装包文件后缀一般为:.7z 或 .zip 、此时直接解压安装包内的文件到指定文件夹即完成安装,建议将其解压到非系统盘之外的地方、例如除 C 盘以外的:D、E、F 盘都是可以的。

需要特别注意:安装包解压到的目标文件夹路径不能含有任何空格或DOS命令符(尤其注意:Program Files),解压后正确的运行路径可参考下方:

  • E:/VcnStudio4.7.2/VcnStudio.exe

  • F:/VCN/VcnStudio4.7.2/VcnStudio.exe

注意:路径中不能包含空格、中文、标点符号、制表符、换行符等特殊符号。

卸载

删除解压安装文件夹即可、例如您将 VcnStudio4.7.2.7z 解压到了 E 盘、直接删除 VcnStudio4.7.2 这个文件夹即可完全卸载 VcnStudio IDE 及所有相关插件。

启动 VcnStudio

当成功将安装包解压到电脑中的指定文件夹后、进入文件夹内会看到有一个 VcnStudio.exe 文件、双击或以管理员方式运行该文件,即可启动 VcnStudio 开发工具。

安装必要的运行环境

VcnStudio IDE 及相关开发插件采用 C# 、C++ 开发,如果在启动时弹出错误提示;

如果在IDE打开代码编辑器时弹出:

初识IDE开发环境

VcnStudio 集成开发环境界面

代码编辑界面

菜单栏

显示集成开发环境中可以使用的菜单命令。除了提供标准“文件”、“编辑”、“工具”、“窗口”和“帮助”菜单之外,还提供了编程专用的功能菜单,例如 “项目”、“开发”。

工具栏

工具栏是菜单栏的快捷指令,在编程环境下提供对于常用命令的快速访问。单击工具栏上的按钮,则执行该按钮所代表的操作。按照缺省规定,启动 VcnStudio 之后显示“标准”工具栏。附加的工具栏菜单只有当打开工程时才会动态加载并显示。

组件箱

提供了所加载应用类型可以使用所有组件;不同的程序类型有不同的组件,鼠标左键单击选中指定组件节点后;将鼠标移动到设计窗口中再次按下鼠标左键不松开移动绘制组件摆放位置;松开鼠标左键后、窗口设计器将添加并显示你所添加的组件。

支持库窗口

支持库窗口提供了所加载应用类型所有可用的组件函数文档;不同的应用类型拥有不同的支持库;你可以在该窗口中查询指定组件的使用方式及函数、属性注释。

属性窗口

属性窗口提供了对设计器中组件的属性编辑功能、当在窗口设计器中选中或同时选中多个组件时;可以在属性窗口中修改组件的属性,属性是指对象的特征,如尺寸大小、标题或颜色。

工程管理窗口

工程管理窗口提供对项目中的各种文件的可视化管理,例如:项目中的源代码、窗口布局文件、静态资源文件等。当打开或加载一个项目时、工程管理窗口将列出该项目的所有必要文件。

窗口设计器

窗口设计器支持在项目中自定义设计应用程序的界面,在设计器窗口中添加可视控件、图形和图片来创建所希望的外观,不同的应用程序类型拥有不同的设计器窗口风格。安卓与微信小程序类似手机界面、视窗类似电脑程序界面。

代码编辑器

用于编写程序中的源代码窗口。

帮助窗口

提供组件的帮助信息;当在支持库窗口中选中不同的组件时,帮助窗口将会同步展示所选中组件的注释信息。

编译输出窗口

当编译项目时;该窗口将会显示项目的编译进度、错误信息、以及编译结果。

其它

设计器窗口与代码同时显示

自定义开发环境窗口布局

加密锁版本

当电脑主机或笔记本的USB孔插入有 VcnStudioUSB加密锁 时,右上角人物头像会有一个 U 型图标。

IDE通用配置

打开IDE并加载一个工程后,在软件顶部菜单栏选择 设置通用设置 将打开 VcnStudio IDE 相关配置窗口,在配置窗口中可以设置 IDE 相关配置信息。

搜索引擎

VcnStudio IDE 中支持便捷的快速搜索功能、当在 IDE 底部编译输出窗口、调试输出窗口中选中待搜索的内容,然后单击鼠标右键、在弹出的菜单中,选择搜索并单击该菜单项,系统将会自动打开电脑中的浏览器并调用通用配置中的搜索URL地址进行搜索。

搜索引擎可以为任意支持GET链接关键字的地址,默认为:百度搜索

  • https://www.baidu.com/s?wd=待搜索内容

  • https://cn.bing.com/search?q=待搜索内容

文件头

当在项目中新建文件时、尤其在新建代码文件时,文件中的顶部将会默认添加文件的注释信息,这些信息记录了文件创建时间、版本、功能、以及作者信息等等。

开发者信息

当在IDE中成功登录账号后,账号信息将会被保存在配置文件中,如果要退出登录账号,可以在该面板中清除账号信息。

代码编辑器

代码编辑器配置包含了对代码编辑时的相关配置,包含对字体、字体大小、关键字颜色、配色方案的设置。


编译设置

编译后自动打开输出目录

如果选中该项,当成功编译一个项目时,将会自动打开编译输出的项目文件夹。

启用安卓增量编译

如果选中该项,当在编译安卓应用时,将会缓存扩展库的依赖文件、多核CPU可以加快编译速度。

可视化界面设计

安卓可视化界面设计

VcnStudio 支持通过可视化快速拖拽的方式设计安卓APP的界面。

可视化设计允许开发者通过拖拽组件(如按钮、文本框、图片等)快速构建界面,减少手动编写XML代码的时间。

视窗桌面软件可视化设计

微信小程序可视化设计

源代码编辑

程序中的源代码编辑通常在一个窗口中完成、每个代码编辑窗口负责一个文件。

当双击工程窗口中程序集节点中的代码文件时、系统将会自动在IDE中打开代码编辑窗口。

注意:在部分缺少VC++环境的Windows操作系统中,打开代码编辑器时可能会出现 Could not load the Scintilla module at the path '...SciLexer.dll' 的错误,请参考 安装VcnStudio 中的环境安装。

支持的输入类型

为了便于快速输入代码,VcnStudio 内置了三种代码输入方式。

  • 首拼

    • 输入关键字或组件、对象名称的拼音首字母、例如:rg -> 如果,bjk1 -> 编辑框1
  • 全拼

    • 输入关键字或组件、对象名称的汉字拼音全拼、例如:ruguo -> 如果,bianjikuang-> 编辑框1
  • 中文

    • 除了通过拼音的方式、编辑器还支持纯中文汉字的输入。

在使用拼音快速输入时有时需要注意多音字的输入;例如:行 (hang/xing)、重(zhong/chong)、调(tiao/diao)、弹(tan/dan)...

智能提示、自动完成

VcnStudio 代码编辑器支持智能提示,在编写代码时编辑器引擎会根据上下文自动完成代码,自动根据用户输入的内容匹配目标提示选项。

例如当在编辑器中输入一个控件名称时,编辑器中的智能提示列表框将会列出该控件的所有属性和方法,并同时将活动焦点移动到列表框上,此时按下键盘上的上键(↑)、下键(↓)可以切换列表中的选项,按下回车(Enter)、或空格键(Space)完成选项并将选择的内容插入到代码编辑器中。

如果智能提示列表中没有你想要的选项;按下键盘上的 ESC 键;即可关闭该提示列表。

智能提示不仅支持对窗口组件的提示;同时也支持对代码中的变量、函数、参数、以及动态创建的对象进行提示。

注释快捷生成

当回车换行时;编辑器会检测行首是否存在注释前缀,如果存在则会自动添加注释字符串模板内容,通用注释前缀指导符:

'

'*

'* --

'* ==

'* **

如果代码中某行以这些字符串(其中一个)为前缀,当在这一行按下回车时;将自动添加对应的注释模板。

'* ******************************************************************************
'* 注释内容
'* ******************************************************************************
函数 注释模板1()

结束 函数

'* ==============================================================================
'* 注释内容
'* ==============================================================================
函数 注释模板2()

结束 函数

'* ------------------------------------------------------------------------------
'* 注释内容
'* ------------------------------------------------------------------------------
函数 注释模板3()

结束 函数

函数提示

当输入类型为一个函数时、编辑器中的函数提示框将会被激活;并显示函数的参数及注释。

快捷输入

在编写代码时、编辑器引擎除了常规的代码输入外;还提供了一些常见关键字语句块的快速输入;以下关键字在输入后;光标放在关键字末尾按下键盘上的 TAB 键;编辑器会自动完成相应代码的语句块。

  • 如果

  • 判断

  • 函数

  • 变量循环

  • 判断循环

  • 计次循环

  • 异步执行首

  • 异常捕获首

快速添加组件事件

为组件添加事件除了通过在设计器中选中组件,在属性框上方的事件列表添加外;在代码编辑器中只需要选中组件名称;然后单击鼠标右键;选择右键菜单中的 添加事件 ,系统将会弹出所选中组件的事件列表窗口;在该窗口中双击指定事件即可自动添加相关事件代码到编辑器中。

代码编辑热键

  • Ctrl + S     保存代码

  • Ctrl + D    切换到设计器

  • Ctrl + E     添加事件

  • Ctrl + J      转到定义位置

  • Ctrl + I      查看类型命令、函数帮助

  • Ctrl + C     复制

  • Ctrl + V     粘贴

  • Ctrl + X     剪切

  • Ctrl + L      折叠或展开代码

  • Ctrl + Q     格式化代码

  • Ctrl + F      查找代码

新建项目工程

启动 VcnStudio 后、在软件左上角点击新建项目标签。

点击新建项目标签后,将弹出新建项目窗口:

左侧为支持创建的项目类型,右侧为项目类型中对应的项目模板。

当使用鼠标左键点击项目类型中的节点时,右侧将会显示对应类型的项目模板。

选中待创建的项目模板,在下方输入项目名称及项目存放位置;再点击确定按钮,系统将会自动创建项目工程并在IDE中打开项目。

项目模板的管理

加载、打开项目工程

在 VcnStudio 中打开或加载轻语言程序,有以下两种方式:

使用项目索引文件

每个轻语言程序都有一个独立的项目索引文件, .vsln ;当需要打开项目工程时,只需要选中该文件使用VcnStudio.exe打开、或双击该文件。

参考:轻语言程序基础结构

在IDE中打开

首先打开 VcnStudio ,然后在软件左上角点击 打开项目 标签,然后选择需要打开的项目工程索引文件即可。

最近使用的项目

当打开一个项目时,IDE 会记录项目,并在下一次打开IDE时依次按照打开的项目顺序显示。

添加、删除、修改工程文件

VcnStudio 使用轻语言作为编写程序的源代码语言,而轻语言程序是以多文件格式存在、代码文件也是以纯文本格式存在,因此所有轻语言程序相关资源文件或代码文件除了在IDE中可以修改,也可以脱离IDE而修改。

具体每种应用类型的工程结构请参考目标平台的开发文档。

项目模板管理

当在 VcnStudio 中新建一个项目时,IDE 将会自动根据选择的项目模板创建含有默认文件的项目。

VcnStudio 中所有工程项目的模板都支持自定义修改、编辑或新增。

项目模板路径

VcnStudio 所有新建项目的模板都位于:安装目录/sdk/{平台}/project-tmpl 该文件夹中。

其中:

  • application 目录为项目模板

  • component 目录为类库模板

其它文件可以通过查看 tmpl.xml 得知。

修改模板

以在 IDE 中新建安卓默认工程为例。

安卓默认工程模板工程路径为:安装目录/sdk/android/project-tmpl/application/默认工程

该模板工程目录下即为项目的源代码及必要文件,除了:目录中的文件夹名称及 Project.vsln 该文件不能修改外、其余文件都可以自行编辑修改,关于安卓工程结构请参考 安卓工程项目结构

例如:修改模板中的主窗口代码;位于 src/主窗口.spl 文件,在其中添加一段自定义代码,保存文件后、再重新启动 IDE 新建安卓默认工程,自定义添加的代码将会被添加到主窗口中。

除此之外也可以修改 layout 文件中的布局文件、添加自定义的 assets 仓库文件。

新建自定义模板

复制一个现有模板项目工程为新的模板、例如:复制 默认工程我的项目模板 ,然后根据自己的需求定制化修改模板中的项目文件即可。

需注意:新建的自定义模板需和原模板保持在同一个目录。

删除模板

删除模板只需要删除模板工程文件夹即可,例如:删除安卓模板工程,只需要删除 默认工程 文件夹即可。

核心支持库

VcnStudio 安装包内提供了大量的不同平台的核心支持库组件、这些组件都是开源的,且同时这些组件是编写程序时必要的资源文件。

核心库文件存放路径

所有的核心库组件都位于 安装目录/sdk/{平台}/components/primary安装目录/sdk/{平台}/components 文件夹中。

所有核心库组件都是以源代码形式存在,开发者在编写程序时可以根据自身需求修改编辑这些核心库文件。

{平台} 代指 android、javafx、web、wechat、mcu 的其中一个。

核心库文件对应的API文档

所有的核心库注释文档都位于:

安装目录/sdk/{平台}/sdk.xml 文件中。

安装、卸载扩展类库

扩展类库与核心库的功能类似;但扩展类库提供了更丰富的组件和功能。由于扩展类库的安装与卸载相对较简单、因此 VcnStudio IDE 中未提供扩展类库的安装与卸载功能;扩展类库的安装与卸载需要手动完成。

安装扩展类库

VcnStudio 中不同平台的扩展类库统一安装路径为:

安装目录/sdk/{平台}/components/extends安装目录/sdk/{平台}/extends

以安卓程序为例,安卓扩展类库安装路径为:

安装目录/sdk/android/components/extends

当获得一个扩展类库文件时,只需要将其复制到上方目录中的任意分组目录中即可。

例如:在 extends 文件夹中新建一个文件夹并命名为:我的私有类库

然后将类库文件复制到该文件夹中;此时关闭 IDE (如果已经打开IDE的状态下),再重新打开 VcnStudio.exe ,如果类库文件格式正确、那么在组件箱窗口中将会加载并显示安装的类库。

这里需要尤其注意:所有的扩展类库必须复制到分组目录中、分组目录建议自行创建、方便后期更新时直接复制。

卸载扩展类库

卸载类库时,只需要直接删除目标类库文件即可。

例如要删除一个 自定义类库.scm ,只需要删除该文件即可卸载。

查看示例程序

VcnStudio 安装包内自带了非常丰富的官方演示程序,参考学习这些示例程序有助于更快掌握使用 VcnStudio 开发应用程序。

如何查看例程

可以通过以下两种方式查看示例程序:

  1. 打开 VcnStudio 软件后,在软件的左上侧点击: 打开本地例程...,点击后将会弹出示例程序的窗口、双击指定例程,IDE 将会自带加载并打开项目。

  2. 在 VcnStudio 的安装目录有一个名为 samples 的文件夹,该文件夹内存放了官方编写的各个不同平台演示工程,进入文件夹后、选择指定平台即可看到项目源码工程、打开项目索引文件 .vsln 即可打开演示例程。

平台类型

samples 文件夹中的子文件夹对应平台类型:

文件夹名称项目类型
android安卓项目例程
javafx视窗项目例程
web网站、后端接口例程
mcu单片机项目例程
wechat微信小程序例程
component.library支持库、类库源码例程

问题反馈

为了更快速解决开发问题;请在反馈时将具体问题尽可能描述清楚、带上必要的截图或含有问题的程序源代码。

开发问题及BUG反馈官方渠道:

VcnStudio 开发者社区

简介

轻语言概述

轻语言是一款支持开发多端应用、且使用中文汉字作为源代码编程的国产自主研发的轻量级编程语言,轻语言有很多现代编程语言的特点,简单易学、面向对象、与平台无关、可移植性强、解释执行、高性能、支持多线程、网络编程等。

设计理念

轻语言的设计理念为:面向中文编程、使用中文编程

语言特性

统一语法

轻语言将编写各个平台应用的常用语言的语法进行统一归纳,根据目标用户定位和实际开发需求,简化语法,增加语法糖,筛减部分复杂特性,吸取优秀特性;最终实现只需要通过一套语法、就可以编写多种程序。简言之:学会轻语言后,使用轻语言编写各种不同平台的程序都是一种语法格式,无需再学其它的语法特性。

按需编译

轻语言提供了多种不同平台应用的中文 SDK 开发包,例如针对安卓,轻语言提供了完整的安卓标准组件库及汉化封装的安卓开发包,针对视窗,轻语言提供了完整的基于 JavaFx 封装的跨平台开发包,针对微信小程序,轻语言提供了完整的小程序中文组件库及开发包,针对单片机,轻语言提供了完整的单片机中文函数、中文库等等。

在编译时,轻语言编译器会根据创建的工程类型,采用不同的编译器先将项目转译成对应目标平台的原生工程,再调用原生平台提供的编译器将项目编译输出为最终可被执行的程序。

简单易懂

轻语言采用类似 BASIC 语言的语法,抛弃了大部分编程初学者或非专业开发人员不会经常使用,且难以理解的各种高级语言特性;从实际角度出发;以简单易懂、上手易学作为目标设计。

中文源代码

轻语言采用中文汉字编写程序源代码;编辑器内置首拼匹配;支持中文语句快速键入,开发人员无需了解或学习英文,降低了编程门槛,不同层次、不同行业的人员只要认识汉字都可以使用轻语言快速上手编写软件程序。

多线程

轻语言支持多线程编程,异步编程;且轻语言针对不同目标平台特别优化了多线程的使用语法,与其它编程语言相比;轻语言使用多线程时、更简洁。详见 多线程

可扩展

轻语言支持在项目中嵌入使用目标原生代码,例如编写安卓APP时,可以直接在源代码中使用 Java 代码。

关键字

在轻语言中,关键字是程序代码中预定义的保留字,用于定义程序的语法结构、数据类型、访问控制等,具有特殊的含义和用途。它们不能被用作标识符(如变量名、窗口名、模块名称、函数名等)。

轻语言基础关键字列表

轻语言基础关键字包含了轻语言基于 Java8 设计的相关语言特性;不包含例如网站、单片机等目标平台的扩展特性。以下是轻语言1.5中的所有核心关键字:

关键字用途
声明变量的类型,例如:变量 age 为 整数型
比较条件判断的或类型,条件双方有真则返回真。
比较条件判断的且类型,条件双方都为真则返回真。
空对象、空数据值,表示对象不存在。
表示逻辑真。
表示逻辑假。
变量声明变量的关键字,例如:变量 name 为 文本型
判断带有分支条件的判断语句关键字。
如果条件判断语句。
否则条件判断语句的分支。
分支判断语句的其它分支条件。
结束用于在代码中指定结束某个代码块、例如:结束 事件 、结束 函数
退出用于退出函数或者循环的关键字;主要用于:1.在分支判断中;用于退出分支语句;2.在循环中退出循环。
跳过用于在循环中跳过某一次循环。
静态静态修饰符、由该修饰符修饰的变量或函数可不用创建对象直接使用类名调用。
私有私有修饰符;由该修饰符修饰的变量或函数仅允许在本文件或模块内使用。注:该修饰符与“静态”修饰符一起使用时、该修饰符必须在“静态”关键字之前。
创建创建数据类型的实例对象关键字,例如:变量 按钮1 = 创建 按钮()
事件定义组件接收回调事件的关键字、以及在自定义数据类型或组件中定义回调事件的关键字。
函数定义函数关键字。
定义定义非变量类型的对象标记、自定义结构体、回调接口、事件的关键字。
公开定义向外公开的自定义回调事件、通常用于在模块或窗口中、向外传递回调事件使用。
属性定义属性的关键字。
对象该关键字用作表示对象类型;除基本数据类型外;所有其它数据类型均为对象。
返回返回函数的结果;也用于不再执行后面的代码。
引用引入并使用原生类型或自定义 Jar 包数据类型关键字。
类属判断指定对象是否属于某个类型。
结构自定义数据结构、回调对象类型关键字。
到主线程该关键字用于将当前线程切换到主线程;一般可在异步函数、线程执行代码块中快速更新UI。
本对象表示当前代码所在的上下文环境。
逻辑型判断条件的结果是否成立或不成立;属性值为真或假;默认值为假。
字节型表示8位有符号整数、用于表示最小数据单位、如文件中数据、值为-128至127;默认值为0。
整数型表示32位的有符号整数值;最小值为(-2^31);最大值为(2^31-1);默认值为0。
短整数表示16位的有符号整数值;最小值为(-2^15);最大值为(2^15-1);默认值为0。
长整数表示64位的有符号整数值;最小值为(-2^63);最大值为(2^63-1);默认值为0L。
双精度小数表示64位双精度小数类型;符合IEEE754标准的浮点数;默认值为0.0。
单精度小数表示64位单精度小数类型;符合IEEE754标准的浮点数;默认值为0.0f。
文本型表示文本字符串类型。
变量循环用于定义一个可自增自减的随着变量改变而循环代码块。
计次循环用于定义一个可以递增计次的变量循环代码块。
判断循环用于定义一个判断循环。
结束循环与循环语句配合使用、用于在循环尾结束循环。
异步执行首启动一个子线程执行该关键字包裹的代码。
异步执行尾结束子线程执行该关键字包裹的代码。
异常捕获首尝试捕获可能导致程序发生错误或崩溃的开始代码。
异常被捕获当尝试捕获代码异常错误、错误被成功捕获时接收错误信息的语句。
异常捕获尾结束异常捕获。

轻语言扩展关键字

除核心关键字外、不同的应用平台有不同的扩展关键字,具体请参考目标平台相关开发文档。

注意事项

  • 不能用作标识符:关键字不能用作变量名、函数名、模块名、窗口名等。

  • 保留字属性 、继承类型 是 轻语言 的保留字,但未在当前发布版本中使用,在后续更新版本中可能会增加,因此同样不建议使用保留字作为标识符。

数据类型

什么是数据类型?

数据类型是一种表示不同数据格式的基本概念,在编程中用于表示数据的种类,不同的数据种类决定了在内存中不同的储存方式以及对应可执行的操作。

例如:数字 12、100、200 ... 表示10 进制整数值、这些值可以在程序中执行加减乘除的运算、而小数 1.2、1.5、3.1414 ... 表示小数值、这些值与整数一样;也可以进行加减乘除的运算操作。

但:"信息提示"、"请输入内容"、"用户名" ... 像这样的字符串的文本内容;在程序中一般表示文本型数据、而文本类型的数据无法像整数那样加减乘除。

而在一个程序(软件)中、不仅可能包含了整数值、小数值、文本字符串这些不同格式的数据,同时还有可能包含其它数据格式值,例如:真、假、自定义数据类型 等等。

轻语言支持哪些数据类型?

在轻语言中;一共支持 7 种基本数据类型和 2 种基础引用类型。

整数型(int)

  • 32位有符号整数类型
  • 最小值:-2,147,483,648(-2^31)
  • 最大值:2,147,483,647(2^31 - 1)
  • 默认:0
  • 例如:变量 a 为 整数型 = 10

短整数(short)

  • 16位有符号整数类型
  • 最小值:-32768(-2^15)
  • 最大值:32767(2^15 - 1)
  • 默认:0
  • 例如:变量 a 为 短整数 = 10

字节型(byte)

  • 8位有符号整数类型
  • 最小值:-128(-2^7)
  • 最大值:127(2^7-1)
  • 默认:0
  • 例如:变量 a 为 字节型 = 10

长整数(long)

  • 64位有符号整数类型
  • 最小值:-9,223,372,036,854,775,808(-2^63)
  • 最大值:9,223,372,036,854,775,807(2^63 -1)
  • 默认:0L
  • 例如:变量 a 为 长整数 = 10L
  • 说明:这种类型主要用在需要较大整数的系统上。

单精度小数(float)

  • 32位符合IEEE754标准的小数
  • 默认:0.0f
  • 例如:变量 a 为 单精度小数 = 1.2f

双精度小数(double)

  • 64 位、符合 IEEE 754 标准的浮点数
  • 默认:0.0
  • 例如:变量 a 为 双精度小数 = 1.2
  • 说明:默认代码中的小数为双精度小数类型

逻辑型(boolean)

  • 表示一位的信息、真或假
  • 默认:假
  • 例如:变量 a 为 逻辑型

文本型(String)

  • 由双引号包裹的字符串文本数据
  • 默认:空 null
  • 例子:变量 url 为 文本型 = "http://www.vcnstudio.com"

对象

  • 所有引用类型及自定义类型都继承自该类。
  • 默认:空
  • 例如:变量 模块1 为 对象

数据类型之间的转换

不同的数据类型之间可以相互转换,例如最常见的将一个整数转成文本字符串、或将一个文本字符串转成整数。

在轻语言中;不同的基础数据类型之间的值可以通过内置的相关转换函数来转换;例如:到整数、到小数等等。

而针对非基础数据类型的自定义数据类型值,在转换时需统一使用转换语法进行转换,转换语法的格式为:

变量 目标值 = (目标类型)待转换的值

' 例如 将一个整数值转成文本信息
变量 文本值1 = (文本型)100
' 但在实际运用中、通过语法强转的方式可以帮助我们更灵活的编程
' 例如下方代码:
' 当我们点击按钮1时、调用自定义函数修改传入的组件宽度与高度值。
事件 按钮1.被单击(来源对象 为 视图)
    修改组件尺寸(按钮1,100,100)
    修改组件尺寸(标签1,50,50)
结束 事件

' 在该自定义函数中、第一个参数值类型为:“对象”类型、该类型是轻舟中所有自定义数据类型的基类
' 当声明函数参数为“对象”类型时;这个参数值可以为任意非基础数据类型值;而这里我们传入的参数
' 值为按钮1、标签1,都为窗口中的可视组件;而所有可视组件都为视图类,因此我们可以先使用关键字:
' “类属”判断传入的参数值是否为可视组件、如果是,再转换成视图对象值、再调用所有可视组件都拥有
' 的宽高属性设置其值。
函数 修改组件尺寸(待修改组件 为 对象,宽度 为 整数型,高度 为 整数型)
    如果(待修改组件 类属 视图)
        变量 目标组件 = (视图)待修改组件
        目标组件.宽度 = 宽度
        目标组件.高度 = 高度
    否则
        弹出提示("目标组件不属于视图类组件;无法设置尺寸")
    结束
结束 函数

注:基础数据类型不能转换成对象、也不能与对象类型的数据互相转换

特殊的文本类型

文本类型的数据是一种特殊的数据类型,任何非文本数据值如果与文本字符串相加都会默认转成文本型。

示例:

变量 文本1 = "整数1的值:" + 100
调试输出(文本1) ' 将输出 整数1的值:100

运算符

计算机的最基本用途之一就是执行数学运算,作为一门计算机编程语言,轻语言也提供了一套针对非专业编程用户、但比较实用的运算符来操纵变量、这有助于帮助大家快速入门、上手学习编程、目前轻语言支持以下几种运算符:

算术运算符

算术运算符用在数学表达式中,它们的作用和在数学中的作用一样、可以在代码中对变量进行赋值运算操作、下表列出了所有的算术运算符:

运算符 描述
+ 加法 - 相加运算符两侧的值
- 减法 - 左操作数减去右操作数
* 乘法 - 相乘操作符两侧的值
/ 除法 - 左操作数除以右操作数
取余 - 左操作数除以右操作数的余数

代码演示(部分):

变量 a = 1 + 2
调试输出("a = " + a) ' 输出3
变量 b = 3 - 2
调试输出("b = " + b) ' 输出1

关系运算符

关系运算符、一般也称为条件运算符、主要用于比较值的关系、下面列出了轻语言中所有的关系运算符:

运算符 描述
== 检查如果两个操作数的值是否相等,如果相等则条件为真。
!= 检查如果两个操作数的值是否相等,如果值不相等则条件为真。
> 检查左操作数的值是否大于右操作数的值,如果是那么条件为真。
< 检查左操作数的值是否小于右操作数的值,如果是那么条件为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。

代码演示(部分)

变量 a = 1
如果(a == 1)
    调试输出("a等于1、成功")
结束 如果
如果(a > 2)
    调试输出("a不大于2、失败")
结束 如果

注:比较两个文本变量是否相等时请使用 “取相等” 函数。

赋值运算符

赋值运算符、相对简单、其主要作用为:将右侧的值赋值给左侧、在轻语言中为了减少用户学习成本、降低用户上手难度、仅支持一个运算操作符。

运算符 描述
= 赋值运算符,将右操作数的值赋给左侧操作数

代码演示:

变量 a = 0 ' 将 0 赋值给 a 在编译时、将设置 a 为整数型
标签1.标题 = "我是标题内容" ' 将字符串内容赋值给标签标题

入口文件

在轻语言中,每个轻语言程序都有一个且唯一的程序入口文件,默认文件名为:App.spl ,在该文件内部有一个名为:应用被启动 的事件,当启动程序时,系统将会先回调该事件,告诉开发者系统已对程序启动就绪,开发者可以在该事件中开始执行程序相关逻辑业务。

入口文件的作用

  • 程序起点应用被启动 事件是轻语言程序被所在系统启动时的起点,系统将从这里开始执行代码。

  • 参数传递:可以通过 应用被启动 事件的参数(参数 为 文本型[])接收命令行参数(如果目标应用支持的话)。

  • 初始化:通常在 应用被启动 事件中初始化应用程序的核心组件,例如加载一个窗口、加载配置文件等。

应用被启动 事件的参数

默认的轻语言程序入口文件中,应用被启动 事件中含有一个类型为文本型的数组;该参数值是外部通过命令行方式启动程序时传入的参数值。

控制台程序示例:

事件 应用被启动(命令参数 为 文本型[])
    如果(取数组成员数(命令参数) == 0)
        调试输出("程序启动成功;未带任何命令参数")
    否则
        变量循环(索引 = 0,取数组成员数(命令参数),1)
            调试输出("命令行参数:" + 命令参数[索引])
        结束循环
    结束 如果
结束 事件

当编译上方程序为一个轻语言可执行程序 jar 时(目标平台为 Java );在命令行窗口中分别传入参数值、与不传入参数值运行:

注意事项

  • 入口文件:一个轻语言程序,只能有一个且唯一的入口文件 App.spl

  • 命令行参数:可以接收多个参数,参数之间用空格分隔。

  • 不同平台:不同应用平台入口文件的启动事件与参数存在不同差异,详细情况请阅读目标平台的相关文档。

变量

什么是变量?

变量是轻语言程序在运行时用于存储数据的基本单元,变量类似一个容器,可以用来存放程序运行过程中需要使用的各种数据值,每个变量都有一个名字(标识符)和一个数据类型,用于指定变量可以存储的数据种类。

变量的作用

  1. 存储数据:变量用于存储程序运行时的数据,例如用户输入、计算结果等。

  2. 提高代码可读性:通过给变量起一个有意义的名称,可以让代码更容易理解。

  3. 复用数据:变量可以多次使用,避免重复计算或重复输入相同的数据。

  4. 动态修改数据:变量的值可以在程序运行过程中被修改。

如何使用变量?

在轻语言中,使用变量通常分为以下三个步骤:

1.声明变量

声明变量时通过关键字“变量”定义;后跟名称和类型,或名称和初始值;声明变量的语法为:

' 显示指定变量的数据类型
变量 变量名称 为 数据类型
' 通过初始值、在编译时由编译器推断类型
变量 变量名称 = 初始值

示例:

变量 A 为 文本型
变量 a 为 文本型
变量 网址URL 为 文本型
变量 x,y 为 整数型
变量 c = "文本类型变量"
变量 d = 100 ' 整数型

2.初始化或修改变量值

当声明变量后、可以同时为变量设置一个初始化值,也可以在其它地方初始化修改变量值。

示例:

变量 m 为 文本型 = "vcnstudio"
变量 pi 为 双精度小数 = 3.14159
变量 url = "http://www.vcnstudio.com"
变量 an1 = 创建 按钮() 
变量 x1,y1 = 0
' 通过设置初始值定义变量类型
变量 a = "文本类型变量"
变量 b = 100 ' 整数型
变量 c = 真  ' 逻辑型
变量 d = 1000L ' 长整数
变量 e = 1.5   ' 双精度小数
变量 f = 1.2f  ' 单精度小数
变量 g = 创建 按钮() ' 按钮对象
变量 h = 取随机数(10,20) ' h为函数返回值、整数型

示例:

' 定义变量、但不设置初始值
变量 变量1 为 文本型
变量 年龄 为 整数型

事件 窗口创建完毕()
    ' 在窗口创建完毕或程序被启动时为变量设置初始值
    变量1 = "变量1的初始值"
    年龄 = 29
结束 事件

示例(修改变量):

事件 按钮1.被单击(来源对象 为 视图)
    ' 当点击按钮1时、变量1 的值将变成:按钮1被单击
    变量1 = "按钮1被单击"
    ' 当点击按钮1时、变量1 的值将变成 30
    年龄 = 30
结束 事件

3.使用变量

当变量初始化或被设置有数据值时,我们可以在程序中使用它;例如读取变量中储存的值。

示例:

事件 按钮2.被单击(来源对象 为 视图)
    ' 当点击按钮2时、将 变量1 储存的数据值显示到窗口标签中
    标签1.标题 = 变量1
    ' 当点击按钮2时,调试输出变量 年龄 储存的值,这里需要注意:
    ' 由于 年龄 这个变量定义的数据类型为 整数型 因此在需要文本值的地方
    ' 我们需要先将其转换成文本类型
    调试输出("变量 年龄 储存的值为:" + 到文本(年龄))
结束 事件

变量的命名规则

  1. 变量名必须以字母、下划线 (_) 或中文开头。

  2. 变量名不能以数字开头。

  3. 变量名不能是轻语言中的关键字(如 整数型如果 等)。

  4. 变量名区分大小写、A 与 a 是两个不同的变量标识符。

  5. 变量名中不能含有任何操作符号、运算符号、或标点符号。

变量的作用域

变量的作用域是指变量在程序中可以被访问、使用的范围。根据声明位置的不同,变量的作用域分为以下几种:

1.局部变量

在函数、事件、或某个语句块中定义的变量,作用域仅限于在该区域内使用。例如:

函数 打印年龄数据()
    ' 局部变量、只能在该函数中使用
    变量 年龄 = 25
    调试输出(年龄)
结束 函数

2.类成员变量

在窗口、模块中但在函数、事件外的区域定义的变量,该变量与函数、事件属于同一层级;可以在整个窗口或模块中使用。例如:

' 与事件、函数同一级别的变量、可以在本窗口中任意地方使用
变量 变量1 为 文本型
变量 年龄 为 整数型

事件 窗口创建完毕()
    ' 在窗口创建完毕或程序被启动时为变量设置初始值
    变量1 = "变量1的初始值"
    年龄 = 29
结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    调试输出("变量1 " + 变量1)
    调试输出("年龄 " + 到文本(年龄))
结束 事件

3.全局静态变量

使用“静态”关键字修饰的变量,作用域是整个程序;可在整个程序中不同的窗口或文件中使用。例如:

' 应用的全局变量、可在整个程序的窗口或其它模块中使用
变量 静态 全局标记 为 文本型 = "http://www.vcnstudio.com"

使用示例:

事件 按钮1.被单击(来源对象 为 视图)
    ' 静态模块1 可在程序集中新建文件、选择 静态模块 创建
    调试输出("全局变量:" + 静态模块1.全局标记)
结束 事件

注意事项

同一个作用域中不能含有两个相同名称的变量。

循环语句

顺序结构的程序语句只能被执行一次;如果要想使同样的操作执行多次,就需要使用循环语句。在轻语言中有 3 种主要的循环语句、每个循环语句都有与之对应的唯一结束标志:"结束循环"、用以当不符合条件时结束并退出循环。

判断循环

判断循环是最基本的循环结构语句、只要传入的逻辑值、或逻辑表达式满足条件为真、程序将会进入循环体、并一直重复执行语句块中的代码;判断循环语句使用关键字:判断循环 定义,其语句结构为:

判断循环(条件)
    ' 待执行的语句代码

结束循环

示例:

变量 计次 为 整数型 = 0
判断循环(计次 < 10)
    ' 循环执行代码、使变量的值加1
    计次 = 计次 + 1
结束循环
调试输出(计次) ' 将输出 10

上述代码解释:

  • 当变量 计次 的值小于10时、则进入循环体内、循环执行代码块内的代码。每次执行完循环代码、让变量计次的值加1;当计次大于10时、不符合条件则不再进入循环体内、程序将跳到结束循环标志、退出循环。

注意:使用判断循环时、确保逻辑值有条件返回假、否则将会导致程序陷入死循环无法退出。

变量循环

变量循环;顾名思义是以变量为开始点、进行循环的结构语句体;因为该语句指定了初始值及目标值、因此在实际开发过程中使用的比较多。该循环使用关键字 “变量循环” 定义。其语句结构为:

变量循环(初始变量 = 初始值, 目标值, 递增值)
    ' 待循环的代码

结束循环

语句释义:

  • 参数一:初始值、指定从什么值开始循环
  • 参数二:目标值、指定循环到那个值就退出循环
  • 参数三:递增值、每次执行循环代码后初始变量增加的值

示例:

变量循环(计次 = 0, 10, 2)
    ' 循环打印输出“计次”的值
    调试输出("计次" + 计次)
结束循环

上述代码解释:

  • 初始变量为0、目标值为10、每次循环后初始变量加2、当初始变量大于10时、将会退出循环。

计次循环

计次循环、是以次数限制循环的语句、多用于在处理循环时指定次数的场景。用关键字“计次循环”定义、其循环结构语句为:

计次循环(总循环次数, 计次变量)
    ' 循环执行的代码

结束循环

语句解释:

  • 参数一:总循环次数、指定要循环的总次数
  • 参数二:计次变量、循环递增计次的变量、每次递增加1

示例:

变量 计次 为 整数型 = 0
计次循环(10,计次)
    ' 待循环执行的代码、循环输出 计次 变量的值
    调试输出("计次:" + 计次)
结束循环

上述代码解释:

  • 循环 10 次、计次变量从 0 开始、每次计次变量加 1 、当循环 10 次后退出循环。

退出循环

如果在执行循环语句过程中、要在中途结束并退出循环(不再执行后续的循环);可以使用关键字 “退出” 提前结束循环。例如在下方代码中;当计次等于 5 时、则提前退出并结束循环。

示例:

变量 计次 为 整数型 = 0
判断循环(计次 < 10)
    ' 当执行第5次循环的时候、提前结束并退出循环
    ' 退出循环后、将不再执行后续的循环
    如果(计次 == 5)
        退出
    否则
        ' 执行语句
    结束 如果
    计次 = 计次 + 1
结束循环

跳过循环

如果在执行循环语句过程中、想跳过某一次循环(但仍需要继续执行后续的循环);可以使用关键字 "跳过" 不执行本次循环语句。例如在下方代码语句中;当计次等于5的时候、则跳过该次循环、但仍然会继续执行后续循环。

示例:

变量循环(索引 = 0,10,1)
    ' 当 索引 等于 5 的时候、程序将跳过本次循环,不再执行本次循环后面的代码
    ' 但下一次循环仍会继续
    如果(索引 == 5)
        跳过
    结束 如果
    调试输出("索引 = " + 索引)
结束循环

使用跳过循环时,需注意只有在调用 “跳过” 关键字后面的代码才不会执行、如果在“跳过” 关键字之前的代码;仍会被执行。

条件判断语句

条件判断语句用于根据不同的条件执行不同的代码块,条件判断是编程中非常重要的控制结构,能够实现逻辑分支。轻语言提供了以下几种条件判断语句:

如果语句

根据条件判断是否执行语句中的代码块、使用 结束 如果 结束代码,如果条件成立(逻辑值为真)、则执行、否则不执行;语法结构为:

如果(条件)
    ' 如果条件成立为真则执行当前代码块中语句

结束 如果

示例:

变量 a 为 整数型 = 10
如果(a == 10)
    ' 条件成立、将执行下面语句
    调试输出("a 的值为 10")
结束 如果

如果否则语句

如果否则语句、根据条件判断、如果条件成立执行如果代码块中的代码、如果不成立执行否则代码块中的代码。语句结构为:

如果(条件)
    ' 执行条件成立的代码
否则
    ' 执行条件不成立的代码
结束 如果

示例:

变量 年龄 = 25
如果(年龄 > 20)
    调试输出("年龄大于20")
否则
    调试输出("年龄小于20")
结束 如果

如果-否则如果 语句

依次检查多个条件、直到执行第一个条件为真的语句代码块;如果所有条件都不成立、则执行“否则”语句块中的代码。语句结构为:

如果(条件1)
    ' 执行条件1成立的代码
否则 如果(条件2)
    ' 执行条件2成立的代码
否则 如果(条件3)
    ' 执行条件3成立的代码
否则 
    ' 以上条件都不成立时、执行的代码
结束 如果

示例:

变量 分数 = 85
如果(分数 > 90)
    调试输出("成绩 A")
否则 如果(分数 >= 80)
    调试输出("成绩 B")
否则 如果(分数 >= 70)
    调试输出("成绩 C")
否则
    调试输出("成绩 D")
结束 如果

上方代码运行后将输出:

成绩 B

判断语句

用于判断条件与一系列值中的某个值是否相等;一个判断语句块中可以包含多个分支条件、其语句结构为:

判断(条件)
    分支 待比较值1
        ' 执行比较成功的代码
    分支 待比较值2
        ' 执行比较成功的代码
    分支 待比较值3
        ' 执行比较成功的代码
结束 判断

语句解释说明及使用规则:

  • 一个判断语句可以包含多个条件分支

  • 判断语句不支持默认的分支

  • 每条分支语句的 待比较值 后面必须为换行(语句结束符)、不得在后面执行代码

  • 比较值及表达式的值只能为基础数据类型和文本型、不能使用对象类型作为比较值

示例:

变量 星期号 = 3
判断(星期号)
    分支 1
        调试输出("星期一")
    分支 2
        调试输出("星期二")
    分支 3
        调试输出("星期三")
结束 判断

运行上方代码后将输出:

星期三

三元运算符(条件运算符)

当条件成立时、返回表达式1的值、不成立时返回表达式2的值,语句结构为:

条件 ? 表达式1 : 表达式2

示例:

变量 年龄 = 18
变量 状态 = (年龄 >= 18) ? "成年" : "未成年"
调试输出(状态)

上方代码运行后将输出:

成年

中断执行

当需要在程序中,中断执行(不再执行后续的代码);可以使用关键字:“返回” 中断执行后续的代码。

示例:

函数 检测输入(年龄 为 整数型)
    如果(年龄 < 0 或 年龄 > 300)
        弹出提示("输入的年龄值不符合常理")
        返回 ' 调用 返回 关键字;中断程序,将不会再执行后续的代码
    结束 如果
    调试输出("你输入的年龄范围符合常理")
结束 函数

条件判断语句的主要作用

  1. 实现逻辑分支:根据不同的条件执行不同的代码块。

  2. 简化复杂逻辑:通过嵌套条件语句,可以处理复杂的逻辑判断。

  3. 提高代码可读性:通过清晰的逻辑分支,使代码更易于理解和维护。

数组集合与哈希表

什么是数组?

数组是一种固定大小的容器,用于存储相同类型的数据。数组中的每个元素通过索引(下标)访问,索引从 0 开始。

数组的特点

  • 固定大小:数组一旦创建,其大小不能改变。

  • 相同类型:数组中的所有元素必须是相同的数据类型。

  • 高效访问:通过索引可以直接访问数组中的元素,时间复杂度为 O(1)。

数组的作用

  • 存储一组相同类型的数据。

  • 适用于已知数据量且数据量固定的场景。

如何使用数组?

在轻语言中,数组的定义与声明 变量 的方式一样,因为数组本身也是一种数据类型。唯一的区别是声明数组时;需要在数据类型后面加上 [] 用于表示这个变量为一个数组。

1.声明和初始化数组

' 声明一个整数数组
变量 数据1 为 整数型[]
' 初始化数组大小、创建一个大小为 5 的整数数组,该数组变量可以储存 5 个整数值
数据1 = 创建 整数型[5]
' 使用索引为数组中指定位置赋值,索引从0开始
数据1[0] = 100 ' 设置数组中第一个值为 100
数据1[1] = 300 ' 设置数组中第二个值为 300
数据1[2] = 666 ' 设置数组中第三个值为 666

针对基础数据类型;也可以使用更简单的方式声明数组并设置初始值:

' 创建一个数组变量并设置 4 个初始值
变量 数据2 = { 100,105,200,300 }

' 创建一个文本数组并设置2个初始值
变量 文本数据1 = { "vcn" , "studio" }

' 创建一个组件数组并设置其对象
变量 按钮组1 为 按钮[] = 创建 按钮[]{ 按钮1,按钮2,按钮3 }

' 创建一个可储存 10 个文本值的空数组变量
变量 数据3 为 文本型[] = 创建 文本型[10] 

2.访问、修改数组元素

' 访问读取数组变量 数据1 中的第一个元素
调试输出("第一个元素:" + 数据1[0]) ' 输出 100

' 修改元素的值
数据1[1] = 999
调试输出("第二个元素:" + 数据1[1]) ' 输出 999

访问组件成员的属性,例如上方的 按钮组1 ,如果通过数组下标设置数组中按钮成员的标题,需使用对应的属性函数。

属性函数是轻语言中兼容原生语言语法的一个扩展特性,该功能支持在非显示指定数据类型的条件下,使用对象的属性,函数,例如:使用拉姆达匿名参数对象、使用数组、集合中的对象等等。

属性函数的具体用法:

' 调用属性对应的函数赋值修改标题
按钮组1[0].标题("我是被修改的标题内容")
' 通过属性对应的函数获取标题内容
调试输出(按钮组1[0].标题())

属性函数与属性功能完全一样,只是语法略有不同,下方两种写法效果是完全一样的:

' 修改属性值
按钮1.标题 = "按钮1标题内容"
按钮1.标题("按钮1标题内容")
' 获取属性值
调试输出(按钮1.标题)
调试输出(按钮1.标题())

只是在属性名称后面使用括号表示函数、属性函数一般用于在未明确指定对象类型的场景使用。

3.遍历数组

变量循环(索引 = 0,取数组成员数(数据1),1)
    调试输出( "成员值:" + 数据1[索引])
结束循环

什么是集合?

集合是轻语言中提供的一组动态大小的容器类,用于存储和操作一组对象。

集合的特点

  • 动态大小:集合的大小可以动态调整。

  • 存储对象:集合可以存储任意类型的对象。

  • 丰富操作:集合提供了丰富的操作方法,如添加、删除、修改等。

集合的作用

  • 存储一组对象,适用于数据量不确定或需要频繁增删的场景。

  • 提供了高效的数据操作方法。

如何使用集合?

1.声明并创建集合

' 声明一个集合变量
变量 集合1 为 集合
' 创建集合对象、集合必须创建对象才能使用
集合1 = 创建 集合()

' 声明集合并同时创建集合
变量 集合2 = 创建 集合()

2.向集合中添加数据

' 添加数据到创建的集合中;可以添加任意数据
' 但实际开发时建议不同类型的数据值使用不同的集合储存
集合1.添加项目("VcnStudio")
集合1.添加项目("http://www.vcnstudio.com")
集合1.添加项目(100)
集合1.添加项目(按钮1)

3.访问集合元素

' 从集合中取出指定位置的值,索引从 0 开始
' 这里需注意储存的什么类型的值、取出时也需要使用对应变量接收
变量 成员1 为 文本型 = 到文本(集合1.取项目(0))
' 如果是组件、自定义数据类型;需要强制转换成对应类型
变量 储存的按钮1 = (按钮)集合1.取项目(3)

4.遍历集合

变量循环(索引 = 0,集合1.取项目数(),1)
    调试输出(到文本(集合1.取项目(索引)))
结束循环

数组与集合的比较

特性数组集合
大小固定大小动态大小
存储类型相同类型任意类型
性能访问速度快操作更丰富,但性能稍低
适用场景数据量固定且已知数据量不确定或需要频繁增删

什么是哈希表?

哈希表是一种数据结构,它通过键值对(Key-Value Pair)的方式存储数据。每个键(Key)通过哈希函数计算出一个哈希值,然后根据哈希值将数据存储在数组的特定位置(称为“桶”或“槽”)。

哈希表的特点

  1. 高效存取:通过哈希函数,可以在平均 O(1) 的时间复杂度内完成数据的插入、删除和查找。

  2. 键唯一:每个键在哈希表中是唯一的,重复的键会覆盖旧值。

  3. 无序性:哈希表中的数据是无序的。

哈希表的作用

  1. 快速查找:通过键快速查找对应的值。

  2. 数据去重:利用键的唯一性,可以用于去重操作。

  3. 缓存实现:哈希表常用于实现缓存。

  4. 统计频率:可以用于统计数据的频率(如统计单词出现的次数)。

如何使用哈希表?

1.创建哈希表

' 声明一个哈希表变量
变量 哈希表1 为 哈希表
' 创建哈希表实例对象
哈希表1 = 创建 哈希表()

' 声明并同时创建对象
变量 哈希表2 = 创建 哈希表()

2.添加键值对

哈希表1.添加项目("key1","苹果")
哈希表1.添加项目("key2","香蕉")
哈希表1.添加项目("key3","梨子")
' 哈希表可以储存任意数据值;取出式需转换
哈希表1.添加项目("按钮1",按钮1)

3.获取表中的值

' 哈希表是无序储存的,只能通过指定键值获取值
变量 键值 = 到文本(哈希表1.取指定键值("key1"))
调试输出("key1 的值:" + 键值)

' 获取按钮对象
变量 btn1 = (按钮)哈希表1.取指定键值("按钮1")

4.删除键值

哈希表1.删除项目("key1")

5.检查表中键或值是否存在

变量 包含指定键 为 逻辑型 = 哈希表1.取包含键("key1")
调试输出("包含 key1:" + 包含指定键)

变量 包含指定值 为 逻辑型 = 哈希表1.取包含值("苹果")
调试输出("包含 苹果:" + 包含指定值)

6.遍历哈希表

哈希表1.创建遍历()
判断循环(哈希表1.取下一个())
    变量 项目键 为 对象 = 哈希表1.取项目键()
    变量 项目值 为 对象 = 哈希表1.取项目值()
    调试输出("项目键:" + 项目键 + ",项目值:" + 项目值)
结束循环

上方代码运行后输出:

项目键:key1,项目值:苹果
项目键:key2,项目值:香蕉
项目键:key3,项目值:梨子

7.清空哈希表

哈希表1.清空()

注意事项

一个哈希表中不能包含两个相同的键名。

函数

轻语言 中,函数(通常也称为方法)是一段可重用的代码块,用于执行特定的任务。函数可以接受输入参数,并可以返回一个结果。函数是面向对象编程的核心概念之一,用于封装代码逻辑,提高代码的可读性和复用性。

函数的作用

  1. 代码复用:将常用的代码逻辑封装到函数中,避免重复编写相同的代码。

  2. 模块化:将程序分解为多个小模块,每个模块负责一个特定的功能,使代码更易于理解和维护。

  3. 提高可读性:通过函数名描述代码的功能,使代码更易于阅读。

  4. 参数化:通过参数传递数据,使方法更加灵活。

函数的定义

轻语言中,函数的定义包括以下几个部分:

  • 修饰符:如 私有静态 等,用于控制方法的访问权限,轻语言中默认函数的修饰符为公开

  • 返回类型:函数返回的数据类型,如果函数不返回任何值,则可以省略。

  • 函数名:函数的名称,遵循变量标识符命名规则。

  • 参数列表:方法接受的输入参数,用逗号分隔。

  • 函数体:函数中的具体实现代码。

语法,以关键字“函数”定义:

函数 修饰符 函数名(参数列表) 为 返回类型
    ' 函数体

结束 函数

示例:

' 无返回值函数、返回值可省略
函数 输出数据(内容 为 文本型)
    调试输出("内容为:" + 内容)
结束 函数

' 有返回值函数、返回参数值计算结果
函数 计算面积(长 为 整数型,宽 为 整数型) 为 整数型
    返回 长 * 宽
结束 函数

函数的分类

1.无参数函数

函数可以不接收任何参数。

示例:

函数 输出你好()
    调试输出("你好!")
结束 函数

2.带参数函数

函数可以接收多个参数,多个参数之间使用,连接,参数可以是轻语言支持的任意数据类型。

示例:

函数 执行加法运算(参数1 为 整数型,参数2 为 整数型)
    调试输出("加法结果:" + (参数1 + 参数2))
结束 函数

3.有返回值函数

函数可返回指定数据类型的值,如果无需返回任何值,可省略函数头最后面的返回类型。

示例:

函数 执行加法运算(参数1 为 整数型,参数2 为 整数型) 为 整数型
    返回 参数1 + 参数2
结束 函数

4.静态函数

使用修饰词 静态 修饰的函数,静态函数属于类本身,可以在程序全局范围内使用。

示例:

函数 静态 执行加法运算(参数1 为 整数型,参数2 为 整数型) 为 整数型
    返回 参数1 + 参数2
结束 函数

5.私有函数

使用修饰词 私有 修饰的函数,私有函数只能在所属类的内部使用,不能在其它地方使用。

示例:

' 只能在定义的窗口、模块中使用
函数 私有 执行加法运算(参数1 为 整数型,参数2 为 整数型) 为 整数型
    返回 参数1 + 参数2
结束 函数

函数的调用

定义一个函数后,可以在程序中通过函数名调用它。如果函数有返回值,可以将返回值赋给变量或直接使用。

示例(视窗程序):

事件 按钮2.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    调试输出("执行加法运算:" + 执行加法运算(10,20))
结束 事件

函数 执行加法运算(参数1 为 整数型,参数2 为 整数型) 为 整数型
    返回 参数1 + 参数2
结束 函数

上述代码运行后将输出:

执行加法运算:30

函数的递归

函数可以调用自身,这种调用方式称为递归。递归通常用于解决可以分解为相似子问题的问题。

视窗程序示例(计算阶乘):

函数 计算阶乘(n 为 整数型) 为 整数型
    如果(n == 0 或 n == 1)
        返回 1
    否则
        返回 n * 计算阶乘(n - 1)
    结束 如果
结束 函数

事件 按钮3.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    调试输出("5 的阶乘为:" + 计算阶乘(5))
结束 事件

上述代码运行后;输出为:

5 的阶乘为:120

事件与回调

什么是事件与回调?

事件

  • 事件是程序中发生的某种动作或状态变化,例如用户点击按钮、键盘输入、定时器触发等。

  • 事件通常由外部操作(如用户交互)或系统内部状态变化触发。

回调

  • 回调是一种编程模式,用于在某个事件发生后执行特定的代码逻辑。

  • 回调通常存在与模块与组件中、通过接口、函数或方法实现,允许程序在特定条件下调用预先定义的操作。

事件与回调的作用

  1. 解耦:将事件触发逻辑与事件处理逻辑分离,提高代码的模块化和可维护性。

  2. 异步处理:在事件驱动的编程模型中,回调可以用于异步处理事件,避免阻塞主线程。

  3. 灵活性:通过回调机制,可以在运行时动态指定事件处理逻辑。

事件与回调的区别?

在轻语言中:

事件通常用于在开发实际应用程序时使用,一个事件只能处理一个动作。

回调通常用于在封装类库时、在类库、组件中向外部传递事件或同时处理多个动作的场景。

如何使用事件与回调?

1.使用事件

使用事件通常也被称为监听事件的发生,主要目的是监听用户对程序产生的动作,例如:在视窗与安卓程序中、当用户打开程序后、点击了程序窗口界面中的某个按钮,此时系统会通过事件的方式,向我们发送用户点击按钮的这个操作,那么我们如何在代码中去接收这个操作返回给我们的事件呢?

在轻语言中一共有 3 种方式接收系统反馈给我们开发者的事件:

方式一:接收事件语句

这种方式与函数类似;通过关键字 事件 定义;可在 IDE 设计窗口中双击组件或通过点击属性窗口的事件下拉列表,自动生成相关语句,语法为:

事件 对象名.事件名(参数列表)
    ' 处理收到事件的代码

结束 事件

示例:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 当按钮1被单击时、通过调试输出窗口输出文本内容
    调试输出("按钮1被单击")
结束 事件

事件代码块适用于可视化窗口中的组件,以及窗口成员变量对象,不能用于局部变量对象。

方式二:子程序引用

当需要监听动态创建的组件的相关事件时;如果采用方式一就必须给每个组件的事件都单独声明一个接收事件的语句块,假设动态创建10个按钮,就需要添加 10 个事件代码语句块,显然这种方式会让代码变的很繁缛,而通过子程序引用的方式只需要使用一个函数接收反馈的事件即可。

视窗程序示例:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 循环创建 10 个按钮
    变量循环(索引 = 0,10,1)
        变量 btn = 创建 按钮()
        btn.标题 = "按钮" + 索引
        ' 使用下方子程序接收当用户被单击时系统反馈的事件
        btn.置被单击回调(&动态创建的按钮被单击)
        垂直滚动框1.添加组件(btn)
    结束循环
结束 事件

' 该函数的名称可以自定义取名,但该函数的参数需与回调接口中的事件参数完全一致
函数 动态创建的按钮被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    变量 被单击的按钮 = (按钮)来源对象
    调试输出("被单击按钮:" + 被单击的按钮.标题)
结束 函数

子程序引用方式适用于动态创建的组件、或局部定义的组件,使用“&”符号引用的子程序函数的参数类型和格式、可以在IDE支持库中查询指定组件接口中的事件、例如:上方我们给动态创建的按钮设置的被单击回调子程序函数、这个函数是我们自定义的、但是这个函数中具体的参数、可以在IDE支持库窗口中找到按钮组件、再找到按钮节点下的“被单击回调”接口、这个接口中事件的参数即是我们需要设置的参数。

方式三:拉姆达表达式

拉姆达表达式是一种编程语法糖,可以更简单、使用更少的代码接收事件。语法为:

(参数列表) -> { 函数体 }
  • 参数列表:方法的参数,可以省略参数类型(由编译器推断)、只需要设置参数名称即可。

  • ->:拉姆达表达式操作符,将参数列表和函数体分开。

  • 函数体:接收事件中具体的操作代码。

将上方,方式二中给动态创建的按钮设置被单击回调时;换成拉姆达的语法则为:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 循环创建 10 个按钮
    变量循环(索引 = 0,10,1)
        变量 btn = 创建 按钮()
        btn.标题 = "按钮" + 索引
        ' 使用拉姆达表达式接收被单击事件,括号类只需设置参数名
        ' 注意:拉姆达表达式中的参数名称不能与上方事件参数名相同
        btn.置被单击回调((局_源对象,局_事件对象)->{
            变量 被单击的按钮 = (按钮)局_源对象
            调试输出("被单击按钮:" + 被单击的按钮.标题)
        })
        垂直滚动框1.添加组件(btn)
    结束循环
结束 事件

拉姆达表达式适用于局部对象组件,例如事件块、函数块中创建的对象。

2.使用回调

在轻语言中,回调是针对多个事件的统一处理方式,当我们在程序中请求获取服务器中的数据时,通常会有两种情况;请求成功、请求失败,而为了方便可以同时监听这两种情况的发生,则可以采用回调的方式来监听。

安卓程序示例:

' 声明异步网络操作对象
变量 异步网络操作1 为 异步网络操作

事件 窗口创建完毕()
    ' 创建对象实例
    异步网络操作1 = 创建 异步网络操作()
结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    异步网络操作1.发送GET请求("get1","http://www.vcnstudio.com/","UTF-8",异步操作回调)
结束 事件

定义 异步操作回调 为 异步网络操作.请求完毕回调
    事件 请求发送成功(标记 为 文本型,响应头 为 哈希表,返回数据 为 字节型[])
        变量 结果 = 字节集到文本(返回数据,"UTF-8")
        标签1.标题 = "请求标记:" + 标记 + " 请求发送成功;返回数据为:\n" + 结果
    结束 事件

    事件 请求发送失败(标记 为 文本型,响应头 为 哈希表,返回数据 为 字节型[],错误信息 为 文本型)
        标签1.标题 = "请求标记:" + 标记 + " 请求发送失败;错误信息:"  + 错误信息
    结束 事件
结束 定义

定义事件

事件的定义一般多用于在组件或模块的封装中,例如自定义一个模块或一个组件时,想通过像普通组件那样事先事件回调,定于语法为:

公开 事件 事件名称(参数列表)

示例:

公开 事件 搜索被触发(关键字 为 文本型)

自定义事件与使用在线视频教程: 自定义事件与模块回调

结构体

结构体是一种自定义的数据类型,通常用于封装一组相关的数据字段为一个整体。例如编程中常见的坐标结构,一个坐标点包含一个XY值,通过结构体的封装,可以将XY封装成一个坐标结构体数据类型。

定义结构体

一个合法的自定义结构类型使用“定义”关键字定义、其结构体中只能包含内部成员变量、成员变量个数无限制、但不能包含构造函数、自定义函数、事件或回调对象;同时内部成员变量不能使用任何修饰符;语法如下:

定义 结构体名称 为 结构
    变量 成员变量1 为 数据类型
    变量 成员变量2 为 数据类型
    ...
结束 定义

注:结构体中不支持一个变量语句定义多个成员变量、即每行只能定义一个变量成员。

示例:

定义 坐标 为 结构
    变量 X 为 整数型
    变量 Y 为 整数型
结束 定义

使用结构体

视窗程序示例:

' 先定义描述坐标的结构体数据类型
定义 坐标 为 结构
    变量 X 为 整数型
    变量 Y 为 整数型
结束 定义

事件 按钮4.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 声明并创建一个坐标变量对象
    变量 坐标1 = 创建 坐标()
    坐标1.X = 10
    坐标1.Y = 20
    调试输出("坐标1 X:" + 坐标1.X + ",Y:" + 坐标1.Y)
    ' 声明并创建坐标、设置初始值,结构体数据默认支持全成员构造函数
    变量 坐标2 = 创建 坐标(30,50)
    ' 由于 坐标2 已经是一个包含X,Y值的整体数据值对象;因此可以添加到集合
    ' 或放到数组中、或设置给组件的标记、或跨窗口传递
    标签1.标记 = 坐标2
结束 事件

事件 按钮5.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 取出 标签1 的标记(上一步设置的 坐标2)
    变量 坐标2 = (坐标)标签1.标记
    调试输出("坐标2 X:" + 坐标2.X + ",Y:" + 坐标2.Y)
结束 事件

注:每个结构体数据都为全局数据类型、在整个项目中的模块、窗口中都可以使用、因此整个项目中不能包含相同名称的结构体。

在实际项目中,建议在专门的文件中声明结构体,轻语言默认存放结构体类型文件的后缀为:.st ,建议将项目中的所有自定义数据结构放在该文件中声明。

多线程

什么是多线程?

多线程是指在一个程序中同时运行多个线程(后台任务),每个线程可以独立执行不同的任务。线程是程序执行的最小单元,多线程允许程序并发(同时)执行多个任务,从而提高程序的效率和响应性。

多线程的作用?

  • 提高程序性能:通过并发执行多个任务,充分利用多核CPU的计算能力。

  • 提高响应性:在图形用户界面(GUI)应用程序中,多线程可以防止主线程被长时间运行的任务阻塞,保持界面的响应性。

  • 简化模型:多线程可以将复杂的任务分解为多个简单的任务,每个任务由一个线程执行,简化程序设计。

使用多线程

在轻语言中支持通过多种方式使用多线程。视频教程:安卓APP高级开发之异步与多线程的使用

1.异步执行语句

该方式是使用多线程较为灵活的一种方式、适合在代码的任何位置使用;使用方法为:通过异步执行首异步执行尾关键字包裹指定代码、被包裹的代码将会在子线程中运行,如果要更新窗口内容,使用关键字 到主线程 切换线程到主线程即可。

视窗示例:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 只在子线程中执行任务,但不更新内容到窗口组件
    异步执行首
        变量 源码 = 取网页源码("http://www.vcnstudio.com","UTF-8",5000)
        调试输出(源码)
    异步执行尾
    ' 在子线程中获取到数据后,将任务从子线程中切换(跳出子线程)到主线程
    ' 然后将获取的内容、赋值给窗口中的编辑框
    异步执行首
        变量 源码 = 取网页源码("http://www.vcnstudio.com","UTF-8",5000)
        到主线程
        编辑框1.内容 = 源码
    异步执行尾
    ' 注意:在子线程中不能修改窗口中任何组件的内容、外观和尺寸
结束 事件

2.内置函数:启动线程

轻语言在支持多线程的平台应用端开发包中内置了线程操作函数:启动线程 只需一句代码就能开启子线程,该函数的参数接收一个无返回值、无参数的函数。

视窗示例:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 函数 子程序1 将在子线程中被执行
    启动线程(&子程序1)

    ' 使用拉姆达表达式传入待执行的代码,下方{ }代码将在子线程中被执行
    启动线程(()->{
        调试输出("我是通过拉姆达表达式设置的代码,可执行耗时操作")
    })
结束 事件

函数 子程序1()
    调试输出("我是在子线程中执行的代码;可执行耗时操作")
结束 函数

3.线程组件

线程组件是轻语言在支持多线程平台应用端开发包中提供的一个集成了消息传递及子线程任务的高级线程工具,线程组件通常为一个不可视组件。

视窗示例1:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 声明并创建线程对象
    变量 局_线程1 = 创建 线程()
    ' 启动线程并设置待执行的子程序函数、及监听从子线程中传出消息到主线程的函数
    局_线程1.启动(&执行子线程任务,&收到子线程传来的消息,"传入给子线程的数据值")
结束 事件

函数 执行子线程任务(源对象 为 线程,数据值 为 对象)
    ' 这里的代码将会在子线程中被执行
    调试输出("启动时传入的数据值:" + 数据值)
    ' 待执行的代码...
    ' 任务执行结束后、发送给主线程,这里的源对象为启动时的线程对象
    源对象.发送消息(1,"任务执行完毕要发给主线程的数据值")
结束 函数

函数 收到子线程传来的消息(源对象 为 线程,消息ID 为 整数型,消息值 为 对象)
    ' 当在子线程中调用发送消息时,这里将收到消息ID、及发出的消息值
    调试输出(消息ID + ":" + 消息值)
结束 函数

视窗示例2:

' 若该变量为真、则下方子线程函数将无限循环执行,为假将会跳出循环
变量 执行任务 为 逻辑型

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    执行任务 = 真
    ' 声明并创建一个子线程、在该线程中每隔 2 秒获取一次热点信息
    变量 局_线程 = 创建 线程()
    局_线程.启动(&执行子线程任务,&收到子线程传出的消息)
结束 事件

函数 执行子线程任务(源对象 为 线程,数据值 为 对象)
    ' 子线程是后台执行、因此可以使用无限循环且不卡顿程序界面
    判断循环(执行任务)
        变量 热点数据 = 取网页源码("https://f.m.suning.com/api/ct.do","UTF-8",5000)
        源对象.发送消息(1,热点数据)
        延时(2000)
    结束循环
结束 函数

函数 收到子线程传出的消息(源对象 为 线程,消息ID 为 整数型,消息值 为 对象)
    如果(消息ID == 1)
        编辑框1.内容 = "新数据:" + 到文本(消息值)
    结束 如果
结束 函数

事件 按钮2.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 跳出循环、停止执行任务
    执行任务 = 假
    编辑框1.内容 = "已停止获取数据"
结束 事件

线程同步

在同时开启多个子线程时,如果这些子线程中都用到了同一个变量或对象资源,由于子线程的执行是无序的,因此就会导致变量或资源出现抢占问题,例如当AB两个子线程读写同一个文件内容时,A 线程刚读到一半、B 线程就写入了新的数据,此时文件内容将会发生无法预估的错误。

为此要想解决这种问题、就需要给文件加锁,加锁的目的是让同一时刻、这个文件只能由一个线程读写,这样就能避免文件被抢占的问题,这种解决方案也叫线程同步。

示例:

' 声明并创建一个资源对象
变量 资源对象 = 创建 对象()

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    启动线程(()->{
        ' 在需要加锁的位置、对资源加锁即可
        加锁(资源对象){
            ' 执行操作...

        }
    })
结束 事件

加锁位置可以在任意子线程中执行的代码里加锁,若部分平台未升级最新版、可以使用:synchronizedlock 关键字代替中文关键字。

修饰符

轻语言中的 修饰符 也成为 约束标记,是用来修饰、约束程序中的函数、变量等元素的关键字,用于控制它们的访问权限,轻语言中一共有 4 个修饰符。

修饰符作用范围
公开公开的,轻语言中变量、函数默认修饰符,在类外部(对象)可访问。
世袭只能在类自身、子类、孙类中访问,类外部(对象)不可访问。
私有私有的,只有在类自身的代码中可以访问。
静态全局的,被修饰的变量、函数属于类本身,可以使用类名直接调用。

示例:

' 公开变量、当窗口在其它地方被创建时,可以使用该变量
变量 变量1 为 文本型

' 可被世袭的变量、所有继承自该窗口的子类窗口都可以使用该变量
变量 世袭 变量2 为 文本型

' 私有变量、只能在本窗口中使用
变量 私有 变量3 为 文本型

' 静态变量、可以通过窗口直接调用,无需创建窗口对象
变量 静态 变量4 为 文本型

' 默认公开函数、创建窗口对象,可通过对象调用
函数 函数1()

结束 函数

' 可被世袭的函数、所有继承自该窗口的子类窗口都可以调用该函数
函数 世袭 函数2()

结束 函数

' 私有函数、只能本窗口中使用
函数 私有 函数3()

结束 函数

' 静态函数、可以通过窗口直接调用,而无需创建窗口对象
函数 静态 函数4()

结束 函数
' 直接使用窗口名称调用静态变量与函数
窗口1.变量4 = ""
窗口1.函数4()

' 创建对象后调用
变量 窗口1对象 = 创建 窗口1()
窗口1对象.变量1 = ""
窗口1对象.函数1 = ""

' 使用世袭、私有修饰的函数或变量,不能在外部调用,只能在窗口内使用

引用

轻语言 中,引用 是一个关键字,用于引入程序外部其他原生库中的类(如果目标平台支持的话),以便在当前代码中直接使用它们。引用 的主要作用是扩展程序功能、引用第三方支持库。引用支持单独引用指定类,和全部引用两种。

语法:

引用 包名.类名 ' 引入指定包中特定的类
引用 包名.* ' 引用指定包中的所有类

例如在安卓程序与视窗程序中,可以直接使用 Java SDK 及 Android SDK 中的类。

示例:

引用 java.util.ArrayList ' 引用 java.util 包中的 ArrayList 类
引用 java.util.* ' 引用 java.util 包中的所有类
引用 android.widget.Button ' 引用安卓SDK中的原生Button
引用 java.io.* ' 引用 java IO 操作包所有类

安卓示例:

' 引用安卓原生 Toast 类
引用 android.widget.Toast

事件 按钮1.被单击(来源对象 为 视图)
    ' 调用安卓原生类显示 Toast 提示
    ' 由于不涉及原生代码特定语法格式、 Toast 支持静态调用,因此无需使用 @{ } 包裹
    Toast.makeText(取应用上下文(), "按钮被点击了!", Toast.LENGTH_SHORT).show()
结束 事件

模板字符串

模板字符串又称为字符串内插标记、是一种可以简化字符串拼接的语法糖,通过字符串插值,可以直接在字符串中嵌入表达式或变量,而不需要使用复杂的格式化方法。

模板字符串的作用

  • 简化字符串拼接:直接在字符串中嵌入变量或表达式,使代码更简洁。

  • 提高可读性:比传统的字符串拼接(如 + 或 格式化文本)更直观。

  • 减少错误:避免手动拼接字符串时可能出现的格式错误。

使用方法

轻语言 中,字符串插值通过在字符串前加上 $ 符号来实现。插值部分用 {} 包裹,其中可以包含变量或表达式。

语法:

变量 内容 为 文本型 = $"文本 {变量或表达式} 文本 {变量或表达式}"

视窗示例:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    变量 姓名 = "熊猫"
    变量 年龄 = 27
    ' 使用字符串插值
    变量 信息 = $"您好,我的名字叫:{姓名},我现在:{年龄}岁。"
    调试输出(信息)
结束 事件

注:模板字符串不支持插入数组、也不支持运算符号、不支持处理字符串中本身含有花括号的字符串。

代码注释

轻语言中,源代码注释是用来对代码进行解释和说明的文本。注释不会被编译器执行,因此不会影响程序的运行。注释的主要作用是提高代码的可读性和可维护性,帮助开发者理解代码的逻辑和功能。

注释的使用方法

在轻语言中,规定使用单引号 ' 来注释单行代码。单引号后的所有内容(直到换行符前)都会被编译器忽略。

1.单行注释

' 这是一个单行注释
变量 x 为 整数型 ' 声明一个整数变量 x
x = 10 ' 给变量 x 赋值

2.多行注释

轻语言本身不支持多行注释,但可以通过每行使用单引号 ' 实现多行注释。

' 这是一个多行注释
' 每行都需要使用单引号
' 这是第三行注释
变量 y 为 整数型
y = 20

3.注释模板

注释模板是一种对注释格式化整理的特殊格式;详见:注释模板

注释的其它说明

  • 不要过度注释:只注释必要的部分,避免冗余。

  • 保持注释的准确性:确保注释与代码的实际功能一致。

  • 使用清晰的注释:注释应简洁明了,避免使用模糊的语言。

语句结束符

在 轻语言 中,语句结束符用于标识一条语句的结束。轻语言的语句结束符是换行符(即按下 Enter/回车 键),这意味着每条语句通常占据一行。

内置函数

轻语言核心库提供了常见的编程函数库,涵盖数组操作、数学运算、字符串处理、数据转换、文件操作、时间操作、正则表达式、网络操作等等。

针对不同的平台应用,同时提供了扩展函数库,例如安卓提供了安卓系统特有的应用操作、屏幕管理、上下文环境、权限申请等函数。

关于具体的平台应用,可查询目标文档或手册,也可以在 IDE 中打开指定类型应用工程、在软件的支持库窗口中查询。

原生支持

助译嵌入指令是轻语言特别支持的一项兼容特性,该特性允许在轻语言程序中直接使用目标平台的原生开发端语言代码;以安卓、视窗举例,使用轻语言开发安卓、视窗程序;可以直接在程序代码中使用 Java 源代码。

语法:

@{ 任意原生代码 }

只需要在代码中任意位置使用 @ { } 包裹原生代码;就能在程序中无缝嵌入并使用原生代码。

视窗示例:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 使用原生代码对指定数组进行排序
    变量 array = { 12,25,34,66,54 }
    @{
        for(int i = 0; i < array.length - 1; i++)
        {
            for(int j = 0; j < array.length - 1 - i; j++)
            {
                if(array[j] > array[j + 1])
                {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
    }
    调试输出(到文本(array))
结束 事件

上方代码运行后将输出:

[12, 25, 34, 54, 66]

安卓示例:

' 引用安卓原生 Toast 类
引用 android.widget.Toast

事件 按钮1.被单击(来源对象 为 视图)
    ' 调用安卓原生类显示 Toast 提示
    ' 由于不涉及原生代码特定语法格式、 Toast 支持静态调用,因此无需使用 @{ } 包裹
    Toast.makeText(取应用上下文(), "按钮被点击了!", Toast.LENGTH_SHORT).show()
结束 事件

更多有关于在安卓程序中使用原生代码及上下文的内容请参考 使用 Jar 包及原生代码

微信小程序示例:

事件 按钮1.被单击(事件源)
    ' 调用微信原生JS代码、只需要使用 @{ 包裹即可 }
    ' 需注意:原生代码中不能含有注释
    ' 官方文档:https://developers.weixin.qq.com/miniprogram/dev/api/
    @{
        wx.showToast({
          title: "成功",
          icon: "success",
          duration: 2000
        })
    }
结束 事件

单片机示例:

' 可以在程序中直接调用 Arduino 代码
函数 调用Arduino代码()
    digitalWrite(13, HIGH)
    delay(1000)
    digitalWrite(13, LOW)
    delay(1000)
结束 函数

' 使用 @{ } 包裹 Arduino 代码
函数 使用嵌入符包裹()
    @{
        int randNumber = random(300);
        Serial.println(randNumber);
        // print a random number from 10 to 19
        randNumber = random(10, 20);
        Serial.println(randNumber);
        delay(50);
    }
结束 函数

注意事项

  • 原生代码中没有特定语法格式时,无需使用 @{ } 包裹

  • 建议使用原生代码的位置在函数、事件或有作用域的语句块中,不建议在函数或事件外使用

  • 使用的原生代码中不能含有语法错误、编译时轻语言编译器不会检查原生代码

  • 原生代码中如果使用了第三方类,需添加对应的引用

使用 AI 辅助

目前 AI 发展迅猛,作为开发人员,我们可以追求更快、更高效的工作方式,AI 的出现可以说改变了很多人的编程方式。

AI 对我们来说就是一个可靠的编程助手,给我们提供了实时的建议和解决方案,无论是快速修复错误、提升代码质量,或者查找关键文档和资源,AI 作为编程助手都能让你事半功倍。

但遗憾的是,目前针对轻语言的专属大模型还在训练中;要想让 AI 直接编写轻语言代码程序,还尚需一些时日。

但幸运的是,轻语言天生拥有兼容任意目标语言的原生支持特性,换句话说在轻语言中,几乎可以100%使用原生代码,而实现功能的原生代码就可以让 AI 代劳,AI 编写后,只需要将代码复制到轻语言程序代码中;就可以正常使用。

在上一篇 原生代码支持 的文章中,我们已经了解到,轻语言可以直接在代码中使用目标平台的原生代码、本文以安卓为例;为大家讲解如何在安卓项目中使用AI生成的代码。

案例1

使用安卓SDK中的 Toast 弹出一个提示:

步骤

1. 先向 AI 提出问题

首先向任意AI提出问题:请帮我写一个可以在安卓中运行的函数;这个函数的功能是在安卓APP中弹出一个提示;开发语言为 Java ,谢谢

2. 分析AI给出的回答

这里我向 通义千问 提出上述的问题;返回的结果为:

import android.content.Context;
import android.widget.Toast;

public class Utils {

    /**
     * 显示一个短暂的提示信息。
     * 
     * @param context 上下文,通常是Activity的this
     * @param message 要显示的消息内容
     */
    public static void showToast(Context context, String message) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }
}
// 使用函数
Utils.showToast(this, "这是一个测试提示");

根据上方的回答内容;这里我们重点看两点:

  • 实现功能的具体代码

  • 代码中用到的引用和安卓上下文环境

实现功能的代码
public static void showToast(Context context, String message) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }
引用
import android.content.Context;
import android.widget.Toast;

根据代码注释可以得知;实现功能的具体函数为:showToast ;这个函数需要2个参数、第一个参数为上下文,第二个是待显示的文本内容。并同时 import (引用) 了安卓 SDK 中两个数据类型。

3. 在轻语言安卓程序中使用

' 将 AI 给出的 import 语句复制到轻语言代码中;将 import 修改为 引用
引用 android.content.Context
引用 android.widget.Toast
' 然后定义一个函数,这个函数里面不需要传入上下文,因为上下文在轻语言
' 安卓框架中可以直接通过函数获取。
函数 showToast(变量 提示内容 为 文本型)
    Toast.makeText(取应用上下文(), 提示内容, Toast.LENGTH_SHORT).show()
结束 函数
上下文

安卓中所有的上下文;在轻语言安卓程序中都可以使用下面两个函数获取:

  • 取应用上下文()

  • MainActivity.getContext()

案例2

步骤

1. 先向 AI 提出问题

首先向任意AI提出问题:我现在正在开发一个安卓APP;我的APP里面需要一个功能:获取储存在安卓SD卡中指定APK文件的包名,能否帮我写一个函数、给这个函数传入APK路径、就能返回apk的包名,我目前使用的编程语言为 Java 、谢谢!

2. 分析AI给出的回答

这里我向 深度求索(DeepSeek) 提出上述的问题;返回的结果为:

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Environment;
import android.content.Context;

public String getApkPackageName(Context context, String apkPath) {
    PackageManager pm = context.getPackageManager();
    PackageInfo packageInfo = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
    if (packageInfo != null) {
        return packageInfo.packageName;
    }
    return null;
}
String apkPath = Environment.getExternalStorageDirectory() + "/your_app.apk";
String packageName = getApkPackageName(this, apkPath);
if (packageName != null) {
    System.out.println("Package Name: " + packageName);
} else {
    System.out.println("Failed to get package name.");
}

上述代码我们需要关注的主要为:函数 getApkPackageName 、及引用部分。

首先将引用部分代码全部复制到轻语言程序中;然后再新建一个同名函数;使用 @{ } 包裹 getApkPackageName 中的代码,注意:我们自定义创建的函数参数需与 AI 给出代码中的函数参数一样。最终在轻语言程序中的代码为:

引用 android.content.pm.PackageInfo
引用 android.content.pm.PackageManager
引用 android.content.pm.PackageManager.NameNotFoundException
引用 android.os.Environment
引用 android.content.Context
函数 getApkPackageName(apkPath 为 文本型) 为 文本型
    @{
        PackageManager pm = MainActivity.getContext().getPackageManager();
        PackageInfo packageInfo = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
        if (packageInfo != null) {
            return packageInfo.packageName;
        }
    }
    返回 ""
结束 函数

在轻语言中使用时,我们修改了原AI给出的代码中的

PackageManager pm = context.getPackageManager();

PackageManager pm = MainActivity.getContext().getPackageManager();

因为 context 为安卓中的上下文对象,原生代码中上下文在轻语言安卓中使用时,必须设置为轻语言安卓上下文。

提问建议

  • 提问时一定要将问题描述清楚;一般的提问公式或模板为:

    • 功能型(我想实现某个功能):

      • 具体功能 + 期望的行为 + 使用的语言

      • 示例:我正在开发安卓APP、我想在这个APP中指定位置显示一个对话框,例如点击按钮后,在左上角显示一个小弹窗,我使用的编程语言为 Java

    • 问题型(我遇到了问题需要解决)

      • 简短描述问题 + 期望的行为 + 实际发生 + 错误日志或信息

      • 示例:我正在开发APP、我的代码中连接了一个Mysql数据库,可以连接成功、但无法查询出数据,我需要正常运行APP后可以获取到数据、但现在实际返回了错误;错误信息为:java.sql.SQLException: Unknown system variable query_cache_size

  • 尽量让 AI 将所需功能集中,生成的代码封装到一个函数中

  • 有时候也不可全信AI、要结合自身经验处理

  • 如果一个AI平台连续给出的代码无效、或是错误的,可以多换几家其它平台

轻语言程序基础结构

一个完整的轻语言程序,通常由一个入口文件、一个配置文件和若干个源代码文件组成:

轻程序/
├── src/
│   ├── 源代码1.spl
│   ├── 源代码2.spl
│   ├── 自定义结构.st
│   ├── 模块1.sm
│   ├── static/
│   │   ├── 图片.jpg
│   │   └── 其它文件.txt
├── App.spl
└── 轻程序.vsln

项目文件夹必须与项目索引文件同名。

1.程序入口文件 App.spl

启动程序时,系统会先从入口文件启动程序;以视窗程序为例:当编译输出一个可被执行的轻语言程序文件时,在 Windows 系统中启动该文件;系统将执行入口文件,并回调入口文件中相关事件。

视窗程序示例 App.spl 文件内代码:

事件 应用被启动(命令参数 为 文本型[])
    ' 当用户使用命令行或双击打开本程序时会先触发该事件
    ' 创建窗口对象
    变量 主窗口1 = 创建 主窗口()
    ' 设置启动窗口的显示尺寸
    主窗口1.置尺寸(300,500)
    ' 加载并显示窗口
    主窗口1.显示()
结束 事件

注意:不同平台的程序入口文件存在略微差异,具体差异请阅读目标平台相关文档。

2.项目索引文件(配置文件)

配置文件主要负责程序的配置管理;轻语言中配置文件采用XML语言描述,配置文件需与工程文件夹名称相同,后缀为:.vsln 默认配置文件结构为:

<?xml version="1.0" encoding="utf-8"?>
<project>
  <version name="4.0" code="4" ide="2023" />
  <property type="app" plugin="javafx">
    <version name="1.0" code="1" />
    <app package="my.app" name="" />
  </property>
</project>
  • project 项目根节点

  • version 可以打开项目的 VcnStudio 的最低版本

  • property 项目属性

    • type 项目类型,app 表示应用程序、component 表示组件、类库。

    • plugin 所属平台。

    • version 程序版本

    • app 程序包名、编译输出名称

3.源代码文件

源代码文件是除入口文件外的,所有其它包含程序源代码的、被存放到项目根目录中 src 文件夹中的文件;这些文件是程序中重要的功能或逻辑组成文件,一个可以被正确编译的源代码文件通常由:变量、事件、函数等组成,以一个普通的轻语言视窗程序为例,其代码结构组成为:

3.1 变量

变量声明是可选的;如果一个窗口或模块中不需要变量,可以省略不写。

变量 窗口变量1 为 文本型

3.1 事件

窗口事件中的窗口创建完毕是必须声明的事件,不能被删除,每个窗口都必须包含该事件,模块中不需要声明默认创建事件。

事件 窗口创建完毕()
    调试输出("窗口创建完毕")
结束 事件

3.2 函数

函数声明是可选的,窗口或模块中如果不需要函数,可以省略。

函数 子程序1()
    变量 和值 为 整数型
    和值 = 100 * 2
    调试输出("和值:" + 和值)
结束 函数

完整源代码

变量 窗口变量1 为 文本型

事件 窗口创建完毕()
    调试输出("窗口创建完")
结束 事件

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    ' 调用子程序
    子程序1()
结束 事件

函数 子程序1()
    变量 和值 为 整数型
    和值 = 100 * 2
    调试输出("和值:" + 和值)
结束 函数

所有源代码文件编码规定为:UTF-8-无-BOM 格式。

源代码文件格式

轻语言在编译时根据不同的源代码文件后缀格式,区分不同的源代码文件类型、以下为轻语言目前支持的文件类型后缀:

  • .spl 实现程序逻辑和业务功能的主要源代码文件。

  • .st 存放自定义结构体数据的文件。

  • .sm 模块文件。

程序执行流程

所有的轻语言程序都是从入口文件启动的,在入口文件中调用其它模块功能、或显示窗口。经过入口程序的引导加载后、最终向用户展示一个完整的程序功能。

编程规范

轻语言是一门编程语言、有自己特定的语法结构、为了养成良好的编程习惯、以及培养编程思维、使用轻语言编写程序时,遵循良好的编程规范可以提高代码的可读性、可维护性和一致性。

以下是轻语言编程中官方定义的常见的编程规范:

命名规范

好的命名规范、有助于让代码逻辑更清晰,代码分工更明确,代码中的变量、函数、模块、窗口命名时的规范:

变量

  • 变量名称不能使用纯数字或数字开头、只能使用中文或字母开头

  • 组件名称按照类型名称加下划线加功能命名、例如:按钮_登录 也可不加下划线、直接使用类型加功能、例如:按钮登录

  • 窗口成员变量按照注释即功能做简约命名、例如:变量 用户名 为 文本型 ;严禁随意命名 a、b、c 或 与业务功能逻辑无关的名称。

  • 局部变量按照 局加下划线 命名、例如:变量 局_结果 为 文本型、也可直接使用符合上下文语义的名称、例如:变量 登录结果 为 文本型 ;严禁使用 a b c 或与业务逻辑无关的名称。

  • 全局变量按照全局加下划线命名、或使用符合上下文语义的名称,例如:变量 全局_站点域名 为 文本型

函数

  • 函数名称不能使用纯数字或数字开头、只能使用中文或字母开头
  • 遵循注释即名称的规范、根据上下文语义命名、例如:获取账号信息
  • 函数名称建议限制在32个字符内、不能超过125个字符
  • 一个窗口文件或模块中不能包含两个相同名称的函数

窗口

  • 窗口名称不能使用纯数字或数字开头、只能使用中文或字母开头
  • 窗口名称按照窗口功能命名、不加任何前缀、但应该对不同功能类的窗口进行分组、例如:与用户有关的窗口、登录窗口注册窗口个人中心等应该放在用户分组中。

代码格式规范

缩进

换行时使用 4 个空格进行缩进,或一个 Tab 键缩进。

行长度

  1. 每行代码不超过 120200 个字符。

  2. 一个函数或事件内不超过 80120 代码。

  3. 一个窗口或类模块中总代码行数不超过 8001000 行,超过时应该对其代码做功能性拆分、将功能放到不同模块中。

语句块

  1. 含有结束标志的语句、例如:如果、判断、函数、事件、循环类代码体等等,结束行与开始行必须独占一行、且开始,结束标记必须匹配。

  2. 使用 “判断” 或 “如果” 语句的时候、最大分支不超过 30 个、如果超过30个分支或条件、应该考虑更换其功能实现的思路。

  3. 使用“判断”或“如果”语句时、内部嵌套“否则 如果”不超过 3 层、超过3层应该考虑使用返回语句、策略模式、状态模式等来实现。

空格

  1. 在运算符两侧添加空格,例如:变量 sum 为 整数型 = a + b

  2. 关键字右侧有括号的,关键字与括号之间不能含有空格;例如:如果(变量循环(判断(判断循环(

注释

  1. 注释符与注释内容之间设置一个空格,例如:' 这是注释内容

  2. 多行注释使用注释模板。

窗口与模块规范

单一职责原则

每个窗口或模块只负责一个功能。模块负责具体功能的实现,窗口负责功能的展示。将指定功能封装到模块中,窗口调用模块,窗口本身不负责复杂的功能业务。

代码复用

  1. 避免重复代码、将重复代码提取到方法或工具类中。

  2. 将程序中通用功能封装到工具类中。

异常处理规范

在容易发生错误的代码处、捕获程序发生的异常错误信息。

视窗示例:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    异常捕获首
        变量 ary1 = {1, 2, 3}
        ' 数组总共只有3个元素,获取其第6个元素、将触发异常信息
        调试输出("元素:" + ary1[5])
    异常被捕获(异常信息 为 对象)
        调试输出("异常信息:" + 异常信息)
    异常捕获尾
结束 事件

运行上方代码将输出:

异常信息:java.lang.ArrayIndexOutOfBoundsException: 5

多线程编程规范

  1. 严禁在子线程内更新窗口组件内容
  2. 不应滥用线程、应该根据自身业务逻辑做出功能型评判后再使用。
  3. 耗时操作、或让程序产生卡顿、无响应操作的代码必须放在子线程中

其它规范

  1. 在不确定文本变量或对象是否为空的情况下、必须先检测对象是否为空、避免引发空指针异常。
  2. 在使用 判断循环 代码语句体时、必须保证判断条件有假、即可以退出的情况;否则会造成程序死循环直接崩溃。
  3. 在使用一般循环体代码时、针对循环取数组成员变量、或取集合数据时、必须判断其索引是否小于成员数、例如:假设一个数组中只有5个元素、当使用下标5或超过5的索引去取数据时、程序将因为超出数组索引发生崩溃。
  4. 严禁在循环遍历中对数组或集合做删除操作。

设计思想与原理

轻语言支持使用面向对象的思想编写程序,面向对象的程序设计思想主要包括:抽象概括,继承重写,自定义封装。

抽象概括

抽象是一种归纳方式,概括是一种总结过程。面向对象的基本思想是从多个不同物体或对象中统一抽取其相同特征的属性进行归纳,总结成一个独立的抽象形容词(类)。

例如:形状、水果、动物、植物等;这些词语都是对一类物体总结归纳后的,抽象的形容词(类)。

我们可以说一个形状,但这个形状具体是什么形状?是三角形?长方形?还是矩形?

我们也可以说一个水果,但这个水果具体表示苹果、还是香蕉?还是葡萄?

继承重写

归纳总结是面向对象的基本思想,那么继承重写就是核心思想。

上文中我们说到:一个形状;一个水果,但仅仅只通过水果一词并不能明确表示这个水果具体是那种水果。

水果一词实在过于抽象。

水果一词可以表示任何水果。

但如果假设现在有一个苹果,一个实实在在的苹果(对象)。

而这个苹果是水果吗?

是水果。

苹果继承了水果的特性。

但苹果又有自己特别的属性,例如:有青苹果、甘肃苹果、红苹果等等

自定义封装

苹果继承了水果的特性,但又拥有与其它水果不同的自定义属性。

而这些属性通过封装的方式,赋予了苹果与其它水果的与众不同。

而通过什么封装方式去表示苹果的与众不同呢?

用:属性、方法(函数)、事件

那么问题来了?一颗苹果怎么封装?

苹果也有生命周期和意义。

例如:

事件:

  • 苹果被培育成熟

  • 苹果被采摘

  • 苹果被人类食用

函数:

  • 摆上货架()

  • 获取产地信息()

属性:

  • 颜色

  • 重量

  • 价格


基本原理

代码示例(轻语言2.0):

定义 水果 为 类型
    ' 定义水果的类型
    变量 员_类型 为 文本型

    ' 定义水果口味,例如:甜、酸
    变量 员_口味 为 文本型

    ' 构造函数、创建水果时传入水果名称,例如:苹果
    函数 水果(参_类型 为 文本型)
        员_类型 = 参_类型
    结束 函数

    函数 取类型() 为 文本型
        返回 员_类型
    结束 函数

    ' 定义水果的口味类型
    属性 口味 为 文本型
        写
            员_口味 = 值
        读
            返回 员_口味
    结束 属性

结束 定义

' 苹果继承了水果所有特性
定义 苹果 继承 水果

    变量 员_产地 为 文本型

    ' 自定义苹果的产地属性
    属性 产地 为 文本型
        写
            员_产地 = 值
        读
            返回 员_产地
    结束 属性

结束 定义

' 葡萄继承了水果所有特性
定义 葡萄 继承 水果

    ' 重写葡萄的口味类型
    属性 口味 为 文本型
        读
            返回 "酸"
    结束 属性

结束 定义

在编程中的实际应用

面向对象的思想在目前主流编程中应用非常普遍。

通俗意义上来说,在现实生活中,面向对象就是归纳总结、概括;用以抽象的形容某一类物体;例如:一个实实在在的苹果,则是一个可以被称为水果的示例对象。

而在编程的世界中;程序都是虚拟的。

很多时候不太好理解面向对象到底是怎么用在编程上面的。

但换个角度;假设我们将其虚拟的软件程序拟物化。

例如:

将一个APP或一个软件看成一个存在虚拟世界的物体;至于是什么形状,可以自行想象。

此时对于一个App来说;这个App像现实世界中的物体一样:

有名字、

有大小、

有编写它的生产厂家(这里指软件作者)、

有生日、

有生辰八字(软件来到虚拟计算机世界中的时间)、

有年龄等等。

OK,此时这个App就是存在于软件世界中的一个实际的对象,虽然好像它是虚拟的。

代码中的面向对象

上面我们讨论了,宏观角度,将一个软件拟物化,现在我们看一下在实际编写程序时,面向对象在代码中是怎么使用的。

首先从一个窗口来说;见下图:

在上方窗口中(App中的一个窗口页面)里面有很多不同的小组件,按钮、标签、编辑框等等,这些组件都是一个对象。每个组件都有自己的名字、属性、事件。

注意:窗口 是表示所有App窗口中的抽象归纳,每个设计器窗口都继承自窗口,是一个独立的对象。

代码示例:

事件 窗口创建完毕()

    ' 按钮 是一个类型
    ' 通过创建关键字、在内存中创建一个按钮对象
    ' 这个对象是按钮实例,可以调用其属性、函数等等
    变量 按钮10 = 创建 按钮()
    ' 通过属性修改按钮标题
    按钮10.标题 = "我是按钮10"
    ' 通过函数的方式给按钮设置圆角
    按钮10.置圆角(10)
    ' 将创建好的按钮添加到窗口中
    根布局.添加组件(按钮10)

结束 事件

这里很多人对创建一词不太理解,程序中的创建与现实生活中的创建生产是一样的,现实生活中的创建多用于生产、创造一个实际的物品。而代码中的创建是作为开发者的我们在计算机内存中创建一个虚拟物品

其它

面向对象其实本质很简单,大家不要想的太复杂。

人类世界与计算机世界不同的地方在于:

人类世界你不是造物主,你是被创建的一个独立的对象,你只能遵循这个宇宙、世界的规律。

但在计算机世界中,你是造物主,只要这个虚拟环境支持,你可以创建任何你想要的对象。

安卓工程项目结构

安卓项目与默认轻语言程序存在一定差异,因为一个标准的安卓APP程序,除了拥有启动文件及相关源代码文件,还包含很多其它的必要的程序组成文件,例如:APP中每个窗口的布局文件、APP中的图片、以及标准安卓应用规定的清单文件等等。

标准的轻语言安卓项目程序,由轻语言编写的程序源代码及其它必要文件组成:

项目根目录

默认必须包含的文件

  • src/:存放由轻语言编写的程序源代码。

    • 包含源代码的分组结构和 窗口模块服务结构体 等等文件。
  • layout/:存放窗口界面布局文件。

    • 包含APP中每个窗口界面的布局文件(.xml),用于在IDE中可视化设计窗口界面。
  • libs/:存放项目中用到的第三方 Jar 包文件。

  • res/:资源文件目录。

    • drawable/:存放编译时会生成 R. 索引的图片资源(如 PNG、JPEG 等)。

    • values/:存放字符串、颜色、样式等资源。

      • strings.xml:字符串资源。

      • colors.xml:颜色资源。

      • styles.xml:样式资源。

    • xml/:存放结构化数据或自定义偏好配置。

  • assets/:存放原始资源文件(如 图片、文本 等)。

  • App.spl:项目启动入口文件。

  • *.vsln:在 IDE 中加载项目的索引文件,该文件同时负责项目的基础配置信息。

其它项目文件

  • AndroidManifest.xml:标准安卓项目的清单配置文件,定义应用的包名、组件(Activity、Service 等)、权限、最低 SDK 版本等,在轻语言安卓项目中该文件会在编译时根据项目配置自动生成。

  • _build:编译输出目录、编译成功的安卓APK文件及编译时产生的相关文件会被存放到该文件夹中。注意:该文件夹创建项目时默认不存在,当编译项目时才会被创建,该文件夹可以被手动删除,删除后再次点击编译项目,仍然会自动生成。

  • src.package:源包文件夹。该文件夹中可以存放 Java 源代码、该文件夹需手动创建,默认项目不包含。注意:该文件夹中的 Java 源码文件需按照包名存在,例如:现在有一个 自定义.java 文件、这个文件中的包名为:com.mytest 那么 自定义.java 文件的路径必须为:src.package/com/mytest/自定义.java

构成安卓程序的基本元素

在轻语言安卓项目中,构成一个安卓程序的基本元素主要有:

窗口

  • 作用:表示用户界面(UI)的一个屏幕。

  • 功能:负责与用户交互,显示界面并处理用户输入。

  • 生命周期窗口创建完毕()窗口切换完毕()窗口被关闭()窗口被销毁()窗口按键被按下() 等。

  • 示例:登录界面、主界面、设置界面等。

  • 链接窗口

服务

  • 作用:在后台执行长时间运行的操作,不提供用户界面。

  • 功能:用于处理网络请求、播放音乐、文件下载等后台任务。

  • 使用:通过 启动服务()启动服务By意图() 启动,任务完成后需手动停止。

  • 示例:音乐播放器后台播放、文件下载服务。

  • 链接后台服务与广播

广播

  • 作用:接收系统或应用发出的广播消息。

  • 功能:用于响应系统事件(如网络状态变化、电池电量变化)或自定义事件。

  • 使用:请参考安装包安卓插件自带例程 广播例程

  • 示例:监听网络连接状态、接收短信、监听手机电量。

  • 链接后台服务与广播

核心库未支持的基本元素

内容提供者

  • 作用:管理应用程序的数据共享。

  • 功能:提供统一接口访问数据(如数据库、文件等),支持跨应用数据共享。

  • 实现:由于本元素在实际开发需求中较少,轻语言核心库针对本元素未在安卓项目中默认支持,如有需求,可自定义封装成扩展支持库使用。

项目配置与签名

项目配置用于在程序中定义项目的属性参数,例如APP版本、名称、图标等等,视频教程:修改应用的图标签名配置信息

项目基本配置

IDE 中加载一个安卓项目后;在工程窗口双击工程配置窗口。

将打开项目配置窗口:

基本信息

  • 应用名称 :设置 APP 安装后的名称。
  • 应用包名 :设置 APP 的包名,包名是区分两个 APP 的标志,当两个 APP 的包名一样时、但名称或图标不一样时,系统仍然会认为是一个 APP ,包名只能由 英文、数字、点 组成,不能含有中文、且不能以数字开头,例如正确的包名:com.myappmy.app123 ,不正确的包名:1com.222我的.App程序
  • 版本序号 :设置版本的序号、只能为整数,安装后用户看不懂。
  • 版本名称 :设置版本的名称,一般与版本序号相同,安装后用户可以看到。

签名

签名文件是什么?

签名文件是一个包含加密密钥的文件,通常以 .keystore 或 .jks(Java KeyStore)为扩展名。

签名文件有什么作用?

  1. 验证应用来源

    • 签名文件可以证明 APK 是由特定的开发者或组织发布的,确保应用来源可信,例如在程序中可以通过获取签名验证是否为官方APK安装包。
  2. 保证应用完整性

    • 签名可以确保 APK 在发布后未被篡改。如果 APK 被修改,签名将失效。
  3. 支持应用更新

    • Android 系统要求更新的 APK 必须使用与原始 APK 相同的签名文件,以确保更新的安全性。

如何生成签名文件?

在 VcnStudio 安装目录中,有一个名为 keystore 的文件夹,该文件夹中官方提供了一个签名证书制作工具,以管理员方式运行该程序、根据程序提示输入信息,生成签名文件即可。

使用签名文件

在项目工程配置文件窗口中、切换到 签名 面板,选择创建的签名文件、并输入文件别名、密码,点击保存后,IDE 将会复制一份选择的别名文件到项目根目录文件夹中,并名为:keystore.keystore 编译时将会优先选择该签名文件对生成的APK文件进行签名,如需删除签名文件、也可以手动删除该文件,并清空设置的别名与密码。

未设置签名文件,默认编译项目时将使用安装包自带的签名文件。

配置窗口中设置的签名文件别名与密码必须与选择的签名文件一致,如果不一致会导致签名失败、APK无法被安装。

自定义Manifest清单文件

AndroidManifest.xml 是 Android 应用程序的核心配置文件,在轻语言安卓项目中,该文件在编译时会根据项目配置窗口配置的信息自动生成,但如果需要自定义该文件;可以在配置窗口中自定义修改该清单文件内容。

当在配置窗口中修改过该清单文件后、将会在项目的根目录下面生成该文件的副本。

清单文件定义了应用的基本信息、组件、权限、硬件需求等,是 Android 系统了解应用的重要依据。以下是 AndroidManifest.xml 的详细说明:

清单文件的作用

  1. 定义应用的基本信息

    • 包名、版本号、应用图标、应用名称等。
  2. 声明应用组件

    • 注册 Activity、Service、BroadcastReceiver、ContentProvider 等组件。
  3. 配置权限

    • 声明应用所需的系统权限(如访问网络、读取联系人等)。
  4. 定义应用行为

    • 配置应用的主题、启动模式、硬件需求等。
  5. 声明应用的最低和目标 SDK 版本

    • 指定应用支持的 Android 版本范围。

AndroidManifest.xml 的结构

AndroidManifest.xml 是一个 XML 文件,其基本结构如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">

    <!-- 应用的基本信息 -->
    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">

        <!-- 声明 Activity -->
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- 声明 Service -->
        <service android:name=".MyService" />

        <!-- 声明 BroadcastReceiver -->
        <receiver android:name=".MyReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <!-- 声明 ContentProvider -->
        <provider android:name=".MyContentProvider"
            android:authorities="com.example.myapp.provider" />
    </application>

    <!-- 声明权限 -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- 声明硬件需求 -->
    <uses-feature android:name="android.hardware.camera" />

    <!-- 声明最低和目标 SDK 版本 -->
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
</manifest>

AndroidManifest.xml 配置详解

1. <manifest> 标签

  • package:定义应用的包名,是应用的唯一标识符。

  • xmlns:android:定义 Android 命名空间。

2. <application> 标签

  • android:icon:指定应用图标。

  • android:label:指定应用名称。

  • android:theme:指定应用的主题。

  • android:allowBackup:是否允许应用备份。

  • android:supportsRtl:是否支持从右到左的布局。

3. 声明组件

  • <activity>:声明 Activity,定义应用的界面。

    • android:name:Activity 的类名。

    • android:label:Activity 的标题。

    • android:launchMode:Activity 的启动模式(如 standardsingleTop)。

    • <intent-filter>:定义 Activity 的意图过滤器。

      • <action>:指定 Activity 可以处理的操作(如 android.intent.action.MAIN)。

      • <category>:指定 Activity 的类别(如 android.intent.category.LAUNCHER)。

  • <service>:声明 Service,定义后台服务。

    • android:name:Service 的类名。
  • <receiver>:声明 BroadcastReceiver,定义广播接收器。

    • android:name:BroadcastReceiver 的类名。

    • <intent-filter>:定义接收的广播类型。

  • <provider>:声明 ContentProvider,定义数据提供者。

    • android:name:ContentProvider 的类名。

    • android:authorities:ContentProvider 的唯一标识符。

4. 声明权限

  • <uses-permission>:声明应用所需的权限。

    • android:name:权限名称(如 android.permission.INTERNET)。
  • <permission>:声明自定义权限。

5. 声明硬件需求

  • <uses-feature>:声明应用所需的硬件特性。

    • android:name:硬件特性名称(如 android.hardware.camera)。

6. 声明 SDK 版本

  • <uses-sdk>:声明应用的最低和目标 SDK 版本。

    • android:minSdkVersion:应用支持的最低 Android 版本。

    • android:targetSdkVersion:应用目标 Android 版本。

7. 其他配置

  • <meta-data>:定义额外的元数据。

  • <instrumentation>:定义测试工具。

如何设置 AndroidManifest.xml?

1. 基本设置

  • 在 <manifest> 标签中设置应用的包名。

  • 在 <application> 标签中设置应用的图标、名称和主题。

2. 声明组件

  • 在 <application> 标签中添加 <activity><service><receiver> 和 <provider> 标签,声明应用的组件。

3. 配置权限

  • 在 <manifest> 标签中添加 <uses-permission> 标签,声明应用所需的权限。

4. 配置硬件需求

  • 在 <manifest> 标签中添加 <uses-feature> 标签,声明应用所需的硬件特性。

5. 配置 SDK 版本

  • 在 <manifest> 标签中添加 <uses-sdk> 标签,声明应用的最低和目标 SDK 版本。

总结

  • AndroidManifest.xml 是 Android 应用的核心配置文件,定义了应用的基本信息、组件、权限、硬件需求等。

  • 作用:声明组件、配置权限、定义应用行为、声明 SDK 版本等。

  • 设置方法:通过 <manifest><application><activity><uses-permission> 等标签进行配置。

  • 重要性AndroidManifest.xml 是 Android 系统了解应用的重要依据,必须正确配置。

程序入口文件

每个轻语言安卓程序都有一个入口文件(App.spl);这个文件是程序的启动入口,当程序(APP)被系统启动时(用户点击APP图标),系统将优先触发该文件中的 应用被启动 事件,告诉开发者,用户准备启动该程序、且系统已经做好准备,开发者可以在该文件中初始化程序设置,或者自该位置打开、加载一个窗口。

每个轻语言程序都有一个、且唯一的入口文件 App.spl ,每次重新启动程序时,系统都会先回调该文件中的 应用被启动事件,该文件默认结构为(基于轻语言V1.5、IDE 4.7.2):

' 定义权限集合表
变量 待申请权限 为 集合

事件 应用被启动()
    ' 由于安卓6及以上系统、部分敏感权限例如读写储存卡权限需要动态申请;因此该代码为创
    ' 建项目时为方便开发自动添加的、如果该APP不需要动态申请任何权限、删除该段代码即可
    申请系统权限()
    ' 创建指定窗口为启动窗口;可任意设置
    变量 启动窗口 = 创建 主窗口()
    切换窗口(启动窗口)
结束 事件

函数 申请系统权限()
    ' 默认权限都已全部屏蔽、可根据你当前APP所需要的权限解除屏蔽
    待申请权限 = 创建 集合()
    ' 读写手机SD卡文件
    '待申请权限.添加项目("android.permission.READ_EXTERNAL_STORAGE")
    '待申请权限.添加项目("android.permission.WRITE_EXTERNAL_STORAGE")
    '读写日历
    '待申请权限.添加项目("android.permission.READ_CALENDAR")
    '待申请权限.添加项目("android.permission.WRITE_CALENDAR")
    ' 相机、拍照、扫码
    '待申请权限.添加项目("android.permission.CAMERA")
    ' 读写电话簿、联系人
    '待申请权限.添加项目("android.permission.READ_CONTACTS")
    '待申请权限.添加项目("android.permission.WRITE_CONTACTS")
    '待申请权限.添加项目("android.permission.GET_ACCOUNTS")
    ' 对设备定位
    '待申请权限.添加项目("android.permission.ACCESS_FINE_LOCATION")
    '待申请权限.添加项目("android.permission.ACCESS_COARSE_LOCATION")
    ' 录音
    '待申请权限.添加项目("android.permission.RECORD_AUDIO")
    ' 获取手机信息、打电话、获取通话记录
    '待申请权限.添加项目("android.permission.READ_PHONE_STATE")
    '待申请权限.添加项目("android.permission.CALL_PHONE")
    '待申请权限.添加项目("android.permission.READ_CALL_LOG")
    '待申请权限.添加项目("android.permission.WRITE_CALL_LOG")
    '待申请权限.添加项目("android.permission.ADD_VOICEMAIL")
    '待申请权限.添加项目("android.permission.USE_SIP")
    '待申请权限.添加项目("android.permission.PROCESS_OUTGOING_CALLS")
    ' 生物特征传感器;跑步计次、记录心率
    '待申请权限.添加项目("android.permission.BODY_SENSORS")
    ' 读写短信
    '待申请权限.添加项目("android.permission.SEND_SMS")
    '待申请权限.添加项目("android.permission.RECEIVE_SMS")
    '待申请权限.添加项目("android.permission.READ_SMS")
    '待申请权限.添加项目("android.permission.RECEIVE_WAP_PUSH")
    '待申请权限.添加项目("android.permission.RECEIVE_MMS")
    ' 将集合权限转成文本数组并开始申请
    如果(待申请权限.取项目数() == 0)
        返回
    结束 如果
    '
    变量 待申请权限数组 为 文本型[] = 创建 文本型[待申请权限.取项目数()]
    变量循环(索引 = 0,取数组成员数(待申请权限数组),1)
        待申请权限数组[索引] = 待申请权限.取项目(索引) + ""
    结束循环
    申请权限(待申请权限数组,1995)
结束 函数

事件 权限申请完毕(请求码 为 整数型,请求成功的权限 为 文本型[],请求成功结果 为 整数型[])
    ' 这里一般根据待申请的权限长度判断请求结果即可;如果申请了两个权限、请求成功结果
    ' 的长度为2、那么说明所有权限申请成功;如果不等于2则说明部分有拒绝、弹出一个提示
    如果(取数组成员数(请求成功结果) != 待申请权限.取项目数())
        弹出提示("部分权限未成功申请;可能会对APP功能产生一定影响!")
    结束 如果
结束 事件

事件 应用被销毁()
    ' 当应用被关闭时将会触发该事件

结束 事件

事件 应用方向被改变(新方向 为 整数型)
    ' 当 APP 方向被改变时触发该事件;在工程配置中修改窗口方向为:自动
    弹出提示("APP方向被改变:" + 新方向)
    ' 向其它窗口发送方向被改变的事件
    发送事件消息(1,"新方向:" + 新方向)
结束 事件

事件说明

安卓入口文件中总共有四个系统事件:

应用被启动

当 APP 被启动时,系统回调执行,告诉开发者应用已经在系统内准备就绪,程序基架已经在系统中入栈(添加到系统内存了)。此时只需要开始编写 APP 启动后要执行的软件功能即可,安卓默认在该事件中完成了两件事情:

  1. 动态申请应用中需要用到的权限

  2. 创建主窗口、并调用系统函数切换到指定窗口,此时系统将打开窗口、并在屏幕中显示窗口界面。这里的启动窗口可以任意根据需求设置。

权限申请完毕

当调用 申请权限 函数后、系统将回调该事件,可在该事件中判断用户是否允许了某些权限。

应用被销毁

当整个 APP 被关闭时、将触发该事件。

应用方向被改变

在配置窗口中设置屏幕方向为:自动时,当 APP 的屏幕方向(手机发生横竖屏切换时)系统将回调该事件,可在该事件中向指定窗口发送消息,处理窗口根据不同屏幕方向的业务需求。

权限的申请与处理

安卓 APP 程序由于性质特殊,谷歌从安全角度、及保护用户隐私和设备安全考虑、为其设计了权限机制。

权限的作用

  1. 保护用户隐私

    • 防止 APP 未经用户同意就访问敏感数据(如联系人、位置、相机等)。
  2. 保障设备安全

    • 防止 APP 滥用系统功能(如发送短信、拨打电话等)。
  3. 增强用户控制

    • 让用户明确知道应用需要哪些权限,并可以选择是否授予这些权限。

安卓程序权限的分类

Android 权限分为两大类:静态权限动态权限

1. 静态权限

  • 定义:普通权限、不涉及用户隐私或设备安全的权限。

  • 特点

    • 在应用安装时自动授予。

    • 不需要用户明确同意。

  • 示例

    • INTERNET:访问网络。

    • ACCESS_NETWORK_STATE:访问网络状态。

  • 声明方式: 只需要在 AndroidManifest.xml 中声明即可、不需要在代码中动态申请,例如访问网络的权限:

<uses-permission android:name="android.permission.INTERNET" />

2. 动态权限

动态权限除了在清单文件中声明外、还需要在代码中申请;使用分为以下几个步骤:

1. 在 AndroidManifest.xml 中声明权限

例如 使用相机、读取通讯录信息:

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.CAMERA" />

2. 在代码中申请

函数 申请系统权限()
    ' 默认权限都已全部屏蔽、可根据你当前APP所需要的权限解除屏蔽
    ' 相机、拍照、扫码
    待申请权限.添加项目("android.permission.CAMERA")
    ' 读写电话簿、联系人
    待申请权限.添加项目("android.permission.READ_CONTACTS")
    待申请权限.添加项目("android.permission.WRITE_CONTACTS")
    待申请权限.添加项目("android.permission.GET_ACCOUNTS")
    ' 将集合权限转成文本数组并开始申请
    如果(待申请权限.取项目数() == 0)
        返回
    结束 如果
    变量 待申请权限数组 为 文本型[] = 创建 文本型[待申请权限.取项目数()]
    变量循环(索引 = 0,取数组成员数(待申请权限数组),1)
        待申请权限数组[索引] = 待申请权限.取项目(索引) + ""
    结束循环
    申请权限(待申请权限数组,1995)
结束 函数

3. 判断权限申请结果

事件 权限申请完毕(请求码 为 整数型,请求成功的权限 为 文本型[],请求成功结果 为 整数型[])
    ' 总共申请了 4 个权限、判断 请求成功结果 长度
    如果(取数组成员数(请求成功结果) != 4)
        弹出提示("所需权限未全部通过")
        返回
    结束 如果
结束 事件

权限组

Android 将动态权限分为多个权限组(Permission Groups),同一组内的权限只需请求一次。例如:

  • 联系人组READ_CONTACTSWRITE_CONTACTS

  • 位置组ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION

  • 相机组CAMERA

如果用户授予了某个权限组中的一个权限,则同一组内的其他权限也会自动授予。

程序中资源文件的使用

在安卓App开发中,资源文件通常是指App运行时所需的各种非代码数据的集合。这些资源包括图像、字符串、布局文件、动画、音频、视频等。通过将这些资源集中管理,开发者可以轻松实现多语言支持、适配不同屏幕尺寸和密度、分离 UI 和逻辑等功能。

在轻语言安卓App中,资源主要分为两大类,分别为:仓库(assets)、资源(res),两种资源不同分工,共同组成了App资源集合系统。

仓库(assets)

仓库(assets)是一个特殊的文件夹,用于存放打包时不会进行编译的原始文件资源。其特点为:

  • 不会生成 R 类条目。
  • 该文件夹中的文件不会被编译,直接以原始形式存储。
  • 不支持资源限定符。
  • 适合存放较大的静态文件(如图片、HTML、CSS、JS 文件、数据库文件等)。

在代码中使用

仓库文件夹中的文件在代码中使用时,均通过文件名以字符串形式使用。

编辑框1.内容 = 读仓库文本("json.txt","UTF-8")
按钮1.背景图片 = "img1.png"

资源(res)

资源(res)是 Android 项目中存放资源的主要目录,所有资源都必须遵循特定的子目录结构,并且可以通过 R 类访问。

子目录结构

  • layout:存放 XML 文件,用于定义用户界面布局。
  • drawable:存放图像资源(如 PNG、JPEG、SVG 等)或可绘制对象(如 XML 定义的形状、层列表等)。
  • mipmap:专门用于存放应用图标(如 launcher icons),确保不同密度屏幕上的显示效果。
  • values:存放各种类型的值资源,如字符串 (strings.xml)、颜色 (colors.xml)、维度 (dimens.xml)、样式 (styles.xml) 和主题 (themes.xml)。
  • raw:存放原始文件资源(如音频、视频等),这些文件不会被编译为二进制格式。
  • xml:存放其他 XML 配置文件(如配置文件、动画定义等)。
  • anim:存放动画资源文件。
  • menu:存放菜单资源文件。
  • navigation:存放导航组件相关的 XML 文件。
  • font:存放字体资源。

特点

  • 资源会被编译并生成对应的 R 类条目。
  • 支持资源限定符(如屏幕密度、语言、方向等),便于实现多语言支持和适配不同设备。

在代码中使用

资源文件中的文件在代码中使用时,均以 R. 开头使用,且一般多数场景为需要设置整数型图片资源ID的地方:

按钮1.背景资源 = R.logo

资源(res) 和 仓库(assets) 的主要区别

特性res 文件夹assets 文件夹
编译方式资源会被编译并生成 R 类条目文件保持原始状态,不生成 R 条目
访问方式通过 R 类访问通过 内置函数 访问
资源限定符支持支持(如屏幕密度、语言等)不支持
适用存放小型资源文件(如图片、字符串、颜色等)大型静态文件(如数据库、HTML 文件等)
性能编译后加载更快原始文件需要手动处理,可能稍慢
使用方式及场景在需要R资源索引ID的地方使用 R. 调用在需要读取仓库文件、或以字符串文本形式调用文件名称时

窗口与布局

窗口是组成安卓APP程序的重要元素,APP 中的窗口除了起着展示内容的作用、还承担着与用户交互的功能。

窗口设计与布局相关视频教程:绝对布局-5678

窗口代码结构

轻语言安卓程序中的窗口,与轻语言普通程序中的源代码文件基本一致,但每个APP窗口默认源代码必须包含事件:窗口创建完毕

示例:

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 文件描述:窗口功能描述、注释,非必须的
' 修改日志:
' ****************************************************************************

' 窗口成员变量、非必须的,可删除
变量 页面标记 为 文本型 = ""

' 默认窗口主要事件,该事件不能被删除
事件 窗口创建完毕()

结束 事件

' 监听窗口中按钮1被单击事件,非必须的
事件 按钮1.被单击(来源对象 为 视图)
    弹出提示("按钮1被单击")
结束 事件

窗口界面设计

APP 中每个窗口都有一个界面设计文件,该文件采用XML语言描述并记录窗口中组件及布局的设计,(文件后缀为:.xml),界面设计文件必须与窗口名称同名,所有窗口设计文件只能存放在项目工程目录中的 layout 文件夹中,设计文件支持使用外部编辑器打开手动修改,修改时需遵守 XML 语言规范,如果布局文件格式错误,在 IDE 中打开可视化设计时将会发生错误,默认窗口界面设计内容如下:

<?xml version="1.0" encoding="utf-8"?>
<设计稿 宽度="" 高度="">
    <绝对布局 名称="根布局">
      <标签 名称="标签1" 标题="我是新建窗口" 左边="12" 顶边="12" 宽度="296" 高度="90" />
      <按钮 名称="按钮1" 标题="点击测试" 左边="12" 顶边="126" 宽度="296" 高度="37" />
    </绝对布局>
</设计稿>
  • 设计稿

    • 设计稿为界面设计的根节点,有两个属性,可以设置设计稿(IDE中设计窗口)的宽高尺寸(单位为:像素);默认设计稿尺寸为宽高:320 * 480
  • 根布局

    • 设计稿节点中只能有一个子组件,该组件为根布局,在根布局中可以存在多个子组件或子布局,在IDE可视化设计时,向窗口中添加的组件或布局默认都会被添加到根布局中。
  • 根布局类型

    • 根布局类型可以为:绝对布局、线性布局、帧布局

常用布局

轻语言安卓框架中内置了 5 种常用布局:

绝对布局

  • 特点

    • 通过指定子视图的精确坐标(x, y)来定位。

    • 灵活性高,但缺乏自适应能力。使用时需要根据屏幕宽高手动计算位置。

  • 用途

    • 适用于需要精确控制视图位置的场景。

    • 适用于快速设计、可视化拖拽设计界面的场景。

    • 绝对布局为轻语言安卓项目中默认布局。

线性布局

  • 特点

    • 子视图按水平(horizontal)或垂直(vertical)方向排列。

    • 通过权重(weight)属性分配剩余空间。

  • 用途

    • 适合简单的线性排列,如表单、列表等。

    • 常用于需要按比例分配空间的场景。

帧布局

  • 特点

    • 子视图可以重叠,默认从左上角开始排列。

    • 适用于单视图显示或视图叠加。

  • 用途

    • 常用于需要重叠视图的场景,如在图片上面显示文字、或标签。

    • 适合显示单一视图或需要动态切换视图的情况。

宫格面板

  • 特点

    • 类似九宫格,子组件按照宫格列表依次排列。
  • 用途

    • 常用于需要整齐、排列、按照等分显示的场景。

弹性布局

  • 特点

    • 子组件按照顺序依次排列,当超过布局宽度时,自动换行从第二行重新开始排列。
  • 用途

    • 适用于不固定、连续单独显示内容的场景。

动态创建组件

在轻语言安卓程序中,除了在设计器中可视化拖拽设计界面外,也可以在代码中动态创建组件,然后将其添加到窗口中。

动态创建组件的优点

  1. 灵活性

    • 动态创建组件允许开发者根据运行时条件(如用户输入、网络请求结果等)动态调整UI。

    • 可以更灵活地控制组件的属性和行为。

  2. 减少资源占用

    • 如果某些组件只在特定条件下显示,动态创建可以避免在XML中预先定义这些组件,从而减少资源占用。
  3. 动态布局

    • 当布局需要根据数据动态变化时(如列表项、网格布局等),代码创建组件可以更高效地实现。
  4. 复用性

    • 动态创建的组件可以封装成方法或类,便于复用。

适用场景

  1. 动态列表或网格

    • 当列表项或网格项的内容和数量不确定时(如从服务器获取数据),适合动态创建组件。
  2. 条件性UI

    • 当某些组件只在特定条件下显示时(如用户登录后才显示的按钮),适合动态创建。
  3. 自定义视图

    • 当需要创建复杂的自定义视图(如自定义图表、动态表格等),代码创建更灵活。
  4. 动态布局调整

    • 当布局需要根据屏幕尺寸、设备方向或用户设置动态调整时,代码创建更合适。
  5. 游戏或动画

    • 在游戏开发或需要频繁更新UI的场景中,动态创建组件可以更好地控制UI的变化。
  6. 减少XML嵌套

    • 当XML布局嵌套过深导致性能问题时,可以通过代码创建组件来优化布局结构。

使用方式

动态添加按钮

  • 在窗口中添加一个垂直滚动框组件(垂直滚动框1),根据用户输入的数量或指定数量动态创建多个按钮,并添加到垂直滚动框中。(注意:这里也可以直接添加到窗口根布局中、但是添加到根布局中需要手动计算位置,而垂直滚动框添加的组件会自动在滚动框从上到下排列,且添加的内容超过滚动框高度时、内容可以上下滑动)
函数 动态创建按钮并添加到滚动框(待创建数量 为 整数型)
    ' 使用循环创建
    变量循环(i = 0,待创建数量,1)
        ' 创建按钮对象、并设置相关属性
        变量 局_按钮 = 创建 按钮()
        局_按钮.标题 = "按钮" + i
        ' 设置当按钮被单击时,接收系统回调的匿名子函数
        局_按钮.置被单击回调((按钮源)->{
            弹出提示(局_按钮.标题 + " 被单击")
        })
        ' 将创建的按钮添加到垂直滚动框1中
        垂直滚动框1.添加组件(局_按钮)
    结束循环
结束 函数

动态创建自定义对话框

事件 按钮2.被单击(来源对象 为 视图)
    变量 msgBox = 创建 对话框()
    msgBox.标题 = "请选择"
    msgBox.信息 = "确定要提交当前已输入的信息吗?"
    msgBox.置按钮("确定","取消","")
    msgBox.触摸空白域关闭 = 假
    msgBox.置按钮被单击回调(&带选择结果信息框被关闭)
    msgBox.显示()
结束 事件

函数 带选择结果信息框被关闭(源对象 为 对话框,按钮索引 为 整数型)
    如果(按钮索引 == -1)
        弹出提示("你点击了确定")
    否则
        弹出提示("你点击了取消")
    结束 如果
结束 函数

动态使用时钟(不可视组件)

时钟是不可视组件,不可视组件可以添加到窗口中,但在运行时不会显示。

这里以通过代码的方式创建使用:

事件 按钮4.被单击(来源对象 为 视图)
    计次 = 0
    ' 动态创建时钟对象、并通过拉姆达回调方式执行周期事件
    变量 局_时钟1 = 创建 时钟()
    局_时钟1.时钟周期 = 1000
    局_时钟1.置周期事件回调((源对象)->{
        ' 注意:这里的计次只能为类成员变量
        计次 = 计次 + 2
        标签1.标题 = "局_时钟1:" + 计次
        ' 如果计次变量大于某个值则停止时钟,这里大于20
        如果(计次 > 20)
            局_时钟1.可用 = 假
        结束 如果
    })
    局_时钟1.可用 = 真
结束 事件

温馨提示

在轻语言安卓中,无论是可视组件还是不可视组件,都可以通过代码方式创建使用。

时钟与延时执行

在安卓开发中,循环执行延时执行是常见的任务调度方式,分别用于重复执行代码和延迟执行代码。以下是它们的详细说明和使用方法:

循环执行(时钟组件)

循环执行用于定期重复执行某段代码,适合需要周期性任务的场景,如更新UI或轮询数据。在轻语言安卓中,要实现循环执行,可以使用时钟组件。

示例代码:

变量 计次 = 0
事件 按钮1.被单击(来源对象 为 视图)
    计次 = 0
    ' 动态创建时钟对象、并通过拉姆达回调方式执行周期事件
    变量 局_时钟1 = 创建 时钟()
    局_时钟1.时钟周期 = 1000
    局_时钟1.置周期事件回调((源对象)->{
        ' 注意:这里的计次只能为类成员变量
        计次 = 计次 + 2
        标签1.标题 = "局_时钟1:" + 计次
        ' 如果计次变量大于某个值则停止时钟,这里大于20
        如果(计次 > 20)
            局_时钟1.可用 = 假
        结束 如果
    })
    局_时钟1.可用 = 真
结束 事件

时钟组件也可以添加到窗口中,使用事件方式执行周期事件。

延时执行

延时执行用于在指定时间后执行某段代码,适合需要延迟操作的场景,如显示提示信息或执行定时任务,在轻语言安卓中可以使用 延时执行 函数实现。

代码示例:

事件 按钮2.被单击(来源对象 为 视图)
    ' 2 秒后调用指定函数
    标签1.标题 = "等待执行..."
    延时执行(&延时执行子程序,2000)
    ' 除了传入子程序外;延时执行 函数也支持拉姆达表达式;例如:
    延时执行(()->{
        弹出提示("拉姆达方式延时 2 秒")
    },2000)
结束 事件

函数 延时执行子程序()
    标签1.标题 = "2秒时间到;延时子程序被执行"
结束 函数

多线程与消息通信

在安卓开发中,多线程是指在一个应用中同时运行多个线程来完成不同的任务。每个线程可以独立执行代码块,而不会阻塞主线程或其他线程的执行。安卓系统默认提供了一个主线程(也叫UI线程),它负责处理与用户界面相关的操作。如果某些耗时操作(如网络请求、文件读写等)直接在主线程中执行,会导致界面卡顿甚至出现ANR(Application Not Responding)错误。

因此,多线程技术被用来将这些耗时任务放到后台线程中执行,从而保证主线程的流畅运行。

多线程的具体作用及应用场景

  • 避免UI卡顿:将耗时任务(如网络请求、数据库操作)放到后台线程,确保主线程流畅运行。

  • 提高性能:通过并行处理任务,充分利用多核CPU,提升应用性能。

  • 异步处理:允许任务在后台执行,完成后通过回调或消息机制更新UI。

如何在轻语言安卓程序中使用多线程

视频教程:安卓APP高级开发之异步与多线程的使用

轻语言安卓SDK开发包中提供了多种多线程的实现方式;详见:多线程

意图与跨窗口传递消息

在安卓开发中,意图 主要用于执行某个系统动作(动机),例如:启动手机中安装的第三方、其它APP,或者在程序中启动一个后台服务。

意图的常用动作

ACTION_MAIN

  • 常量值:android.intent.action.MAIN

  • 用途:应用的主入口点,通常用于启动应用的主界面。

ACTION_VIEW

  • 常量值:android.intent.action.VIEW

  • 用途:根据 URI 显示数据,例如打开网页、查看图片等。

ACTION_SEND

  • 常量值:android.intent.action.SEND

  • 用途:分享文本、图片等内容。

ACTION_DIAL

  • 常量值:android.intent.action.DIAL

  • 用途:打开拨号界面并显示号码。

ACTION_IMAGE_CAPTURE

  • 常量值:android.media.action.IMAGE_CAPTURE

  • 用途:启动相机应用拍照。

ACTION_PICK

  • 常量值:android.intent.action.PICK

  • 用途:从内容提供者中选择数据,例如选择联系人、图片等。

ACTION_SEARCH

  • 常量值:android.intent.action.SEARCH

  • 用途:执行搜索操作。

ACTION_BOOT_COMPLETED

  • 常量值:android.intent.action.BOOT_COMPLETED

  • 用途:系统启动完成后发送广播。

ACTION_SETTINGS

  • 常量值:android.settings.SETTINGS

  • 用途:打开系统设置界面。

在程序中使用意图

1.启动系统浏览器打开网页

事件 按钮1.被单击(来源对象 为 视图)
    变量 意图1 = 创建 意图()
    ' 设置当前意图的具体动作,常用动作可参考官方文档
    ' 这里指定当前意图1的动作为:打开一个系统视图浏览网页
    意图1.动作 = "android.intent.action.VIEW"
    意图1.置数据("http://www.vcnstudio.com") 
    启动意图(意图1)
结束 事件

2.启动手机中安装的其它APP

事件 按钮2.被单击(来源对象 为 视图)
    变量 意图1 = 创建 意图()
    ' 启动雷电模拟器中的谷歌浏览器
    意图1.置自定义启动类("com.android.chrome","com.google.android.apps.chrome.Main")
    启动意图(意图1)
结束 事件

3.调用系统分享内容

事件 按钮3.被单击(来源对象 为 视图)
    变量 意图1 = 创建 意图()
    意图1.取原生对象().setType("text/plain")
    意图1.取原生对象().putExtra(android.content.Intent.EXTRA_TEXT, "具体要分享的内容")
    取应用上下文().startActivity(android.content.Intent.createChooser(意图1.取原生对象(), "分享到"))
结束 事件

4.启动后台服务

详见安装包内自带安卓例程:后台服务例程

事件 按钮3.被单击(来源对象 为 视图)
    变量 意图1 = 创建 意图()
    ' Ser2 为后台服务代码文件名称
    意图1.置启动类("Ser2")
    意图1.添加数据("city","成都")
    意图1.添加数据("sw","off")    
    启动服务By意图(意图1)
结束 事件

跨窗口传递消息

在轻语言安卓程序中,跨窗口传递消息可以使用多种方式:

事件 按钮1.被单击(来源对象 为 视图)
    保存对象("key1","数据值1")
    保存设置("long-key2","持久化储存设置的数据值")
    切换窗口(创建 窗口2())
结束 事件

事件 按钮2.被单击(来源对象 为 视图)
    ' 先创建一个局部的窗口对象
    变量 局_窗口2 = 创建 窗口2()
    ' 窗口2 中自定义了一个变量;为其设置数据值
    局_窗口2.数据值 = "主窗口按钮2被单击时设置的数据值"
    ' 再切换到窗口2中
    切换窗口(局_窗口2)
结束 事件

事件 按钮3.被单击(来源对象 为 视图)
    公用模块1.全局标记 = "公用模块数据:欢迎使用VcnStudio开发工具"
    ' 注意这里切换时重新创建的窗口对象
    切换窗口(创建 窗口2())
结束 事件

事件 按钮4.被单击(来源对象 为 视图)
    ' 上面的方法在传递数据时都需要先设置数据再切换窗口
    ' 如果需要当切换到窗口2时,还可以实时或延时接收其它地方传递的数据则需要使用消息事件
    延时执行(()->{
        发送事件消息(1,"切换到窗口2后,等待2秒传递的数据值:123890")
    },2000)
    切换窗口(创建 窗口2())
结束 事件

接收数据:

' 由外部设置(通过本窗口对象)
变量 数据值 为 文本型

事件 窗口创建完毕()
    ' 读取从其它窗口传递过来的数据
    标签1.追加文本行("key1:" + 读取对象("key1"))
    标签1.追加文本行("long-key2:" + 读取设置("long-key2"))
    ' 接收延时传递的数据
    接收事件消息((消息ID,消息值)->{
        标签1.追加文本行("消息ID:" + 消息ID + ",消息值:" + 消息值)
    })
结束 事件

事件 窗口切换完毕()
    ' 通过方式二传递的数据、只能在窗口切换完毕中获取
    标签1.追加文本行("方式二:" + 数据值)
    ' 读取公用模块的值(建议在窗口切换完毕中读取)
    标签1.追加文本行("方式三:" + 公用模块1.全局标记)
结束 事件

后台服务与广播

在安卓开发中,后台服务(Service) 是一种能够在后台运行的组件,它不与用户界面直接交互。即使用户的设备屏幕被锁住或切换到其他应用,服务仍然可以继续运行。

后台服务的作用及应用场景

  1. 执行长时间运行的任务:

    • 播放音乐。
    • 下载或上传文件。
    • 同步数据。
    • 定时任务(如通知提醒)。
  2. 无需用户界面的操作:

    • 服务可以在没有窗口的情况下运行,适合处理不需要与用户交互的任务。
  3. 保持应用的核心功能运行:

    • 比如即时通讯应用中的消息推送、位置跟踪、天气情况监听等。

使用后台服务

详见安装包内自带的安卓例程:后台服务例程

1.创建服务

在IDE工程窗口中选中程序集节点;新建文件;选择文件类型为:后台服务,输入服务名称:Ser1 点击确定。

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 服务描述:本服务演示了一个实时在后台获取当前时间并传递给主窗口标签中显示的功能。
' 修改日志:
' ****************************************************************************

' 定义当前服务的类成员变量
变量 类成员1 为 文本型

' 接收子线程传出的消息
变量 类_消息句柄1 为 消息句柄

' 当服务被创建时触发该事件
事件 服务创建完毕()
    调试输出("服务创建完毕")
结束 事件

' 当从外部启动当前服务时、将触发该事件;并返回启动时传入的意图对象
事件 收到指令(源意图 为 意图,标志值 为 整数型,服务ID 为 整数型)
    调试输出("收到服务指令")
    如果(类_消息句柄1 == 空)
        类_消息句柄1 = 创建 消息句柄()
        类_消息句柄1.置收到消息回调(&类_消息句柄1_收到消息)
    结束 如果
    ' 实时获取时间、并显示到主窗口标签中显示
    异步执行首
        ' 在子线程中无限循环获取时间
        判断循环(真)
            变量 当前时间 = 取现行时间到文本("yyyy-MM-dd HH:mm:ss")
            ' 由于安卓系统设计、这里在子线程中获取的时间数据必须先发送给消息句柄
            类_消息句柄1.发送消息(1,当前时间)
            ' 每隔1秒获取一次时间、注意:这里必须添加延时防止CPU占用100%
            延时(1000)
        结束循环
    异步执行尾
结束 事件

函数 类_消息句柄1_收到消息(源对象 为 消息句柄,消息ID 为 整数型,数据值 为 对象)
    ' 收到来自子线程中获取的时间、然后将时间投递给主窗口
    发送事件消息(1,数据值)
结束 函数

' 当服务被系统销毁或内存不足导致服务被关闭时触发该事件
事件 服务被销毁()

结束 事件

2.启动服务并接收后台服务传出的消息及数据值

事件 窗口创建完毕()
    标签1.标题 = "APP启动完毕;窗口创建完毕!"
    接收事件消息(&接收服务数据)
结束 事件

函数 接收服务数据(ID 为 整数型,数据值 为 对象)
    如果(ID == 1)
        ' 获取的时间
        标签1.标题 = 到文本(数据值)
    结束 如果
结束 函数

事件 按钮1.被单击(来源对象 为 视图)
    启动服务("Ser1")
结束 事件

广播

在安卓开发中,广播(Broadcast) 是一种用于在应用程序之间或应用程序内部传递消息的机制。它允许一个组件向系统或其他应用发送事件通知,其他组件可以通过注册接收器来监听这些事件并作出响应。

广播的作用及应用场景

  1. 系统事件通知:

    • 监听系统级别的事件,例如电池电量低、网络状态变化、屏幕亮灭等。
  2. 应用内通信:

    • 在应用的不同组件(如窗口、后台服务)之间传递数据或通知。
  3. 跨应用通信:

    • 不同应用之间可以通过广播共享信息或触发操作。
  4. 全局事件管理:

    • 广播可以用于实现全局事件监听和分发,例如通知用户完成某项任务。

使用广播

1.发送广播

通过意图对象封装待发送的广播消息,然后再使用内置函数 发送全局广播

事件 按钮1.被单击(来源对象 为 视图)
    变量 局_意图 = 创建 意图()
    ' 这里的动作可以自定义,其作用是:定义一个广播标识,在接收广播消息时通过这个动作判断广播来源
    局_意图.动作 = "mymsg"
    局_意图.添加数据("msg","这是在窗口2发送的广播消息")
    发送全局广播(局_意图)
结束 事件

2.接收广播消息

接收广播消息需要先创建一个广播对象,然后通过 收到新广播 事件处理广播消息,代码示例:

' 定义接收广播消息的对象
变量 广播1 为 广播

事件 窗口创建完毕()
    广播1 = 创建 广播()
结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    ' 创建广播之后、必须先注册待监听的动作
    ' 可一次注册多个动作、也可以注册单个动作
    变量 动作 = { "android.intent.action.BATTERY_CHANGED" , "ACTION_VCN_BROADCAST_TESTMSG" }
    广播1.注册监听动作(动作)
    弹出提示("注册广播成功")
结束 事件

事件 广播1.收到新广播(源对象 为 广播,意图对象 为 意图)
    ' 这里返回的意图对象即为发送广播时返回的意图对象
    ' 除了可以接收自定义广播对象外、还可以接收系统广播、例如:手机电池电量被改变
    变量 action 为 文本型 = 意图对象.动作
    如果(action == "android.intent.action.BATTERY_CHANGED")
        ' 这里返回的动作即为电池电量被改变的广播
        ' 通过指定字段名称从意图对象中取出电池电量
        变量 当前电量 为 整数型
        变量 总电量 为 整数型
        变量 电量百分比 为 文本型
        当前电量 = 意图对象.取整数值("level")
        总电量 = 意图对象.取整数值("scale")
        电量百分比 = 到文本(当前电量 / (单精度小数)总电量) + "%"
        标签1.标题 = "电池电量:" + 当前电量 + "," + 电量百分比
    否则 如果(action == "mymsg")
        ' 接收我们从其它窗口、或模块、或后台服务中传递的自定义广播信息
        变量 消息值 为 文本型 = 意图对象.取文本值("msg")
        标签1.标题 = "自定义广播消息:" + 消息值
    结束 如果
结束 事件

事件 按钮2.被单击(来源对象 为 视图)
    广播1.注销广播()
结束 事件

常见系统广播

以下是一些常见的系统广播及用途:

广播名称常量值描述
电池电量低"android.intent.action.BATTERY_LOW"电池电量低
电池电量恢复正常"android.intent.action.BATTERY_OKAY"电池电量恢复正常
系统启动完成"android.intent.action.BOOT_COMPLETED"系统启动完成
屏幕点亮"android.intent.action.SCREEN_ON"屏幕点亮
屏幕熄灭"android.intent.action.SCREEN_OFF"屏幕熄灭
网络状态变化"android.net.conn.CONNECTIVITY_CHANGE"网络状态变化

注意事项

  1. 性能优化:

    • 实际开发时应在 收到新广播 事件中快速完成任务,避免阻塞主线程。如果需要执行耗时操作,可以将任务交给子线程或后台服务。
  2. 注销广播:

    • 广播不使用了,或者完成了任务后,应在适当时候注销广播,以避免内存泄漏。

使用 Java 源包

在轻语言安卓项目中,除了可以直接在项目中使用第三方 jar 包,同时也可以在项目中直接使用开源 Java 库。

使用方式

1.创建 src.package 文件夹

在项目根目录手动创建一个名为:src.package 的文件夹。

2.复制 Java 源代码

将 Java 源代码复制到该文件夹中、或自定义根据包名创建 Java 源码文件。

3.在IDE中打开项目

在IDE中打开项目后,会在工程窗口中显示 源包(Java) 节点。

注意:如果项目根目录中没有 src.package 文件夹、工程数据列表中将不会显示 源包 节点。

4.在代码中使用

源包中可以存放任意 Java 源代码文件,在轻语言中使用时,只需要通过 引用 关键字,引用指定类即可使用。

例程中的源包内的 自定义类.java

package 我的包;

// 引用安卓核心库(如果需要的话)
import com.simple.android.*;
// 引用安卓原生类或组件
import android.content.Context;
import android.widget.Toast;

public class 自定义类
{

    /**
     * 显示短时间的 Toast 提示
     *
     * @param context 上下文对象
     * @param message 要显示的消息
     */
    public static void 弹出提示(String message) {
        if (message != null) {
            Toast.makeText(MainActivity.getContext(), message, Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 显示长时间的 Toast 提示
     *
     * @param context 上下文对象
     * @param message 要显示的消息
     */
    public static void 弹出长提示( String message) {
        if ( message != null) {
            Toast.makeText(MainActivity.getContext(), message, Toast.LENGTH_LONG).show();
        }
    }

    // 对象方法、需创建对象后方可使用
    public int[] 冒泡排序(int[] val)
    {
        return 冒泡排序By静态(val);
    }

    // 静态方法、通过类名调用方法名称即可使用
    public static int[] 冒泡排序By静态(int[] arr) {
        int n = arr.length;
        // 外层循环控制排序轮数
        for (int i = 0; i < n - 1; i++) {
            // 内层循环控制每轮比较次数
            for (int j = 0; j < n - i - 1; j++) {
                // 前一个比后一个大时,交换它们的位置
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        return arr;
    }
}

使用:

' 引用源包中“我的包”下面的所有类
引用 我的包.*

' 窗口成员变量、可以在整个窗口中使用
变量 数组1 = { 10,2,33,100,34,23 }

事件 窗口创建完毕()
    标签1.标题 = "APP启动完毕;窗口创建完毕!"
结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    ' 原包中的类名叫:自定义类
    标签1.标题 = "调用静态方法排序后的数组:\n" + 到文本(自定义类.冒泡排序By静态(数组1))
结束 事件

事件 按钮2.被单击(来源对象 为 视图)
    变量 源包类1 = 创建 自定义类()
    标签1.标题 = "调用对象方法排序后的数组:\n" + 到文本(源包类1.冒泡排序(数组1))
结束 事件

注:源包内只能创建标准的 *.java 文件,代码格式也只能使用 Java 语法,不能在源包中使用轻语言的语法,源包内可以使用任意第三方安卓开源库。

使用 Jar 包及原生代码

在安卓开发中,JAR 文件 是一种常用的依赖管理方式。它本质上是一个 Java 归档文件(Java Archive),用于打包多个类文件、资源文件和其他元数据到一个单独的文件中,也就是我们常说的组件类库。

视频教程:在项目中使用Java原生代码及Jar包

使用 JAR 文件意义

  1. Java 兼容性:

    • 安卓应用基于 Java 语言开发,而 JAR 文件是 Java 平台的标准格式,因此可以直接在安卓项目中使用。
  2. 模块化开发:

    • JAR 文件将代码和资源打包成一个独立的模块,便于在不同项目中复用。
  3. 简化依赖管理:

    • JAR 文件可以将复杂的库或工具封装起来,开发者只需将其添加到项目中即可使用,无需手动复制粘贴代码。

使用方式

1.手动添加 Jar 文件

打开项目根目录文件夹,将 JAR 文件放入项目的 libs 文件夹中。

2.添加引用

在需要使用 Jar 包的窗口或模块,引用 Jar 包内的指定数据类型。

' 要使用 Jar 中的功能、首先我们需要先对其所在的包及类添加引用;经过查阅本库的文档可
' 知、本库的包名为:com.github.promeg.pinyinhelper 因此我们直接添加其引用即可
引用 dynamic.test.Math
引用 com.github.promeg.pinyinhelper.*

事件 窗口创建完毕()

结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    ' 调用库中的“Pinyin”类中的函数、获取中文汉字的拼音
    ' 函数参数一为中文、参数二为拼音的链接符合、这里为空格
    如果(编辑框1.内容等于(""))
        弹出提示("请输入待转换的中文")
        返回
    结束 如果
    标签1.标题 = Pinyin.toPinyin(编辑框1.内容," ")
结束 事件

事件 按钮2.被单击(来源对象 为 视图)
    ' 除了对静态类直接使用外、对象类在使用时、我们必须先创建对象
    ' 然后才能使用、例如这里使用一个数学计算的 Jar 包
    变量 m = 创建 Math()
    标签1.标题 = "执行结果:" + m.add(100,20)
结束 事件

' 引用安卓原生 Toast 类
引用 android.widget.Toast

事件 按钮4.被单击(来源对象 为 视图)
    ' 调用安卓原生类显示 Toast 提示
    ' 由于不涉及原生代码特定语法格式、 Toast 支持静态调用,因此无需使用 @{ } 包裹
    Toast.makeText(取应用上下文(), "按钮被点击了!", Toast.LENGTH_SHORT).show()
结束 事件

使用原生代码

轻语言支持在程序代码中直接使用目标平台的原生代码;安卓采用 Java 语言作为目标开发语言,在轻语言中可以通过内置的编译嵌入符号 @{ } 包裹 Java 代码。

事件 按钮3.被单击(来源对象 为 视图)
    ' 直接在项目中使用 Java 代码只需要通过 @{ } 包裹即可
    ' 例如;下方我们使用原生代码 Java 对一个整数数组排序
    ' 但需注意:源JAVA代码中不能包含任何注释内容
    变量 数组1 = { 10,30,52,23,60 }
    @{
        int len = 数组1.length;
        for (int i = 0; i < len - 1; i++)
        {
            for (int j = 0; j < len - i - 1; j++) 
            {
                if (数组1[j] > 数组1[j + 1]) 
                {
                    int temp = 数组1[j];
                    数组1[j] = 数组1[j + 1];
                    数组1[j + 1] = temp;
                }
            }
        }
    }    
    标签1.标题 = "排序后的数组为:" + 到文本(数组1)
结束 事件

更多信息请参考:原生支持

在项目中设计组件

轻语言安卓开发插件支持直接在项目中通过可视化的方式设计并自定义创建、封装组件,并将其设计的组件一键导出为单个类库组件。

视频教程:可视化设计封装自定义组件

自定义设计组件的意义

1. 满足特定需求

  • 默认控件功能不足:当系统提供的标准控件无法满足特定需求时,自定义组件可以扩展或修改现有控件的行为。

  • 复杂UI设计:需要实现复杂或独特的UI效果时,自定义组件是必要的。

2. 提升性能

  • 优化绘制和布局:通过自定义组件可以优化绘制和布局过程,减少不必要的计算和绘制,提升性能。

  • 减少层级:减少视图层级,避免过度绘制,提升渲染效率。

3. 代码复用

  • 封装通用功能:将常用功能封装到自定义组件中,便于在不同项目中复用,减少重复代码。

  • 组件化开发:自定义组件可以作为独立组件,便于团队协作和维护。

自定义设计组件步骤

1.创建组件文件

在项目的工程窗口中,选中程序集新建文件,文件类型选择 自定义组件 ;然后输入组件名称,名称可以自定义;然后点击确定。

这里我们创建一个 计时器 组件。

默认组件的设计界面:

默认创建后的代码:

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 组件描述:
' 修改日志:
' ****************************************************************************

' 定义加减计次变量
变量 计次 = 0

' 组件创建完毕时触发该事件
事件 组件创建完毕()

结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    计次 = 计次 - 1
    如果(计次 <= 0)
        返回
    结束 如果
    编辑框1.内容 = 到文本(计次)
结束 事件

事件 按钮2.被单击(来源对象 为 视图)
    计次 = 计次 + 1
    编辑框1.内容 = 到文本(计次)
结束 事件

2.设计组件

计时器的作用是用于计时,这里的界面我们通过两个按钮和一个标签来实现,两个按钮作用分别为:开始、停止。标签的作用用于显示时间。

设计方式与设计窗口界面完全一样,点击组件后拖拽到面板中即可,设计后的界面为:

3.修改代码

点击开始按钮,清空标签内容、并复位开始计时,点击停止按钮停止计时,代码中我们需要使用一个时钟组件来完成计时核心功能。

最终代码为:

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 组件描述:
' 修改日志:
' ****************************************************************************

' 定义类成员变量时钟1
变量 时钟1 为 时钟

' 定义计时的计次变量
变量 计次 = 0

' 组件创建完毕时触发该事件
事件 组件创建完毕()
    时钟1 = 创建 时钟()
    时钟1.时钟周期 = 1000
    标签1.文本尺寸 = 20
结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    计次 = 0
    标签1.标题 = "0S"
    时钟1.可用 = 真
结束 事件

事件 按钮2.被单击(来源对象 为 视图)
    时钟1.可用 = 假
结束 事件

事件 时钟1.周期事件(源对象 为 时钟)
    计次 = 计次 + 1
    标签1.标题 = 计次 + "S"
结束 事件

4.使用组件

在IDE右侧组件箱中,选中 项目自定义组件 然后右键单击鼠标,单击:刷新自定义组件 菜单项。

刷新自定义组件后、在项目自定义组件节点中会出现当前我们项目中自定义的组件:计时器

鼠标左键选中并单击计时器,将其添加到窗口中。

此时的 计时器 像按钮、标签、编辑框一样,已经是一个独立的组件;可以向窗口中添加多个计时器组件,也可以在多个窗口中使用。

编译并运行程序,效果:

至此我们已经通过可视化、中文代码的方式轻松的完成,并封装了一个计时器组件。

5.导出组件为单个类库组件文件

在工程列表中,选中组件 计时器.sc 然后单击鼠标右键:导出组件为类库 将弹出一个组件配置窗口,在该窗口中可以输入类库相关信息,及添加导出时类库需要的资源文件,以及当组件添加到窗口中时显示的预览图片。

预览图片一般可以截图组件运行时的图片。

使用导出的组件

导出的组件将默认被保存到 安装目录/sdk/android/components/extends/我的自定义组件 文件夹中,关闭 IDE 并重新启动,即可在组件箱中看到刚刚被导出的组件。

新建一个项目,将计时器添加到窗口中即可正常使用。

注意事项

项目中如果存在相同的组件、即自定义组件和导出的类库组件时,在编译时会优先使用项目中自定义的组件。

例如:

项目中含有自定义组件:计时器 ,但同时类库目录中已经存在了导出的 计时器 组件,那么在编译时会优先使用项目中的自定义组件。

事件的声明

关于自定义组件事件的声明,将在后期更新文档,敬请关注。

编译、运行APP

当编写完APP代码后、需要执行编译操作,才能将写好的代码编译成一个可以安装到手机中运行的APP安装包。

编译

在 VcnStudio 安卓开发插件中,当打开一个安卓项目后,有三种方式可以执行编译操作。

  1. 点击IDE顶部工具栏 图标

  2. 点击IDE顶部菜单栏中的项目 编译项目 菜单项

  3. 使用快捷键 F6

编译输出的APK文件在什么地方

默认情况下,APK 文件会生成在项目的根目录 _build 文件夹中。

具体路径通常是:

项目根目录/_build/bin/目标APP.apk

运行

VcnStudio 安卓插件支持一键运行项目,一键运行有 3 种方式:

  1. 点击IDE顶部工具栏 图标

  2. 点击IDE顶部菜单栏中的项目 运行 菜单项

  3. 使用快捷键 F5

运行编译后的 APK 文件需要运行环境,一般有两种方式可以运行编译输出的 APK 文件。

  • 安卓手机真机

  • 模拟器

模拟器是什么?

模拟器可以在电脑中模拟一个手机,模拟器提供了一个虚拟的 Android 运行环境,开发者可以在不依赖真实设备的情况下测试编译输出的APP的功能。

在哪里下载模拟器?

下方列出了国内常用模拟器,可以根据自身电脑选择最佳模拟器下载并安装:

运行APP到模拟器

当安装并启动模拟器后,再启动 VcnStudio IDE 并打开一个安卓项目,在 IDE 底部将会显示一个 调试输出 窗口。

在该窗口中,如果下拉列表中存在设备名称则说明 IDE 已经检测到电脑中的模拟器,点击 IDE 工具栏中的 图标,程序将开始编译项目并自动将编译输出的 APP 安装到模拟器中。

上方图片中的 emulator-5554 为电脑中打开的模拟器。

运行到真机

将APK文件安装到手机真机有多种方式;常见方法有:

  • 通过聊天软件将APK文件发送给手机安装

  • 使用USB连接手机到电脑,手机需先开启开发者模式,然后点击调试输出面板中的刷新图标 ,如果连接成功将会在左侧列表中显示连接的手机设备,选择手机真机设备,此时运行项目将自动编译并安装到真机中。

  • 使用 VcnStudio IDE 安卓插件中提供的 临时云 功能,当编译项目后、点击顶部菜单栏 项目/上传临时云 菜单项,系统会将编译输出的APK文件上传到 VcnStudio 官方提供的一个临时云盘中,上传成功后会返回一个二维码及下载地址,使用真机扫描二维码即可下载安装,该方法适用于需要在多台真机设备中测试时使用。每个上传的APK文件有效时间为5分钟。

APP调试与闪退、异常捕获

当成功编译项目并输出一个APK文件时、要想查看其效果或运行功能是否达到我们的要求、则必须先将其APK文件安装到手机或模拟器中、为了方便调试 VcnStdio IDE 为开发者提供了一个简单的调试插件、当新建一个安卓项目工程、或在 IDE 中打开安卓工程时,在 VcnStudio IDE 底部会出现一个 调试输出 的小窗口、点击小窗口标题、则可以切换到该调试窗口界面、本文将为大家介绍该调试窗口的具体用法和功能。

相关视频教程:调试并捕获APP崩溃异常信息

调试输出窗口

设备列表

如果电脑打开有模拟器,或者电脑使用USB连接了手机(手机已经开启开发者模式)、打开IDE后或者点击右侧刷新列表图标、如果设备连接成功、将会在日志输出区面板打印出设备名称信息、并同时会将设备添加到设备下拉框中。

安装卸载APK

当设备连接成功、且成功添加到设备列表中时、点击右侧 (+) 号图标按钮、系统将自动安装当前项目工程编译输出的APK文件到选择的设备中、如果要在设备中卸载当前APP、点击右侧 (-) 号图标按钮即可。

捕获输出日志

在开发时需要对代码或者函数返回值、变量值进行打印输出查看调试信息时、或者当APP发生异常崩溃的时候、可以点击工具栏中的 ▶ (开启捕获日志)的图标按钮、如果开启捕获成功、该图标按钮将会变成灰色禁止状态;且下方日志输出区将会立即输出设备的运行信息、如果想结束或停止捕获日志、点击最右侧 ⏹(停止捕获日志)按钮即可关闭。

输出自定义调试信息

要在面板区输出自定义调试信息、只需要在代码中使用调试输出函数即可、代码示例:

事件 按钮1.被单击(来源对象 为 视图)
    调试输出("我是自定义输出的信息")
    变量 a 为 文本型
    a = "欢迎使用VcnStudio"
    调试输出("我是自定义输出的变量值:" + a)
结束 事件

在模拟器中运行APP,点击窗口中的按钮1,在面板日志输出区将输出:

捕获APP运行错误崩溃闪退信息

当 APP 运行发生闪退、崩溃错误时,在轻语言安卓中总共有3种方式,这里介绍一种最常见的捕获方式;其它方法请参考文章开头引用的视频教程。

事件 按钮1.被单击(来源对象 为 视图)
    ' 异常捕获语句可用于针对性的捕获引起 APP 崩溃异常的代码
    ' 例如针对某部分代码、运行APP时报错、闪退、崩溃;则可以
    ' 通过 异常捕获语句 捕获其引起错误的原因
    ' 提示:
    ' 输入 异常捕获首 按下键盘上的 TAB 键、会自动完成代码块
    异常捕获首
        ' 这里我们模拟一个数组索引越界的异常
        变量 ints = { 1,2,3 }
        ' 数组总长度为3、但获取下标为10的元素、则会引发异常
        调试输出("" + ints[10])
    异常被捕获(异常信息 为 对象)
        ' 这里返回的异常信息变量就是具体导致程序崩溃的代码、可以
        ' 将错误输出到标签或调试输出具体错误信息
        ' 注意:这里的变量名“异常信息”不可修改
        标签1.标题 = "异常信息:" + 异常信息
        调试输出("异常信息:" + 异常信息)
    异常捕获尾
结束 事件

其它问题

如果在调试面板中输出的错误信息;尤其是崩溃信息的具体行数显示“Unknown Source”;这种情况一般是在编译类库时、采用了发布版编译;发布版类库的 Jar 包文件中不包含调试信息;因此如果遇到这种未知资源时、只需要在编译类库时;标志为“debug”模式即可。标记方式:

在类库的“libtree.xml”文件中的 package 节点;添加 debug 属性即可;例如:

<package debug="ture">

添加后、再编译类库;则为调试版类库;

注:编译发布版类库时建议删除该 debug 标记。

安卓类库封装(向导)

本章将为大家讲解如何封装轻语言安卓程序中的组件类库,轻语言安卓程序底层开发语言为 Java ,因此学习本章内容前,读者需掌握一些基本的 Java 编程知识和原生安卓开发知识。

轻语言安卓类库一般分为两种格式:

  • 可视组件

  • 不可视组件

两种组件的工程结构基本一样,区别在与配置文件和具体代码的实现。

视频教程:安卓支持库类库组件封装教程

类库工程结构

  • static (存放静态资源文件夹)

    • assets 存放不进行编译但会被打包到最终类库压缩包的文件
    • libs 存放第三方 jar 包
    • aar 存放第三方 aar 包
    • res 存放drawable、layout、values自定义资源值
  • src 存放类库的源代码、允许多个包名

  • libtree.xml

    • 该文件为类库的核心配置描述文件、在开发时非常重要;整个类库的函数声明、类库信息、包名等都需要在该文件中配置
  • *.vsln 类库项目索引文件

libtree.xml

该文件为类库核心配置描述文件,使用XML编写,在IDE中打开一个类库项目时,双击该文件将在 IDE 编辑器中被打开,默认内容如下图所示:

<?xml version="1.0" encoding="utf-8"?>
<package>
    <library
        name = "蓝色按钮" 
        author = "" 
        package = "myapp.component" 
        description = "类库功能描述;蓝色按钮组件" 
        type = "control">

        <control name="蓝色按钮" comment="背景为蓝色、字体为白色的按钮组件">
            <property name="标题" type="文本型" comment="设置或获取当前蓝色按钮的标题。" />
            <method name="标题等于" return="逻辑型" args="(内容 为 文本型)" comment="标题等于。" />
            <method name="置被拖拽回调" return="" args="(回调对象 为 被拖拽回调)" comment="设置被拖拽回调。" />
            <interface name="被拖拽回调" comment="蓝色按钮的被拖拽回调接口。">
                <event name="被拖拽" return="" args="(源对象 为 视图)" comment="当被拖拽时触发并回调该事件。" />
            </interface>
        </control>

    </library>

    <permission xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-permission android:name="android.permission.INTERNET" />
    </permission>

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
    </manifest>
</package>
  • package :配置文件根节点,不可修改

    • library :具体描述当前类库的节点、所有组件或类的声明都必须作为子节点添加到该节点中;同时该节点中也用于配置整个类库的具体信息、该节点包含以下属性:

      • name :描述指定类库的名称

      • author :描述类库作者或联系方式

      • package :设置类库当前的包名

      • description :类库的功能描述

      • version :版本(可省略)

      • type :指定类库的类型值;必须;(用于指定类库为可视类库还是不可视类)

        • control 可视组件

        • component 不可视控件

    • library :节点中支持添加的子节点标签类型

      • control 表示该节点为一个可视组件,支持的子节点类型:

        • property 属性
        • constant 常量
        • method 函数
        • interface 事件接口回调
          • event 具体事件
      • component 表示该节点为一个不可视组件,支持的子节点类型:

        • property 属性
        • constant 常量
        • method 函数
        • interface 事件接口回调
          • event 具体事件
      • class 表示该节点为一个纯数据类型,纯数据类型不能被添添加到窗口中,只能在代码中创建使用,纯数据类型不能含有属性、事件等子节点,只支持一个子节点类型:

        • method 函数
    • permission :表示权限节点;在该节点中可添加用于当前类库可能用到的安卓静态权限。

    • manifest :用于配置当前类库在编译时,需要额外添加到(使用该类库的)App项目中的 AndroidManifest.xml 文件里 application 节点中的内容;该节点中允许添加的子节点标签支持原生安卓清单文件中 application 节点的任意内容;例如常见的:

      • <activity>

        • 定义一个原生的Activity窗口,示例:

        • <activity android:name=".MainActivity" />
          
      • <service>

        • 定义一个 Service(后台服务),示例:

        • <service android:name=".MyService" />
          
      • <receiver>

        • 定义一个 Broadcast Receiver(广播接收器),示例:
        • <receiver android:name=".MyBroadcastReceiver" />
          
      • <provider>

        • 定义一个 Content Provider(内容提供者),用于与其他应用共享数据,示例:
        • <provider
              android:name=".MyContentProvider"
              android:authorities="com.example.provider" />
          
      • <meta-data>

        • 元数据节点,为组件或整个应用提供自定义元数据,示例:

        • <meta-data
              android:name="com.google.android.geo.API_KEY"
              android:value="your_api_key_here" />
          
      • 其它更多...

      • 特殊节点 main-activity 主节点子元素、该节点下的内容会被添加到轻语言安卓框架中的主 Activity 中、例如:intent-filter、meta-data、activity-alias 等等;注意:该节点默认配置文档中并未添加、如有需要、需自行添加。

        <main-activity>
            <intent-filter>
            ...
            </<intent-filter>
        </main-activity>
        

    注意:一个类库中可以添加无限个组件或数据类型、例如:当你要封装一个阅读APP的类库时、你可以将相关的组件或数据类型都封装到一个类库中;从而方便使用、分享。

可视组件

可视组件、顾名思义表示是可视的、可以看得见的组件;例如在APP中的按钮、标签、文本内容列表框等等;这些组件都属于可视组件;在 IDE 安装包中、位于 “sdk/android/components/primary” 该目录中都是官方已经封装好的组件、大家在封装时可以参考。

所有可视组件必须继承自视图

封装组件时首先需要先下载 VcnStudio 开发工具、并解压至非C盘目录;该步骤本教程跳过;打开IDE程序后、点击新建项目、在弹出的窗口中依次选择:移动应用->安卓支持库->可视组件 然后输入项目名称、点击确定;等待数秒、系统将会创建默认的类库项目。

点击确定后、如果无错误、将会打开创建成功的项目;如下图:

默认创建的项目包名为 myapp.component 、位于工程窗口中的 src 节点下面;在我们自定义创建类库时、可以自定义创建自己的包名;删除掉默认包名即可。然后将自己的组件源文件放到你自定义创建的包下面;例如:下方我们创建了一个自己的包名(选中src节点后右键菜单新建背包)、并在这个包中创建一个蓝色背景的标签组件:

默认创建打开后如上图所示为默认代码;此时我们需要修改为可视组件的模板(与默认蓝色按钮一致即可)、然后添加我们自己的代码;完成之后;代码为:

package exp.mytest;

/* 引入安卓开发框架的核心类 */
import com.simple.android.*;
/* 由于项目中没有用到这两个包的内容;需要屏蔽掉、否则编译器会报错 */
//import com.simple.components.*;
//import com.simple.control.*;
/* 引入安卓原生组件相关包 */
import android.view.View;
import android.widget.TextView;
import android.graphics.Color;

public class 蓝色标签 extends 视图
{
    private TextView mTextView;

    @Override
    public View createView()
    {
        mTextView = new TextView(MainActivity.getContext());
        mTextView.setBackgroundColor(Color.BLUE);
        mTextView.setTextColor(Color.WHITE);
        return mTextView;
    }

    public void 标题(String text)
    {
        this.mTextView.setText(text);
    }

    public String 标题()
    {
        return this.mTextView.getText().toString();
    }
}

然后点击编译;如果代码编写无误、将会在IDE底部编译输出窗口输出编译信息;如果编译出现错误;将会输出错误信息、并同时结束编译;如果编译成功;将会提示包含“类库编译成功”的提示内容;并且在项目根目录文件夹中会新增一个“_build”文件夹;在该文件夹中会输出一个未压缩状态的类库目录、和一个后缀为“.scm”的单文件库(方便分享);复制该文件到 “IDE安装目录\sdk\android\components\extends”中的分类文件夹、

注意:类库文件必须放在分类文件夹中,任意分类文件夹中即可。

至此、一个简单的可视类库就封装完毕了。

不可视组件

不可视组件、顾名思义在APP中是不可视的;例如时钟、网络操作库等等。不可视组件相对于可视组件、在封装时较简单;首先还是一样、新建项目时选择安卓不可视组件、创建项目后;会默认加载一个空的项目;该项目的默认工程模板与可视组件不完全一样;默认的类为一个普通的数据运算类;因为不可视组件不需要继承任何轻舟框架中规定的父类;其封装方式与原生 Java 编写 Jar 文件一模一样;因此相较可视组件而言、封装不可视组件更为简单、本文以自带的默认工程做示例讲解。

首先当我们打开项目并加载成功后的默认不可视组件代码为:

由于代码相对较简单、这里不做过多解释;但在实际封装时;应该将待封装的类放在自己创建的包中。

配置文档编写

在代码编辑窗口中;当代码编写完毕时、单击右键菜单;选择“生成类文档”菜单项、即可快速生成编辑窗口类的函数、方法文档;这里需要注意自动生成功能只会提取源码中声明为 public 公开的方法、及接口;非公共修饰符的类成员、包含方法接口都不会处理;除此之外只读与只写属性需要自行处理。

如果方法名称相同;且只有一个参数、参数类型和返回值都一样时、会自动识别为可读可写属性;例如:标题;如果方法为只读或只写属性、在方法前输入 /** 属性 */ 标记注释;生成时将会自动处理为属性。

代码示例:

/** 属性;只读属性 */
public String 只读方法名()
{
    return "";
}

/** 属性;只写属性 */
public void 只写方法名(String value)
{

}

MainActivity 回调接口

当组件需要监听APP启动、窗口加载完毕、窗口被关闭事件时、可以通过在类库中实现轻舟安卓框架中预先定义的相关回调接口:

  • IOnRequestPermissions :OnRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)

  • IOnActivityResult :OnActivityResult(int requestCode, int resultCode, Intent data)

  • IOnConfigurationChanged :OnConfigurationChanged(Configuration newConfig)

  • IOnNewIntent :OnNewIntent(Intent intent)

  • IOnCreate :OnCreate(Bundle savedInstanceState)

  • IOnDestroy :OnDestroy()

  • IOnKeyDown :OnKeyDown(int keyValue)

  • IOnStart :OnStart()

  • IOnResume :OnResume()

  • IOnPause :OnPause()

  • IOnStop :OnStop()

使用示例:

package mylc.ext;
import com.simple.android.*;
public class 我的组件 extends 视图 implements 
IActivity.IOnCreate,
IActivity.IOnDestroy
{
    Button mButton;
    @Override
    public View createView(){
        this.mButton = new Button(MainActivity.getContext());
        // 注册接口
        IActivity.IOnCreates.add(this);
        IActivity.IOnDestroys.add(this);
        return mButton;
    }
}

事件锚点,快速生成回调事件

在类库中如果含有回调事件、也就是给组件添加事件;可以在需要添加事件分发的代码处添加下方代码:

//dispatch:回调事件名称(String arg,int arg1)

例如:

@Override
public void onMarkerDrag(Marker arg0)
{
    高德地图标记 flag = new 高德地图标记(arg0);
    //dispatch:标记被拖动(高德地图标记 flag)
}

然后在代码编辑框中右键单击“插入锚点事件”即可自动生成相关联的回调接口代码和事件;需注意:如果存在多个相同名称的事件回调、只能保留一个回调事件。

其它问题

R资源处理

所有复制到 res 文件夹中的资源文件,默认引用时的包名为配置文档中 package 属性设置的包名,如果类库源代码中使用了第三方开源 Java 代码、第三方代码中用到了R 资源的引用,需修改成配置文档中设置的包名,修改后在编译时系统会自动处理,无需额外操作。

代码示例:

// 源代码中引用R资源时必须为配置文件中的包名
import myapp.component.R;

Jar包的使用

将待封装的 Jar 包文件放到类库项目文件夹中的 static/libs 文件夹内,在代码中即可像正常使用 Java 代码一样使用。

AAR包的使用

将待封装的 aar 包文件放到项目文件夹中的 static/aars 文件夹中即可;无需解压;封装时按照使用 jar 包一样、import 引用待封装的类正常使用即可;aar 包中的 R 资源文件会在编译时自动处理。

需特别注意:aar 包中如果引用了其它的 jar 或 aar 文件、也需要一并添加到相应文件夹中,但通常情况下;不建议一个类库中含有多个 aar 文件,因为在合并 AndroidManifest.xml 文件内容时可能会发生冲突或错误,当一个类库项目中含有多个 aar 包时,建议将其拆分。

AndroidX 的使用

将待封装的 androidx-*.jarandroidx-*.aar 包放到 static 文件夹下面对于文件夹中,在代码中正常引用指定类使用即可,但需特别注意:

  1. AndroidX 会出现兼容问题,需自行处理。

  2. AndroidX 包含很多小包、各个小包之间存在互相依赖,封装时需要找到所有用到的包。

  3. 非必要情况下不建议使用 AndroidX 包

可视组件的默认属性及事件

所有的可视组件都必须继承自视图类、而默认的视图类,是所有可视组件的抽象类,视图类中包含了所有可视组件都有的属性、函数、事件,例如每个可视组件都有相同的:

  • 属性

    • 可视

    • 宽度

    • 高度

    • ...

  • 函数

    • 移动

    • 到顶层

    • 取原生对象

    • ...

  • 事件

    • 被单击

    • 被长按

    • 焦点被改变

    • ...

等等。

视图类是所有可视组件的抽象类,每个组件默认都有视图类中的属性、函数、事件,因此在封装组件时、您封装的组件里面不能包含已经存在的属性、函数或事件。

视图类中具体包含了哪些属性、函数、事件,可以在 IDE 中打开一个安卓项目,然后在支持库窗口中按下列路径查看:

核心支持库/基础类/视图

类库线上发布

封装好的类库可以发布到类库市场,销售;类库市场地址:VcnStudio - 类库市场

安卓类库封装(语法)

本章将讲解封装及编写轻语言安卓类库组件的详细实现细节,轻语言安卓程序的类库组件采用 Java 语言编写,正式编写之前您需要掌握基础的 Java 编程知识。

基础

类型映射

使用 Java 编写安卓组件时,需要将 Java 的数据类型映射到轻语言的数据类型,反之亦然。下表列出了轻语言对应的 Java 同等数据类型:

轻语言Java
逻辑型boolean
字节型byte
短整数short
整数型int
长整数long
单精度小数float
双精度小数double
文本型java.lang.String
对象java.lang.Object

原生类型包装

轻语言每个组件默认都由一个 Java 类组成,其中表示可视组件的类必须继承自轻语言安卓框架中的 视图 类型,视图 是每个可视组件的基础数据类型,视图 拥有所有可视组件公有的属性,函数和事件,表示不可视组件的类与 Java 标准类的封装完全一致,无需继承额外的基类。

表示可视组件的类必须实现基类视图的抽象函数 createView() ,该函数需返回一个安卓标准 View 对象,一般该对象会被定义为一个私有的类成员变量,该成员变量表示需要被封装的安卓原生组件,代码示例:

// 自定义封装一个默认背景为蓝色、文本为白色的按钮
public class 蓝色按钮 extends 视图
{
    // 定义类成员变量安卓原生按钮对象
    private Button mButton;

    // 重写并实现抽象函数,该函数返回安卓原生 View 对象
    @Override
    public View createView()
    {
        // 轻语言安卓框架的默认上下文,创建原生对象时必须使用:MainActivity.getContext()
        mButton = new TextView(MainActivity.getContext());
        mButton.setBackgroundColor(Color.BLUE);
        mButton.setTextColor(Color.WHITE);
        return mButton;
    }
}

当上方的 蓝色按钮 在轻语言安卓程序中被创建时,系统首先将执行 createView 函数获取封装返回的原生安卓 Button 对象,并将其添加到窗口中。

属性

属性是一种类似字段的成员变量,通常使用 = 符号取值、赋值,但由于 Java 语言本身不支持属性功能,因此在编写轻语言安卓组件时,在 Java 代码中我们使用 伪属性 来定义属性,具体实现方式是:

当代码中含有两个相同名称的方法时,且这两个方法满足一个赋值,一个取值,且值的数据类型完全一样时,我们则规定在轻语言中,这两个方法表示一个属性。

代码示例:

// 自定义封装一个默认背景为蓝色、文本为白色的按钮
public class 蓝色按钮 extends 视图
{
    // 定义类成员变量安卓原生按钮对象
    private Button mButton;

    // 重写并实现抽象函数,该函数返回安卓原生 View 对象
    @Override
    public View createView()
    {
        // 轻语言安卓框架的默认上下文,创建原生对象时必须使用:MainActivity.getContext()
        mButton = new TextView(MainActivity.getContext());
        mButton.setBackgroundColor(Color.BLUE);
        mButton.setTextColor(Color.WHITE);
        return mButton;
    }

    /** 设置按钮的标题文本内容。 */
    public void 标题(String text)
    {
        this.mButton.setText(text);
    }

    /** 获取按钮的标题文本内容。 */
    public String 标题()
    {
        return this.mButton.getText().toString();
    }
}

上方代码中名为 标题 的方法,一共有 2 个,并且满足一个方法取值,一个方法赋值,且目标操作值的数据类型都为 String(文本型) ,那么我们规定在轻语言中,这两个方法为一个 属性。在编写组件配置文档时,应该以属性方式添加。

例如在配置XML文档时:

<control name="蓝色按钮" comment="蓝色按钮组件;默认背景蓝色,字体白色。">
    <property name="标题" type="文本型" comment="设置或获取当前按钮的标题内容。" />
</control>

在轻语言中使用时:

变量 蓝色按钮1 = 创建 蓝色按钮()
蓝色按钮1.标题 = "自定义按钮1"
调试输出(蓝色按钮1.标题)

函数

Java 代码中的方法即为轻语言中的函数。例如:

// 自定义封装一个默认背景为蓝色、文本为白色的按钮
public class 蓝色按钮 extends 视图
{
    // 定义类成员变量安卓原生按钮对象
    private Button mButton;

    // 重写并实现抽象函数,该函数返回安卓原生 View 对象
    @Override
    public View createView()
    {
        // 轻语言安卓框架的默认上下文,创建原生对象时必须使用:MainActivity.getContext()
        mButton = new TextView(MainActivity.getContext());
        mButton.setBackgroundColor(Color.BLUE);
        mButton.setTextColor(Color.WHITE);
        return mButton;
    }

    /** 设置按钮的标题文本内容。 */
    public void 标题(String text)
    {
        this.mButton.setText(text);
    }

    /** 获取按钮的标题文本内容。 */
    public String 标题()
    {
        return this.mButton.getText().toString();
    }

    /** 判断当前按钮的标题是否等于指定字符串内容。 */
    public boolean 标题等于(String value)
    {
        return this.mButton.getText().equals(value);
    }

}

配置XML文档:

<control name="蓝色按钮" comment="背景为蓝色、字体为白色的按钮组件">
    <property name="标题" type="文本型" comment="设置或获取当前蓝色按钮的标题。" />
    <method name="标题等于" return="逻辑型" args="(内容 为 文本型)" comment="判断当前按钮的标题是否等于指定字符串内容。" />
</control>

事件

轻语言中事件的定义与 Java 的回调接口一致;由于 Java 本身不支持使用事件驱动方式进行回调,因此在轻语言中表示事件时、需要对其声明的回调接口做格式化处理,类似在 Java 中约定俗成的使用 “On”或“on”开头来表示回调一样,轻语言规定:

字开始设置回调接口的方法。

回调 结尾作为回调接口的名称。

事件名称 作为回调接口名称。

例如现在我们要监听组件被拖拽,示例代码:

// 自定义封装一个默认背景为蓝色、文本为白色的按钮
public class 蓝色按钮 extends 视图
{
    // 定义类成员变量安卓原生按钮对象
    private Button mButton;

    // 重写并实现抽象函数,该函数返回安卓原生 View 对象
    @Override
    public View createView()
    {
        // 轻语言安卓框架的默认上下文,创建原生对象时必须使用:MainActivity.getContext()
        mButton = new TextView(MainActivity.getContext());
        mButton.setBackgroundColor(Color.BLUE);
        mButton.setTextColor(Color.WHITE);
        return mButton;
    }

    /** 设置按钮的标题文本内容。 */
    public void 标题(String text)
    {
        this.mButton.setText(text);
    }

    /** 获取按钮的标题文本内容。 */
    public String 标题()
    {
        return this.mButton.getText().toString();
    }

    /** 判断当前按钮的标题是否等于指定字符串内容。 */
    public boolean 标题等于(String value)
    {
        return this.mButton.getText().equals(value);
    }

    /** 定义组件被拖拽时接收回调事件的方法。 */
    public void 置被拖拽回调(final 被拖拽回调 iOnDrag)
    {
        mButton.setOnDragListener(new OnDragListener()
        {
            @Override
            public boolean onDrag(View v, DragEvent event)
            {
                if(iOnDrag != null)
                    iOnDrag.被拖拽(蓝色按钮.this);
                return true;
            }
        });
    }

    /** 表示处理被拖拽的回调,对“被拖拽”这个事件做一个封装。 */
    public interface 被拖拽回调
    {
        void 被拖拽(视图 view);
    }

}

上方在轻语言中对应的事件为:被拖拽

配置文档XML编写格式为:

<control name="蓝色按钮" comment="背景为蓝色、字体为白色的按钮组件">
    <method name="置被拖拽回调" return="" args="(回调对象 为 被拖拽回调)" comment="设置被拖拽回调。" />
    <interface name="被拖拽回调" comment="蓝色按钮的被拖拽回调接口。">
        <event name="被拖拽" return="" args="(源对象 为 视图)" comment="当被拖拽时触发并回调该事件。" />
    </interface>
</control>

在轻语言中使用,假设已编译为类库文件并且已安装到VcnStudio指定目录,在工具箱中选中 蓝色按钮 组件,并将其添加到APP窗口中,在属性框事件下拉列表中选择事件:被拖拽 IDE 将自动在代码编辑器中生成对应的事件代码块,示例:

事件 蓝色按钮1.被拖拽(来源对象 为 视图)
    调试输出("蓝色按钮1被拖拽")
结束 事件

注意:这里的被拖拽事件只是一个简单的演示,具体封装时,可能会返回事件参数。

在项目中设计组件

轻语言安卓开发插件支持直接在项目中通过可视化的方式设计并自定义创建、封装组件,并将其设计的组件一键导出为单个类库组件。

视频教程:可视化设计封装自定义组件

自定义设计组件的意义

1. 满足特定需求

  • 默认控件功能不足:当系统提供的标准控件无法满足特定需求时,自定义组件可以扩展或修改现有控件的行为。

  • 复杂UI设计:需要实现复杂或独特的UI效果时,自定义组件是必要的。

2. 提升性能

  • 优化绘制和布局:通过自定义组件可以优化绘制和布局过程,减少不必要的计算和绘制,提升性能。

  • 减少层级:减少视图层级,避免过度绘制,提升渲染效率。

3. 代码复用

  • 封装通用功能:将常用功能封装到自定义组件中,便于在不同项目中复用,减少重复代码。

  • 组件化开发:自定义组件可以作为独立组件,便于团队协作和维护。

自定义设计组件步骤

1.创建组件文件

在项目的工程窗口中,选中程序集新建文件,文件类型选择 自定义组件 ;然后输入组件名称,名称可以自定义;然后点击确定。

这里我们创建一个 计时器 组件。

默认组件的设计界面:

默认创建后的代码:

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 组件描述:
' 修改日志:
' ****************************************************************************

' 定义加减计次变量
变量 计次 = 0

' 组件创建完毕时触发该事件
事件 组件创建完毕()

结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    计次 = 计次 - 1
    如果(计次 <= 0)
        返回
    结束 如果
    编辑框1.内容 = 到文本(计次)
结束 事件

事件 按钮2.被单击(来源对象 为 视图)
    计次 = 计次 + 1
    编辑框1.内容 = 到文本(计次)
结束 事件

2.设计组件

计时器的作用是用于计时,这里的界面我们通过两个按钮和一个标签来实现,两个按钮作用分别为:开始、停止。标签的作用用于显示时间。

设计方式与设计窗口界面完全一样,点击组件后拖拽到面板中即可,设计后的界面为:

3.修改代码

点击开始按钮,清空标签内容、并复位开始计时,点击停止按钮停止计时,代码中我们需要使用一个时钟组件来完成计时核心功能。

最终代码为:

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 组件描述:
' 修改日志:
' ****************************************************************************

' 定义类成员变量时钟1
变量 时钟1 为 时钟

' 定义计时的计次变量
变量 计次 = 0

' 组件创建完毕时触发该事件
事件 组件创建完毕()
    时钟1 = 创建 时钟()
    时钟1.时钟周期 = 1000
    标签1.文本尺寸 = 20
结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    计次 = 0
    标签1.标题 = "0S"
    时钟1.可用 = 真
结束 事件

事件 按钮2.被单击(来源对象 为 视图)
    时钟1.可用 = 假
结束 事件

事件 时钟1.周期事件(源对象 为 时钟)
    计次 = 计次 + 1
    标签1.标题 = 计次 + "S"
结束 事件

4.使用组件

在IDE右侧组件箱中,选中 项目自定义组件 然后右键单击鼠标,单击:刷新自定义组件 菜单项。

刷新自定义组件后、在项目自定义组件节点中会出现当前我们项目中自定义的组件:计时器

鼠标左键选中并单击计时器,将其添加到窗口中。

此时的 计时器 像按钮、标签、编辑框一样,已经是一个独立的组件;可以向窗口中添加多个计时器组件,也可以在多个窗口中使用。

编译并运行程序,效果:

至此我们已经通过可视化、中文代码的方式轻松的完成,并封装了一个计时器组件。

5.导出组件为单个类库组件文件

在工程列表中,选中组件 计时器.sc 然后单击鼠标右键:导出组件为类库 将弹出一个组件配置窗口,在该窗口中可以输入类库相关信息,及添加导出时类库需要的资源文件,以及当组件添加到窗口中时显示的预览图片。

预览图片一般可以截图组件运行时的图片。

使用导出的组件

导出的组件将默认被保存到 安装目录/sdk/android/components/extends/我的自定义组件 文件夹中,关闭 IDE 并重新启动,即可在组件箱中看到刚刚被导出的组件。

新建一个项目,将计时器添加到窗口中即可正常使用。

注意事项

项目中如果存在相同的组件、即自定义组件和导出的类库组件时,在编译时会优先使用项目中自定义的组件。

例如:

项目中含有自定义组件:计时器 ,但同时类库目录中已经存在了导出的 计时器 组件,那么在编译时会优先使用项目中的自定义组件。

事件的声明

关于自定义组件事件的声明,将在后期更新文档,敬请关注。

安卓开发常见问题

本文整理了安卓程序常见的开发问题:

字符串文本比较

在轻语言安卓中,如果要比较两个字符串文本或文本变量的值是否相等,不能使用 === 符号,建议使用内置函数:取相等

事件 按钮1.被单击(来源对象 为 视图)
    变量 局_文本1 = "VcnStudio"
    变量 局_文本2 = "VcnStudio2"
    如果(取相等(局_文本1,局_文本2))
        弹出提示("两个文本变量的值相等")
    否则
        弹出提示("两个变量值不相等")
    结束 如果
    ' 也可以使用文本变量的原生函数比较
    如果(局_文本1.equals(局_文本2))
        弹出提示("两个变量值相等")
    结束 如果
    ' 也可以通过常量值比较
    如果(局_文本1 == "VcnStudio")
        弹出提示("两个变量值相等")
    结束 如果
结束 事件

比较两个文本变量值是否相等,只能使用 取相等 函数或使用文本变量的原生函数比较。

修改安卓SDK版本

轻语言安卓框架默认使用的安卓SDK版本为安卓8.0;默认支持的安卓系统最小为安卓5.0;轻语言安卓项目编译输出的APK文件,低于5.0的安卓系统默认无法安装;如果需要兼容低版本或高版本的安装系统,请参考该文章:如何修改安卓项目中的SDK目标版本

初始化获取窗口组件宽高位置为0

在窗口创建完毕中无法正确获取到窗口中指定组件的位置、尺寸值,请参考文章:窗口创建完毕里面如何获取组件宽高和位置的值

安装 APK 失败或解析错误

  • 检查手机或模拟器中是否已经安装有相同包名但签名不同的APP

  • 检查SDK兼容版本是否与系统版本兼容

如何在APP中使用全局字体

参考文章:如何在APP中使用全局自定义字体

批量修改参考界面组件属性

参考文章:在安卓中批量取窗口标签按钮批量修改组件属性

权限问题

在安卓6.0系统及以上的系统中,敏感权限需要在 App.spl 动态申请,常用敏感权限:读取通讯录、使用相机、读写储存卡数据、拨打电话等等。

APP卡顿

检查主线程中是否存在耗时操作,如果有耗时操作,将其放在子线程中执行,常见的耗时操作:访问网络请求、发送POST或GET数据、下载文件、读写大数据文件。

框架设计参考

轻语言安卓框架底层采用 Java 语言结合安卓标准SDK设计,由轻语言驱动运行。

框架核心特性

1. 单 Activity 设计理念

该设计理念参考并借鉴了谷歌 2009 年发布的一款实验性 Simple 编程语言及 App Inventor 编程工具,轻语言安卓框架优化了底层设计,旨在简化安卓开发工作。

  • 核心机制 整个应用仅存在一个 MainActivity,所有界面切换通过替换 Activity 的根视图(setContentView)实现,避免传统多 Activity 的启动开销和生命周期复杂性。

  • 视图即窗口 每个独立界面对应一个 窗口(如 登录窗口信息窗口),通过动态加载/卸载视图模拟“窗口切换”。

  • 代码示例

    // MainActivity.java
    public class MainActivity extends Activity {
        public void switchToView(Class<? extends View> viewClass) {
            try {
                View newView = viewClass.newInstance();
                setContentView(newView);
            } catch (Exception e) { /* 异常处理 */ }
        }
    }
    

为什么采用单一Activity而不采用原生式多Activity?

首先轻语言的设计目的是简化开发,节约成本,将编程尽可能变简单,轻语言安卓框架的主要应用场景为:开发轻量级APP应用,如工具类、行业通用类,个人学习,简单实用的中小型APP程序,因此如果使用原生多 Activity 时,对窗口上下文的处理与封装会变得更复杂,不利于用户使用,也不利于类库组件的封装。

单一 Activity 是否会存在性能问题?

性能问题主要看框架底层设计,轻语言安卓框架采用纯原生架构,无运行时 RunTime 损耗,视图类窗口自带栈堆储存与销毁,按下返回键,关闭窗口即回收内存,单一 Activity 的设计,让APP始终只存在一个 Activity 实例,相同界面内容,系统占用资源更低,因此只要代码逻辑合理,基本不会有任何性能问题。

轻语言安卓框架与原生安卓的比较

对比维度轻语言安卓框架原生安卓
启动速度✅ 视图切换更快(无系统级开销)❌ 每次跳转需初始化新Activity
内存占用✅ 窗口自带栈堆管理,关闭即销毁,系统自动回收资源。✅ 通过系统回收机制自动释放非活跃Activity
导航灵活性✅ 完全自定义路由逻辑,支持从入口文件启动指定窗口❌ 依赖系统 Back Stack,灵活性受限
模块化开发✅ 支持自定义窗口视图,自定义组件、模块✅ 按 Activity 拆分模块,易于隔离
系统兼容性✅ 与原生安卓兼容性完全一致✅ 系统原生支持所有特性
学习曲线✅ 中文语法编程,简单易学,组件丰富❌ 需要会 Java 语言,需要学习安卓官方SDK及文档
开发大型应用❌不建议开发超过125个窗口的App应用。✅ 支持开发大型,专业级复杂APP

2. 窗口管理模块

  • 窗口生命周期
    • 窗口创建完毕():窗口视图初始化(替代Activity的onCreate)。
    • 窗口切换完毕():窗口视图显示时触发(类似Activity的onStart)。
    • 窗口被关闭():窗口视图被销毁时触发(类似Activity的onDestroy)。
  • 视图栈管理
    • 使用栈结构(ViewStack)记录历史视图,支持返回操作(类似浏览器后退逻辑)。
    • 示例:用户从 主页窗口 → 信息窗口,按返回键时弹出栈顶视图并显示前一个视图。

3. 事件绑定与通信

  • 声明式事件处理

    • 通过定义事件语句块或设置回调,监听组件事件(如按钮被点击)。

    • 示例(类似VB语法):

      事件 按钮1.被单击(来源对象 为 视图)
          弹出提示("按钮1被单击")
      结束 事件
      
  • 跨视图数据传递

    • 全局单例 AppContext 存储共享数据。
    • 自定义事件消息跨窗口传递

4. 资源与布局管理

  • 动态资源生成及加载

    • 每个窗口关联独立的布局XML文件(如 登录窗口.xml),但编译时自动生成对应的组件创建代码。

    • 每个窗口的组件根据组件名称动态生成组件对象,例如:向窗口中添加了一个按钮组件、无需使用 findViewByID 寻找组件,编译时自动生成。

  • 开放布局描述

    • 每个窗口的布局采用XML描述,支持自定义、使用第三方工具设计。

语言核心特性

1. 纯中文编写上层应用

轻语言安卓框架核心采用 Java 设计,但运行到框架的上层应用采用轻语言编写,而轻语言是纯中文编程语言。

2. 类VB语法

轻语言语法与 Visual Basic 的语法类似,简单易懂,易学。

运行时架构

1. 编译与执行流程

  • 编译阶段:轻语言代码 → 轻语言编译器 → 安卓标准原生项目 → 通过 Android 官方 SDK 工具链打包并生成APK。

  • 运行时引擎:内置轻量级虚拟机,负责视图切换、事件分发及资源管理。

2. 资源管理机制

  • 动态资源加载:资源文件(如图片、字符串)按视图模块分包,运行时按需加载。
  • 全局资源池:通过 AppContext.Resources 访问共享资源,避免重复初始化。

3. 与Android原生交互

  • API桥接层:直接通过内嵌编译符 @{ } 嵌入原生代码:

    引用 android.widget.Toast;
    函数 弹出自定义提示(信息 为 文本型)
        Toast.makeText(MainActivity.getContext(), 信息, Toast.LENGTH_SHORT).show();
    结束 函数
    
  • 组件扩展支持:允许开发者通过 Java 编写自定义组件。

运行时Runtime参考

轻语言安卓框架运行时环境采用纯 Java 库封装,所有函数均为直接调用,无中间类型转换,无运行时性能损耗。

Runtime核心职责

Qing Android Runtime 是连接 轻语言 与 Android 系统的桥梁,主要负责以下任务:

  1. 视图生命周期管理
    管理单 Activity 内多视图(View)的动态加载、切换和销毁,模拟传统多 Activity 的生命周期行为(如 onCreateonStart)。

  2. 事件驱动模型
    将用户交互(点击、滑动等)和系统事件(传感器、网络状态)映射到轻语言定义的事件回调接口中。

  3. 资源动态加载
    按需加载布局、图片、字符串等资源,避免一次性加载所有资源导致内存压力。

  4. 跨视图通信
    提供数据传递机制(如全局变量、消息总线),支持视图间共享状态。

  5. 与Android原生交互
    连接 Android SDK 接口,允许轻语言代码调用 Java API(如启动服务、访问传感器)。

启动流程

轻语言安卓应用启动时,首先启动入口文件,入口文件 App.spl 继承自Runtime中的 MainActivity 类,MainActivity 中的 onCreate 被系统回调时将触发 App.spl 文件中的 应用被启动 事件,该事件则为轻语言App的入口事件,在该事件中可以创建指定窗口并显示,或申请权限,初始化加载数据。

事件传递机制

编译时,编译器会自动生成组件注册事件相关的代码。

视窗工程项目结构

视窗项目与默认轻语言程序存在一定差异,因为一个标准的视窗程序,除了拥有启动文件及相关源代码文件,还包含很多其它的必要的程序组成文件,例如:视窗程序中每个窗口的布局文件、程序中的图片、资源文件等等。

标准的轻语言视窗项目程序,由轻语言编写的程序源代码及其它必要文件组成:

项目根目录

默认必须包含的文件

  • src/:存放由轻语言编写的程序源代码。

    • 包含源代码的分组结构和 窗口模块结构体 等等文件。
  • layout/:存放窗口界面布局文件。

    • 包含程序中每个窗口界面的布局文件(.xml),用于在IDE中可视化设计窗口界面。
  • libs/:存放项目中用到的第三方 Jar 包文件。

  • static/:静态资源文件目录、用于储存图片、文本、其它程序中可能用到的数据,在编译时将会被打包到程序中。

  • App.spl:项目启动入口文件。

  • *.vsln:在 IDE 中加载项目的索引文件,该文件同时负责项目的基础配置信息。

其它项目文件

  • _build:编译输出目录、编译成功的可执行程序及编译时产生的相关文件会被存放到该文件夹中。注意:该文件夹创建项目时默认不存在,当编译项目时才会被创建,该文件夹可以被手动删除,删除后再次点击编译项目,仍然会自动生成。

  • src.package:源包文件夹。该文件夹中可以存放 Java 源代码、该文件夹需手动创建,默认项目不包含。注意:该文件夹中的 Java 源码文件需按照包名存在,例如:现在有一个 自定义.java 文件、这个文件中的包名为:com.mytest 那么 自定义.java 文件的路径必须为:src.package/com/mytest/自定义.java

视窗跨平台特性

轻语言视窗程序基于 JavaFx 框架设计,JavaFX 是一个用于构建桌面应用程序的图形用户界面(GUI)工具包,由 Oracle 公司开发并集成到 Java 平台中。它旨在替代早期的 Swing 和 AWT 工具包,提供更现代化、功能更强大的 GUI 开发框架。JavaFX 的设计目标是支持丰富的多媒体内容和动态用户界面,适用于从简单的桌面应用到复杂的商业软件。

JavaFx跨平台特性

基于 JavaFx 的轻语言视窗框架,天生便拥有极高的跨平台特性:

  1. 一次编写,到处运行

    • JavaFX 应用程序基于 Java 编写,因此可以在任何安装了 JVM 的平台上运行,无需额外的移植工作。
  2. 统一的 API

    • JavaFX 提供了一套统一的 API,开发者无需为不同平台编写特定的代码。
  3. 硬件加速支持

    • JavaFX 使用底层的硬件加速技术(如 OpenGL 或 DirectX),确保在不同平台上都能获得流畅的图形性能。
  4. 平台无关的 UI 组件

    • JavaFX 的 UI 组件(如按钮、文本框、表格等)在所有平台上具有一致的外观和行为。
  5. 多平台部署选项

    • JavaFX 应用可以通过打包为 JAR 文件、原生可执行文件(使用工具如 jlink 或第三方工具)等方式进行分发,适应不同的部署需求。

JavaFx优势

  1. 现代的架构设计

    • JavaFX 使用场景图(Scene Graph)来管理 UI 元素,相比传统的事件驱动模型更加直观和高效。
  2. 丰富的动画和特效

    • 内置了大量的动画和过渡效果,适合开发视觉吸引力强的应用程序。
  3. CSS 样式支持

    • JavaFX 支持通过 CSS 定义 UI 样式,方便开发者实现灵活的界面设计。
  4. FXML 布局定义

    • 使用 FXML 文件可以将 UI 布局与逻辑代码分离,便于团队协作和维护。
  5. 开放源代码

    • JavaFX 是开源项目(OpenJFX),开发者可以自由访问其源代码并参与改进。

总结

轻语言视窗采用 JavaFx 框架设计,不仅保留了 JavaFx 框架所有完整功能,同时基于中文代码,提供可视化设计,可以更快完成程序开发,支持同一个项目打包输出为 Windows、Linux、MacOS 等多个操作系统可以运行的程序。

程序入口文件

每个轻语言视窗程序都有一个入口文件(App.spl);这个文件是程序的启动入口,当程序被系统启动时(用户点击软件图标或从命令行启动),系统将优先触发该文件中的 应用被启动 事件,告诉开发者,用户准备启动该程序、且系统已经做好准备,开发者可以在该文件中初始化程序设置,或者自该位置起打开、加载一个窗口。

每个轻语言视窗程序都有一个、且唯一的入口文件 App.spl ,每次重新启动程序时,系统都会先回调该文件中的 应用被启动事件,该文件默认结构为(基于轻语言V1.5视窗框架、IDE 4.7.2):

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 程序作者:
' 联系信息:
' 文件描述:应用入口文件、当首次打开或重新启动程序时、都将会先执行该文件
'      并回调该文件中的相关事件;在实际开发时、可在该文件中做应用的
'      全局化初始工作。
' ****************************************************************************
事件 应用被启动(命令参数 为 文本型[])
    ' 当用户使用命令行或双击打开本程序时会先触发该事件
    ' 并返回在调用程序时、后面携带的命令参数值
    变量 主窗口1 = 创建 主窗口()
    主窗口1.可调整尺寸 = 真
    主窗口1.显示()
结束 事件

事件说明

每个视窗入口文件中都仅支持一个事件(相当于C语言中的主函数 main):

应用被启动

当程序被启动时,系统回调告诉开发者程序已经在系统内准备就绪,程序基架已经在系统中入栈(添加到系统内存了)。此时只需要开始编写程序启动后要执行的软件功能即可,例如视窗默认项目在该事件中创建了主窗口、并显示。

可视与命令行程序

轻语言视窗程序基于 JavaFx 框架,因此天生支持 Java 编程语言的特性,由于 Java 能够同时支持开发命令行程序和视窗程序,因此轻语言视窗除了开发含有GUI界面的程序外,还可以开发无界面的纯命令行工具。

什么是命令行程序?

命令行程序(CLI,Command Line Interface)是一种没有传统软件图形界面的程序。

在日常使用电脑时,大部分用户,尤其是使用微软 Windows 操作系统的用户,都是基于图形化界面操作,例如双击软件图标,系统将启动一个软件界面,然后整个操作流程都是可视化,通过鼠标操作的。

但是命令行程序,这类程序通过文本命令与用户交互,没有图形用户界面。通常在终端或命令提示符环境下运行(CMD窗口中)。

示例:

如上图所示,命令行没有传统的软件图形界面、通过在CMD命令行窗口中执行。

命令行程序特点

  • 资源效率高:命令行程序消耗的系统资源较少,适合在资源有限的环境中运行。

  • 速度快:对于熟悉命令行操作的用户来说,执行任务的速度往往比图形界面更快。

  • 灵活性和控制力:用户可以直接指定参数和选项,精确控制程序的行为。

  • 可编程性强:易于与其他工具和脚本结合使用,支持自动化任务的创建。

命令行程序适用场景

命令行程序在多种场景下都非常有用,尤其是对于那些需要高效执行、自动化以及资源受限的环境。以下是命令行程序的一些典型适用场景:

  • 服务器管理与运维:许多服务器管理和配置任务通过命令行工具完成,因为它们可以提供快速、直接的方式来进行操作。
  • 脚本编写和自动化:用于编写自动化脚本,例如部署代码、运行测试套件等,尤其是在CI/CD管道中。
  • 数据处理与分析:处理大量数据时,命令行程序可以非常高效,如使用grep查找文本、awk进行文本处理等。
  • 开发工具链:编译器、解释器、构建工具等通常都提供命令行接口,方便集成到开发流程中。

什么是GUI视窗程序?

GUI(Graphical User Interface,图形用户界面 视窗程序是指那些通过图形元素(如窗口、图标、按钮、菜单等)与用户进行交互的应用程序。与命令行程序不同,GUI程序提供了一个更加直观和友好的界面,使用户可以通过鼠标点击、拖拽以及键盘快捷键等方式来操作软件,而不需要记住复杂的命令。

GUI视窗程序的特点

  • 直观性:利用图标、按钮和其他视觉元素代替文字命令,使得操作更为直观,易于理解。
  • 易用性:即使是技术不熟练的用户也能快速上手使用,因为它们依赖于熟悉的视觉元素和操作方式。
  • 互动性:支持多种输入方法,包括鼠标、触摸屏等,允许更丰富的用户交互体验。
  • 多任务处理:可以同时打开多个窗口,每个窗口都可以独立操作,方便用户在不同的任务间切换。

GUI视窗程序适用场景

  • 办公软件(如Microsoft Word、Excel)
  • 图像编辑软件(如Adobe Photoshop)
  • 游戏
  • 媒体播放器
  • 需要图形化界面操作软件的需求

编写命令行程序

使用轻语言编写命令行程序非常简单,以下为使用 VcnStudio 编写命令行程序通用流程:

创建控制台程序

控制台程序即为命令行程序,只是名称不一样而已,打开VcnStudio在软件左上角新建项目、在弹出的对话框中选择桌面应用,控制程序。

点击确定后,IDE将会自动根据选择的模板创建一个项目,并在IDE中打开。

代码编写

默认控制台程序的程序集中有一个 主程序.spl 文件,App.spl 文件是程序入口文件,当程序被启动时,系统将先回调并执行 App.spl 文件中的 应用被启动 事件,在该事件中,通过实例化创建程序集中的主程序执行软件功能。

App.spl

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 程序作者:
' 联系信息:
' 文件描述:程序入口文件、当首次打开或重新启动程序时、都将会先执行该文件
'      并回调该文件中的相关事件;在实际开发时、可在该文件中做程序的
'      全局化初始工作。
' ****************************************************************************
事件 应用被启动(命令参数 为 文本型[])
    ' 当用户使用命令行或双击打开本程序时会先触发该事件
    ' 并返回在调用程序时、后面携带的命令参数值
    变量 主程序1 = 创建 主程序()
    主程序1.开始执行(命令参数)
结束 事件

主程序.spl

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 程序作者:
' 联系信息:
' 文件描述:本文件为控制台项目默认模板启动类、如果需修改启动程序、可在 App.spl 
'      文件中修改;注:该程序为无界面的命令行程序、使用时需在命令行
'      窗口中调用:例如
'      java -jar 程序.jar
' ****************************************************************************

' 在程序运行后开始执行该函数
函数 开始执行(命令参数 为 文本型[])
    如果(取数组成员数(命令参数) == 0)
        调试输出("程序启动成功;未带任何命令参数")
    否则
        调试输出(到文本(命令参数))
    结束 如果
    ' 下方代码需会员权限才可正常执行
    ' 调试输出("已成功启动任务、当前时间为:" + 取现行时间到文本("yyyy-MM-dd"))
结束 函数

编译输出

点击 IDE 工具栏或菜单栏中的编译按钮, 如果程序中代码没有错误、项目将会被编译成一个 Jar 文件,打开编译输出目录,将会看到目录中有一个和项目名称一样的 .jar 文件。

我的控制台程序1.jar

注意:轻语言命令行程序默认输出为 Java 程序,如果要输出为不同的目标语言可在编译时进行设置,目前定制版本支持输出为 Go 或 C/C++ 程序。

运行程序

命令行程序没有GUI界面、因此只能在CMD控制台中运行、以在 Windows 系统中为例:

  1. 打开CMD命令行窗口

    • 进入到程序输出目录、如下图:

  2. 使用 Java.exe 执行程序

    • 如果您的电脑中已经安装了版本一致的 JDK 并且已经配置有环境变量,那么可以直接通过下方命令执行刚刚编译输出的 Jar 程序。

    • F:\VcnStudio.Project\我的控制台程序1\_build>java -jar 我的控制台程序1.jar
      
    • 输入上方代码按下回车,控制台将输出:

    • 程序启动成功;未带任何命令参数
      
    • 再在执行命令后面加上参数值,多个参数值使用空格分隔,例如:

    • F:\VcnStudio.Project\我的控制台程序1\_build>java -jar 我的控制台程序1.jar 你好 欢迎使用VcnStudio开发工具
      
    • 回车执行程序后,将输出:

    • [你好, 欢迎使用VcnStudio开发工具]
      
  3. 使用 Java.exe 绝对路径执行

    • 大多数情况下,您的电脑可能并没有安装适配轻语言 SDK 的 JDK ,也或许没有正确配置环境变量、因此无法像方式2那样直接使用 Java.exe 执行。此时换成 VcnStudio 安装包内自带的 JRE 环境中的 Java.exe 也可正常执行。

    • 首先找到您的电脑中的 VcnStudio 安装目录下 jre / bin / java.exe 文件路径,例如:

      VcnStudio安装目录\jre\bin\java.exe
      
    • 然后在命令行中将方法2中的 java.exe 换成绝对路径即可:

    • F:\VcnStudio.Project\我的控制台程序1\_build>F:\VcnStudio\jre\bin\java -jar 我的控制台程序1.jar
      
    • 执行上方程序后将输出:

    • 程序启动成功;未带任何命令参数
      
    • 设置参数方式与方法2一样,在命令行尾部设置即可,多个参数注意使用空格分隔。

参数的作用

执行命令行程序时、在尾部添加的参数可以在代码中获取到,从而开发者可以根据使用者传入的参数,调用程序中不同的功能。

编写视窗程序

编写视窗程序的流程与命令行程序大致一样,在软件中新建项目需选择桌面应用。

创建项目后,默认入口文件 App.spl 代码:

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 程序作者:
' 联系信息:
' 文件描述:应用入口文件、当首次打开或重新启动程序时、都将会先执行该文件
'      并回调该文件中的相关事件;在实际开发时、可在该文件中做应用的
'      全局化初始工作。
' ****************************************************************************
事件 应用被启动(命令参数 为 文本型[])
    ' 当用户使用命令行或双击打开本程序时会先触发该事件
    ' 并返回在调用程序时、后面携带的命令参数值
    变量 主窗口1 = 创建 主窗口()
    主窗口1.显示()
结束 事件

默认 主窗口.spl 代码:

' ****************************************************************************
' 版权说明:Copyright(C) All Rights Reserved VcnStudio
' 程序版本:V1.0
' 程序作者:
' 联系信息:
' 窗口描述:默认启动窗口。
' ****************************************************************************

' 窗口域变量、该变量可在窗口中任意位置使用
变量 窗口变量 为 文本型

事件 窗口创建完毕()
    标签1.标题 = "窗口创建完毕"
结束 事件

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    标签1.标题 = "欢迎使用 VcnStudio 桌面端开发插件!"
结束 事件

设计器窗口:

编译运行程序

点击 IDE 工具栏运行图标 ,项目将会被编译为一个 jar 文件,并自动运行。

运行后示例:

注:

  • 编译输出的 jar 文件位于项目根目录文件夹中的 _build 文件夹中。

  • 在IDE中运行程序后默认将启动为调试模式,关闭程序后、调试结束。

  • 如果无法正确关闭程序,可在系统任务管理器中手动关闭:Java Platform 进程。

窗口与布局

在GUI(图形用户界面)视窗程序中,窗口是用户与应用程序交互的主要界面元素之一。窗口提供了一个可视化的容器,在这个容器内可以放置各种控件和组件,如按钮、文本框、标签等,以实现特定的功能或展示信息。

窗口逻辑文件

在轻语言视窗程序中,用于处理窗口逻辑的代码文件后缀为:.spl ,例如:主窗口.spl 窗口逻辑文件主要用于处理与用户的交互、展示界面内容、修改窗口内容、监听用户操作、监听并处理系统事件等等。

窗口上下文

由于设计器布局和窗口是分开的,因此如果要设置窗口标题或窗口其它属性,需要在窗口代码中使用自身上下文设置,在窗口中上下文一般表示为:本窗口/本对象

示例:

事件 窗口创建完毕()
    本对象.标题 = "我的视窗程序演示1"
    本对象.置尺寸(500,300)
结束 事件

窗口事件

轻语言视窗程序中每个窗口都有自己的独立事件,这些事件主要用于监听系统反馈给窗口的回调通知,例如常见的事件有:

  • 窗口创建完毕

  • 窗口被显示

  • 窗口按键被按下

  • 窗口尺寸被改变

  • ...

更多事件及注释,请参考IDE支持库中的:系统基础类/窗口 中的内容。

需要特别注意的是:

窗口事件 ≠ 布局事件

在设计器中双击根布局添加的事件不为窗口事件,窗口事件只能在窗口代码编辑器中通过右键菜单:添加事件 菜单项进行添加。

窗口布局

轻语言视窗程序中,每个窗口都有一个与之对应的布局文件。该布局文件名称必须与窗口逻辑代码文件相同,布局文件的主要作用为:管理显示到窗口中的所有可视组件或内容。

例如在程序集中有以下两个窗口代码文件:

主窗口.spl
登录窗口.spl

对应的布局文件则为:

主窗口.xml
登录窗口.xml

每个窗口布局的内容都使用 XML 编写,可手动修改布局,也可直接在IDE中快速设计,布局内容示例:

<窗口 标题="窗口标题" 宽度="523" 高度="298">
    <绝对布局 名称="根布局" >
      <标签 名称="标签1" 左边="12" 顶边="12" 高度="40" 宽度="218" 标题="我是最棒的!" />
      <按钮 名称="按钮1" 左边="12" 宽度="218" 顶边="70" 高度="40" 标题="点击测试" />
    </绝对布局>
</窗口>

每个窗口的布局文件都统一位于项目根目录下的 layout 文件夹中。

窗口根布局

每个布局文件中都有一个根布局、所有窗口中的可视组件都必须添加到该根布局中,在对应的窗口逻辑代码中,可以直接使用 根布局 对象。

根布局最终将会被添加到窗口中,因此程序在运行时显示的内容即为根布局内容。

基础控件与事件处理

基础控件

轻语言视窗框架内置了丰富的基础组件,

按钮、标签、编辑框的使用。

事件监听

在设计器中,双击组件自动添加事件。

使用拉姆达表达式添加事件。

使用子程序地址方式添加事件。

鼠标与键盘事件处理

监听鼠标与键盘事件。

通过CSS样式美化组件

轻语言视窗程序支持使用类似在HTML中使用 CSS 那样美化界面。

CSS(层叠样式表)是一种用于定义用户界面元素外观的样式语言。它允许开发者分离应用程序的视觉设计与功能逻辑,使得修改和维护应用的界面变得更加容易。通过使用 CSS 您可以为您编写的轻语言视窗程序中的的控件设置如颜色、字体、大小等样式属性。

支持的样式属性

JavaFx 官方 CSS 支持属性:查看 JavaFx CSS样式属性

CSS样式的作用

  • 统一风格:通过一个或多个 CSS 文件,可以确保整个应用程序保持一致的外观。

  • 易于维护:将样式从代码中分离出来,可以在不影响功能代码的情况下更新UI。

  • 灵活性:可以在运行时动态更改样式,提供更灵活的用户体验。

在代码中使用

在轻语言视窗程序中使用CSS样式有 2 种方式。

1.使用可视组件自带函数

使用每个可视组件自带的函数 置样式 设置键值对样式值。

例如:

标签1.置样式("-fx-background-color:#225678;-fx-text-fill:#ffffff;")

2.使用样式表

样式表可以方便我们管理多个样式类,与HTML一样,可以将多个样式通过名称分类编写到一个 .css 样式表中。

首先在项目根文件夹中的 static 文件夹中新建一个 CSS 样式文件,这里命名为:mystyle.css

然后编写不同的样式类:

.my-btn {
    -fx-background-color: #4CAF50; /* 设置按钮背景颜色 */
    -fx-text-fill: white; /* 设置文本颜色 */
}

/* 圆角按钮 */
.my-btn2 {
	-fx-background-color: #908978;
    -fx-text-fill: #ffffff;
    -fx-border-radius:20px;
    -fx-border-color:#335566;
    -fx-background-radius:20px;
    -fx-cursor:hand;
}

/* 圆角渐变按钮 */
.my-btn3 {
	-fx-background-color: radial-gradient(center 50% 50%, radius 50%, #1E90FF, #4C8897);
    -fx-text-fill: #ffffff;
    -fx-background-radius:20px;
    -fx-cursor:hand;
}

/* 圆角标签 */
.my-bel{
    -fx-background-color: #3CB371;
    -fx-text-fill: #ffffff;
    -fx-background-radius:5px;
    -fx-padding:4px;
}

/* 圆角背景渐变标签 */
.my-bel2{
    -fx-background-color: linear-gradient(to right, #4CAF50, #FFEB3B);
    -fx-text-fill: #ffffff;
    -fx-background-radius:5px;
    -fx-padding:4px;
}

.my-btn-cs {
    -fx-background-color: linear-gradient(to bottom right, #6a11cb, #2575fc); /* 渐变背景 */
    -fx-text-fill: white; /* 文本颜色 */
    -fx-font-size: 14px; /* 字体大小 */
    -fx-padding: 10 20; /* 内边距 */
    -fx-background-radius: 30; /* 圆角半径 */
    -fx-border-radius: 30; /* 边框圆角半径 */
    -fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.3), 10, 0.5, 0, 5); /* 阴影效果 */
    -fx-cursor: hand; /* 鼠标指针悬停时变为手型 */
}

.my-btn-cs:hover {
    -fx-background-color: linear-gradient(to bottom right, #8c2ce4, #4aa8fe); /* 悬停时的背景颜色 */
}

.my-btn-cs:pressed {
    -fx-background-color: linear-gradient(to top left, #6a11cb, #2575fc); /* 点击时的背景颜色 */
}

在窗口逻辑代码中使用:

事件 窗口创建完毕()
    标签1.标题 = "窗口创建完毕"
    
    ' 设置样式属性值,修改标签背景颜色和文本颜色
    标签1.置样式("-fx-background-color:#225678;-fx-text-fill:#ffffff;")
    
    ' 加载位于项目/static文件夹中的样式表文件
    本对象.加载样式表("mystyle.css")
    
    ' 将样式表中指定样式(根据名称)添加给按钮
    按钮1.添加样式类("my-btn")
    按钮2.添加样式类("my-btn2")
    按钮3.添加样式类("my-btn3")
    按钮4.添加样式类("my-btn-cs")
    ' 将样式表中的样式添加到标签中
    标签2.添加样式类("my-bel")
    标签3.添加样式类("my-bel2")
结束 事件

编译运行效果:

注意:

  1. 仅支持可视组件设置样式。

  2. JavaFx支持的样式和HTML支持的并不完全相同,有一定差距,部分HTML中CSS支持的样式在JavaFx并不支持。

程序中资源的使用

资源文件是程序中除代码外,其它组成程序功能的额外的数据文件,例如:常见的图片文件、文本文件、音频文件等等。

资源存放位置

轻语言视窗程序中的资源文件一般有两种存放位置:

  • 项目文件夹中的 static 文件夹内

  • 程序运行目录

项目资源(static)文件夹

该文件夹中存放的文件在编译打包时,将会被一同打包进输出的可执行程序中,例如:在该文件夹中存放的图片、或文本文件,当编译项目输出为一个可被执行的 Jar 程序时,这些文件将会一并打包到 Jar 文件中。

使用时一般通过文件名称使用,示例:

' 设置资源文件中的图片
标签1.背景图片 = "bg.png"
' 读取资源文件夹中的json数据到编辑框
编辑框1.内容 = 读取文本文件("data.json","UBF-8")

需注意:static 文件夹中的文件只能在编译前人为添加、在代码中读取使用,不能在运行时写入,也就是运行程序时不能向这个文件夹中写入、或向其保存文件。

程序运行目录

程序运行目录一般是指编译输出后与可执行程序位于同一个文件夹中的文件,该类型文件便于修改而不需重新打包应用,一般这类型文件多以配置文件、或日志存在。

在代码中使用时,只需要传入其绝对或相对路径即可,示例:

' 设置资源文件中的图片
标签1.背景图片 = 取运行目录(本对象) + "/bg.png"
' 读取资源文件夹中的json数据到编辑框
编辑框1.内容 = 读取文本文件(取运行目录(本对象) + "/data.json","UBF-8")

资源分类及使用场景

  • 图片资源:用于界面设计,比如按钮图标、背景图等,提升用户体验。
  • 文本文件:可能包含配置信息、语言本地化文件、帮助文档等。
  • 其它资源:包括音频、视频文件等多媒体内容,或者其他任何对应用程序运行有帮助的数据。

注意事项

对于需要频繁访问的资源,考虑缓存机制以提高性能。确保资源文件在编译时被正确地复制到输出目录,并且在打包成 JAR 文件时也包含这些资源。如果资源是从外部目录加载的,请确保该目录存在并且路径配置正确。

调用DLL文件

DLL是Dynamic Link Library的缩写,中文名称为动态链接库。在Windows操作系统中,DLL是一种包含代码和数据的文件,可以同时被多个程序使用。通过使用DLL,程序能够实现模块化,从可执行文件中分离出常用函数,从而减少内存消耗和磁盘空间占用。此外,DLL还支持插件功能以及便于更新应用程序的部分功能而不必重新编译整个程序。

在轻语言视窗程序中调用 Windows 下使用C语言编写的 DLL 文件时,通常需要借助 Java Native Interface (JNI) 技术。以下是基本步骤:

  1. 创建DLL:首先确保您的C语言编写的DLL已经正确编写并编译完成,且包含了你需要调用的函数。

  2. 生成头文件:使用javac命令编译包含native方法声明的Java类,然后使用javah工具根据这个类生成对应的C语言头文件。这个头文件定义了JNI与本地代码之间的接口。

  3. 编写桥接代码:基于上一步生成的头文件,在C源文件中实现相应的函数,这些函数会作为Java代码和你的DLL之间的桥梁。在这个阶段,你将调用原始DLL中的函数,并处理必要的数据转换。

  4. 加载DLL:在Java代码中,使用System.loadLibrary("yourdllname");来加载你的DLL。注意这里的"yourdllname"不包括".dll"扩展名。

  5. 调用本地方法:在Java中声明native方法,并在适当的地方调用它们。这些方法实际上是在DLL中实现的。

需要注意的是,直接操作DLL文件可能会涉及到复杂的细节,如数据类型映射、异常处理等。如果你不是特别熟悉JNI的工作原理,可能需要花费一些时间来学习和调试。此外,为了简化跨语言调用的过程,也可以考虑使用第三方库或工具,例如JNA(Java Native Access),它提供了更简单的方式来调用本地库,而不需要生成额外的胶水代码。

使用 jna-x.jar 调用DLL

jna-x.jar 是 Java Native Access (JNA) 库的一个版本。JNA 是一个开源的Java库,它允许Java代码直接调用本地动态链接库(如Windows上的DLL文件、Linux上的SO文件等)中的函数,而无需编写任何JNI(Java Native Interface)代码或桥接代码。这意味着开发者可以更简单地将Java应用程序与使用C、C++、Assembly等语言编写的本地代码集成起来。

本文使用 jna-5.13.0.jar 为大家讲解如何在轻语言视窗程序中调用DLL中的函数。

1.添加必要文件

将 jna-5.13.0.jar 与需要调用的 DLL 文件放在项目中的 libs 文件夹中。

2.在代码中使用原生代码调用

由于调用DLL对一般用户来说,相对较复杂,需要同时掌握 Java 与 C 语言、因此在使用该功能之前,建议先学习相关基础开发知识。

这里演示在视窗中调用并弹出 Windows 中的 User32 的系统信息框,代码示例:

引用 com.sun.jna.Library
引用 com.sun.jna.Native
引用 com.sun.jna.win32.StdCallLibrary
引用 com.sun.jna.platform.win32.WinDef.HWND
引用 com.sun.jna.ptr.IntByReference
@{
    public interface User32 extends StdCallLibrary {
        User32 INSTANCE = Native.load("user32", User32.class);
        int MessageBoxA(int hWnd, String lpText, String lpCaption, int uType);
        boolean SetWindowTextA(HWND hWnd, String lpString);
        HWND FindWindowA(String lpClassName, String lpWindowName);
    }
}

事件 按钮4.被单击(来源对象 为 对象,事件对象 为 鼠标事件)    
    User32.INSTANCE.MessageBoxA(0, "欢迎使用 VcnStudio 轻舟视窗开发插件!", "VcnStudio 视窗", 0)
结束 事件

事件 按钮5.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    变量 目标窗口句柄 为 HWND = User32.INSTANCE.FindWindowA(null, "视窗DLL演示")
    如果(目标窗口句柄 != 空)
        User32.INSTANCE.SetWindowTextA(目标窗口句柄, "窗口标题被修改(通过DLL)")
    否则
        信息框("未找到窗口句柄")
    结束 如果
结束 事件

编译运行效果

例程与库参考

VcnStudio 安装包内视窗程序,已自带:调用DLL演示例程 详细方法可参考该例程。

同时位于 VcnStudio 安装目录/samples/component.library 该文件夹中内置官方开源的类库封装参考例程,其中包含 测试DLL库 的库源码,该例程演示了如何将调用 DLL 封装成一个类库使用。

其它说明

在轻语言视窗中调用 Dll 文件,流程相对较复杂,建议一般将其封装成类库独立使用。

通过代码方式使用组件

在某些场景下,相对于直接在窗口中可视化添加组件,动态创建组件会更灵活,尤其是针对部分不可视组件的使用时。

动态创建组件

轻语言视窗中的所有组件都可以在代码中创建使用。

示例:

' 动态创建可视组件按钮、标签
变量 局_按钮1 = 创建 按钮()
变量 局_标签 = 创建 标签()
' 动态创建不可视组件
变量 局_时钟1 = 创建 时钟()
变量 局_音频播放器1 = 创建 音频播放器()

使用组件

通过代码创建好组件之后,可视组件需要将其添加到窗口中。

示例:

事件 窗口创建完毕()

    ' 动态创建可视组件按钮、标签
    变量 局_按钮1 = 创建 按钮()
    ' 设置按钮的标题及位置
    局_按钮1.标题 = "局_按钮1"
    局_按钮1.移动(10,10,100,30)
    ' 将按钮添加到窗口根布局中
    根布局.添加组件(局_按钮1)
    ' 创建标签并设置相关值
    变量 局_标签1 = 创建 标签()
    局_标签1.标题 = "局_标签1"
    局_标签1.背景颜色 = "#334455"
    局_标签1.移动(10,50,100,50)
    局_标签1.文本颜色 = "#ffffff"
    根布局.添加组件(局_标签1)

结束 事件

上方代码运行后,按钮与标签将分别添加到窗口左上角,运行效果如下图:

窗口坐标原点为窗口根布局左上角。

为组件添加事件

在轻语言中,为组件添加事件一共有三种方式:事件与回调 针对动态创建的组件,一般使用函数子程序地址或拉姆达表达式。

示例:

事件 窗口创建完毕()
    
    ' 动态创建可视组件按钮、标签
    变量 局_按钮1 = 创建 按钮()
    ' 设置按钮的标题及位置
    局_按钮1.标题 = "局_按钮1"
    局_按钮1.移动(10,10,100,30)
    ' 将按钮添加到窗口根布局中
    根布局.添加组件(局_按钮1)
    ' 创建标签并设置相关值
    变量 局_标签1 = 创建 标签()
    局_标签1.标题 = "局_标签1"
    局_标签1.背景颜色 = "#334455"
    局_标签1.移动(10,50,100,50)
    局_标签1.文本颜色 = "#ffffff"
    根布局.添加组件(局_标签1)
    ' 为 局_按钮1 注册被单击事件,当点击按钮时,改变 局_标签1 的文本内容
    局_按钮1.置被单击回调((来源对象,事件对象)->{
        局_标签1.标题 = "局_按钮1被单击"
    })
    
结束 事件

当点击按钮时、标签内容将会被改变,运行效果:

使用事件块语句

通过事件块监听事件,通常情况下只有在可视化设计时添加到窗口中的组件才能使用,但对于动态创建的组件,如果组件对象声明位置为窗口类成员变量时,也可以使用事件块监听组件事件,快捷添加事件方式:选中组件右键菜单项添加事件。

' 将 局_按钮1 声明为窗口成员组件,与事件、函数位于同一级别
' 鼠标选中变量名称,右键菜单添加事件块语句
变量 局_按钮1 为 按钮

事件 窗口创建完毕()
    ' 定义类成员后,记得仍需创建对象
    局_按钮1 = 创建 按钮()
    ' 设置按钮的标题及位置
    局_按钮1.标题 = "局_按钮1"
    局_按钮1.移动(10,10,100,30)
    ' 将按钮添加到窗口根布局中
    根布局.添加组件(局_按钮1)
结束 事件

' 当按钮声明为窗口类成员时,可以像可视化设计时添加的组件一样使用代码块语句
事件 局_按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    信息框("局_按钮1被单击")
结束 事件

不可视组件用法与上方可视组件用法基本相同,不同的地方在于:不可视组件无需将其添加到窗口根布局中。

在项目中使用 Jar 包

在轻语言视窗程序中,直接在项目中使用 Jar 包与安卓基本一致。

步骤与流程

1.手动添加 Jar 文件

打开项目根目录文件夹,将 JAR 文件放入项目的 libs 文件夹中。

2.添加引用

在需要使用 Jar 包的窗口或模块,引用 Jar 包内的指定数据类型。

 要使用 Jar 中的功能、首先我们需要先对其所在的包及类添加引用;经过查阅本库的文档可
' 知、本库的包名为:com.github.promeg.pinyinhelper 因此我们直接添加其引用即可
引用 dynamic.test.Math
引用 com.github.promeg.pinyinhelper.*

事件 窗口创建完毕()

结束 事件

事件 按钮1.被单击(来源对象 为 视图)
    ' 调用库中的“Pinyin”类中的函数、获取中文汉字的拼音
    ' 函数参数一为中文、参数二为拼音的链接符合、这里为空格
    如果(编辑框1.内容等于(""))
        弹出提示("请输入待转换的中文")
        返回
    结束 如果
    标签1.标题 = Pinyin.toPinyin(编辑框1.内容," ")
结束 事件

事件 按钮2.被单击(来源对象 为 视图)
    ' 除了对静态类直接使用外、对象类在使用时、我们必须先创建对象
    ' 然后才能使用、例如这里使用一个数学计算的 Jar 包
    变量 m = 创建 Math()
    标签1.标题 = "执行结果:" + m.add(100,20)
结束 事件

使用原生代码

轻语言支持在程序代码中直接使用目标平台的原生代码;安卓采用 Java 语言作为目标开发语言,在轻语言中可以通过内置的编译嵌入符号 @{ } 包裹 Java 代码。

事件 按钮3.被单击(来源对象 为 视图)
    ' 直接在项目中使用 Java 代码只需要通过 @{ } 包裹即可
    ' 例如;下方我们使用原生代码 Java 对一个整数数组排序
    ' 但需注意:源JAVA代码中不能包含任何注释内容
    变量 数组1 = { 10,30,52,23,60 }
    @{
        int len = 数组1.length;
        for (int i = 0; i < len - 1; i++)
        {
            for (int j = 0; j < len - i - 1; j++) 
            {
                if (数组1[j] > 数组1[j + 1]) 
                {
                    int temp = 数组1[j];
                    数组1[j] = 数组1[j + 1];
                    数组1[j + 1] = temp;
                }
            }
        }
    }    
    标签1.标题 = "排序后的数组为:" + 到文本(数组1)
结束 事件

更多信息请参考:原生支持

编译、运行、调试项目

本文将讲解当程序编写完毕后,如何编译、运行、调试项目。

编译项目

点击软件工具栏 图标,IDE 将开始编译并打包项目。

最终编译输出的可执行程序为一个标准 Jar 文件,位于项目 根目录/_build 中,可执行程序文件名称通常为 classes.jar 该文件可以直接在命令行中运行。

输出项目结构

默认编译输出的项目结构只包含 libs 与 classes.jar 文件,其中 libs 文件夹中主要存放程序运行时必要的依赖库。

程序/_build/
├── libs/
│   ├── jar1.jar
│   ├── jar2.jar
└── classes.jar

编译模式

视窗的编译方式分为静态编译与非静态编译两种。

  • 静态编译

    • 静态编译模式下所有第三方库及 libs 文件夹中的 jar 包都会被合并打包到最终编译输出的可执行 jar 文件中(单个可执行文件)、该文件在执行的时候不再需要使用外部 jar 包,但当项目中使用较多的jar文件时、采用静态编译、编译速度会很慢。
  • 非静态编译(纯净编译模式)

    • 纯净编译模式下,只会编译项目中的代码,在成功输出的可执行 jar 程序包中,仅包含视窗核心库相关类,不包含其它第三方 jar 文件中的类文件,第三方 jar 文件会被拷贝到输出目录(或可执行程序包相同曾经目录)中的 libs 文件夹中,纯净编译模式下,编译速度相对较快,但在运行时需要显示指定程序中用到的依赖包。

注:纯净编译模式为默认编译模式。

可执行文件格式

由于轻舟视窗是基于 Java 作为底层开发语言、为了支持跨平台运行、因此当编译输出的可执行程序文件并不是大家在 Windows 平台常见的 EXE 格式文件。

轻舟视窗输出的可执行程序文件后缀为:.jar

默认可执行文件名称为:classes.jar

运行项目

点击软件工具栏 图标,IDE 将先编译项目为可执行程序,然后再运行程序。

调试项目

当点击工具栏运行图标时,IDE将自动编译并启用调试模式允许程序。

视窗程序暂不支持断点调试功能。

如需在编译输出窗口输出代码变量的值,可以使用 调试输出 函数。示例:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    调试输出("这是调试输出的信息")
    变量 数据值 = 10
    调试输出("数据值:" + 数据值)
    变量循环(索引 = 0,5,1)
        调试输出("索引 = " + 索引)
    结束循环
结束 事件

运行程序后将在IDE底部编译输出窗口中输出调试信息:

12:49:47 这是调试输出的信息
12:49:47 数据值:10
12:49:47 索引 = 0
12:49:47 索引 = 1
12:49:47 索引 = 2
12:49:47 索引 = 3
12:49:47 索引 = 4

错误捕获

当程序运行时发生错误,但想查明其导致错误发生的原因,则可以使用异步捕获语句进行捕获,示例:

事件 按钮1.被单击(来源对象 为 对象,事件对象 为 鼠标事件)
    异常捕获首
        ' 创建一个只有3个元素的整数型数组
        变量 数组1 = { 1, 2, 3 }
        ' 尝试获取这个数组中第10个元素
        ' 由于这个数组并没有10个元素、因此会出现索引超过范围的错误
        调试输出(到文本(数组1[9]))
    异常被捕获(异常信息 为 对象)
        调试输出("异常信息:" + 异常信息)
    异常捕获尾
结束 事件

运行上方代码后,程序将输出错误信息:

异常信息:java.lang.ArrayIndexOutOfBoundsException: 9

发布向导及配置

轻语言视窗程序基于 JavaFx ,因此编译输出的程序可以运行到任何装有 JDK 的系统中,常见的桌面操作系统有 Windows 、基于 Linux 的国产操作系统、MacOS 苹果操作系统等等。

注意:打包发布应用时必须以管理员方式运行 VcnStudio.exe 程序。

目标 JDK 版本

轻语言视窗程序基于 JDK8 开发,因此您的目标设备或操作系统需安装 JDK8 才能正常运行轻语言程序。

下载地址:https://repo.huaweicloud.com/java/jdk/8u151-b12/

在电脑浏览器中根据您的目标操作系统下载对应的 JDK 安装即可。

  • Linux 平台

    • 下载含有 linux 关键字的版本、注意:部分 arm 芯片可能不支持,可自行下载测试。
  • MacOS苹果电脑

    • 下载含有 macosx 关键字的版本。
  • Windows 平台

    • 下载含有 windows 关键字的版本、其中需要注意位数:64(64位) 与 X86(32位),Windows 平台下载后需要安装、对于编程新朋友;安装时建议在非C盘目录新建一个文件夹、将 JDK 安装到此文件夹中;例如:D盘、新建一个名为 jdk8 的文件夹、然后安装时选择这个文件夹;因为安装后我们只需要使用其 jre 环境、并不需要使用其完整的 JDK 开发环境。

发布应用

点击 IDE 菜单栏 项目/发布应用 菜单项,将弹出应用发布配置窗口。

  • 输出文件目录

    • 指定可运行程序的完整依赖及相关文件保存目录。
  • 输出平台类型

    • 根据您的目标平台选择即可。
  • 输出目标位数

    • 在下载JDK版本时,根据您的目标系统位数选择即可。

当输入相关参数后,点击确定按钮,IDE 将开始编译项目并根据选择的平台类型打包并输出相关文件。

不同的平台输出的文件略有不同,但核心文件基本一致。

注意事项

1.发布的视窗程序非独立文件,而是在一个文件夹内包含多个文件组成的安装包。

2.由于发布时在线下载 JDK 非常耗时,因此暂时未开通该功能,在上方提供的网站中根据您的目标系统下载对应的 JDK 即可,JDK 的具体使用方式请参考发布对应平台的相关文档内容。

发布为 Windows 程序

在IDE发布应用配置窗口中,输入相关参数、选中 Windows 平台,点击确定后,将会在输出目录文件夹中输出完整的可被执行的程序。

Windows 运行包结构

Windows/
├── jre/
│   ├── lib
│   ├── LICENSE
│   ├── bin/
│   │   ├── java.exe
│   │   └── javaw.exe
├── libs/
│   ├── jar1.jar
│   └── jar2.jar
├── classes.jar
├── start.config.ini
└── 启动程序名称.exe

输出的视窗程序运行包默认将被保存到 Windows 文件夹中,该文件夹中各个文件的作用为:

  • jre

    • 存放 JDK 安装包中的 Jre 运行环境,下载 JDK 后,直接解压到本地,然后复制 JDK 中 jre 文件夹中的所有文件到该文件夹中,即可正常使用软件。注意:jre 文件夹中的 java 路径,正确路径应该为 jre/bin/java.exe
  • libs

    • 存放程序中的用到的扩展类库或第三方的 jar 依赖包,以及 DLL 文件。
  • classes.jar

    • 程序核心执行文件。
  • start.config.ini

    • 程序启动时的配置文件,该文件不可被删除、也不可修改名称,该文件主要作用为配置启动 classes.jar 时的 Java.exe 路径,以及启动时的主类。

    • Windows下该文件默认配置内容为:

    • [Config]
      # 设置 java 文件路径,默认使用 VcnStudio 安装路径中的环境
      # 如果目标电脑中没有相关环境、可以到 https://repo.huaweicloud.com/java/jdk/8u151-b12 该地址中下载含有 windows 关键字的环境包
      # 下载时需根据自身设备芯片及位数选择合适的环境包
      # 下载后、解压其依赖包到 jre 文件夹中,并调整其路径为:当前目录/jre/bin/java
      JAVA_PATH=VcnStudio安装目录\jre\bin\javaw.exe
      # 设置待启动的主类文件,一般不需要修改,编译时会默认设置
      MAIN_CLASS=my.app.App
      
  • 启动程序名称.exe

    • 该文件为 Windows 下的可执行程序,采用VB编译,相当于是一个调用 Java 启动 classes.jar 的壳文件,双击即可启动程序。

注意事项

配置文件 start.config.ini 中,默认 Java 文件路径为 VcnStudio 安装目录下的 Jre 环境中的 Java.exe 如果您将程序运行包,压缩后发给客户,或复制到其它电脑中时,需要修改该配置文件中的 Java 文件路径,如果目标电脑没有 Jdk 或 jre 环境、则需要先下载。

发布为 Linux 程序

Linux 运行包中没有像 Windows 那样的 exe 启动文件,文件内容略有不同。

Linux 运行包结构

Linux/
├── jre/
│   ├── lib
│   ├── LICENSE
│   ├── bin/
│   │   ├── java.exe
│   │   └── javaw.exe
├── libs/
│   ├── jar1.jar
│   └── jar2.jar
├── classes.jar
├── start.config.ini
└── 启动程序名称.sh

输出的视窗程序运行包默认将被保存到 Linux 文件夹中,该文件夹中各个文件的作用为:

  • jre

    • 存放 JDK 安装包中的 Jre 运行环境,下载 JDK 后,直接解压到本地,然后复制 JDK 中 jre 文件夹中的所有文件到该文件夹中,即可正常使用软件。注意:jre 文件夹中的 java 路径,正确路径应该为 jre/bin/java.exe
  • libs

    • 存放程序中的用到的扩展类库或第三方的 jar 依赖包,以及 DLL 文件。
  • classes.jar

    • 程序核心执行文件。
  • start.config.ini

    • 程序启动时的配置文件,该文件不可被删除、也不可修改名称,该文件主要作用为配置启动 classes.jar 时的 Java.exe 路径,以及启动时的主类。

    • Linux下该文件默认配置内容为:

    • # 设置 java 文件路径,注意:Linux 平台下的 java 没有后缀,默认使用当前运行目录 jre 文件夹中的环境
      # 如果还未下载环境、可以到 https://repo.huaweicloud.com/java/jdk/8u151-b12 该地址中下载含有 linux 关键字的环境包
      # 下载时需根据自身设备芯片及位数选择合适的环境包
      # 下载后、解压其依赖包到 jre 文件夹中,并调整其路径为:当前目录/jre/bin/java
      JAVA_PATH=./jre/bin/java
      # 设置待启动的主类文件,一般不需要修改,编译时会默认设置
      MAIN_CLASS=my.app.App
      
  • 启动程序名称.sh

    • 该文件为 Linux 下的脚本执行程序,相当于是一个调用 Java 启动 classes.jar 脚本文件,在Linux系统中双击即可启动程序。

注意事项

配置文件 start.config.ini 中,默认 Java 文件路径为当前运行包中的 Jre 环境中的 Java.exe ,但发布的运行包内的 jre 是空的,因此直接复制项目到 Linux 系统中是无法正常启动程序。

有两种方式可以解决该问题:

  1. 下载您目标系统对应的 JDK,然后再将其 jre 文件夹内容复制到运行目录中的 jre 文件夹中。

  2. 如果您的 Linux 系统已经安装有 JDK8 ,则可以直接修改配置文件中的路径为您 Linux 系统中已经安装的 JDK 的 Java.exe 文件即可。

发布到其它平台

轻语言视窗程序的运行核心逻辑是使用 Java 在命令行中执行 jar 文件。

因为编译输出的程序是一个 jar 文件。

示例:

java -jar 您的程序.jar

Windows 与 Linux 运行包为了方便使用,因此默认添加了启动文件。

如果要发布到其它平台,其实原理也是一样的。

无非就是如何启动程序。

以非标国产操作系统举例,要在其中运行 轻语言视窗程序,那么只需要保留 Windows 或 Linux 输出目录中的2个必要文件即可。

  • libs 文件夹中的依赖,如果程序中没有用到任何依赖,也可以不需要

  • classes.jar 核心运行程序,必要

接下来只需要在 https://repo.huaweicloud.com/java/jdk/8u151-b12/ 这里下载您的目标操作系统 JDK 安装包到本地。

假设您正在使用的是 银河麒麟(X86) 、您要将写好的视窗程序复制到这个操作系统中运行。

步骤与流程

  1. 下载 JDK 解压到任意文件夹

  2. 拷贝视窗程序 libs 与 classes.jar 文件到麒麟系统中任意文件夹中,注意:libs 与 classes.jar 要在同一个目录

  3. 在控制台进入 classes.jar 这个文件夹

  4. 拷贝您第一步解压的 JDK 里面的 java 文件地址,注意:是 java 这个文件的地址,一般绝对路径为:.../jdk1.8.0.X/bin/java

  5. 在终端控制台中输入以下命令:

    .../jdk1.8.0.X/bin/java -cp classes.jar;libs/* my.app.APP
    

    命令说明:

    • .../jdk1.8.0.X/bin/java 是您系统中 Java 文件的绝对路径。

    • -cp classes.jar;libs/* 固定命令、无需修改,设置待启动jar文件及依赖文件夹

    • my.app.APP 视窗程序的包名+APP、后面的APP是固定的主类,不能修改。

根据上面的步骤,您就可以在任意能使用 JDK 的操作系统中运行轻语言视窗程序了。

视窗类库的封装

视窗组件的类库封装方式与安卓类库封装类似。

区别在于:

  1. 视窗配置文件中没有清单文件附加节点,及权限节点。

  2. 视窗类库程序没有R资源概念,所有资源均放在 static 文件夹中。

安卓类库组件临时参考: 轻语言安卓类库组件封装向导

框架设计参考

轻语言视窗框架底层采用 JavaFx 结合 Java8 标准SDK设计,由轻语言驱动运行。

入口文件

轻语言视窗程序入口文件 App.spl 继承自 javafx.application.Application 类,当入口文件编译后,通过系统回调 应用被启动 事件,启动程序。

编译后的入口文件代码示例:

package my.app;

import javafx.application.Application;
import javafx.stage.Stage;

public class App extends Application {
  public static void main(String[] paramArrayOfString) {
    launch(paramArrayOfString);
  }
  
  public void start(Stage paramStage) throws Exception {
    String[] arrayOfString = getParameters().getRaw().<String>toArray(new String[getParameters().getRaw().size()]);
    应用被启动(arrayOfString);
  }
  
  public void 应用被启动(String[] paramArrayOfString) {
    主窗口 启动窗口1 = new 主窗口();
    启动窗口1.显示();
  }
}

窗口

轻语言视窗程序中的窗口类封装了 JavaFx 中的 StageScene 类;以类成员的方式集中管理舞台与场景对象。

窗口的显示与切换,由内部的 Stage 、Scene 控制。

组件

所有可视组件都继承自视图类,视图 类是一个封装了 JavaFx 节点的轻语言视窗基类,在该类中,通过类成员的方式,封装了 JavaFx 节点相关方法及事件。

其它

未完待续

关于单片机

单片机是什么?

单片机(Microcontroller Unit,简称MCU)是一种将计算机的主要部分集成在一个芯片上的微型计算机。它通常包括处理器(CPU)、存储器(RAM、ROM)、输入/输出端口(I/O)、定时器/计数器以及其他外设功能模块。单片机具有体积小、功耗低、性能稳定等特点,因此被广泛应用于各种嵌入式系统中。

单片机的作用

  1. 控制功能:单片机的核心作用是对设备或系统进行实时控制,完成特定的任务。
  2. 数据处理:能够对采集到的数据进行分析和处理。
  3. 接口功能:通过其丰富的I/O端口与其他硬件设备通信。
  4. 智能化:为传统设备增加智能化功能,使其具备自动控制能力。

单片机在生活中的实际应用

单片机在现代生活中无处不在,几乎所有的电子设备中都可以找到它的身影。以下是一些常见的应用场景:

1. 家用电器

  • 空调、冰箱、洗衣机等家电中的温控、模式切换等功能都依赖于单片机。
  • 微波炉的定时加热、电饭煲的智能烹饪模式等也由单片机控制。

2. 汽车电子

  • 汽车中的发动机控制单元(ECU)、防抱死制动系统(ABS)、倒车雷达、导航系统等都使用单片机。
  • 车窗升降、座椅调节、车内环境控制系统等也离不开单片机的支持。

3. 工业自动化

  • 在工厂中,单片机用于控制生产线上的机械设备,如机器人手臂、传送带等。
  • 温度、湿度、压力等传感器的数据采集与处理也依靠单片机。

4. 消费电子产品

  • 手表、计算器、遥控器、游戏控制器等小型电子设备中都有单片机的身影。
  • 智能音箱、智能家居设备(如智能灯泡、智能插座)也依赖单片机实现功能。

5. 通信设备

  • 路由器、交换机、调制解调器等网络设备中,单片机负责数据传输和协议处理。
  • 移动通信基站和卫星通信系统中也有单片机的应用。

6. 玩具与教育

  • 智能玩具、编程机器人等产品中,单片机用于实现交互功能。
  • 学生用的开发板(如Arduino、STM32)也是基于单片机设计的。

VcnStudio单片机开发插件

VcnStudio · 轻舟单片机开发插件是 VcnStudio 开发平台推出的一款用于嵌入式设备开发的中文编程插件、插件采用中文作为第一开发语言、以 Arduino Esp32-framework 作为基础开发框架、采用 PlatformIO 作为编译工具栈、兼容 Arduino 全部特性、支持直接使用 Arduino 函数、库、支持 C++ 代码的嵌入使用、支持在项目中使用自定义类库。

除了传统的纯代码嵌入式应用、VcnStudio 单片机插件同时还支持可视化GUI界面设计、并采用轻舟编程语言实现事件驱动、相比市面上只能做界面的GUI工具来说、轻舟单片机在可视化开发中具有更大的优势。

环境搭建与安装

请参考论坛帖子:

Esp32单片机编译及烧录环境部署教程

VcnStudio开发者交流社区

(来源:VcnStudio开发者社区)

单片机工程项目结构

本章将为大家介绍轻语言 单片机 工程项目结构;在了解详细的工程结构后;以便于能更好的进行开发工作;在 VcnStudio 中、单片机一共分为两个不同的工程类型、分别为纯代码项目与含GUI界面的项目:

  • 不可视纯代码工程

    • src 存放程序运行时的主要代码文件。

    • static 存放静态资源文件

    • include 存放自定义或第三方 c++、.h 文件

    • lib 存放第三方C++库

    • App.spl 保留文件、暂不参与项目的编译

    • *.vsln 项目工程索引文件

    • _build 项目编译输出文件夹

  • 含有GUI界面的可视化工程

    • layout 存在界面布局文件夹。

含GUI界面的可视化项目工程文件结构与纯代码工程基本一致;只是多了一个存放界面设计的布局文件夹。

注意:含GUI界面的工程必须配合 TFT_eSPI 类型屏幕使用。

src

该文件夹主要存放程序或窗口逻辑代码;对应IDE工程列表窗口的:程序集 节点。

static

在该文件夹中主要存放程序的静态资源、例如:文本、图片等内容。

include

存放自定义原生 C++ ,.cpp 文件、轻舟单片机可以与 C++ 混合开发、如果在开发时需要使用到原生 C++ 相关的代码、可以直接将Cpp文件放在该文件夹中;在代码中使用“引用”关键字引用文件。注意:该文件夹需自行在项目根目录手动创建。

注:.h 头文件不能放在该文件夹;如果有头文件请使用自定义库的方式。

lib

存放自定义或第三方 C++ 库;轻舟单片机可以与C++混合开发、如果在开发时需要使用到原生 C++ 相关的库、可以直接放在该文件夹中;在代码中使用“引用”关键字引用头文件。注意:该文件夹需自行在项目根目录手动创建。

App.spl

该文件为保留文件、目前不参与项目的编译。

_build

项目编译输出文件;编译成功后的二进制文件将会被存放到该目录。

layout

界面设计布局文件的存放路径、仅在GUI项目中生效。

支持的芯片与开发板

本章将介绍轻舟支持的单片机相关芯片与开发板;根据市场需求的调研、目前我们支持下列嵌入式芯片:

  • ESP32

    • ‌ESP32是一款由乐鑫信息科技(Espressif Systems)推出的高度集成的低功耗系统级芯片(SoC),特别适用于各种物联网(IoT)应用。;ESP32集成了双核处理器、无线通信、丰富的外设和接口,以及低功耗特性。

支持的相关开发板类型为(相关模组或芯片类型可在IDE工程配置中选择)

  • Esp32

    • 特点:具有双核处理器,支持 Wi-Fi 和 Bluetooth Classic + BLE,拥有大量的 I/O 引脚和外设。

    • 适用场景:适合需要高性能计算和大量外设连接的复杂物联网项目,如智能家居控制中心、复杂的机器人控制系统等。

  • Esp32C2

    • 特点:单核处理器,支持 Wi-Fi,主要用于低成本、低功耗应用。

    • 适用场景:适用于成本敏感、低功耗要求的物联网应用,如简单的环境监测设备、小型家庭自动化装置等。

  • Esp32C3

    • 特点:单核处理器,支持 Wi-Fi 和 Bluetooth 5 (BLE),低成本、低功耗。

    • 适用场景:适合需要蓝牙连接、成本敏感的应用,如智能穿戴设备、低功耗的物联网设备等。

  • Esp32C6

    • 特点:支持 Wi-Fi 6 (802.11ax),提供更高的传输速率和更低的延迟。

    • 适用场景:适用于需要高速网络连接的应用,如视频流媒体设备、远程监控系统等。

  • Esp32h2

    • 特点:支持 Wi-Fi 和 Bluetooth 5 (BLE),强调低功耗性能。

    • 适用场景:适用于需要低功耗和蓝牙连接的应用,如便携式健康监测设备、智能手表等。

  • Esp32s2

    • 特点:单核处理器,支持 Wi-Fi,具有大量 I/O 引脚,强化了模拟信号处理能力。

    • 适用场景:适合需要较多模拟信号输入的应用,如音频处理设备、环境监测设备等。

  • Esp32s3

    • 特点:支持 Wi-Fi 和 Bluetooth 5 (BLE),增加了 AI 功能,如唤醒词检测。

    • 适用场景:适用于需要语音识别、AI 功能的应用,如智能音箱、语音助手等。

由于Esp32相关模组、及开发板类型较多、在实际开发时可以根据自身需求在乐鑫官网查看适合自己的产品类型;地址:开发板概览 | 乐鑫科技

另外需特别注意;芯片、模组、开发板 之间的关系、VcnStudio 编译输出的二进制程序在一般情况下默认只能在项目配置中所选择的芯片类型及模组中运行、例如:如果两个开发板芯片与模组类型不一样、则程序只能稳定运行在指定芯片和模组封装的开发板中;其它类型的开发板中可能会出现错误。

例如:在开发时选择的目标开发板为:Esp32s3/esp32-s3-devkitc-1 则编译输出的二进制文件建议仅运行在s3系列的开发板中;如果要运行在其它类型开发板中可以在项目配置中修改开发板后再重新编译。

芯片,模组、开发板之间的关系

类型芯片模组开发板
功能纯集成电路;无法直接烧录程序运行在芯片的基础上含有时钟与闪存;可运行程序、计算数据;但无法直接烧录、需要使用下载器。芯片、模组加接口;像电脑主板一样;有USB接口、可以直接与电脑连接下载烧录数据到开发板闪存中。

芯片一般是无法直接使用的、需要配合模组。

开发板一般包含了芯片、模组、以及IO口、可以直接用于开发环境测试。

建议在开发前先选择好目标开发板;目前轻舟单片机仅支持ESP32;暂不支持其它类型芯片。

选择建议

目前市面上关于ESP32的开发板非常多、作为新手朋友来说、如果想学习物联网相关的编程、想自己:

实现APP控制硬件、

通过APP点亮LED灯、

APP控制蓝牙小车、

独立实现自动浇花系统(土壤湿度传感器)、

自定义商品扫码机、

实时检测温湿度桌面日历、

无线门铃、

DIY洗衣机、

遥控窗帘、

智能照明控制系统(灯光传感器)、

自定义宠物喂食机、

环境温湿度自动控制、

可远控插座、

智能健身器材、

智能音响、

红外遥控家用电器、

智能药盒、

宠物追踪器、

自动晾衣架(雨点传感器检测到下雨自动收衣服)、

智能书架、

便携式防盗报警器、

智能儿童玩具、

自动烘干机(温湿度传感器)、

智能电水壶、

共享洗车系统、

自助按摩椅、

智能烟雾探测器、

智能水培系统、

自动清理猫砂盆、

自定义扫地机器人、

智能油烟机清洗、

商品自动贩卖机、

共享停车位、

智能农业设备(远程遥控机器收割小麦、稻谷)、

互动音响、

数据实时采集、

自动灌溉系统、

工厂自动化控制、

智能安防、

运动追踪定位、

无线打印机、

智能体重秤(压力传感器)、

鱼缸智能温控、

无人机控制、

户外互动游戏、

创意灯光秀、

智能鞋柜、衣柜

共享图书室、

便携式广告牌、

LED点阵显示...

等等;第一步就需要选择一个适合自己需求的开发板;这里为大家推荐三款我们官方相关项目中也在使用的:

  • Esp32

    • 后面没有带类型、名字就叫 ESP32、相关开发板推荐选择:ESP32-DevKitC 、ESP32-DevKitM-1 ;4 / 8 MB Flash;I/O USB;适合大多数对性能要求稍高但不是特别高的场景。
  • ESP32C3

    • 对标ESP8266、性价比较高、价格不贵、支持蓝牙;4 MB Flash ;I/O USB;适合大多数对性能要求不高的场景。
  • ESP32S3

    • 功能较强、运算速度快、价格稍贵、8 MB Flash + 3.3V 2 MB / 32 MB Flash + 1.8V 8 MB ;I/O USB;适合大多数对性能要求较高或含有GUI可视化操作的场景。

总结:

个人学习、体验、摸索;建议选择 ESP32、ESP32S3 ;因为这两款基本上价格方面稍贵、但是功能方面比较全面、也比较强大、基本上可以适合各种场景。

项目使用、产品研发 如果要求控制成本、在一般情况下、可以选择C系列、例如:ESP32C3或者其它适合你需求的类型。详细参考:开发板概览 | 乐鑫科技

传感器的选择

在使用ESP32开发物联网(IoT)应用时,选择合适的传感器是至关重要的一步。下面是一些选择传感器时的考虑因素、注意事项、常用的驱动库、传感器类别以及它们的应用场景。

考虑因素

  1. 应用需求:明确你的项目需要监测哪些参数,如温度、湿度、光照强度等。
  2. 精度要求:根据项目的精确度需求来选择传感器,高精度传感器通常成本更高。
  3. 功耗:对于电池供电的应用,选择低功耗的传感器非常重要。
  4. 通信接口:ESP32支持多种通信协议,包括I2C、SPI、UART等,确保所选传感器支持这些接口之一。
  5. 环境适应性:考虑传感器是否能适应你的工作环境,比如高温、高湿或强电磁干扰等条件。
  6. 成本:根据项目的预算选择性价比高的传感器。

注意事项

  • 在购买前仔细阅读传感器的数据手册,了解其工作原理、电气特性、物理尺寸等信息。
  • 考虑传感器与ESP32之间的兼容性问题,包括供电电压、信号电平转换等。
  • 对于室外或恶劣环境下使用的传感器,需要考虑防水防尘设计。
  • 测试传感器的实际性能,确保它能满足项目的实际需求。

常用传感器类别及应用场景

目前轻舟单片机支持市面上98%的传感器、只要是Esp32支持的;VcnStudio 单片机全都支持;常见的传感器有:

  1. 温度传感器(如DS18B20, DHT11/DHT22):用于监测室内外温度变化,适用于智能家居、农业监控等领域。
  2. 湿度传感器(如DHT11/DHT22, HTU21D):与温度传感器一起使用,可以提供更全面的环境监测数据。
  3. 光照传感器(如BH1750, TSL2591):用于检测光照强度,适用于智能照明系统、植物生长灯控制等。
  4. 气体传感器(如MQ-2, CCS811):监测空气质量,可用于家庭安全、工业污染监测等。
  5. 位置/距离传感器(如HC-SR04, VL53L0X):测量物体间的距离,适合机器人避障、停车位检测等应用。
  6. 加速度计/陀螺仪(如MPU6050, BNO055):检测运动状态,广泛应用于无人机、健身追踪器等。
  7. 心率传感器(如MAX30102):健康监测设备中常见,可集成到手环、手表中。

屏幕的选择

除了常用传感器;轻舟支持的屏幕有:

  • OLED(Organic Light-Emitting Diode)

    • 自发光:每个像素都能独立发光,不需要背光源,因此可以实现非常薄的设计。

    • 对比度高:因为没有背光,所以黑色显示更加纯粹,对比度极高。

    • 视角宽广:从任何角度观看颜色变化不大。

    • 功耗低:仅在显示图像的部分消耗电力,显示纯黑时不耗电。

    • 响应速度快:刷新速度快,适合动态图像显示。

    • 轻舟默认支持库及例程适用于:SSD1306 芯片控制的 OLED 显示屏

    • 适用场景智能手表、手环等可穿戴设备、小型便携式设备,如移动支付终端、健康监测设备、实验室仪器仪表的小型显示屏。

  • TFT_eSPI(Thin Film Transistor - Extended SPI Interface)

    • 色彩丰富:支持16位甚至24位真彩色显示,色彩表现力强。

    • 分辨率高:可以达到较高的分辨率,适合显示复杂的图形界面。

    • 亮度高:有独立的背光源,亮度较高,适合户外使用。

    • 触控功能:部分TFT屏幕支持触摸操作,增加了人机交互的可能性。

    • 应用场景移动设备的主屏幕,如智能手机和平板电脑。工业控制面板、医疗设备的人机界面。游戏设备、多媒体播放器等需要高质量视觉输出的场合。

  • LED点阵屏

    • 模块化设计:由多个LED灯珠组成,可以根据需要拼接成不同大小的屏幕。

    • 亮度高:每个LED灯珠都可以发出很高的亮度,适合户外广告牌等远距离观看的场合。

    • 能耗较低:虽然单个LED亮度高,但由于只点亮需要的部分,整体能耗相对较低。

    • 寿命长:LED的使用寿命较长,维护成本低。

    • 应用场景户外广告牌、公交站牌等公共信息展示。商场、车站等人流密集场所的信息提示。大型活动现场的背景屏幕。

插件内置支持库

除了核心支持库外、安装包已内置常用第三方扩展开发库;这些开发库都可以开箱即用;例如:BLE蓝牙、CAN通信、DHT22温湿度传感器、DS时钟、OLED显示器、U8G2(可在屏幕中显示中文汉字)、WS2812灯带、看门狗、软串口等等;这些组件适用于市面上面大部分传感器组件。

核心支持库内置时钟、HTTP、服务器、SPI操作、闪存读写器、SD卡操作、WIFI操作、中断、串口通信、键鼠操作、USB串口等等功能。

商业支持库

除了自带的扩展库外;轻舟还有部分未开放的付费组件库;例如:LED点阵屏组件库(电子日历、数据采集大屏显示)、共享系统套件(共享充电宝、共享按摩椅、共享钓鱼/渔具/池塘)、机电一体化工业控制 等等。

由于这些组件库需要搭配专门的硬件和传感器、并且使用时也相对复杂一些;因此未免费公开;如有需要、可联系官方网站中的客服或发送邮件至:80852516@qq.com

温馨提示:如果 VcnStudio 单片机没有封装的函数或功能;而正好你的项目需要时;你可以直接在代码中使用ESP32或Arduino提供的函数。

额外语法特性

由于单片机程序的特殊性,单片机语法与轻语言标准语法略有不同。

轻语言目前支持编写 ESP32 芯片的程序。

底层语言为 C++ ,也就是轻语言编写的代码最终会转译成 C++ 代码、再调用相关编译工具链进行编译。

宏定

单片机语法中新增了一个 宏定 关键字、熟悉C++编程的朋友,应该听说过 宏定义 ,宏定关键字的作用就等于宏定义,主要用于在编写代码时,定义预编译时常量值,通过 宏定义 声明的变量,在编译时会将代码中的变量替换成常量值。

对象实例化

在编写单片机程序时,创建组件的实例对象,不能使用 创建 关键字,只能在定义时构建。

示例:

' 在定义变量时同时通过指定构造参数实例化对象
' 下方变量相当于是定义了一个端口为80的服务器对象
变量 服务器1 为 服务器(80)
' 定义使用指定参数构建的OLED显示器变量
变量 Oled显示1 为 OLED显示器(128,64,&Wire,-1)

注册回调事件

轻语言标准语法中,支持 3 种回调事件,但单片机中仅支持:子程序引用 这一种。

同时在引用子程序地址时,需要使用 & 符号链接待使用的子程序。

但在单片机中,不能使用 & 符号,直接使用函数名称即可。

示例:

' 定义时钟对象、用于循环执行任务
变量 时钟1 为 时钟

事件 程序被启动()
	初始化串口通信(115200)
    调试输出("程序被启动")
    ' 调用时钟1每1秒执行一次任务
    时钟1.开始任务(1,时钟1任务)
结束 事件

变量 时钟1计次 = 0

函数 时钟1任务()
    时钟1计次 = 时钟1计次 + 1
    调试打印("时钟1计次:")
    调试输出(时钟1计次)
结束 函数

上方代码中:

时钟1.开始任务(1,时钟1任务)

调用开始任务中的参数二即为执行任务的周期事件子程序,这里无需使用 & 符号链接,直接使用函数名称即可。

其它

除上述三个额外语法特性外,单片机其它语法与轻语言标准语法完全一致。

无UI程序结构

无UI程序是指程序中不包含可视化界面内容的程序,这种程序写好后,烧录到单片机中即可运行,一般无屏幕连接、也无需展示画面。

例如常见的:距离测绘、温湿度监控、继电器控制等等。

轻语言单片机程序默认工程即为无UI程序。

在单片机程序中,App.spl 入口文件为保留文件、目前的版本不会参加编译工作。

核心文件

在轻语言单片机项目中 主程序.spl 为程序核心文件,是启动文件、也是实现功能的核心文件,该文件中含有一个事件和一个函数,文件代码基础结构为:

事件 程序被启动()
	初始化串口通信(115200)
    调试输出("程序被启动")

结束 事件

函数 无限循环()
    
结束 函数
  • 程序被启动

    • 该事件为程序入口函数,等同于 Arduino 程序中的 setup 函数,当程序编译成功并被写入到连接的开发板闪存时;ESP32 自带的操作系统 FreeRTOS 将会启动本程序、并同时回调该事件;您可以在此事件中初始化程序相关配置并开始实现自己的业务逻辑和程序功能。
  • 无限循环

    • 该函数当程序启动后,将开始连续循环执行,等同于 Arduino 程序中的 loop 函数,一般在该函数中实时检测传感器返回的数据。

注意事项

程序被启动、无限循环 这两函数不能被删除,必须存在,就算代码中用不到也不能删除,否则会编译报错。

编译、下载与烧录

本文将为大家介绍写好程序后、如何编译程序、并将程序下载(烧录)到开发板中。

环境配置

编译前请先配置环境,注意:如果更换电脑、更换安装包路径,重新下载解压安装 都需要重新部署环境。

环境配置:环境搭建

流程与步骤

  1. 编写程序代码

  2. 将开发板与电脑连接

  3. 打开项目工程配置;选择目标平台(芯片类型)与开发板。

  4. 选择COM端口;注意:要先连接开发板;再打开配置窗口才会显示COM端口

  5. 点击确定。

  6. 点击软件工具栏运行小图标(绿色的向右小三角形)也可以点击菜单 项目 - 运行;也可以直接按F5快捷键。

  7. 等待编译;第一次编译稍慢。

  8. 如果未发生任何错误、且提示编译成功;程序也成功下载到开发板中。

那么恭喜你;你成功的使用 VcnStudio 编写了一个嵌入式程序。

编译错误问题

由于目前轻舟单片机使用的相关编译器以及链接工具为乐鑫官方提供的编译器;但这些编译器都不支持 Unicode 字符以及中文、汉字作为变量或标识符;因此目前在编译输出阶段、所有的变量与标识符名称都会输出为随机字符串。

当编译发生错误时;相关的变量名、函数名也都将变成随机字符串;因此这个问题目前是正常的;在后期我们将逐步进行优化。

单片机类库封装

轻语言单片机的类库与 Arduino Library 结构基本一致,封装前需要您掌握基础的 C/C++ 编程知识。

内置类库参考

安装包里面已经内置了常用传感器的扩展库,路径位于:

VcnStudio安装目录/sdk/mcu/components/esp32

上方路径指向的文件夹中,每个子文件夹表示一个独立类库。

每个类库的文件夹结构都是相同的,具体含义请参考下方结构说明。

类库结构

轻语言单片机类库采用 文件夹/文件 结构,非独立类库文件,因为方便修改类库源代码、测试,轻语言类库文件结构为:

类库名称文件夹/
├── static/
│   ├── libs/
│   └── └── C|C++|Arduino类库
└── libtree.xml
  • static

    • 静态资源文件夹、在该文件夹中含有一个 libs 文件夹, libs 文件夹中存放封装好的 C 或 Arduino 标准库。

    • 该文件夹中目前不能储存其它数据,只能在libs中存放原始C/C++库。

  • libtree.xml

    • 类库配置文件,该文件用于配置类库的名称、描述、以及类库组件的函数。

配置文件 libtree.xml 详解

轻语言单片机类库封装的本质是将原生 Arduino 库或 C++ 写的库翻译成中文。

因此如果您已经有了一个 Arduino 的库,那么只需要在配置文件中添加其中文函数即可,如果没有 Arduino 库需要先将需要的功能或者传感器代码封装成 Arduino 库。

以安装包内置的 DHT22 温湿度传感器库为例,该库中的配置文档内容为:

<?xml version="1.0" encoding="utf-8"?>
<package>
  <library 
    name="DHT22" 
    author="官方" 
    package="" 
    description="‌DHT22温度传感器是一种结合了温度和湿度测量功能的数字传感器,广泛用于各种环境监测和控制系统中。‌ 它通过数字信号输出测量结果,具有高精度、快速响应和稳定性,适用于物联网应用‌。" 
    type="component">
    <component 
        name="DHT22" 
        en="DHT22"
        include="DHT22.h" 
        comment="本库封装自开源库 https://github.com/dvarrel/DHT22 可用于在单片机中读取基于DHT22系列的温湿度传感器相关数据。">
            <construct name="DHT22" args="(数据引脚 为 整数型)" comment="使用指定的接收数据的引脚构造一个DHT22对象。" />
            <method name="取原始数据值" en="getRawData" args="()" return="整数型" comment="获取传感器原始数据(40位)。返回类型:uint64_t 类型的变量,包含40位的原始数据。" />
            <method name="取原始文本数据值" en="getRawStrData" args="()" return="文本型" comment="获取传感器原始数据(40位)并转换为字符串;包含40位的原始数据,并在左侧补零。" />
            <method name="取湿度百分比" en="getHumidity" args="()" return="单精度小数" comment="获取湿度百分比(%rH)、单位为百分比(%rH)。" />
            <method name="取温度" en="getTemperature" args="()" return="单精度小数" comment="获取温度值、单位为摄氏度(°C)。" />
            <method name="取错误代码" en="getLastError" args="()" return="整数型" comment="获取上次读取传感器时的错误代码。" />
            <method name="取调试信息" en="debug" args="()" return="文本型" comment="获取调试信息,包括定时信息、40位数据和计算值。" />
    </component>
  </library>
</package>

上方文档中,library 节点中的属性含义分别为:

  • name 表示类库名称

  • author 表示类库作者

  • package 单片机暂时不需要设置包名,但需要保留设置为空

  • description 描述类库的功能

  • type 类库类型,默认为:component 不可视组件、后期可能会支持可视组件。

library 节点中存放当前类库中的组件,可以含有多个组件:

组件节点(不可视)必须使用 component 标签名,component 节点中的属性含义为:

  • name 组件名称

  • en 组件对应的原生英文名称

  • include 使用这个组件时需要导入的头文件

  • comment 组件注释、描述

component 节点即表示一个组件,其子节点表示组件的方法和构造函数,componen 节点中支持的标签有:

  • construct 表示构造函数

    • name 构造函数名称,必须为原生类构造函数

    • args 表示构造函数参数

    • comment 构造函数注释

  • method 表示函数方法

    • name 函数名称

    • en 函数对应英文名称

    • args 函数参数

    • return 函数返回值

    • comment 函数注释说明

核心封装逻辑

将英文版本的库翻译成中文,核心逻辑是通过在配置文件中配置 component、 method 等节点实现将原库中使用 public 修饰的英文函数翻译成中文。

#ifndef _DHT22_H
#define _DHT22_H
#include "Arduino.h"

class DHT22{
  public:
    enum error{
            OK,
            ERR_TIMING_80,
            ERR_TIMING_50,
            ERR_TIMING_BITS,
            ERR_CRC
          };
  private:
    uint8_t _pinData;
    uint32_t _timer;
    uint64_t _rawData;
    uint16_t _h16bits;
    uint16_t _t16bits;
    uint8_t _crc8bits;
    uint8_t _timing80L = 80;
    uint8_t _timing80H = 80;
    uint8_t _timing50 = 50;
    uint8_t _timingBit0 = 27; //specs for AM2303
    uint8_t _timingBit1 = 70; //specs for AM2303
    bool _firstStart=true;
    error _lastError;

    const uint8_t T = 30;
    const uint16_t cSamplingTime = 2100; // ms : dht22 sampling rate ~0.5Hz

  public:
    DHT22(uint8_t pinData){
      _pinData = pinData;
    };

    /** @return 40bits of data sensor : h16 + t16 + crc8**/
    uint64_t getRawData();

    /** @return 40bits in a String ("0" left include)**/
    String getRawStrData();

    /** @return humidity %rH **/
    float getHumidity();

    /** @return temperature in °C **/
    float getTemperature();

    /** @return code from last readSensor() request **/
      uint8_t getLastError();

    /** @return String with timings, 40bits, and calculate values**/
    String debug();

  private:
    /** @brief measure timings of sensor*/
    void measureTimings();

    /**
    *@brief read the 40bits sensor data
    *@return 0 if no error, num of error instead
    */
    uint8_t readSensor();

    /** @brief compute checksum of h & t data
     * @return true if checksum==crc**/
    bool computeCRC();
};
#endif

上方代码中 public 修饰的函数即为我们要封装翻译成中文的函数。

例如构造函数:

DHT22(uint8_t pinData){
  _pinData = pinData;
};

对应的配置节点为:

<construct name="DHT22" args="(数据引脚 为 整数型)" comment="使用指定的接收数据的引脚构造一个DHT22对象。" />

其它函数:

 /** @return 40bits of data sensor : h16 + t16 + crc8**/
 uint64_t getRawData();

对应配置节点为:

<method name="取原始数据值" en="getRawData" args="()" return="整数型" comment="获取传感器原始数据(40位)。返回类型:uint64_t 类型的变量,包含40位的原始数据。" />

构造函数节点中,name 属性值为 英文类名。

函数节点中,name 属性值为中文函数名,en 为对应的英文函数名称。

注意事项

大多数情况下,文件名与库中的类名应该是一致的。

如果类名与文件名称不一致,那么 component 节点中的 en 属性的值应该设置为类名。

同时 component 中的 construct 节点的构造函数 name 属性也必须设置为类名。

小程序工程项目结构

轻语言小程序采用微信小程序官方框架进行封装,标准的轻语言小程序项目结构为:

  • layout 存放界面设计文件

  • src 存放窗口页面逻辑、模块代码文件

  • static 存放静态资源文件

  • App.spl 应用入口文件

  • Config.xml 小程序配置文件

  • *.vsln 项目索引文件

  • _build 项目编译输出文

layout

在该文件夹中主要存放应用的界面可视化设计文件、文件格式为".xml"。

src

该文件中主要存放窗口页面逻辑及模块代码文件。

static

在该文件夹中主要存放图片、或者其他静态文件。

App.spl

该文件为应用的启动入口文件、当应用每次重新打开、或启动的时候、都会先执行该文件、开发者可以在该文件中添加初始化相关代码。

Config.xml

应用配置文件、该文件用于配置整个站点或小程序的样式、颜色、主题、首页、以及底部导航框。

项目配置与导航栏设置

小程序项目的配置由项目根目录中的 Config.xml 文件进行管理。

该文件属于XML编写的文本文件,可以使用任意编辑器打开编辑。

以下将分别对该文件中的相关节点进行说明:

  • 首页

    • value : 设置应用首页窗口名称、即应用第一次打开的页面、例如:你的项目有多个页面、需要将 home.sim 这个代码页设置为首页、则设置value的值为“home”即可、注意名称不能有后缀名。
  • 全局页面样式

    • 该节点下方的配置主要影响应用的颜色、风格、以及主题、如果无需特别设置、建议采用默认配置即可、关于每个节点的详细说明请参考:官方文档 全局配置 | 微信开放文档
  • 底部导航栏

    • show : 设置是否展示底部导航栏、如果设置为“false”则在编译时将会忽略该项、设置为“true”时、如果配置了页面列表、且列表数量大于2、小于6的时候将会显示应用底部导航。(true:真、false:假)

    • 基础配置:设置选项卡标题颜色、背景颜色等等。

    • 页面列表:配置底部选项卡的对应页面、其中的子节点属性为:

      • text:选项卡标题、例如:首页
      • pagePath:页面路径(名称)、例如:home
      • iconPath:图标路径、设置默认显示时的图标路径、例如:static/home.png
      • selectedIconPath:选中时图标路径、设置选中时(点击后)显示的图标路径、例如:static/home_ac.png

注:暂不支持在配置文件中直接添加自定义配置项、如要添加自定义配置、可以编译输出为友好源代码后再添加。

程序入口文件

小程序入口文件为项目中的 App.spl 文件,当小程序第一次打开或每次重新打开时、系统都会先执行该文件、并回调相关事件、你可以在该文件中做一些程序的初始化工作;但需注意在该文件内、不能定义任何静态变量、页面变量或静态函数、仅可以根据相关事件初始化程序。

文件结构

入口文件中有四个系统回调事件,默认文件代码为:

事件 程序被启动()
    
结束 事件

事件 应用被显示()
    
结束 事件

事件 应用被隐藏()
    
结束 事件

事件 应用发生错误()
    
结束 事件
  • 程序被启动

    • 当小程序被启动时,回调该事件。
  • 程序被显示

    • 当小程序渲染完毕时,回调该事件。
  • 应用被隐藏

    • 当小程序被隐藏(手机回到系统桌面)时回到该事件。
  • 应用发生错误

    • 当小程序发生错误时触发该事件。

静态资源的使用

微信小程序中的所有图片、文本或其它资源文件都必须存放在项目根目录中的 static 文件夹中。

在页面代码中使用时,需带上 ../../static/ 前缀。

示例:

图片框1.图片 = "../../static/head.jpg"
列表框1.添加项目("../../static/ico_group.png","文本内容")

为什么需要使用 ../../static/ 前缀

因为当轻语言小程序项目编译为微信原生小程序工程项目时。

页面文件与资源文件不在一个文件夹中。

因此如果要在页面中正常使用静态资源文件夹中的文件,就必须使用相对路径。

窗口与程序集

微信小程序中窗口即表示小程序中的每个页面。

程序集是包含窗口与模块文件的总称。

由于微信小程序官方限制、小程序窗口不支持使用中文。

目前正在优化解决这一问题。

布局与界面设计

请参考相关视频教程:

微信小程序基础开发教程

访问网络请求

在微信小程序中访问网络请求,一般为 POST/GET 请求协议。

代码示例:

事件 按钮1.被单击(事件源)
    变量 url = "https://www.ipip5.com/today/api.php?type=txt"
    ' 参数一为发送请求的标记、可通过该标记在回调函数中区分是那一个请求
    取网页源码("get1",url,"",5000,发送请求完毕)
结束 事件

事件 按钮2.被单击(事件源)
    ' 由于临时没有可用的post演示、这里使用ip5的地址模拟
    变量 url = "https://www.ipip5.com/today/api.php?type=txt"
    ' 这里待发送的POST数据必须为对象
    变量 data = { key:"vcnstudio",sign:"simple" }
    ' 设置请求头;默认为 application/x-www-form-urlencoded
    变量 header = { "content-type" : "application/x-www-form-urlencoded" }
    ' 开始发送请求
    发送POST数据("post1",url,data,header,5000,发送请求完毕)
结束 事件

' 该回调函数由我们自定义命名;但参数需与“取网页源码”函数注释中的
' 回调函数一致
函数 发送请求完毕(标记,结果)
    ' 在实际开发时、可先将获取到的数据在控制台中打印输出
    调试输出("标记:" + 标记)
    调试输出(结果)
    如果(标记 == "get1")
        标签1.标题 = "取到的GET结果:\n" + 结果.data
    否则 如果(标记 == "post1")
        标签1.标题 = "发送的POST结果:\n" + 结果.data
    结束 如果
结束 函数

注意事项

  1. 由于微信小程序官方规定;在小程序上线、发布时,代码中所有发生的请求域名,都必须在管理后台配置且必须为 https 协议。

  2. 在开发阶段将项目导入到微信小程序官方开发IDE中时、可在IDE右上角“详情”菜单中、本地设置选项中将“不校验合法域名...及HTTPS证书”勾选上;勾选该选项后、可在本地发送请求。

额外语法特性

由于微信小程序底层语言为 JavaScript ,因此在使用轻语言开发微信小程序时的语法与轻语言标准语法略有不同。

以下为详细不同点:

变量

小程序中的变量在声明时,无变量类型,定义格式为:

变量 标识符 
变量 标识符 = 初始值
变量 标识符1,标识符2 = 初始值

代码示例:

变量 时钟ID
变量 a,b,c
变量 x = 0
变量 x,y = 0

数组

小程序的数组声明与变量类似、只是在设置默认值时、需要使用“[]”中括号包裹值;如果没有任何值、则表示为一个空数组、格式为:

变量 变量名 = [ 初始值 ]
变量 变量名 = []

代码示例:

变量 a = [ "vcn","studio" ]  '定义一个含有文本初始值的数组
变量 b = [ 1,2,3 ]  '定义一个含有整数数据初始值的数组
变量 c = []  '定义一个没有任何数据的空数组

注意:数组下标从 0 开始

对象

定义对象与定义数组类似、只是默认值换成了 “{ }”花括号、使用花括号即可定义一个对象实例、与 JSON 中的对象基本一致。

代码示例:

' 定义一个用户对象
变量 用户1 = { 名称: "vcnstudio",年龄:12,班级:10}
' 获取或输出字段值
调试输出("用户1的名称为:" + 用户1.名称)

函数参数

小程序中由于没有数据类型的概念,因此函数中的参数也没有类型,在定义函数时,函数中的参数不需要指定数据类型。

代码示例:

' 无返回值函数
函数 函数名称(参数1,参数2)

结束 函数

'有返回值函数
函数 函数名称(参数1,参数2)
	返回 参数1 + 参数2
结束 函数

模块

微信小程序只支持包含使用静态修饰符,修饰的静态变量或静态函数的模块。

代码示例:

静态 变量 全局变量URL = "http://www.vcnstudio.com"

静态 函数 全局公用函数(参数一,参数二)
	返回 参数一 + 参数二
结束 函数

动态创建组件

微信小程序中不支持动态创建可视组件,仅支持创建不可视组件。

部署调试、发布项目

小程序最终编译输出的为基于官方开发框架的项目工程源代码、因此如果要发布小程序、或预览、调试相关功能、需要将项目加载并部署到官方开发工具中。在阅读本文档之前、你需要先下载微信小程序 官方开发工具 (请下载稳定版) 具体步骤如下:

视频教程:微信小程序基础视频教程

步骤与流程

1.安装微信官方小程序开发工具

安装方式较简单、下载安装包文件后双击点开、然后选择下一步、下一步即可;这里不做详细说明;但需要注意:默认会把程序安装在C盘、如果您不想装在C盘、记得修改路径。

2.打开小程序官方开发工具并新建项目

打开后的界面如果工具版本类似或者正常情况下;应该是如下图所示、然后点击新建项目。

3.新建项目

新建项目时注意、请选择不使用云服务、不使用模板、然后选择我们项目的 _build 文件夹目录(如果没有请先编译一次项目)、然后输入项目名称、点击测试号、获取APPid、然后点击确定。

4.加载项目

点击确定之后、根据电脑设备的配置和性能不一样、初始化项目、要等待10-30秒、当在小程序开发工具中能够正常看到渲染界面的时候、则说明项目已经添加成功、可以开始进行开发工作。

注意事项

  • 加载之后在控制台输出红色错误信息

    • 解决方案:如果是新建的项目编译后导入报错、请在官方QQ群或论坛反馈;如果是已经进行过开发工作的项目编译后产生红色报错信息、请先根据报错详情、检查代码;如果无法解决、请在QQ群或论坛向我们反馈。
  • 打开IDE之后提示需要登录账号

    • 属于正常情况、点击左上角图标扫描二维码登录即可。
  • 提示JS或库文件未被使用

    • 由于一个小程序不能超过2M、因此为了节省应用包体积、任何没有用到的文件或者代码都必须删除掉、遇到这种情况时、只需要根据提示删除指定的文件即可、注意:如果是你新建了一个模块文件、但是在代码中没有用到、请先备份模块文件再删除。
  • 其他未知问题

    • 请到QQ群或官方论坛反馈。

小程序类库封装

组件的复用在软件开发中有着非常重要的作用、在本文、我们将介绍、怎样从0开始自己动手封装一个微信小程序的可视化组件;在学习本章教程之前、您需要先掌握或持有基础的微信小程序开发或JS相关开发知识、一个基于微信小程序原生框架的前端组件主要由以下三个部分组成:

  • 界面模板<template>

  • JS代码<script>

  • CSS效果<style>

注:在 VcnStudio 安装包中已自带大量基础组件;可参考其基础组件进行封装;路径:VcnStudio安装目录/sdk/wxapp/components

界面模板

界面模板为在页面中显示的内容、由 HTML 代码组成、小程序组件界面代码都必须放在 template 标签中;且根组件必须设置 style 的值为“ {{customStyle}} ”变量。 例如:

<template>
    <view style="{{customStyle}}">
        <text>我是具体组件</text>
    </view>
</template>

JS代码

JS代码主要定义组件的属性、方法、事件、处理组件中的计算属性与界面模板的显示;在JS代码中、主要分为以下几个重要的部分:

  • 数据(data) 用于定义封装组件所属的特有功能或特点、例如:在一个文本类组件中、可以通过定义属性的方式设置该组件中的文本字体颜色、在可视化设计时则可以通过属性编辑框为组件设置、在代码中可以通过"组件名.属性名"的方式进行设置;属性支持以下5种类型值:

    • 文本型
    • 整数型(数值型)
    • 逻辑型
    • 数组
    • 对象(可视化设计时不可用)
  • 方法(methods) 用于定义组件的方法、在代码中使用、例如一个列表组件如果要想向列表框中添加项目、则可以定义一个“添加项目”的方法、用户在代码中通过"组件对象.添加项目"即可向列表框中添加数据。

  • 事件 用于定义组件的回调事件、例如一个列表框组件、当用户点击项目时、要回调点击事件告诉开发者、分发事件需要使用“triggerEvent”方法。

以下为一个简单的组件代码示例:

<script>
    const sview = require("../sview")
    Component({
        behaviors:[sview],
        data:{
           mTitle:""
        },
        methods:{
           置标题(mTitle){ this.setData({mTitle:mTitle}); },
           取标题(){ return this.data.mTitle; },
           disOnClick(e){
           this.triggerEvent("onClick",{e:e})
           },
        }
    })
</script>

上述代码讲解:

1.引入基础类组件(地址和名称固定)、所有可视组件都必须继承该组件。

const sview = require('../sview')

2.定义组件字段、继承、属性。

behaviors:固定用法、设置当前组件继承自 sview 即可。

data:组件的字段、用于接收属性方法的值。

methods: 定义组件的方法

3.定义属性

当在方法中定义了、含有“置”和“取”的前缀方法、如果名字一样、则表示为属性;否则为普通方法、例如上方代码中的标题、即为一个属性。

4.定义事件

定义事件时需要注意:由于事件需要先在 template 模板中注册、因此不能使用中文、且建议以 disOn 开头、后跟具体事件名称、例如:disOnClick 表示当组件被单击时触发该事件、然后通过“triggerEvent”函数分发出去;这个函数中有两个方法、第一个是这个组件在被使用时注册的事件名称(非类库封装开发者不需要了解)、第二个为事件传递出去的参数对象、例如:这里传出去的为“e”也就是原事件源、如果你还需要传出其它参数、添加再添加一个字段及值即可。但需要注意的是:在编写 xml 节点树的时候、需要指定 disargs 属性。默认为 disargs="(e)"

methods:{
    disOnClick(e){
        this.triggerEvent('onClick',{e:e})
    }
}

CSS效果

CSS 即为渲染界面的 style 样式代码、通过编写 style 样式、可以渲染出不同的界面或布局、微信小程序开发框架支持所有H5的 style 、因此较简单这里不详细说明、示例代码:

<style>
    .border-style{
        border: #007AFF 1px solid;
    }
</style>