@TOC
前言
一个流式渲染呈现的标记语言,就需要有能够控制渲染呈现流程的标签。
TinML中(以TinText1.4版本为例),控制渲染呈现流程的标签主要有<stop>, <part>, <wait>
,这三种标签分别对应以下流程控制:
-
暂停一段时间
-
划定一段内容,由读者决定是否显示并阅读
-
暂停渲染,等待读者确认继续阅读
为了使整个程序不会因为渲染暂停而被阻塞,TinText的渲染操作在子线程中进行。
暂停一段时间
这个很简单,由<stop>
标签确定。
<stop>3
|-暂停三秒
在TinText中,由线程等待事件实现:
#t为暂停的时间,单位为秒
self.render_flag.clear()
self.render_flag.wait(t)
self.render_flag.set()
self.render_flag
的定义如下:
self.render_flag=threading.Event()#渲染线程标志
划定可选阅读内容
TinML允许划定可选的阅读内容,由读者选择是否进行渲染呈现并阅读。
比如:
<p>接下来将介绍TinText的各个组成部分
<pt>dev
<p>开发介绍。。。
</pt>dev
<pt>apps
<p>TinText由TinReader、TinWriter、TinMaker等组成
<pt>reader
<p>TinReader是TinText的阅读器
</pt>reader
<pt>writer
<p>TinWriter是TinText的编辑器
</pt>writer
<pt>maker
<p>TinMaker是TinText的加密与集成TIN文件生成器
</pt>maker
</pt>apps
|-......
在新版TinML规范中,可选呈现内容标签允许嵌套,如果上级内容未被选择阅读,则下级所有内容,包括下级可选呈现内容,均会被跳过,所以尽量不要半嵌套
这就划定了两大可选内容,第二个可选内容下又分三个可选内容,这些内容都可以允许读者选择是否阅读,同来减少不必要的阅读信息。
在TinText的实现中,会在阅读框底部询问是否进行阅读某一个内容。内部实现由内容块名称记录表完成。
class PartTag:
"""
TinText <part> <pt> </part> </pt>
"""
def __init__(self):
self.names={'':True}
def named(self,name):
if name in self.names:
return True
else:
return False
def edit(self,name,state:bool):
self.names[name]=state
def delete(self,name):
del self.names[name]
def check(self):
return self.names[tuple(self.names.keys())[-1]]
def now(self):
return tuple(self.names.keys())[-1]
def clear(self):
#删除除了''以外的所有值
self.names.clear()
self.names['']=True
具体记录实现:
ttpaf=TinTextPartAskFrame(self,name)
result=ttpaf.initial()
self.parttag.edit(name,result)
TinTextPartAskFrame
为TinText自身实现的询问对话框,result
为对话结果
每一个开头标签都会在TinText的内容名称表末尾添加一个元素,TinText对于接下来内容是否渲染的判定依据,就是名称表最后一个元素的值。
if not self.parttag.check():
#<part>未被允许阅读
if unit[1] not in ('</part>','</pt>'):
#不是<part>结束标签
continue
if unit[2] != self.parttag.now():
#不是当前忽略层级(名称)
continue
当碰到结束标签时(显然,必须是同一个名称,毕竟是否渲染就取决于当前名称内容),则在名称表中删除这个元素:
self.parttag.delete(name)
暂停渲染并等待
暂停渲染肯定不能退出渲染,然后再进去,这对一个流式呈现的内容是不合理,因为会丢失上文信息。好在,TinText子线程渲染能够实现线程的暂停。
另外,这个和是否继续阅读不同,这个不要求读者立刻做出决定,所以不适合锁死整个GUI,我们只是想让渲染线程停止。
先看一个TinML例子:
|-......
<p>这就是今天学的全部内容和总结,接下来会布置作业。
<wait>作业要求
<p>今天的作业是……
当TinText渲染器读到<wait>
时,会触发以下操作:
ttwf=TinTextWaitFrame(self,content)
ttwf.initial()
self.render_flag.clear()
self.render_flag.wait()
TinTextWaitFrame
用来显示“继续阅读”按钮
这样,我们就在这个线程里暂停了这个线程,那等读者按下继续阅读的按钮之后,又怎么恢复线程呢?
TinText的实现如下。
绑定恢复渲染的虚拟事件:
self.bind('<<ResumeRender>>', lambda e:self.resume_thread_render())
def resume_thread_render(self):
#恢复渲染
self.render_flag.set()
然后在TinTextWaitFrame
获得读者确定后触发TinText的<<ResumeRender>>
即可。