Sciter教程_03_分析ulayered例程

本文详细介绍了SciterSDK的ulayered示例,涉及C++代码中如何通过分层窗口实现透明度和自定义UI,以及如何将C++函数注册到TIScript脚本中。教程还涵盖了HTML/CSS和TIScript的使用,以及如何通过SciterAPI和脚本控制窗口和元素行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Sciter教程系列-03 分析sdk/demos/ulayered例程

本例程用分层窗口的方式渲染了一个挂钟,分层窗口(Layered Windows)简单说就是支持透明度的窗口。分层窗口可以实现任意形状的窗口,例程中将涉及BEGIN_FUNCTION_MAP/END_FUNCTION_MAP注册C++函数、元素行为、弹性布局、自定义UI等方面的内容。

编译demos/ulayered例程

将文件sdk/demos/ulayered/ulayered.cppsdk/include/sciter-win-main.cpp拷贝到解决方案下的src/文件夹,在VS中移除筛选器src下的所有文件,然后添加这两个文件。拷贝sdk/demos/ulayered/res/文件夹,覆盖解决方案下的res文件夹。

如下图所示,更改项目的部分配置。首先在属性页的"常规–输出目录/中键目录"将值分别改为$(SolutionDir)bin\$(SolutionDir)obj\,前者将生成的执行文件输出到解决方案下的bin目录,后者将生成过程的中间文件输出到obj目录,方便管理生成的文件,当然,这里只是说明可以这么改。然后单击属性页的配置管理器,将活动解决方案中配置和平台的Debug/Win32删除,也就是只留下Release/x64这一组配置,同样,将项目中的其他配置/平台也删除,接着将sdk/bin.win/x64/sciter.dll拷贝到解决方案下的bin目录。注意:如果VS中解决方案平台的位数和sciter.dll的位数对不上,运行会报错返回0xFFFFFFFF。
在这里插入图片描述

运行打包脚本,在VS中编译C++代码并运行,结果如下图所示。

在这里插入图片描述

分析C++代码

在frame类的实现中,指定了窗口启用Alpha通道以及毛玻璃效果,同时将成员函数注册到脚本。

宏定义BEGIN/END_FUNCTION_MAP

这对宏定义标示需要注册到脚本的成员函数,宏定义FUNCTION_0的含义是将参数数量为0的成员函数architecture注册到脚本,在脚本中可以通过view.architecture();语句调用到C++中该成员函数。

frame() : window( SW_MAIN | SW_ENABLE_DEBUG | SW_ALPHA | SW_GLASSY, wrc) {}

BEGIN_FUNCTION_MAP
  FUNCTION_0("architecture", architecture);
END_FUNCTION_MAP

类frame间接继承于类event_handler_raw,此父类具有虚函数on_script_call,当TIScript脚本通过view.func()调用C++函数时,会调用函数on_script_call进行命令的分发。而上述将C++函数注册到脚本的宏展开之后其实就是在子类frame中重写了虚函数,函数体不同的分支构成注册函数查询表,脚本调用C++函数时on_script_call通过这个查询表就可以调用对应的注册函数。

分析HTML/CSS代码

关于html标签这里有几个要注意的写法。

  • #name,相当于<tag id="name" />
  • .name,相当于<tag class="name" />
  • |name,相当于<tag type="name" />
  • (somename),相当于<tag name="somename" />

样式表中有两点需要关注。

  • prototype: Clock url(analog-clock.tis);。表示body这个元素要继承自Clock类,该类定义在analog-clock.tis中。Clock类组件,也叫做行为,包含绘制挂钟的脚本代码,通过prototype的将行为绑定到元素上,这些元素将会按照行为的规则去显示;
  • margin:*;。这为元素定义了可变的外边距,就像是在元素的四周放置了四个弹簧一样,弹簧的存在将元素固定在所在容器的中心。如下图所示。

在这里插入图片描述

分析TIS代码

sciter使用的脚本是TIScript,要读懂这种脚本代码,需要借助官方的帮助文档,这里使用中文手册进行演示,关于中文手册,见系列教程02。

1.内联脚本

在html文件中<script type="text/tiscript">...</script>之间的脚本为内联脚本。

const body = $(body);

self.ready = function() // html loaded - DOM ready
{
    view.caption = "Sciter Clock";

    // positioning the window in the middle of the screen:
    var (sx,sy,sw,sh) = view.screenBox(#workarea,#rectw); // gettting screen/monitor size
    var (w,h) = self.$(body).box(#dimension); 
    w += w/2; h += h/2; // to accomodate expanding animation
    
    view.move( sx + (sw - w) / 2, sy + (sh - h) / 2, w, h);

    body.timer(40ms, function() { body.attributes.addClass("shown") });
    $(span#platform).text = System.PLATFORM;
    $(span#arch).text = view.architecture(); // calling native function defined in ulayered.cpp
}

上述脚本代码出现的一些语法以及方法说明如下。

  • $(body),取到<body></body>这个元素,类似的还有$(span#platform).text,含义为取到id为platform的span元素的text文本;
  • self.ready,html元素的事件,文档加载的最后一步生成该事件;
  • view.caption,view对象的属性,view是当前运行脚本的视图对象;
  • view.screenBox(),view对象的方法;
  • body.timer(),元素对象的方法;

这里以view对象举例,介绍在帮助文档中定位属性或者方法的流程。如下图所示,打开帮助文档,在左侧选项卡中打开Sciter DOM类,定位到其下的视图对象,在右侧的方法列表中找到screenBox方法,中间的视图即定位到该方法的详细描述。同样,也能找到caption属性的描述,不过文档里叫做windowCaption,实测二者没区别。另外视图对象用view/View貌似也没区别。

在这里插入图片描述

关于按钮等页面元素事件响应,写法如下。

event click $(#close)
{
    body.timer(600ms, () => view.close() );
    body.attributes.removeClass("shown");
}

这种写法叫做符号事件名称,通过event "name" (evt) {}来使用,name就是对应的符号事件名称,click这个符号事件是按钮和超链接点击。更多的符号事件名称可查看帮助手册Sciter DOM类中事件对象下的符号事件名称。

2.外联脚本

通过<script type="text/tiscript">include "xxx.tis";</script>或者url(xxx.tis)的方式指定的位于其他文件内的脚本叫做外联脚本。

class Clock: Behavior 
{
  function attached() { 
    this.paintForeground = this.drawclock; // attaching draw handler to paintForeground layer
    this.timer(300,::this.refresh());
    
    this.borderWidth = this.style["border-width"] || 3;
    this.borderColor = this.style["border-color"] || color("brown");
  }

  function drawclock(gfx)
  {
  }
}

上述脚本代码展示了利用行为(Behavior)类扩展DOM元素的一种自定义UI组件的方式,这个类可以定义新的属性、方法和事件处理器,通过使用CSS中的prototype属性或者在代码中手动修改已存在DOM元素的prototype属性将该行为绑定到DOM元素。

selector {
    prototype: ClassName url(file.tis);
    /* ... 其他CSS属性 */
}

以下代码是声明式行为赋值。

  • selector是一个有效的CSS选择器;
  • ClassName是脚本类的名称;
  • url(file.tis)是包含该脚本类的脚本文件的url。如果脚本类是定义在文档本身的script节中的话,这个字段是可省略的。

Behavior是一个从Element类或其他行为类派生的类。下面是一个行为类的模板:

class MyWidget : Element
{
   // 实例变量, 每个元素将拥有这些变量的一份副本。
   this var foo = "foo";
   ...
   // 类变量, 所有实例共享这个类的这些变量
   var bar = "bar";
   ...

   // 生命周期方法:

   // behavior的"constructor", 当元素获取到该类时被调用
   function attached() { /* this 指代该元素 */ }

   // behavior的"destructor", 当元素失去该类时被调用
   function detached() { /* this指代该元素 */ }

   // 虚拟(virtual)属性
   property baz(v) { ... }
   // 和方法
   function boo() { ... }

   // 事件处理器:
   
   // 点击事件
   event click (evt, that) { /* 注意: this指代生成click事件的元素
                                that为订阅元素 - 一个MyWidget类的实例 */ }

   // 在 <a class="next">元素上的点击事件
   event click $(a.next) (evt, that) { ... /* 注意: this指代a.next元素,即生成click事件的元素 */  }
   ...
}

注意,所有的方法、事件处理器和属性在运行期被调用时,this变量被设置为该行为类绑定的元素实例上。

在例程中,analog-clock.tis通过body.paintForeground属性调用了行为类的自定义绘制函数,该函数是一个参数为gfx对象(全局对象)的脚本函数,通过该对象可以实现图像、文本的绘制。有关绘图对象的信息可查看帮助手册Sciter DOM类中绘图对象。

总结

通过ulayered这个例程,分析了C++注册函数到脚本的原理,演示了如何通过帮助手册定位信息,这给理解脚本代码提供了一个可行的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值