在Flex中实现自定义的Caret

本文介绍了一种在Flex中实现Caret(光标)闪烁效果的方法,通过使用Timer类并结合系统时间来精确控制Caret的状态切换,解决了常规Timer触发事件不准确的问题。
部署运行你感兴趣的模型镜像
Flex中只有TextField组件实现了Caret,即插入位置的显示功能。最近研究Editor,自己实现了一个Caret类。

难点:如何按固有频率切换状态(显示--擦除)

大家知道Flex中,用Timer触发定期事件不准确,因此使用Timer处理Caret状态,自然也有类似问题。经试验确实存在此问题,需另寻途径。

还要回到Timer定时器上,如果我们定义一个间隔非常短的定时器,对系统时间进行轮询,有了系统时间,而且在极短的时间内如毫秒级,几乎可以认为是连续的“Thread”了。只要能记住第一次显示Caret的时间,就可以在擦除时刻或下一个显示时刻进行相应的操作。

最终效果不错。

代码如下:


package
{
import flash.events.TimerEvent;
import flash.utils.Timer;

import mx.core.UIComponent;

public class Caret extends UIComponent
{
private static var DELAY:uint = 700; //mileseconds
private static var PERIOD:uint = 1000; //mileseconds
private static var DELTA:uint = 20;
private var startTime:Date;

private var started:Boolean = false;

private var checkTimer:Timer = new Timer(1);
override public function Caret()
{
super();
createCaret();
}

private function createCaret():void{
draw();
checkTimer.addEventListener(TimerEvent.TIMER,checkTimer_handler);
checkTimer.start();
}


private function checkTimer_handler(event:TimerEvent):void{
var date:Date = new Date();
var elapsed:Number = (date.time-startTime.time)%PERIOD;
trace(elapsed);
if(elapsed>=(DELAY-DELTA) && elapsed<=DELAY){
this.graphics.clear();
trace("clear");
}
else if(elapsed>(PERIOD-DELTA) && elapsed<=PERIOD){
draw();
}
}

public function draw():void{
if(!started){
this.startTime = new Date();
started = true;
}
this.graphics.drawRect(10,30,2,20);
this.graphics.beginFill(0x000000);
trace("draw");
}
}
}


今天的研究结果表明,上述连续的Thread根本不可能保证,视代码而定。这部分内容属于高级内容。如有兴趣,请见http://www.bit-101.com/blog/?p=910。

您可能感兴趣的与本文相关的镜像

Wan2.2-T2V-A5B

Wan2.2-T2V-A5B

文生视频
Wan2.2

Wan2.2是由通义万相开源高效文本到视频生成模型,是有​50亿参数的轻量级视频生成模型,专为快速内容创作优化。支持480P视频生成,具备优秀的时序连贯性和运动推理能力

<think>我们正在讨论Flex中的yy_ec数组。根据Flex的工作原理,yy_ec是“等价类表”(Equivalence Class Table)的缩写,它在词法分析中起到关键作用,特别是在状态机压缩和效率优化方面。 ### 一、yy_ec的核心作用 1. **字符映射压缩** 将256个可能的输入字符(8位)映射到更小的**等价类编号**(通常0-255),从而减少状态转移表的大小[^1]。 - 例如:大小写字母可映射到同一等价类(当规则不区分大小写时) 2. **优化状态转移表** 状态转移表`yy_nxt`的维度从`[状态数][256]`压缩为`[状态数][等价类数]`,大幅减少内存占用。 3. **支持字符集抽象** 用户可通过`%option case-insensitive`等指令,由Flex自动生成合适的`yy_ec`映射。 ### 二、生成逻辑 Flex根据规则中的字符使用情况生成`yy_ec`: ```c static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, // 0-15 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 16-31 2, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18, // 32-47 19,19,19,19,19,19,19,19,19,19,20,21,22,23,24,25, // 48-63 26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27, // 64-79 27,27,27,27,27,27,27,27,27,27,27,28,29,30,31,32, // 80-95 33,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34, // 96-111 34,34,34,34,34,34,34,34,34,34,34,35,36,37,38, 1 // 112-127 // ... 剩余128-255通常映射为0或1(无效类) }; ``` - **映射规则**: - `0`:保留用于文件结束符`EOF` - `1`:默认无效字符(触发`REJECT`或错误) - `2`:换行符`\n` - `3`:回车符`\r` - `4`-`38`:根据规则出现的字符分组(如数字、字母、特定符号) ### 三、工作流程 1. **输入字符转换** 读取字符时,先通过`yy_ec`转换为等价类编号: ```c int c = *yy_c_buf_p; // 获取原始字符 int ec = yy_ec[c]; // 查表得到等价类 ``` 2. **状态转移** 使用等价类编号进行状态跳转: ```c yy_current_state = yy_nxt[yy_current_state][ec]; ``` ### 四、自定义调整 1. **大小写不敏感** 使用`%option case-insensitive`时,Flex会将`A-Z`和`a-z`映射到同一组等价类。 2. **手动修改(不推荐)** 可通过`%x`修改字符集,但需重新生成词法分析器: ```flex %% [a-z] { ... } // 隐式定义小写字母等价类 ``` ### 五、调试技巧 1. **查看生成代码** 检查`lex.yy.c`中的`yy_ec`数组,确认字符映射关系。 2. **使用`-v`选项** 生成`lex.yy.c`时添加`-v`,输出`.output`文件包含等价类详细信息: ```bash flex -v lexer.l ``` ### 六、典型问题解决 **场景:规则无法匹配特定字符** 1. 检查`yy_ec`中该字符的映射值: - 若为`0`或`1`,说明Flex未将其识别为有效字符 2. 解决方案: - 确保规则包含该字符(如`[+]`匹配`+`) - 使用转义符处理特殊字符(如`[\]]`匹配`]`) ### 七、性能影响 - **优势**:状态表内存占用减少$O(k \times n)$($k$为状态数,$n$从256降至等价类数) - **代价**:增加一次查表操作(现代CPU可忽略) ```mermaid graph TD A[输入字符] --> B[yy_ec查表] B --> C[得到等价类编号] C --> D[状态转移 yy_nxt] D --> E{接受状态?} E -->|是| F[执行规则] E -->|否| G[读取下一字符] ``` §§相关问题§§ 1. Flex如何生成状态转移表`yy_nxt`? 2. 如何优化Flex词法分析器的内存占用? 3. 在Flex中如何处理Unicode字符集? 4. 等价类压缩技术的数学原理是什么?</think>### Flex中`yy_ec`的作用及使用方法 `yy_ec`(等价类表)是Flex生成的词法分析器中用于**字符分类优化的核心数据结构**。它通过将输入字符映射到更小的等价类编号,大幅压缩状态转移表的大小,提升词法分析效率。以下是详细解析: --- #### 一、核心作用 1. **字符分类压缩** 将256个可能的ASCII字符(0-255)映射到更小的**等价类编号**(通常少于50个): ```c static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, // 等价类映射 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18, 19,19,19,19,19,19,19,19,19,19,20,21,22,23,24,25, 26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27, 27,27,27,27,27,27,27,27,27,27,27,28,29,30,31,32, 33,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34, 34,34,34,34,34,34,34,34,34,34,34,35,36,37,38, 1 }; ``` - **示例**:所有数字字符`0-9`可能映射到同一个等价类编号19 2. **状态表压缩** 状态转移表`yy_nxt`的维度从$[状态数] \times 256$压缩为$[状态数] \times [等价类数]$,内存占用减少60%-90%[^1]。 3. **性能优化** 减少缓存未命中率,加速状态转移查询: ```c // 原始查询(未压缩) next_state = yy_nxt[state][raw_char]; // 使用yy_ec优化后 ec = yy_ec[raw_char]; // 先映射到等价类 next_state = yy_nxt[state][ec]; // 再用等价类查询 ``` --- #### 二、生成逻辑 Flex根据词法规则自动生成`yy_ec`: 1. **字符分组** 将词法规则中行为相同的字符归为一组: - 示例规则:`[0-9]+`(数字)和`[a-z]+`(小写字母) - 结果:所有数字分配到等价类A,小写字母分配到等价类B 2. **特殊字符处理** - `EOF`固定映射为0 - 未出现的字符映射为1(无效类) - 换行符`\n`通常单独映射(如类2) 3. **大小写敏感控制** 当使用`%option case-insensitive`时,`A-Z`和`a-z`会映射到同一组等价类。 --- #### 三、工作流程 ```mermaid graph LR A[输入字符] --> B[查yy_ec表] B --> C[获得等价类编号] C --> D[用等价类查yy_nxt] D --> E[得到新状态] E --> F{是否接受状态?} F -->|是| G[执行规则动作] F -->|否| H[继续读取字符] ``` --- #### 四、调试与优化 1. **查看等价类分配** 编译时添加`-v`选项生成`.output`文件: ```bash flex -v lexer.l ``` 文件包含类似内容: ``` Equivalence classes: 0 = EOF 1 = all other chars 2 = '\n' 19 = [0-9] 27 = [A-Z] 34 = [a-z] ``` 2. **性能问题定位** 若某些字符匹配缓慢: - 检查`.output`中该字符的等价类分配 - 确认是否被错误归入"其他字符"类(值1) 3. **手动干预(高级)** 可通过`%x`指令强制字符分组(不推荐): ```flex %x SPECIAL_CHARS %% [@#$] { BEGIN(SPECIAL_CHARS); } // 自定义分组 ``` --- #### 五、典型问题解决 **场景:规则`[a-z]+`无法匹配大写字母** 原因:默认大小写敏感 解决方案: 1. 启用不敏感选项: ```flex %option case-insensitive ``` 2. 或显式扩展规则: ```flex [a-zA-Z]+ { /* 动作 */ } ``` **场景:特殊字符未识别** 检查步骤: 1. 确认规则包含该字符(如`[\^]`匹配`^`) 2. 查看`.output`文件确认其等价类非1 3. 若需单独处理,添加专属规则: ```flex \^ { return CARET; } ``` --- #### 六、数学原理 设字符集大小为$C$(256),实际有效类数为$E$,则: - 状态表压缩比:$\frac{C}{E}$ - 当$E \ll C$时(如$E=40$),压缩比达6.4倍 - 状态查询时间复杂度:$O(1)$(两次数组访问) ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值