插件集合帖
foobar2000插件包v0.0.4
提问的规范和技巧,发问帖必看。
foobar2000插件兼容性与故障检测
Foobar20000.9.6.8增强版8.22new!
Beta版本汉化更新 0.9.6.5 B1
Foobar2000基础帮助中心
无损音乐资源共享
标题格式化和媒体库查询表达式帮助 Foobar2000 1.0.1 Final 汉化版发布 new! changelog升级日志与翻译0.9.5.4 b1-0.9.6.2

[FUI配置] 用FUI从头弄一个自己满意的Foobar2000 《Foobar2000集成实例讲义》

[ 29265 查看 / 313 回复 ]



本楼是茶话楼

提纲在下楼,正文从第三楼至第十一楼,附录也是正文。

几个时间点:2009.10.9起笔,2009.10.23完稿,2009.11.19定稿。

敬请各路朋友指正,以免误导读者。

谢谢!
_________________________________________________________________________________________________________

感谢gdzqj88等诸多朋友的一再建议性的意见

感谢梵音声处等许许多多朋友热情鼓励

感谢dreamawake等朋友的关心

感谢大家的支持

谢谢!

…………………………………………………………………………………………………………………………

12-02-2009 新设想:


 附件: 您所在的用户组无法下载或查看附件



提纲


前言


初级篇
第一章、我需要什么样的音频工具?
第二章、用什么来集成这个音频工具?
第三章、凡壳初步
第四章、规划
第五章、备料
第六章、起
1、建立窗体
2、加入面板
3、组织代码
第七章、调试
第八章、实地运行
第九章、改进
第十章、成品


中级篇
第十一章、浅谈Func之Bug
第十二章、浅谈Func之Animation
第十三章、浅谈Func之Pop-up menu
第十四章、浅谈Func之Map
第十五章、浅谈Func之Hash
第十六章、浅谈Func之Efficiency


高级篇
第十七章、浅议Func之一体化设计
第十八章、浅议Func之沟通
第十九章、浅议Func之功能再生


后语

最后编辑kmpfor 最后编辑于 2009-12-02 11:59:15
3

评分次数

    本主题由 管理员 Smoking 于 2009-10-19 21:47:53 执行 设置精华/取消 操作
    分享 转发
    TOP

    提纲(今天起笔,未定稿,欢迎批评指正

    一、我需要什么样的Foobar2000?
    二、用什么来集成Foobar2000?
    三、FUI初步
    四、规划
    五、备料
    六、起
    1、建立窗体
    2、加入面板
    3、组织代码
    七、调试
    八、实地运行
    九、改进
    十、成品:导出或者打包
    十一、附录(
    规划文档实例、
    插件选择(复杂的单独介绍)、
    FUI“零件”
    最后编辑kmpfor 最后编辑于 2009-10-09 14:20:34
    TOP

    前言


    第一句话,结束后才看到的:本讲义原只想写个FUI教程而已,写明FUI的特点特色、基本用法、注意事项这样的东西。没想到一起笔就失控。熬过十个几夜,一鼓作气以上百个业余工作日的精力换来的是一册出乎始料的讲义。此时,我不在乎叫教程或者叫讲义或者叫别的什么,反正当初的目的是达到了,FUI教程的内容是客观了。抽出FUI教程的方法是,将第三章FUI初步、第五章备料、第六章起、第七章调试这四章独立出来。这四章的内容已经可以构成完整的FUI教程,虽然还是以例析的形式。但,
    不论称教程叫讲义,其实,那都是狐假虎威的称谓,也有一点是为了方便阅读。实质上,应当只是一个比较完整的学习笔记而已。

    第二句话,回头想了想,为什么得以在Foobar2000中国社区发表?是因为切身感觉到Smoking是位暖人心窝的知心人,是因为这里活动有好多位良师益友。
    至于我的创作水平,恐怕会是半桶水偏要淌得狠。我的用意只不过是介绍Foobar2000的一种新鲜玩法,只不过希望共同催热FUI的应用而已。

    第三句话,也是这讲义的缘起。2009-10-9感言:
    无偿天天使用FUI已经半年多了,总感觉很对不起作者,很对不起Foobar2000。本人很土生土长的中国渔民,与FUI作者kandata没有丝毫亲戚关系。只是觉得这FUI就好像专门为本人而开发的,这k仿佛事先知晓本人的想法和意愿,一开始就把困扰我多年的难题一扫而光。然后,是功能上的一跃再跃。
    我先前的难题重点有:


    标题栏一定要去掉;
    一定要能全屏(不是最大化);
    图片显示一定要在支持底坐透明的同时支持通配符关联;
    一定要长文本支持,中文自动换行,可滚动;
    类触摸操作(地图化操作,不是按钮操作);
    媒体库可以借助通用数据库软件进行管理。

    带着这些问题,我跨越千山万水,四处寻师访友,始终找不到问题的出口。是FUI可怜见,才使问题全部完满解决。好像应当开心才对,但不知怎的,一时间感觉十分茫然,不知该往什么方向上再努力。
    所以,
    想,写一本FUI教程。不行,这好比BIFU(不会写,也可能念错了)撼大树。
    想,整理一些满意的FUI零件,不过好像旱了。
    可能不少人急于需要是一本中文说明书,可是,我完全不懂日文,翻不了。
    所以,就想,写一个专题,名字先叫《用FUI从头弄一个自己满意的Foobar2000》,不敢自称为教程,但一定象教程那样高度重视、谨慎对待、认真编排、相对完整、数据翔实、有插图、言简意赅、讲话先经过一下大脑。
    又想想,这个工程好像也好大哦!
    硬着头皮,做一头乳猪渡一趟沧海,做一只菜鸟飞一趟网络时空。



    《Foobar2000集成实例讲义》


    ——用FUI从头弄一个自己满意的Foobar2000


    提纲(见上楼)
    $if($and(%Title Formatting Syntax Reference%,%Query Syntax Help%),请从第三章FUI初步开始阅读,顺序阅读)

    一、我需要什么样的Foobar2000?
    Foobar2000是个优秀的音频播放、转换、管理工具,核心程序由Peter Pawlowski开发,功能组件由五湖四海的Foobar2000爱好者自愿开发。这种模块化的拼凑式给使用者一个自我实现的可能,让人一人一个Foobar2000,个个Foobar2000都不一样。同时这也给程序本身的广泛使用筑起一道门坎。这道门坎高高的,对一些人来说,它的高度已经高成一堵墙。
    然而,一旦入门,就将很难不被其中的功能丰富、使用适应个人习惯、外观符合个人审美取向等等所深深吸引,甚至从此欲罢不能。
    如今,错,一直以来,网络上活跃着一群热心人,他们热衷于软件DIY,从自己的需要和喜好出发改造程序,并重新整合、封装,发布,以另一种面貌流行在网络上。Foobar2000也不例外,它也被DIY着,也被打包着,而且它天生就是被DIY被打包的优良品种。
    如果刚要开始喜欢,各种打包版的Foobar2000正是入门的好途径。在五花八门中不妨优先考虑一下著名的版本,比如0.8.3时候的蓝色网际版,比如0.9.x当今的Asion版。
    当使用一段时间之后,可能发现这种通用版本不一定恰巧配合自己的口味和品味。这时,有一种“半包”版可能可以用来解解渴。这种半包版其实就是以一个配置文件为中心,集合了这个配置所需要的组件,共同形成一个配置包。这个配置包不能独立运行,它需要解压到Foobar2000程序中,经过一个导入动作和一些个或繁或简的设置动作,就能使Foobar2000以崭新的面目投入工作。半包版琳琅满目,绚烂多采,令人美不胜收。
    当可以独立应用半包版,说明自己已经对Foobar2000有相当的了解。这时,许多人难免想再深入一点,动动其中的参数选项,动动其中的代码,动动。
    所以,很可能已经阅读了Foobar2000自带的帮助文档,但是这个文档对初学者几乎没有什么实际的帮助,因为它通篇尽是在解释那些“标题格式语法”。所以,许多人可能就这样被迫地找到《Foobar2000中文全教程》,这是Jense老师的著作。它不但十分有益于初学者,对已经入门乃至资深用户同样不无裨益。
    此时,如果对那些“语法”依然非常不了解,建议详细阅读上述教程的高级篇。theo大侠翻译过查询语法《查询表达式参考》,就在Foobar2000中文Wiki里,请一道学习一下。
    有了这个基础,往下探讨才不会浪费时间。
    我需要什么样的Foobar2000?这一刻我们的正确答案是:当手上现成的Foobar2000不象我内心里真正所要的样子。这就是我需要的。而如果手上现成的Foobar2000已经满意,以下内容请尽快别看。

    二、用什么来集成Foobar2000?
    用来集成Foobar2000的零件,与上面提到的功能组件一样,自身也是一个组件,通常以Dll文档形式参与活动,坊间称它作UI(user interface 用户界面)。在UI的历史上,出现过CUI、GFX、EUI、PUI、DUI……CUI的出现,使Foobar2000的定制变得十分直观、简便。毫不过分地说,是CUI打先锋帮Foobar2000打下了大片天。没有CUI的昨天,就没有Foobar2000的今天。PUI的诞生,给Foobar2000带来的首先是视觉上的强力冲击,其次是对CUI的再思考。PUI流星般地划过,但它活的灵魂并没有立即消散。PSS和WSHM有如新生的重臣辅佐CUI这座老皇上。现在CUI被应用,其实很大一部分仅仅借助它的支架,门面和支柱基本都让位给PSS与WSHM。是PSS与WSHM给CUI注入新生血液,没有PSS与WSHM的鼎力扶持,CUI恐怕无力拢聚人心,更别想站住主流的位置。然而,就象一个腐朽的王朝,千疮百孔,貌合神离,光靠几位能人志士几根中流砥柱终究挡不住就要喷薄而出土崩瓦解的历史潮流。
    CUI有个死结,不是一个,是一些个。举个例子哦,它受操作系统风格制约相当严重,标题栏去不掉,滚动条贼不好办,冷不丁就从某地方挤出一个“白眼”。另外,插图底坐要么无法透明要么不支持通配符。还有一些深层次的死结,有待进一步探讨。
    在这人心思动的动荡时局,FUI揭杆而起。头儿不叫陈胜吴广,他就是尚未被大导演重视重用从而还不太众所周知的神秘飞大侠kandata。短短一个多月发布近40个版本。这个数字是许多组件需要花几年时间才能走完的。也许还有更加优越更加优秀的UI在暗暗酝酿在整装待发。
    如果您怀疑FUI可能不够稳定、不够成熟、效率低下、功能简易。举手回答,我以我亲身经历回答:“不!”不够成熟也许,但稳定是可靠的稳定、效率是普遍的高、功能是绝对的强悍。一些从前想都不敢想的要求,FUI可以轻易地满足人们,譬如预告节目、再譬如读写文档。
    假如,想好了真的选择用FUI来集成Foobar2000,以下的内容才算正题。

    三、FUI初步

    ——概述
    FUI,全称Func User Interface,突出F,Func,Function也,函数、功能是也。一句话,用函数的手段实现多种多样的已知未知功能。是的,是已知和未知。这也正是函数的魅力所在之一。
    FUI已经突破界面的面层,透过程序操作层,深入控制层,觊觎各种用户本分非分的要求。是的,本分和非分。这体现在它有“再编程能力”,更体现在它是一体化地对待界面整合,一体化地考虑到对非界面元素的凝聚,还体现在它有超强的内外沟通能力。
    所以,FUI是一个零件总成,本身归属于界面零件。要它、它要集成Foobar2000,几乎没有图形撮合,全靠代码穿梭。这些代码有些类似“标题格式”有些类似脚本语言甚至程序语言。也许就因为这样,掌握标题格式代码的同志说它难懂,掌握脚本语言的同志也说它难搞。
    要命的是,FUI自身没有准确完整的英文说明书,没有中文说明书,也没有得力的同志到Foobar2000主要阵地上摇旗呐喊,缺乏霸道的应用实例,只有四面楚歌——PUI临终前哀叹的流言飞语。
    不过,既然只剩FUI肯帮忙,我们别给它失望,别给自己绝望。打起精神,鼓足信心,张飞做豆腐。记住,这是我们最后一次的迟疑,最后一次的有些胆怯,最后一次的不够坚定信念。
    其实,按部就班,循循而进,每一步都并不难弄。甚至有时会感觉居然这么不可思议的容易。

    ——Readme
    要了解FUI,首先得从它自带的文本来入手。
    Readme 人尽皆知的说,是不应当任意跳过的。
    这个原文档在我读来,与天书无异。后来,在我要求下neonasahi优先翻译它。从此天书变成经文。现在终于不用猜了,13大点:
    1、前言  简便创建对象方法(从主菜单Func-> Easy creating轻松创建)
    顺便赶紧重点补充:
    工作台(Func UI Configuration,FUI 用户界面配置窗体)和工具箱(Palette,调色板)启动方法:
    1)可以从Func菜单启动。
    2)右击窗体选择脚本(Script)然后随便选择一项。
    3)可以通过设置快捷键。(强烈建议,也建议在FUI工程完工成品出厂前撤销这快捷键)
    4)可以通过设计按钮等。(强烈不建议)
    5)工具箱还可以从工作台启动。
    6)而工作台也缩身于主程序参数设置窗体的显示页(Display)中。
      7)记住了其中之一吗?起码要求有点印象。
    2、FAQ,常见问题对答计有8个(关于图像旋转、按钮、面板导入、窗体加载、内嵌窗体、窗体隐藏等出现异象的解答,这些都不是Bug。)
    3、对象归类(高级如窗体、中级如控件、一般如图文、特殊如Map行为与主菜单)
    4、创建中级与一般对象的注意事项(独立刷新、整页刷新)
    5、窗体类型(主;父;子;内嵌)
    6、窗体事件 6个,其执行顺序为:Load→(Resize,Move,Activate)→Open,重点在Load、Open、Resize

    -Load
    -Open
    -Close
    -Resize
    -Move
    -Activate

    7、共通事件 23个,重点在Init、New Track、Edited、Time、Selection Change

    -On Init
    -On Quit
    -On Playback Starting
    -On Playback New Track
    -On Playback Stop
    -On Playback Seek
    -On Playback Pause
    -On Playback Edited
    -On Playback Time (Per Second)
    -On Playback Order Changed
    -On Playlist Activate
    -On Playlist Created
    -On Playlist Removed
    -On Playlist Renamed
    -On Playlist Reordered
    -On Playlist Item Selection Change
    -On Playlist Item Focus Change
    -On Playlist Item Added
    -On Playlist Item Removed
    -On Playlist Item Modified
    -On Playlist Item Reordered
    -On Volume Change
    -On Timer

    8、用户脚本  2个,没有重点,都是重点

    #function <name>
    <scripts>
    #end

    #define <name>
    <value>
    #end

    9、选项设定说明:通知栏、脚本模式、备份方式、导入导出
    10、特别交代(

    元数据的获取被限制情况下的另外方法$pl_getmeta
    更新窗口与更新对象的区别,要灵活应用
    窗体中同一时间对象绘写按子窗体、面板、图文、按钮顺序进行。
    设置页(前面所称的工作台)启动方法,从菜单Func->Configuration比从参数页Preferences启动更好。
    虚拟画面与实际画面从dmode和level的应用来体现。
    $hash函数特别说明。这个函数非常重要。类似$puts,但有区别。$puts在FUI 中赋值结果属于局部变量。不要感觉重复,要想办法让它们互相配合。这是我特别交代的。)

    11、预定要添加的功能(在编辑框添加查找与替换功能,添加文本框等容器,增强函数性能,增加列表的排序功能。不打算为$map添加绘矩形、不打算添加上下专辑函数。)
    12、关于Bugs(作者信心满满,更积极等待着BUG信息的到来啊。)
    13、更新日志(不急看这个)

    Readme阅毕,今日即便不懂日文,也会发现我对原文语蔫不详,却添油加醋自作主张乱比划。对,我只是以Readme为由头,强调一下,我不是在也无力也不必再翻译文档。我想在此做个小结,FUI有意义最简单时大概这样走流程的:
    程序启动加载Init代码,然后Starting,从New Track运送数据和指令给各个指向的窗体,窗体中的代码就此活跃起来,该显示的文本显示,该亮相的图片亮相,该计数的计数,该干什么干什么起来。用户脚本不会自动运行,它如同预置的函数,只在被调用的时候才生效。每个窗体可以单独关闭,当主窗体关闭时Quit中的代码在退出程序前回头挣扎了一下。所有这些,只存在想中,肉眼通常难于察觉。

    ——示例
    跃跃欲试了吧。好的,我们先摸摸看FUI作者的示例。
    首先建议重新另外安装一个干净的Foobar2000,添加FUI组件后,启动程序。遇程序启动过程的对话时,选择FUI界面。
    请启动工作台,别说不会,上面苦口婆心了。然后点击Option(选项),点击Import(导入)。找到sample_001.config文档确定。重启。

    《插图 FUI作者示例 sample.config v0.0.1》


    先别管这个示例实不实用,美不美观。我们要集中精神,摸索摸索。随便弄吧!大家请随便。越随便越好。[插图,暂缺]
    这个示例大约出生于V 0.1.9时期。有三点令我记忆犹新。
    其一,那组会闪荧光的播放按钮,其实那不是按钮。既不是通过加载图片而成,也不是由某个字体实现,它们原来是通过点阵绘出来的。这说明FUI的方法可以开通一条暗道非常的靠近高级语言。这个效果我有些喜欢,可是找不着地给安容,所以至今有点遗憾。注意其操作方法不是$button,而是$map。map,我还说不清什么意思,地图吗?这个命令,我从G4D中见过。$map,请多多重视,后面我们将广泛起用这个$map。依靠它,类触摸操作的方法一下子容易了。
    其二,$base,用法是以$base(x,y)与$base()夹住一般对象如图文甚至高级对象如窗体,其目的是形成一个矩形位移,这样的话,便于对齐,便于代码组团的群体迁移、便于简化其间的代码。
    其三,一幅活的星空图。这图在表达什么呢?许多星星在随机地四处飞行。肯定不是康德仰望的那个星罗棋布的夜空,也不会是贝多芬月光下踱进人家父女相依为命的钢琴小屋所产生的音乐故事。
    从现在起,我要自觉养成摸索一个配置主要在于分析提炼人家的优点、亮点,汲取精华,为我所用。

    ——章小结
    FUI文档重点有三个,上面一起初了解其中必须先熟悉的一个:
    foo_ui_func_readme.txt,还有两个:
    foo_ui_func_variables.txt,
    foo_ui_func_functions.txt。
    这三个文档指定放在Foobar2000根目录。最好从工作台来阅读,这样条理性好。而且它们根本就是工具集,是FUI组件本身不可分割的一部分,不能仅看它是文本文档而已。从工具箱看:
    Func 分12个组,具体函数数目有点多,数了几次没数清。其实本来就不该去要数。
    Var 分4个组,2组局部变量,2组全局变量。别再想数了,今后有应用自然就渐渐熟悉。
    变量和函数哥俩,就先不介绍了。我在开发前将其组头译成中文或英文,好懂了,方便了。怎么说方便了呢?用了就知道,这个会无数次使用到的。看看图,留点印象就够了。有关含义与使用方法我们等到组织代码环节再行探讨。那样才不致于枯燥感太浓。
    需要注意的是,本讲义初始对应的Func版本是:

    1.Func User Interface V0.2.1 By kandata
    2.Func User Interface V0.2.1 汉化版 By Asion
    3.Func User Interface V0.2.1 中文文档(上述三个) 翻译:neonasahi

    《插图 工作台及工具箱》


    在FUI初步阶段,我们主要任务是对FUI有个初步的印象,但必须至少搞懂以下第一项:
    1、怎么启动FUI工作台,怎么调出Palette辅助工具箱。
    2、初步了解工作台上的页面布局,大体熟悉工具箱各个功能页的相对位置。
    3、初步了解脚本代码页内的选单。
    4、大概了解FUI的内部运作流程。了解窗体事件执行顺序,了解窗体内绘写对象的优先顺序。
    5、预习函数,通览,不要求马上理解。重点关注几个函数:$hash,$map……
    6、预习变量,留个印象就行。重点关注几个变量:%_result%,%pl_playingname%,%pi_activeindex%……

    <注:上述示例插图版权归kandata。这些是朋友“话仙”走后的某夜凭印象写的,但在读过neonasahi的中文说明文档后已经修补原先的一些猜测。译名也尽量与Asion的组件汉化及neonasahi的中文说明尽量统一。为防修订遗漏,特此注明,通常事件=常规事件=共通事件,窗体约等于窗口,工作台=Func用户界面配置窗体,工具盒=工具箱=调色板,我想,这个讲义主要针对中文版,也兼顾一点原版。>
    最后编辑kmpfor 最后编辑于 2009-11-19 11:19:30
    TOP

    四、规划

    ——概述
    代码的事情先放一边。也别刻意强记。轻松点,一步一步来,每个步骤功课扎实了,下一步保准没事儿。FUI不但有体贴的代码编写设计,还是一个相当一体化的总成工具。就算冲作者的用心,我们也应有义务在码代码前,确保用点时间用点心思规划规划。
    这是做好一个界面的关键一步,何况我们面对的是一次集成。这是第一步。跳过这一步,常常会象跳入陷井、跨入迷宫。你可以抬扛说陷井锻炼人迷宫有乐趣,说的也是哦。

    ——问自己
    问问自己,自己到底需要的是什么样的Foobar2000?这问题不是一开始回答了吗?是的,刚才的回答是问题的一面。现在面临的是问题的另一面,现在一定要搞清楚这个到底。

    比如,只是要Foobar2000放放音乐,少量的音乐。或者更多地用于背景音乐播放而已。
    比如,要Foobar2000播放音乐,还要做点转换。
    比如,需要Foobar2000播放音乐,转换音频文档,还要它管理音频文档。流行多?古典多?量呢?
    还比如,是装在本本上?装在普通台式机上?装在客厅HPC上?还是装在服务器上?
    这个需要,还有操作方面的,比如主要靠键盘?鼠标?遥控器?触摸屏?别的什么?个人操作习惯?
    这需要,还有审美方面的,比如基色?比如形状?比如单体分体?比如模拟物?比如表格化否?
    还有一点,可能被忽视了。我的主要音源是什么?CD、DVD-A、DTS(多声道情况)、镜像、WAV、无损压缩、Mp3、流媒体、其他。

    问自己这么多,到底有啥意思嘛?当然有意思。拿看似最不相关的音源方面来说吧,如果以听CD为主,那么打开CD的命令就要优先考虑,要放在最方便的位置,列表也要考虑CD的特点。搜索器可能就要瞄准全部列表。如果主要听WAV,媒体库扫瞄就要考虑对CUE的处理,元字段就要考虑CUE不能承载的补救办法。同时音源还直接关系到输入组件的多寡。所有这些每一点都与我们的集成工作紧密相关。
    我们不能太啰嗦,讲得过详细自己不烦人也烦了。总的来说,以需定产就是我们进行规划的根本方针。
    规划需要,也要规划行动。这是规划是否切实可行的要点。不说道理,下面描述一个直接有用的规划。它将用于指导后面的真格的行动。是本专题所试图剖析的一个实例的正式开始。

    ——示例
    现在,我们假设自己的Foobar2000要用来播放、转换、管理音频文档。将安装在本本或者普通桌面系统上。主要操作工具是鼠标和键盘。希望能够直接了当。
    根据这种需求,我们拟设计一个普通窗口模样的、以播放列表和媒体库筛选为主要组成的主体,在核心部件周围安插操作对象和重点显示元素。
    为方便和洁净,考虑内嵌二级窗体,以显示音乐介绍、歌词、封面等扩展信息。其中歌词与封面搭配搞一个,音乐文本信息与艺术家图片搭配搞一个。
    主体与二级窗体来回切换务必做到一点即达,一点即回。二级窗体之间也应当一点即切。
    由于本本和桌面系统经常上网或者用于其他工作、生活、学习,所以,有必要设计一个悬浮窗口,在适当的时候好将Foobar2000转入全局次要地位。
    如果,在主窗体上不便于安插过多的功用,可以考虑搞一个应急窗体,在它上面集成不太日常的操作和显示需求。比如,切换播放模式、音量、定位条、频谱等。当然,如果这些于自己正好非常日常,那这个安排就需要重新考虑。
    这些想法既然成了规划,最好打打规划图,也就是草图。这图要是做得仔细,对后面的步骤帮助会很大。如果有可能,最好是把各个零件的内外尺寸、比例都标上去。
    这些只是这次规划的简要描述,有兴趣者可以进一步选阅附录《AtWill Audio 开发无皮书》。
    有的家伙他不情愿这么麻烦,又规划又搞图多累人啊。他高兴即兴创作,边弄边想,边想边弄。好,反正是为自己干活,谁又能多干涉什么。

    ——章小结
    下面就要着手备料。之前,请记住,规划在于帮助我们了解自我,根据内在需求来定制界面,选用组件,而不能被组件功能牵着鼻子走,酱油一古脑忘了打,尽情被路边的放蛇表演迷得太阳落山都不晓得回家。一定要记住,是我在用组件,不能变成组件在用我。并非耸人听闻,这将决定今后出厂的Foobar2000根本上在为我服务,还是我受它折磨的命运。

    五、备料
    ——
    有了图纸,施工前还一步,就是粮草先行嘛。
    1、主体背景,缺省图必备,可选图也准备三两张。
    2、应急窗体背景图。如几何图、景物图、实物图。
    3、图中图要。象各种按钮、蒙片。否则,都要由代码现绘。
    4、字体。优先选择系统自带。就地取材,孙子也是这个法。
    5、自定义变量名、值。为避免与未知的变量重名,可以设计一组个样的变量名,比如统一加个前叠后叠,象AtW_X_X。自定义变量打算取几个值,值如何规范。这个要尽量有先见之明,省得临时慌乱东一个样西一个准,混乱不堪,搞晕自己不说,毛病发作还难于找着症结。
    6、外围程序路径。象外援。
    7、编辑工具。文本的也要,图形的也要。象工地上需要脚手架。比如准备好PhotoFiltre Studio以绘图、取色值、抓图、测量图片大小。比如准备好Editplus以修改代码,它可以定义语法高亮,身怀查找与替换绝技。(编写代码建议还是在FUI编辑框中进行,好歹它有专门的工具和支持。老实说,自有UI以来还没有见过这么体贴好使的代码编辑器。)
    8、计算器。

    六、起

    ——概述
    起者,行之始也,起者,物之建也,起者,神之树也。

    ——1、建立窗体
    FUI工作台的第一个页面就是Window(窗体)。在这一页,我们可以建立规划好的窗体。主窗体肯定是要的,这个不用动手,本来就在。但是,这时给她取个显示名,比如AtWill Audio,这个名字将显示在标题栏,如果有的话,我是说如果,也将显示在任务栏。被内嵌的窗体名字将被什么显示,我没有明白。一切独立的窗体名字总有被显示的时候,这个显示名就象人的外号或曾用名。那么正式名,端正就行,不用人工记忆,也不靠复制,这个名字会被自动记载到工具盒的窗体标签内。今后代码需要时仅双击即可完事。
    内嵌的窗体也要先在这里建立。窗体建立不分三七二十一,没有顺序要求。

    1)一个艺术家窗体、
    2)一个封面窗体、
    3)一个信息窗体或分级窗体……
    4)应急窗体也是一个窗体。
    5)悬浮窗可以单独建立,不过,由于悬浮窗将不与主体同时出现,我们可以将上面艺术家窗体时而分离出来充当悬浮。这样就不必多建一个窗体。相反的,应急窗体也可以临时内嵌到主窗体或者其他窗体之中。

    这种灵活适变的设计平台正是我们梦寐以求的。从大到小,FUI处处体现这一点。
    反想一下,为什么这次建立窗体这么顺利?因为我们事先做过比较详细的规划,才能批量快速地完成窗体建立工作。不至于一帮人傻站烈日风头不知所措。不仅如此,还有一个好消息,这种顺利的局面将会沿着既定的工作路线一路保持直到手上的工作全部完成。

    ——2、加入面板
    与建立窗体相仿,工作台的第二个页面用于加入我们需要的面板。这些面板是从已经安装的组件中取得自己的本名,大部分面板允许多次加入。第二次加入时,工作台会自动为其编号。但建议根据实际用途更名。
    根据规划,我们要加入

    Elplaylist一个,
    Libray Tree一个,
    Text Box一个,
    Lyrs Show一个,
    QUICK SEARCH一个。

    万一不小心多加了一个。没关系,删除它。先前的窗体同样也是可以删除、更名的。
    面板名如窗体,也可有小名。但只有大名将被记载到工具盒,以待它时代码求用。
    页面的右侧,是按钮区,有个设置按钮,用来调出面板的设置窗口。很方便。现在就可以对面板进行局部设置。这个设置我觉得分三步走比较好。首先先粗设。等下一步代码组织结束,在调试的过程中再回头来精设,最后在实地运行中微调。
    纵观全部这少得可怜的几个面板,5个面板,少吗?蜀汉王朝不也只封了5虎将。这个Textbox算谁?赵云马超?我看黄忠比较象。一出场就已经老成稳重,不见则已,见则一鸣惊人。好,就先设置这个,就只举这个例子。
    点开设置窗口,哦,也是一个代码编辑框。看看,语法特点与FUI很象。象就对了,这也是Kandata大侠的作品。日后可能被一个函数$drawtext所消灭。
    但是,现在它老当益壮。这玩艺儿支持透明、支持无级混色透明,支持长文本显示,支持中文自动换行,支持滚动条,支持只读编辑。这真是辅助欣赏古典音乐的不二法宝。难得啊!我苦苦等候了多少个春华秋实。

    ——3、组织代码
    概述——
    吓唬人的工作放个鞭炮立即开工。这算现场开幕式,总得允许我先讲两句。要我说啊,这代码工作真并不难,至少并不象他们传说的那么难。为什么不难咧?
    因为,我不说什么,说多嫌我鸡婆。我们看,请大家看。

    《插图 又一状态下的工作台 工具箱》



    先看这个代码编辑框。拉下事件盒,别看好像一大串似的,其实里头只有三样。一条通常事件,一条用户脚本,其他总一条都是窗体事件(这次我们工程比较大,所以事件会多一点,要是遇上简单的估摸一两条窗体事件就够了)。用户脚本只一个编辑页,只2个函数,早在FUI初步我们就了解了。通常事件貌似有23个编辑页,咋看怪吓人的!然而根据上级下来的规划我们将重点用到的也只不过其中三五个,并且有的页代码只要三言两语就能完事走人。再说窗体事件,看似各有6个编辑页,但主要也就3个,有些窗体代码主要仅集中在Resize一处。

    再看,在码代码的过程中,变量、函数名甚至全句都可以从工具盒直接复制过来,函数变量均早分门别类,甚为直观。窗体名、面板名也从工具盒中取。TF需要的命令,不论主菜单命令、右键菜单命令都可以从工具盒双击点取,其中由函数创建的主菜单命令与右键菜单命令自然分别归入其中。这样一来,全部代码根本不需要人工记忆,整个操作起来还就真活象从调色板中醮取颜色。此刻,Palette的用意我似乎恍然大悟了。如果不是亲眼所见,要对人说:“工作台的这个辅助窗体是一个调色板。”人家必定打死也不能点头,还指不定人前人后笑我神经胡错了说乱话。

    还有,看,有个Test测试页。这页上中下三个口。上可粘写代码,点Run运行,结果尽现下面两口中。底下那口子,别小看!千万别小看!!这是一个Console控制台。它有双料,它长千里眼,它手下养一群没事找事的各类记者。我们的活动一丝一毫逃不过它那魔掌般的眼皮。不顺眼的话,哪怕就一丁点破事,它就把咱给曝光啦。这时咱就得乖乖整改。不过,要咱表现出色,这地也就摇身变成咱的光荣榜。
    这工具盒共有8个选页,八音盒?至此全给看光光了。别说Readme没请看。那请问这位仁兄,FUI初步是怎么过来的。

    我不说,要说就说最后一句。这调色板的前6页合伙起来仅是为工作台上的脚本编辑服务的。我的意思是说,代码工作在我们FUI战线上早不能算做难事。我们不是一个人在战斗,我们有英明的领导决策核心,我们有强有力的后方保障。就算派张飞同志一个人去做豆腐。只要细心一点,豆腐照样还是只能做出香喷喷的细滑滑的模样来。
    我们感觉比较困扰的依然就是一些我们的思路、是创意、想象力、是一个完善的规划案。
    最后编辑kmpfor 最后编辑于 2009-10-23 13:47:58
    TOP

    $closewindow(六、起)
    $window(六、起——组织代码之具体实例)


    六、起——组织代码之具体实例

    具体实例——
    体例为,先码代码,然后跟随解释用义。

    1、User Custom Script 用户脚本
    用户为先,代码设计也从这里出发。用户脚本形如战壕备料。机枪、手榴弹什么的,上。用户代码有两个函数。一个是定义,一个是函数。语法已经在FUI初步列过。这是我们首先列出的语法。因为全部代码将从这里讲起。定义规定的是常量,函数规定的是脚本,这是有区别,但也不知什么情况下会有交叉,界时尽量首选定义。

    ——例1.1
    #function tag_data

    $hash(_ALBUM_ARTIST,$if2($meta(album artist),))
    $hash(_ARTIST,$if2(%artist%,))
    $hash(_ALBUM,$if2(%album%,))
    $hash(_TITLE,%title%)
    // $hash(_DATE,$if2(%date%,))
    $hash(_GENRE,$if2(%genre%,))
    // $hash(_PERFORMER,$if2(%PERFORMER%,))
    // $hash(_COMPOSER,$if2(%COMPOSER%,))
    // $hash(_BRAND,$if2(%brand%,))
    // $hash(_LANGUAGE,$if2(%language%,))
    // $hash(_COUNT,$if2(%play_count_CD%,))
    $hash(_RATING,$if2(%rating_CD%,))
    $hash(_RATING_ALBUM,$if2(%rating_album%,))

    #end

    解说:
    tag_data名是用户取的(注意那条连线,是TF与FUI函数共同没有的),它处于用户自定义的函数名的位置,其功能就从两个#夹住的代码体现。有了这个自定义(其实也是一种赋值。正好,其值本身是一组赋值语句。这就有点意思),$tag_data()俨然一个正式函数。哪里有需要它它就可以现身。至于具体的这一个,它主要会被在New Track事件、Edited事件调用。后面我们从这两个事件页中可以看见它的身影。
    这些功能行都在$hash,这是全局性的赋值语句,由于FUI将Tag变量局限在有限的几个通常事件中,为使这些信息可以顺利体现到窗体,所以需要这样做。简单一句话,目的在把局部变量转变为全局变量。
    有些行首加//,这表明所在行变为注释代码,这例中不属于注释。它只是被临时停用。这些代码来自于先前的版本,因这个版本减少重点显示信息,又考虑到也许将来会再度启用,所以一时不直接删除。
    #配对使用,行首夹击,在用户脚本中有,以后没再以这种方式出现。如果出现,大约是在取定义的值。我的举例只有函数,在我的应用实例中,我想不出什么需要定义。
    再对照一下,下面的函数表达式与上面实例的形状。
    #function <name>
    <scripts>
    #end

    ——例1.2

    #function dsp_bt

    $puts(tx1_n,8)
    $puts(tx1_t,89)
    $puts(tx1_W,$calc($w(CCONTROL,_cwidth%)*10/100))
    $puts(tx1_H,9)
    $removeobject(%dsp_rect1%,redraw:true)
    $gp_rect(CCONTROL,$calc($w(CCONTROL,_cwidth%)/2-$get(tx1_N)*$get(tx1_W)/2+$get(tx1_W)*$if2(%bt1_site%,11)),$get(tx1_t),$get(tx1_W),$get(tx1_H),brush:21-0-0-255,pen:255-255-128-0)
    $hash(dsp_rect1,%_result%)
    $updateobject(%dsp_rect1%)
    $removeobject(%dsp_rect2%,redraw:true)
    $gp_rect(CCONTROL,$calc($w(CCONTROL,_cwidth%)/2-$get(tx1_N)*$get(tx1_W)/2+$get(tx1_W)*$if2(%AtW_dsp_txt%,11)),$get(tx1_t),$get(tx1_W),$get(tx1_H),brush:11-0-0-255,pen:61-255-128-0)
    $hash(dsp_rect2,%_result%)
    $updateobject(%dsp_rect2%)

    #end

    解说:
    这个好像有点复杂了。复杂是相对的,复杂是临时的,复杂也总是由简单组成的。我们这样看,先只看最后一段。4行语句:
    第一行,作用在删除名为%dsp_rect2%的对象(这里现身为矩形图)。这个对象是由第三行%_result%赋予的。记得这个%_result%吗?FUI初步提示重点关注的。中文意思是后果,那么这个后果从哪里来的?
    这个后果是第二行造成的。第二行的意思是到CCONTROL窗体指定的地点画一个矩形。
    问:既然画一个矩形,何不直接第二行就好了?
    答:这就是FUI的绘写机制。它把任何对象(按钮、文本、Map行为、甚至窗体)都视为一种对象,任何一个对象在窗体逗留的位置都是临时的(窗体也可以逗留于窗体上的),位置就象工作岗位,你占着别人就没有机会,你走了别人好顶上。另外也允许别人竞争把你挤走。如果一个位置从头到尾只打算分给一个对象占着,那就直接第二行可以了。但如果这个位置需要轮换或者多个位置有此起彼伏的关联,就得先考虑画上后怎么洗。第三行把第二行的整体后果转化为%dsp_rect2%对象,就是为了等待必要时的清洗。一句话,无非就是搞一个名份,第二行做为一个对象的时候它没名没份,只有有了名份,程序才懂得你要清洗谁对不对。
    本例中的清洗原因是此起彼伏的需要。这组语句用于实现鼠标点击之处画出一个矩形框。中间那段与此相似,但其用于在鼠标停留之处临时一画。两组结合起来就能实现,当鼠标游到示意,当鼠标点击DSP功能生效后印记。记号保留直到别的DSP位置被点击。外观效果有点象按钮,是象而已。它在模拟某个音响的按钮四周微光。
    问:%AtW_dsp_txt%这哪来的玩艺?
    答:是从该位置Map命令而来的有条件循环变量。其代码写在CCONTROL窗体事件中。后面我们会与之见面的。
    第四句作用是更新。第一句把老的清除,这一句把新的补上。如果不删除,前后就会相叠。有人如果曾遇到按钮叠加好多层的现象。其原因就在这里。处理方法至少有两条,一、画在不被更新的位置,二、采用本例的重绘方法。你认为这是一个Bug吗?这绝对不是Bug。这是由于我们一时对具体函数的原理不够理解,想当然地所造成的。其实我也遇到过,只不过我的情况不是Button,而是tooltip。
    问:什么位置不被更新?
    答:不能一概而论。后面我们会主动告诉你。别急,胖子慢慢吃。另外,补充一点,这段代码它本来并不原生在这里,它从别处移来,虽然作用没问题。但作为用户脚本,它还可以写得更完美。如果有机会,将来再行探讨。
    这段代码有广泛应用。这里绘矩形,别处也许绘文本,函数稍改点就成。
    这段解说讲多了,怪我表达能力欠佳,言简意赅没成。不过,有些东西继续往下走,接触多些就好懂了。毕竟前后是关联的。还是老话,先留点印象就成。毅然往下走,回头就全懂啦。

    ——两例联解:
    第三章我们提到过$hash与$puts的异同。这伙它们在一地方相遇。
    问:将两例中$hash与$puts对调好不好?
    答:非常不好。第一例换上$puts后,从窗体取不到值。赋值工作不但徒劳无功,还徒增资源消耗。这种事绝不能干。第二例换上$hash后,运行没问题。但是,所赋之值立刻不安份起来,它们不再安心于既定的窗体事件中,而会成群结队漫游到所有本不干它什么事的所有事件中。用函数犹如用人,你管韩信管米仓,他的心思在想离开你。你换赵括带大军,打了败仗回来怪谁呀?
    问:$hash与$puts能不能混合使用?
    答:非常欢迎。我是用了,但是否会举到,现在料不准。

    ——章小结
    事后诸葛亮,
    其实有必要放在用户代码这一页,都是些需要在多处运行的代码群,只有少数个别是为了使执行命令显得简捷好懂。
    通常我们先写用户代码,但有时会在写后面代码的时候,感到代码过于复杂,需要一个过度。这时才反过来写用户代码。

    2、Init 入口事件(初始化时)

    ——例2.1
    $hash_load(/Presets\hash.data)
    $hash(AtW_tree_state,s_how)
    $hash(AtW_artist_size,s_mall)
    $if(%AtW_bg_trans%,,$hash(AtW_bg_trans,255))
    //$hash(ARTpath,$textfile(/Presets\artPath.txt,charcode:utf8,crlf:true))
    $mainmenu_set(active NOWPLAYING,'$pl_active(%pl_playingname%)$pi_select(%pl_activename%,%pi_playingindex%)')

    解说:
    第一句,目的在从目标文件夹中的data文件取值。取啥值?从Quit页可知。
    第二句,第三句,给自定义变量初始化。
    第三句,也是,但要了条件。我记得当初有位朋友使用W的配置,出来一片黑。不知怎办?原因就是当时没有想到用这一句。自己用当然不需要这一句,自己知道怎么第一次使之有值。往后它就保存到Data中。从此这一句就多余了。也正因为怕是多余,才要了条件。
    第四句,意思是先从目标文件夹中的TXT文件读取封面目录路径,然后将其赋予ARTpath。这%ARTpath%就成变量了。它将在今后与封面命名粘合从而组成完成的封面路径。这样也是为了让别人方便使用的做法。要不然,直接给个绝对路径,直截了当,效率必高。这一句,是非常早大约V0.0.5之前的遗留。那时$hash_save功能不健全,只能靠读取TXT文本来过渡。当然,这个句式现在还是有用。下例提及的用户指南与设置窗体就用过这样的句法了。从这一句我们可以初步感觉FUI的沟通能力的确前所未有。
    第五句,在主菜单中建立一条新命令active NOWPLAYING,这样就可以被其他组件调动。其实如果没有其他组件需要,这也不一定这么做。顺便一说,右键菜单命令的建立方法与此类似。
    问:怎么取消,这条命令?能直接删除或者注释掉吗?
    答:不能。看,只有用这个$mainmenu_remove(active NOWPLAYING)来。然后,再注销。
    问:怎么执行它?
    答:$mainmenu_execute('Func\User\active NOWPLAYING')。有点疑惑对不对,粘到Test页中去Run一下。不过,真马上要Run,在未重启之前,就先粘$pl_active(%pl_playingname%)$pi_select(%pl_activename%,%pi_playingindex%)这一句去Run。从现在起,最好随时记得时不时可以去Run下下。主菜单函数共3个来全了,右键菜单情况类似。后面就不多说。

    ——例2.2
    //--popup--
    $popupmenu_remove(popup_0)
    $popupmenu_create(popup_0)
    $popupmenu_additem(popup_0,Help && Expand,'')
    $popupmenu_additem(popup_0,-sep1,'')
    $popupmenu_additem(popup_0,AtWill Handbook,'$hash(AtW_bg_state,)$window(HANDBOOK,20,2,400,600)')
    //$popupmenu_additem(popup_0,AtWill Handbook,'$execute('d:\Program Files\WongMedia\index.htm',,)')
    $popupmenu_additem(popup_0,-sep2,'')
    $popupmenu_additem(popup_0,Application menu,'$popupmenu_view_mainmenu()')
    $popupmenu_additem(popup_0,Auto Play,'$if(%AtW_start_state%,$hash(AtW_start_state,),$hash(AtW_start_state,p_lay))',
    check:'$if(%AtW_start_state%,1,0)')
    $popupmenu_additem(popup_0,Hide,'$mainmenu_execute('View/Hide')')
    $popupmenu_additem(popup_0,Exit,'$mainmenu_execute('File/Exit')')
    $popupmenu_additem(popup_0,-sep3,'')
    $popupmenu_additem(popup_0,Open/Rip Audio CD,'$mainmenu_execute('File/Open Audio CD...')')
    $popupmenu_additem(popup_0,Update Item <for Bind>,'$mainmenu_execute('File/Bind/Update')')
    $popupmenu_additem(popup_0,Convert to Album Image,'$contextmenu_execute('Convert/Convert to Album Images with Cuesheets or Chapters',playlist)')
    $popupmenu_additem(popup_0,Tool1,'$execute('%AtW_exe1_PATH%',,normal))')
    $popupmenu_additem(popup_0,Tool2,'$execute('%AtW_exe2_PATH%',,normal))')
    $popupmenu_additem(popup_0,-sep4,'')
    $popupmenu_additem(popup_0,        TC,'$execute('%AtW_exe3_PATH%',,normal)')

    解说:
    这是建一个弹出菜单(同时可能是悬停菜单,关键取决于调用它的方式),将来可以被灵活调用。用Map,可以左点、右点、鼠标指处、滚轮、甚至加强按钮等等方式激活它。
    欲知效果,请弄去Run。然后,再Run一条$popupmenu_view(popup_0)。
    问:看到许多外部链接,网页、可执行文件都有?
    答:对。这一组是帮助与扩展应用。首先得可以启动由网页方式写成的用户手册。当然,手册原先不是仅针对音频的,而且考虑到一些用户设置的需要,我就在非全屏化的同时,多建了一个用户指南与基本设置窗体。这个窗体用于读取用户指南文档,也用于读取用户工具路径,看见这个%AtW_exe1_PATH%了吗?我的值它是EAC程序。别人要它是啥,我可不得而知。用户字体也一并在这窗体上给定了。
    单独建一个帮助与设置窗体的好处是当它读取并确定完设置项之后,我们可以关闭它。这样即实现了帮助与设置的需要,同时不必用户通过资源浏览器到什么文件夹去做什么设置。一来方便用户,二来不增加程序开销。关于开销,补充说明一下,如果当初用户设置参数是通过主窗体或Init本页(例如上例第四句)加载,必须是每回程序启动这些都要再重复加载一趟对不对。喔,少说了一点,因为用户设置的参数在程序退出前已经保存到data文档中。如果感觉段文字有点绕弯弯,别管它,过。毕竟这个不急。我是工作全结束之后才又搞这个的。如果自用,这些无啥意义,如果给人用,这可就大有意思啦。也不对,因为更换背景也由这个工具性窗体完成,所以看来自用也是需要的。
    弹出菜单有效指令之:

    第一条,用户指南与基本设置。
    第二条,主菜单。
    第三条,选择启动后是否自动播放。
    第四条,第五条,隐藏、退出。
    第六条,抓取CD音轨。
    第七条,更新绑定文件夹。(达到无需通过资源浏览器访问以下工具抓获的音轨文档的目的)
    第八条,转换为单文件专辑。(主要用来转换由EAC抓获的WAV)
    第九、十、十一条,外部辅助应用。(我很依赖于TC)

    11条命令,貌似乱了,好在有分组。这是最杂的一个菜单。其他的菜单都是针对单项内容的。这一组命令,进一步展现FUI内外尤其是对外沟通能力的前所未有。
    注意每个弹出菜单不要太长,也不要太短。长了操作困难,短了菜单价值不高。

    ——章小结:
    程序启动时,FUI的第一波加载项目。所以叫Init初始化时。
    与用户脚本的被动激活不同,Init中的项目是要自动加载的。
    所以,
    这里主要用来加载一些初始项。这些项目有个共同的特点,它们将不再也不需要随未来节目的变化或者界面的变幻而更换新值。
    所以,
    如果现在新加一条语句,这条语句的作用只能等待下回程序启动才可发挥。当然,除非又去弄那个Run。
    最后编辑kmpfor 最后编辑于 2009-11-07 17:48:09
    TOP

    3、New Track 新音轨事件

    毫无疑问,新音轨事件是任何一个开发案都不可以不要,不可以不认真对待的。美好的音符就要跳跃起来,兴致开始盎然的时候了。

    ——例3.1
    //--skip--
    $if(%skip%,$playback_control(next),)
    $if($strcmp(%AtW_skip%,no_star),$if($or(%rating_cd%,%rating_album%),,$playback_control(next)),)
    $if($or(

    $regexpi(%title%,'(伴奏'),
    $regexpi(%title%,'\(伴奏'),
    $regexpi(%title%,'\(卡拉OK'),
    $regexpi(%title%,'\(伴唱\)')
    $regexpi(%title%,'off vocal'),
    $regexpi(%title%,'less vocal')

    ),$playback_control(next),)

    解说:
    问:为什么一开播就要跳?
    答:只有跳过不喜爱的,才能确保所喜爱的。不过,这典型是玩笑话。把跳过功能置于页首,目的是避免程序死板地再为这条不想听的音轨多动脑筋。
    这个功能从是与否的唯2值角度看,也属于对节目的分级行为。它跟音轨分级,专辑分级,其实质与作用紧密相关。你看
    第二句,如果开启跳过无星选项,当音轨,同时音轨所在专辑没有被评过级,那么,就要被排挤掉。
    第三句,跳过带敏感字眼的节目。也可以对文档类型、音轨品质、时间长度等等放进类似方案。
    原理与方法放在这儿,具体应用则要看个人了。谁知道谁都注意些什么啊。所以,只有自己动手,才能真正令自己满意。FUI已然最大限度地支持这种需要。接下来就看你的抉择了。

    ——例3.2
    //--art--
    $hash(ART8t_img,$files_ex(0,%AtW_art1_PATH%,*%album%-%tracknumber%*.jpg))
    $hash(ART8_img,$files_ex(0,%AtW_art1_PATH%,*%album artist%*%album%*.jpg))
    $albumart_find(%ART8_img%,once)
    $if(%_flag%,,$hash(ART8_img,$files_ex(0,%AtW_art1_PATH%,*%album%*.jpg,*%album%*.png,*%album%*.gif,*%album%*.bmp))
    //$albumart_find(%ART8_img%,once)
    //$if(%_flag%,,$hash(ART8_img,$files_ex(0,%AtW_art1_PATH%,*%album artist%*.jpg,*%album artist%*.png,*%album artist%*.gif,*%album artist%*.bmp)))
    $albumart_find(%ART8_img%,once)
    $if(%_flag%,,$hash(ART8_img,/images\AtWill\NO-COVER.png)))

    $if($strcmp(%AtW_artist_state%,no_embed)
    ,

    $hash(ART0_img,$files_ex(0,%AtW_art2_PATH%,%artist%.png,%artist%.jpg,%artist%.gif,%artist%.bmp))
    $hash(ART1_img,$files_ex(0,%AtW_art2_PATH%,%album artist%.gif,%album artist%.png,%album artist%.jpg,%album artist%.bmp))
    $hash(ART2_img,$files_ex(0,%AtW_art2_PATH%,%COMPOSER%.jpg,%COMPOSER%.gif,%COMPOSER%.png,%COMPOSER%.bmp))
    $hash(ART3_img,$files_ex(0,%AtW_art2_PATH%,%PERFORMER%.jpg,%PERFORMER%.gif,%PERFORMER%.png,%PERFORMER%.bmp))
    $hash(ART4_img,$files_ex(0,%AtW_art1_PATH%,[*%album artist%]*%album%*back.jpg))
    $hash(ART5_img,$files_ex(0,%AtW_art1_PATH%,[*%album artist%]*%album%*disc.jpg))
    $hash(ART6_img,$files_ex(0,%AtW_art1_PATH%,[*%album artist%]*%album%*box.jpg))
    $hash(ART7_img,$files_ex(0,%AtW_art1_PATH%,[*%album artist%]*%album%*front.jpg))
    $albumart_find(%ART0_img%,once)

    $if(%_flag%,,
    $for(i,1,8,1,'
    $albumart_find($hash(ART%i%_img),once)
    $if(%_flag%,$hash(ART0_img,$hash(ART%i%_img))$bradk(),)
    '))

    ,
    $hash(ART0_img,$files_ex(0,%AtW_art2_PATH%,%artist%.png,%artist%.jpg,%artist%.gif,%artist%.bmp))
    //$albumart_find(%ART0_img%,once)
    //$if(%_flag%,,$hash(ART0_img,$files_ex(0,%AtW_art2_PATH%,%album artist%.gif,%album artist%.png,%album artist%.jpg,%album artist%.bmp))
    //$albumart_find(%ART0_img%,once)
    //$if(%_flag%,,$hash(ART0_img,$files_ex(0,%AtW_art2_PATH%,%COMPOSER%.jpg,%COMPOSER%.gif,%COMPOSER%.png,%COMPOSER%.bmp)))
    //$albumart_find(%ART0_img%,once)
    //$if(%_flag%,,$hash(ART0_img,$files_ex(0,%AtW_art2_PATH%,%PERFORMER%.jpg,%PERFORMER%.gif,%PERFORMER%.png,%PERFORMER%.bmp)))
    $albumart_find(%ART0_img%,once)
    $if(%_flag%,,$hash(ART0_img,$files_ex(0,%AtW_art1_PATH%,[*$or(%album artist%,%artist%)]*%album%*back.jpg))
    $albumart_find(%ART0_img%,once)
    $if(%_flag%,,$hash(ART0_img,%ART8_img%)))

    )
    解说:
    问:好复杂啊!
    答:复杂在哪?只是因为代码多!
    问:干啥非得这么多?
    答:为了通吃。又为了尽可能节约资源。一般而言,代码少可以减少资源消耗,有时候,代码多了反而才能。
    如果不是为了实现图片匹配可以通配符。这里仅需三两句就可以读到封面与艺术家图片路径。
    为了通配符,为了全面读取从艺术家、专辑艺术家、作家、表演者到专辑封面、封底、CD图、盒子图,我们才需要这般大费周章。
    但是,问题在并非每个窗体下都需要这些全部的路径。所以,要把图片只仅送往需要它的窗体。其二,图片绝大部分是Jpg格式,当程序优先寻找这个格式总体上算可以节省好几倍的时间。
    又要读得快,又要读得全,这是我们对这群读图代码的苛刻要求。实际上,它们也确实挤出吃奶的力气了。你是剥削阶级吗?请你戴上放大镜检阅检阅。又要牛干活,又要牛不用吃草。
    要知道,又能底板透明,又能支持通配符配图的,全世界仅此一家,别无分店。而且这家的送图上门速度不敢说最快也一定不会太慢。它们敢于承诺,以相同要求标准读图,一定跑在前列。
    提示:
    1)%AtW_art1_PATH%,这个从Init加载的data数据中来。而其根源是通过用户帮助与配置窗体进行接受用户本人真人指令。
    2)如果换$files检查图片存在与否,代码将大量减少。不过,不知从哪个版本开始,对这样的做法,Console那个鸟鸟蛋就要出来抖抖。看它熊样,不爽。
    3)注意,我们没有用到$albumart(file,type)函数。你可以试试看它行不行。
    我们的解说慢慢在变化。如果对这种变化心存不满,大声说。
    问:这此代码功能与效率的关系如何?怎么安排图形显示?
    答:刚刚已经说过一些,话音才落是不是。再强调一点,本例代码实际应用时,可以酌情关闭其中个人不需要的语句。那样效率将显著提高。关于如何分离出超高效的图片读取器、如何改进全功能读取器使之进一步提高代码效率,这样的问题,我们只有留到附录FUI零件中去共同探讨。而采取怎样一种图片显示形式,这个问题在这里说也不好,它应当到窗体事件中去让争论。
    问:何不写在用户脚本?
    答:因何?我不是事后诸葛亮。
    问:是否可以放到窗体事件中去?
    答:可以。但一,时机问题,但二,Tag字段变量要依赖于下例。

    ——例3.3
    //--update--
    $tag_data()


      $updatewindow(MAIN,event:resize,update:false)
      $updatewindow(RATINGEX,event:resize,update:false)
      $updatewindow(ARTIST,resize)
      $updatewindow(ALBUMART,resize)
      $if($iswindowvisible(CCONTROL),$updatewindow(CCONTROL,resize))

    解说:
    久违了!$tag_data()。曾记否,用户脚本家里,我们热情交谈过的。
    如今,她当首领了。她一挥手,许多小指挥立马带领一群群小喽喽冲啊冲啊……
    1)$if($iswindowvisible(CCONTROL)之类的就是给点抑制。
    2),update:false)之类的是别一种抑制。
    3)没看见窗体名的之类更是一种绝对的抑制。就如不批它世贸名单,它想啥国际交易对等都没门。我看还有几个窗体就没有被加入到这个名单中来。所以,请别因为小处着着手,就不大处着眼了。只有放眼全世界,才能更好更快的理解代码含义。钻一小洞里,能看到啥?
    答:那样对睡眠好。

    ——例3.4
    //--rating--
    // $if(%rt_TEXT%,$removeobject(%rt_TEXT%,redraw:true))
    // $gp_text(RATINGEX,$repeat($char(176) ,%rating_CD%),$calc(0.5*$w(RATINGEX,_cwidth)),$calc(0.075*$w(RATINGEX,_cheight)),$calc(0.5*$w(RATINGEX,_cwidth)),$calc(0.5*$w(RATINGEX,_cheight)),brush:121-55-55-255,pen:61-55-55-255-1,font-name:Wingdings,font-size:16,glow:100-200-255-1-3,halign:center,valign:top,font-size:11,shadow:rightbottom-1-1)
    // $hash(rt_TEXT,%_result%)
    // $updateobject(%rt_TEXT%)

    $if($ispanelvisible(ELPLAYLIST),
    $if(%ra_TEXT%,$removeobject(%ra_TEXT%,redraw:true))
    $gp_text(TREE2,$repeat($char(90) ,%rating_album%),0,0,$calc(0.31*$w(%mainid%,_cwidth)),$calc(0.04*$w(TREE2,_cheight))
      ,brush:11-128-128-255,pen:31-128-128-255-1,font-name:Wingdings,glow:100-200-255-1-1,halign:center,font-size:10,shadow:righttop-1-1)
    $hash(ra_TEXT,%_result%)
    $updateobject(%ra_TEXT%)

    ,$if($strcmp(%AtW_artist_size%,l_arge),
    $if(%ra_TEXT%,$removeobject(%ra_TEXT%,redraw:true))
    $gp_text(TEXT,$repeat($char(90) ,%rating_album%),$calc(8/100*$w(TEXT,_cwidth)),$calc(0.78*$w(TEXT,_cheight)),$calc(93/100*$w(TEXT,_cwidth)),$calc(0.04*$w(TEXT,_cheight))
      ,brush:11-128-128-255,pen:91-255-255-255-1,font-name:Wingdings,glow:100-200-255-1-1,halign:center,font-size:10,shadow:righttop-1-1)
    $hash(ra_TEXT,%_result%)
    $updateobject(%ra_TEXT%)
    ))

    $if(%skip_TEXT%,$removeobject(%skip_TEXT%,redraw:true))
    $gp_text(RATINGEX,$char(82),$calc($w(RATINGEX,_cwidth)*0.5),0,38,21
      ,brush:191-255-0-0,pen:91-255-128-0-1,font-name:Wingdings,font-size:11,glow:255-0-0-3-4,halign:center)
    $hash(skip_TEXT,%_result%)
    $updateobject(%skip_TEXT%)

    解说:
    问:代码还这么多啊?
    答:闭着眼镜说话吗?这有好几例了,大同小异。故意乱人眼的。
    新东西就这个$calc($w(RATINGEX,_cwidth%)*0.5),其实,这也不算新东西,如果细心就该发觉在用户脚本页已经出现过。只不过,我觉得该当放这里说比较对头。这个计算式,要想在Ratingex窗体指定一个位置,就是宽度50%的地点。注意,是地点,不是地方。假如这个计算式在所在语句向后推移两个逗号,那么,其后果就不是地点了。
    还有,$w(RATINGEX,_cwidth)这玩艺儿有点奇怪?%_cwidth%这样不奇怪了吧。本来就是嘛。不过,人出差到这里,说%_cwidth%是没人懂的。好比说西安人在当地说本市明白,但他到佳木斯去说本市啥个意思?或者西安人在当地不能称佳木斯叫做本市吧?所以,对西安人而言,$w(RATINGEX,_cwidth)相当佳木斯市,%_cwidth%相当于本市。代数一下,$w(RATINGEX,)就是指代本的意思了,哈哈!千万不能时刻忘记啊,本市是个局部变量!!!
    问:$ispanelvisible(ELPLAYLIST)这个也是新的!
    答:$iswindowvisible(CCONTROL)上例这个算啥回事?一定要100%吗?我大声说了,FUI支持小数点计算,计算能力也比TF强无数倍。

    ——例3.5
    //--Item Switcher--
    $if($or(%AtW_artist_state%,$iswindowvisible(CCONTROL)),
    $popupmenu_remove(Itemlist)
    $popupmenu_create(Itemlist)
    //$popupmenu_additem(Itemlist,Item Switcher,'')
    //$popupmenu_additem(Itemlist,-sep1,'')
    $for(i,$calc(%pi_playingindex%-7),$calc(%pi_playingindex%+8),1,'
    $puts(item_Focus,\"$pi_select(%pl_playingname%,\"%i%\",select:true,focus:true)$playback_control(play)\")
    $popupmenu_additem(Itemlist,$ifequal(%i%,%pi_playingindex%,◆,$ifequal(%i%,%pi_activeindex%,■,  ))$wstrsplit($if2($pl_getmeta(\"%title%\",%pl_playingname%,%i%),^_^),30,0)
    //$popupmenu_additem(Itemlist,$if($pl_getmeta(\"%title%\",%pl_playingname%,%i%),$ifequal(%i%,%pi_playingindex%,◆,$ifequal(%i%,%pi_activeindex%,■,  ))$calc(%i%+1) - $pl_getmeta(\"%title%\",%pl_playingname%,%i%),)
    ,$get(item_Focus))
    ',escape:true)
    ,)

    解说:
    问:干啥哩,打群架还是开群体大会啊!难道是广场看真人演出?
    答:只不过节目切换表单。瞧瞧,爱看谁,仔细瞅哟。靠近点,再靠近点。额酒兴致,先闪,先闪。

    ——章小结
    总算放一首了。刚听完九个太阳。
    新音轨事件,主要是先把不想听的先剔掉。不给它予捣乱的机会。
    然后,主要是抓紧读取音轨信息,按轻重缓急贩卖给需要的窗体事件、控制事件(象弹出菜单)等潜在消费者,或者干脆送货上门,直接送人家里(例3.4就这德行,人家姑娘俊摆。唉)。
    最后编辑kmpfor 最后编辑于 2009-11-11 11:21:46
    TOP

    4、Event Window 窗体事件

    1)MAIN 主窗体

    ——例4.1.1 Load 加载
    $style(%_id%,clear,thickframe:on)
    $bgcolor(%_id%,0-0-0)
    $transwindow(%_id%,alpha:%AtW_body_trans%)

    解说:
    第一句,窗体风格,仅保留可拖拉边框。(末项参考可以换dlgframe:on看看,也可以去掉看看,只Clear也许正好满您的意。如果在这on上设变量,是否去边框也就由得自己调拨了。)想立马看看结果?又去Run?不要去Run了,请右击窗体未被覆盖处,点击Refresh刷新。
    第二句,设定窗口底色为纯黑。(为什么要纯黑?愿意思考吗)
    第三句,给整个窗体一个透明变量。这样就能调整窗体对桌面的透明度。(后面我们会看到还有一种透明方式,即窗体对窗体的透明。扩而小之,还有面板的透明、控件的透明、图形图像的透明、文本的透明……总之是对象的透明。)

    //--bg & menu--
    $clearobject(%_id%,event:load)

    $if($files([%AtW_bg_image%]),,$hash(AtW_bg_image,/images\AtWill\bg00.jpg))
    $gp_image(%_id%,%AtW_bg_image%,0,0,%_cwidth%,%_cheight%,cache:false,alpha:%AtW_bg_trans%)

    $gp_image(%_id%,/images\AtWill\menu.png,$calc(0.69*%_cwidth%),$calc(0.92*%_cheight%),170,16,keepaspect:false,cache:false,alpha:$if($strcmp(%AtW_bg_trans%,85),25,$calc(%AtW_bg_trans%-95)))
    $gp_image(%_id%,/images\AtWill\menuR.png,$calc(0.69*%_cwidth%),$calc(0.96*%_cheight%),170,16,keepaspect:false,cache:false,alpha:$if($strcmp(%AtW_bg_trans%,85),25,$calc(%AtW_bg_trans%-115)))

    解说:
    第一句,清除窗体原有对象。(若不设背景更换,且将无对象更新,这一句可去除。)
    第二段,在整个窗体上画一幅背景。开头一句是设一个缺省图。(注意一下%_cwidth%与%_width%的区别。)
    第三段,于窗体右下角加一条菜单位置提示图,同时做一个真倒影效果。
    所有图片都赋予透明参数的变量,可以反调窗体的黑底来调节明暗度。以便更广泛地对付不同的背景图,同时也使得在夜间聆听与白昼欣赏有适应心境的光亮度选择。
    本例背景没有变动尺寸的需要,如果个人需要调整窗体尺寸,则应考虑将这些代码转移到后面将介绍的Resize中,当然在Resize中给定一条反过来刷新Load的命令也可能是一种方法。
    问:既然如此,为何不干脆写在Resize中?
    答:随机应变。写在Resize不是什么坏处都没有的。待到Resize那看看再说。
    需要注意的是,
    keepaspect:false 参数可以为真,但不能没有。不过先前的版本没有这么严格。这个参数应该算受重视的,以后在封面窗体上将进一步体现。
    cache:false 参数值为假,也就关闭了Cache。你应该与封面窗体的相同语句比较一下(你看,不合时宜这不,封面窗体远在后边。所谓言之过早)。然后想想它们为什么要不同?开动脑筋了吧?
    其实早就该开了。或者说你早开了,只是我无从知道。现在我晓得了嘞,我知道往后该少点解释,多点提示,多点提问,直到提示提问也越来越少甚至最终没有了。

    <写到这,Foobar2000中国社区发生了重大事件。Asion终于出手汉化FUI组件。neonasahi在翻译日文文档的过程中提出统一汉化称谓的问题。neonasahi的汉化文档与Asion的汉化组件,这样说不对,应当说Asion与neonasahi共同在汉化FUI组件(因为这些文档在FUI组件中是不可分割的)。这是FUI在中国社区中的一件标志性的事件。我隐隐感觉FUI的春天就在来临。心里暖洋洋的。
    至此,我觉得这个教程需要重新思考一下,先前是照着原版来写,往下呢?跟进中文版写?那么前面的呢?我的表达与他们不一致的地方怎么来处理?因为我们的一致服务对象是同一个用家。我们不能各行已道,把困扰留给用家。所以,我们也在一起商量这个事情。
    再说,我也该当反思一下,这样写对大家有用吗?会不会是反作用?一开始想写教程,但从现在看,由于采用gdzqj88等朋友的建议加强对实例的分析并致使其内容太重,已经不知不觉演变为写讲义了。
    我想呀,不管叫什么,其实叫什么都无所谓。只要对读者有益,有实际帮助就好。
    如果正好读到这,不论下面的内容是否已经推出,请稍作停顿,也停一停,想一想。怎么让自己的时间不被白读了?怎么提高阅读效益?>

    //--panel--
    $panel(%_id%,QUICK_SEARCH_TOOLBAR,$calc(0.46*%_cwidth%),$calc(0.92*%_cheight%),$calc(0.22*%_cwidth%),22,hide)
    $panel(%_id%,LYRIC_SHOW,$calc(0.12*%_cwidth%),$calc(0.06*%_cheight%),$calc(0.37*%_cwidth%),$calc(0.46*%_cheight%),hide)
    $panel(%_id%,ELPLAYLIST,$calc(0.12*%_cwidth%),$calc(0.04*%_cheight%),$calc(0.56*%_cwidth%),$calc(0.86*%_cheight%))

    $updatewindow(%_id%,load)

    //-- embed --
    $window(RATINGEX,0,0,$calc(0.12*%_cwidth%),$calc(0.84*%_cheight%),parent:%_id%,embed:true)
    $window(ALBUMART,$calc(0.69*%_cwidth%),$calc(0.07*%_cheight%),$calc(0.31*%_cwidth%+10),$calc(0.65*%_cwidth%),parent:%mainid%,embed:true,hide)
    $window(ARTIST,6,$calc(%_cheight%-55),40,55,parent:%_id%,embed:true)
    $window(TREE2,$calc(0.69*%_cwidth%),0,$calc(51*%_cwidth%),$calc(0.92*%_cheight%),parent:%_id%,embed:true)
    $window(TEXT,$calc(0.45*%_cwidth%),0,$calc(0.53*%_cwidth%),$calc(0.92*%_cheight%),parent:%mainid%,embed:true,hide)

    解说:
    我们先不说这些板啊,这些窗体。
    请先比较一下,前后两组语句的写法。这样:
    $panel(windowid,panelid,x,y,w,h[,options...])
    $window(windowid[,x,y,w,h][,options...])
    相差在两个地方,上多一个panelid,下多一个[]。仅此而已。为什么?想想愿意吗?它们为什么要不同?它们为什么可以不同?
    其实,这个时候,我们已经可以把FUI的全部函数都给归纳一下,
    记得在新音轨事件中见过:
    $gp_text(TREE2,$repeat($char(90) ,%rating_album%),0,0,$calc(0.31*$w(%mainid%,_cwidth%)),$calc(0.04*$w(TREE2,_cheight%)),brush:11-128-128-255,pen:31-128-128-255-1,font-name:Wingdings,glow:100-200-255-1-1,halign:center,font-size:10,shadow:righttop-1-1)
    好长啊,其实它的写法只是:
    $gp_text(windowid,text,x,y[,w,h][,options...])
    再看
    $gp_image(windowid,filename,x,y[,w,h][,options...])
    $drawtext(windowid,text,x,y,w,h[,options...])
    ……
    太像了吧?就是
    $函数名(窗体户口簿名,对象,位置与尺寸,选项)
    这个选项个别变种加强为(TF,选项)。
    一种了,
    还有
    $函数名(对象名,位置与尺寸,选项)
    $函数名(新函数名,旧函数或变量或常量)
    $函数名(窗体户口簿名,动作名,函数或变量或常量)
    $函数名(对象,函数或变量或常量)
    差不多就这五种了。我说差不多的。你尽可以把见过的函数翻出来对较对较,也可以拿着这五种写法到后面的每一个函数去校验校验。
    面对繁杂,我们需要总结归纳,面对简单,我们需要解剖分析。苟能此,也就能举重若轻、宠辱不惊。

    话说至此,再回头问上述面板与窗体语句,还有什么值得再说呢?
    真没什么再说的了啦。
    一定要挤的话,就请注意一下它们的Hide与否,Embed与否。

    ——看图想代码
    (不然,缩小一下范围:
    其一,对照本例从头的代码每句下来,看看体现在哪里。
    其二,上溯,不必上溯几千年,只要上一事件就行。
    其三,自己扩大范围。




    ——例4.1.2 Resize 重置尺寸
    $clearobject(%_id%,event:resize)


    解说:
    清除本页中的全部内容。event:resize在Resize页就是本页。记得本市的例子吧。这又一种了。

    //--art--
    $if($strcmp(%AtW_artist_state%,no_embed)
    ,,
    $if($strcmp(%AtW_artist_size%,s_mall)
    ,$movewindow(ARTIST,6,$calc(0.845*%_cheight%),$calc(0.135*%_cheight%),$calc(0.155*%_cheight%),activate:false)
    ,$if($strcmp(%AtW_artist_size%,l_arge)
    ,$movewindow(ARTIST,$calc(0.12*%_cwidth%),$calc(0.25*%_cheight%),$calc(0.33*%_cwidth%),$calc(0.75*%_cheight%),activate:false)
    ,$if($strcmp(%AtW_artist_size%,b_ig)
    ,$movewindow(ARTIST,$calc(0.12*%_cwidth%),$calc(0.68*%_cheight%),$calc(0.35*%_cwidth%),$calc(0.32*%_cheight%),activate:false)
    )))
    )

    $if($strcmp(%AtW_albumArt_size%,l_arge)
    ,$movewindow(ALBUMART,$calc(0.13*%_cwidth%),0,$calc(0.56*%_cwidth%),$calc(0.91*%_cheight%))
      ,$if($strcmp(%AtW_albumArt_size%,s_mall)
    ,$movewindow(ALBUMART,$calc(0.001*%_cwidth%),$calc(0.88*%_cheight%),$calc(0.07*%_cwidth%),$calc(0.07*%_cwidth%))
    ,$movewindow(ALBUMART,$calc(0.49*%_cwidth%),$calc(0.06*%_cheight%),$calc(0.50*%_cwidth%),$calc(0.70*%_cheight%))
    ))

    $if($strcmp(%AtW_albumArt_size%,l_arge)
    ,
    $showpanel(LYRIC_SHOW,false)
    $showwindow(TEXT,0)
    $movewindow(RATINGEX,$calc(0.81*%_cwidth%),0)
    $updatewindow(RATINGEX,event:resize)
    ,
    $movewindow(RATINGEX,0,0)
    $updatewindow(RATINGEX,event:resize)
    $if($ispanelvisible(ELPLAYLIST)
    ,$showpanel(LYRIC_SHOW,false)
    $showwindow(TEXT,0)
    ,$if($strcmp(%AtW_text_state%,a_uto)
    ,$if($strcmp(%AtW_artist_size%,b_ig)
    ,$showpanel(LYRIC_SHOW,true)$mainmenu_execute('View/Lyric Show/Refresh')
    $showwindow(TEXT,0)
    ,$if($strcmp(%AtW_artist_size%,l_arge)
    ,$showpanel(LYRIC_SHOW,false)
    $showwindow(TEXT,1)$updatewindow(TEXT,event:resize)
    )))
    ))

    解说:
    大嵌套套小嵌套的用法。
    第一段,专讲艺术家图片,在其在作为子窗体的时候,跟随自身尺码的变化而转移位置。在其作为独立窗体的时候(记得我们的规划有个悬浮窗),这里管不着,那就交给其他方面去处理。
    第二段,专讲封面,当其尺码变化时,位置也相应地改变。
    第三段,当封面或艺术家图片在某种尺码下,相应的其他音轨信息(基本信息、分级信息、歌词、艺术家与专辑扩展信息)跟随变化位置。同时,自动显示或隐藏。而是否自动隐藏,也设置了一个开关。原本有多项关联,当前的情况就只剩下一个歌词秀了。
    这个例子,不象前一例Load中的语句在窗体上有直接的表现。也就是说它是人的话,可不再是什么都写在脸上的人,而是颇有城府的了。这城府有些还来自于Load这个心直口快的人。
    所以,这三段尤其第三段理解起来也相对比较困难一些。现在可以试着解读。但当全面完工投入使用,回头再来理解,它城府再深也是可以看清真面目的。所谓事久见人心呗。所谓读万卷书行千里路呗。
    注意,

    $strcmp(%AtW_text_state%,a_uto)这样的句式不少。这是比较字符串的TF,这例只要%AtW_text_state%就够了,因为该变量其值只剩有与空两种情况。而$strcmp(%AtW_artist_size%,s_mall)之类的就不好再有其他的简化。
    比较两个函数的用法
    $showpanel()
    $showwindow()
    移动窗体函数带activate:false参数。这个参数是不想让被移动的对象获取焦点。
    最后一段,在移动窗体或显示面板之后,多有进一步的附加处理,可以思考一下,它们干嘛咧?画蛇添足吗?
    思考下下,Resize中代码与Load中代码的关系?它们为什么不写在一起?


    // $updatewindow(%_id%,event:resize)
    解说:
    当主窗体设置为可调整外尺寸时,本句应开启。本例无需。

    ——看图想代码
    好像也不必俟全面完工,现在就从我这先抓两张图,看看。想什么,别开小差喔。上次提醒,这次不了。

    听流行——


    听古典——


    想专心一些些



    ——例4.1.3 Open 打开
    $minmax(%_id%,640,360,640,360)

    解说:
    限制窗体尺码。有关用法请见工具箱中的函数页的窗体组中的该函数。
    其实,FUI的函数对自身的释义、写法、用法、例子、补充说明等已经写得相当具体、好懂(就算不懂日语也足以猜个八九)。所以,本讲义一直以来都不太在这方面多费口舌。如今,函数文档已在汉化推进中。不久之后,更将水落石出。我真有点后悔,为啥不等有中文文档再开始写,再开始应用FUI啊。

    以下代码供预习,下次更新再解说。
    可以给自己提一些问题,然后自己解答。
    可以带着自己的需求,然后问,这个可以用在我那吗?其实早就可以不停地这般地问。要本着自己的需求去学习,学以致用。

    $map(%_id%,lbuttondblclk:'$ifequal(%playback_isplaying%,1,$mainmenu_execute('Playback/Play or Pause'),$mainmenu_execute('Playback/Play'))')
    $map_rect(%_result%,$calc(0.12*%_cwidth%),0,$calc(0.88*%_cwidth%),$calc(0.92*%_cheight%))
    $map(%_id%,lbuttondown:'$hash(AtW_albumArt_size,)$updatewindow(MAIN,resize)')
    $map_rect(%_result%,0,0,$calc(0.12*%_cwidth%),$calc(0.80*%_cheight%))
    $map(%_id%,lbuttonup:'
    $if($strcmp(%AtW_tree_state%,s_how)
    ,$hash(AtW_tree_state,)$hash(AtW_albumArt_size,l_arge)$hash(AtW_artist_size,s_mall)$showwindow(ALBUMART,1)$showpanel(ELPLAYLIST,false)$showwindow(TREE2,0)
    ,$if($strcmp(%AtW_albumArt_size%,l_arge)
    ,$hash(AtW_albumArt_size,b_ig)$hash(AtW_artist_size,b_ig)
    ,$hash(AtW_albumArt_size,l_arge)$hash(AtW_artist_size,s_mall)
    ))$updatewindow(MAIN,event:resize)
    ')
    $map_rect(%_result%,$calc(0.12*%_cwidth%),$calc(0.92*%_cheight%),$calc(0.57*%_cwidth%),$calc(0.08*%_cheight%))

    //--show/hide tree2--
    $map(%_id%,lbuttondown:'
    $if($strcmp(%AtW_tree_state%,s_how)
    ,$hash(AtW_tree_state,)$hash(AtW_albumArt_size,b_ig)$hash(AtW_artist_size,b_ig)$showwindow(ALBUMART,1)$showpanel(ELPLAYLIST,false)$showwindow(TREE2,0)
    ,$hash(AtW_tree_state,s_how)$showpanel(ELPLAYLIST,true)$hash(AtW_albumArt_size,s_mall)$hash(AtW_artist_size,s_mall)$showwindow(ALBUMART,0)$showwindow(TREE2,1)
    )$updatewindow(MAIN,event:resize)
    ')
    $map_rect(%_result%,0,$calc(0.82*%_cheight%),$calc(0.1*%_cwidth%),$calc(0.18*%_cheight%))

    //--menu--
    $hash(ax,$calc(0.69*%_cwidth%))
    $hash(ay,$calc(0.90*%_cheight%))
    $hash(bw,26)
    $hash(bh,40)
    $for(i,0,5,1,'
    $puts(tip0_text,Help & Expand)
    $puts(tip1_text,Set Background)
    $puts(tip2_text,Set Layout)
    $puts(tip3_text,Image & Text)
    $puts(tip4_text,Playlist Switcher)
    $puts(tip5_text,Make Item)
    $tooltip(%_id%,$get(tip%i%_text),$calc(%ax%+%bw%*%i%),%ay%,%bw%,%bh%,font-name:Nyala,font-size:19)
    $map(%mainid%,lbuttondown:\"$popupmenu_view(popup_\"%i%\")\")
    $map_rect(%_result%,$calc(%ax%+%bw%*%i%),%ay%,%bw%,%bh%)
    ',escape:true)
    $tooltip(%_id%,Open/Close Searcher,$calc(%ax%+%bw%*6),%ay%,%bw%,%bh%,font-name:Nyala,font-size:19)
    $map(%mainid%,lbuttondown:'$if($ispanelvisible(QUICK_SEARCH_TOOLBAR),$showpanel(QUICK_SEARCH_TOOLBAR,false),$showpanel(QUICK_SEARCH_TOOLBAR,true))')
    $map_rect(%_result%,$calc(%ax%+%bw%*6),%ay%,%bw%,%bh%)

    $if($strcmp(%AtW_start_state%,p_lay),$playback_control(play),)
    最后编辑kmpfor 最后编辑于 2009-11-06 10:25:23
    TOP

    //--misc--
    $map(%_id%,lbuttondblclk:'$ifequal(%playback_isplaying%,1,$mainmenu_execute('Playback/Play or Pause'),$mainmenu_execute('Playback/Play'))')
    $map_rect(%_result%,$calc(0.12*%_cwidth%),0,$calc(0.88*%_cwidth%),$calc(0.92*%_cheight%))
    $map(%_id%,lbuttondown:'$hash(AtW_albumArt_size,)$updatewindow(MAIN,resize)')
    $map_rect(%_result%,0,0,$calc(0.12*%_cwidth%),$calc(0.80*%_cheight%))
    $map(%_id%,lbuttonup:'
    $if($strcmp(%AtW_tree_state%,s_how)
    ,$hash(AtW_tree_state,)$hash(AtW_albumArt_size,l_arge)$hash(AtW_artist_size,s_mall)$showwindow(ALBUMART,1)$showpanel(ELPLAYLIST,false)$showwindow(TREE2,0)
    ,$if($strcmp(%AtW_albumArt_size%,l_arge)
    ,$hash(AtW_albumArt_size,b_ig)$hash(AtW_artist_size,b_ig)
    ,$hash(AtW_albumArt_size,l_arge)$hash(AtW_artist_size,s_mall)
    ))$updatewindow(MAIN,event:resize)
    ')
    $map_rect(%_result%,$calc(0.12*%_cwidth%),$calc(0.92*%_cheight%),$calc(0.57*%_cwidth%),$calc(0.08*%_cheight%))
    解说:
    Map出场了!
    始终不知道该怎么翻译它。地图?映射?……?没办法,英文水平不够,找字典罗——有声字典说

    map: [ mæp ]读的不准,听起来象骂人。“妈的。”
    n. 地图
    v. 映射,绘制...之地图,计划
    [计算机] 存储区分配图
    一道再找一下Hash——字典又说
    hash: [ hæʃ ]  读的还是不准,“孩子。”
    n.无用信息, 杂乱信号
    搞半天,原来她们是母子关系啊!难怪!!!

    Map组有4个函数。$map与$map_rect或$map_circle如影随形,亲如父子。其中前者负责将行为函数赋予鼠标动作,而后者负责在窗体上划一块或方或圆的地方给前者施展拳脚。
    由于所赋动作具有或同时具有其中多样甚至全部:点击、右击、中击、悬停、离开、上滚、下滚、加强键击……真乃太极八卦六合地躺拳打脚踢啊。所以,不论从原意、不论从动作要领、行动轨迹、甚或控件外形,实在难以找着一个贴切的说法。
    经过长时间的使用琢磨,一并考虑包揽鼠标手势,我们决定以触摸和触摸区来归纳这一系列的动作和外形。这样说来,Map的意思就是同时含有地图和映射的意思。
    也就是说,在指定区域内,用鼠标施行全方位动作,以达到执行用户旨意的目的。这已经远不是按钮可以形容的。这就是Map。存储区分配图?不,不是这么平面化的。我觉得这个命名相当有诗意。
    再想想第一个亮相的Hash。比较一下它们的语法:

    $hash([name][,val])
    $hash_save(filename,key[,key...])
    $hash_load(filename)

    $map(windowid[,options...])
    $map_circle(objectid,x,y,w,h)或$map_rect(objectid,x,y,w,h)
    $map_preview(objectid[,options...])

    表面看起来不一样的样子。其实很神似。
    Hash是全局性的,不需要指定活动范围;Map是局部性的,需要指定国籍(窗体ID)和生活城市(活动区域)。
    Hash的赋值范围十分广泛(杂乱者,无所不包也;无用者,有用之所。我真是对作者的命名能力佩服得五体投地啊!调色板,多有童心!!!请允许我念念不忘好不好);Map也一样,但主要是动作映射。
    Hash就象李勣更象张良,足智多谋,运筹帷幄,决胜千里。
    Map就象李靖更象韩信,能征善战,攻城略地,开疆拓土。
    是他们忠于职守,迎来FUI大汉盛唐般的繁荣富强。
    牛吹远了,还是落地看看这Map都来这干些啥事比较实在。
    第一个Map,用于播放或暂停或续播。
    第二个map,用来改变封面尺寸并在此前提下更新主窗体的Resize页。
    第三个Map,用来变幻界面以适应选曲或欣赏。内容比较多,有了Resize第三段一回遭遇战的经验,这一次读者自己分析看看应当不成问题了。
    第二第三个Map中,均有Hash活动其间。看来它们也是你中有我,我中有你的。都说了,一对母子,能不亲乎?
    标准用法中, $map都需要通过$hash来赋值取得名份objectid,然后由$map_circle或$map_rect方圆到地图上。可是这些例子都不见有这些标准的$hash。是的,FUI在其函数示例中没有这样写。但是,我总怀疑$hash思想不纯正,它们动不动就想搞政变,必须尽可能减少它们的数量,压住其居心叵测的有生力量。这不,经过%_result%这一杯酒释兵权,$hash队伍被大大减少了。

    //--show/hide tree2--
    $map(%_id%,lbuttondown:'
    $if($strcmp(%AtW_tree_state%,s_how)
    ,$hash(AtW_tree_state,)$hash(AtW_albumArt_size,b_ig)$hash(AtW_artist_size,b_ig)$showwindow(ALBUMART,1)$showpanel(ELPLAYLIST,false)$showwindow(TREE2,0)
    ,$hash(AtW_tree_state,s_how)$showpanel(ELPLAYLIST,true)$hash(AtW_albumArt_size,s_mall)$hash(AtW_artist_size,s_mall)$showwindow(ALBUMART,0)$showwindow(TREE2,1)
    )$updatewindow(MAIN,event:resize)
    ')
    $map_rect(%_result%,0,$calc(0.82*%_cheight%),$calc(0.1*%_cwidth%),$calc(0.18*%_cheight%))

    解说:
    依然Map。
    从注解知,无非就是显示或隐藏Tree罢了。
    反正Map就是岳飞,就是主战。
    喔,我们不敢忘怀,曾经的许诺。要主动告诉你什么地方不被刷新的。这回就在Open地区,这是一片相对安定的国土。下面的$tooltip深有体会。在这里,花团锦簇、绿树成荫。吃饭不用干活,睡觉不会做恶梦。

    //--menu--
    $hash(ax,$calc(0.69*%_cwidth%))
    $hash(ay,$calc(0.90*%_cheight%))
    $hash(bw,26)
    $hash(bh,40)
    $for(i,0,5,1,'
    $puts(tip0_text,Help & Expand)
    $puts(tip1_text,Set Background)
    $puts(tip2_text,Set Layout)
    $puts(tip3_text,Image & Text)
    $puts(tip4_text,Playlist Switcher)
    $puts(tip5_text,Make Item)
    $tooltip(%_id%,$get(tip%i%_text),$calc(%ax%+%bw%*%i%),%ay%,%bw%,%bh%,font-name:Nyala,font-size:19)
    $map(%mainid%,lbuttondown:\"$popupmenu_view(popup_\"%i%\")\")
    $map_rect(%_result%,$calc(%ax%+%bw%*%i%),%ay%,%bw%,%bh%)
    ',escape:true)
    $tooltip(%_id%,Open/Close Searcher,$calc(%ax%+%bw%*6),%ay%,%bw%,%bh%,font-name:Nyala,font-size:19)
    $map(%mainid%,lbuttondown:'$if($ispanelvisible(QUICK_SEARCH_TOOLBAR),$showpanel(QUICK_SEARCH_TOOLBAR,false),$showpanel(QUICK_SEARCH_TOOLBAR,true))')
    $map_rect(%_result%,$calc(%ax%+%bw%*6),%ay%,%bw%,%bh%)

    解说:
    依然还是Map。
    这回他们乔装打扮,混迹于$for中。打的是迂回战术。
    这个$for函数给FUI带来一个新式武器。它就象一颗重磅炸弹,外形不大,却可以炸开一片花。
    其实,它就象7z或zip之类,本质上是一个压缩工具。7z压缩文档,它压缩代码。要用好$for,关键就在于抓住代码的同质性规律。
    由于$for在实际应用中普遍需要事先赋值,所以只有步进数量在4个以上,才比较地有压缩封装的价值。
    在本次Map胶着战中,Hash与Puts同时参战。Hash在外,Puts在内,里应外合,大敌当前,体现了英勇奋战的一面,但街坊邻居都晓得,他们原本也是一对善于坑人的发过国难财的店家夫妻。
    这次封装的Map之外还有Map,仿佛淮海战役。
    不过,我们不希望战争,我们热爱和平。$tooltip就象战前的决心书,人手一份;还象战后的标语,贴满大街小巷,高举在游行人群的最前头。这就是提示,胜利的提示,喜悦的提示,举国欢庆的提示。

    $if($strcmp(%AtW_start_state%,p_lay),$playback_control(play),)
    解说:
    这一句也不一定强调放这地。可以认为它是逃亡来的,战火纷飞的说不是吗。
    一个开关,用于判断是否发来自动播放的指令。如果是,执行。如果不是,也执行。只是执行内容不同了。哈哈!哈。仿佛敌战区的一名地下交通员。
    真没想到啊,宏伟的主窗体事件就这么轻易地结束在一个小小的交通员手上。

    不妨参观一下整体结果
    最后编辑kmpfor 最后编辑于 2009-11-06 09:49:15
    TOP

    2)其他窗体事件

    除了主窗体,本规划还创建有如下窗体。

    ARTIST 艺术家窗体(悬浮窗体)
    ALBUMART 封面窗体
    RATINGEX 分级窗体
    TEXT 大文本窗体
    TREE2 节目树窗体
    CCONTROL 应急窗体

    由于它们均属于窗体范畴,在代码方面与上述主窗体的情况并无大不了的不同。所以,不打算一一解说。要再一一解说,那最多的只能是徒增重复感。当然,学习常常需要不断的重复,重复本身就是一种学习。所谓温故而知新,温故而知故。
    前面代码主要从内部的角度来观察,来解说,下面让我们一起调整一下视角,从外部来看看。因为美女与青蛙剖开肚皮看看到的总是医学上的差别。


    ——看图想代码

    TREE2窗体
    显然这是一个伪装用的窗体。它专门用于装载Library Tree面板,目的是隐蔽滚动条。要说美女吗,她象西施。西施衣长拖地意在蔽其足。
    西施本是越国民间浣纱女,因常年赤足导致脚大,因其脚大,故安排她管理媒体库过滤与播放列表两大区。西施习水,有源远流长之韵,正合媒体库的特点。此外,西施也从事过国际间谍工作,善于伪装,故安排她执行这个伪装窗体的任务。媒体库与列表犹如吴越两国,一衣带水,战事频频。
    问:踏遍吴越,为何总不见西施身形?
    答:夫施隐民间、或潜吴宫、终与陶朱公叩舟淡远,不见为正。来日方长,或不期而遇也未可知矣。



    MAIN窗体 补遗
    在主窗体事件中,我们沉浸于内部代码,基本上对其外表是视而不见。主窗体仅加载背景,然后就是面板与子窗体(注意,窗体事件的加载顺序,这与现在的表述无关)除外,还有一个无比重要的大使。她就是总菜单条。她就是王昭君。
    昭君生于蜀,得蜀山剑侠真传,入宫侍君,因延寿老儿一点之陷,导致塞外和番。瞧,AtWill 脸上有一点,那点相传正是当年著名科学家兼工笔画家毛延寿留下的非生物标本。昭君大漠勤夫,母仪一方,肩负过大汉民族百年安宁的历史使命。她完全有觉悟完全有能力管好我们全部的这六个“左键”弹出菜单。
    菜单所在位置,正是边界,快要离开祖国了,回头望啊!眼框湿……


    ARTIST 艺术家窗体(悬浮窗体)
    用$gp_image(windowid,filename,x,y[,w,h][,options...])绘写New Track事件发送来的艺术家图片。
    $gp_image(%_id%,%ART_img%,……)具体一点,并设定%art0_img%优先且默认。现在不该列完整句式了,自己动手丰衣足食。
    整个窗体附着Map。左击一变,右击另一变。
    当它作为独立窗体的时候,将其图片范围扩大到艺术家、专辑艺术家、作家、表演者、专辑封面、封底、CD图、盒子图8幅(这些图片也来自于New Track事件,记得吗,回忆也是学习)。并作为悬浮窗的背景。
    当悬浮窗放大,这个窗体就变成一个图片阅览器。阅图器可无极放大,最大可达全屏。全屏下有预告节目功能。这样看图就爽歪歪了。
    爽歪歪的事不仅如此。这个艺术家窗体并非女魔术师。她是貂蝉。
    貂蝉拜月。月挂于东,人自在西,月高于天,人自在地,月明于夜,人自在暗。故貂蝉蜇伏西南角。角之西南,火金交加,战事在即。故,左点貂蝉,吕布持戟冲出。吕布年轻,“Hi Ha Hai Hi 快使用三节棍……”听的端的是流行歌曲。右点貂蝉,董卓背手踱至。卓喜群舞,好古典。嘿!董卓古典?阮大铖都能写《燕子矶》,董卓如何不能古典?快,快去传湖北省歌舞团来,今夜编钟乐舞,一曲乐歌·桔颂毕,接一曲房中乐·关睢。此间乐,不思蜀却思人。可怜貂蝉,为报王允深恩,身傍虎狼,心寄赤免,满怀辛酸无处诉,惟有泪千行……


    《插图 悬浮窗、阅图器》



    RATINGEX 分级窗体
    以$for为重。
    原本将跳、单曲分级、专辑分级合一块。后将专辑分级分出。单曲分级采用竖形结构。
    简明的音轨信息也在此显示。
    问:竖排信息只见中文?
    答:对。楼下有朋友用$len和$lenb去比较想得出是否为汉字。这个方法可行。但我没用,我用$ascii。一个就行。
    分级代码在《FUI零件共享》中已详细解说。有兴趣者看看去。
    哪还有想去?此窗体体态丰腴,身披纱羽,宛若出浴之贵妃。茫茫大唐,只见玉环手擒荔枝,风姿绰约。那荔枝,才刚剥成晶莹剔透,三个五个,入口甘臾,回味无穷啊。
    问:那纱羽,可是西施所浣?
    答:吾亦未知。然,施环左右相映,实乃今学之非均衡性对称是也。
    问:荔枝,没有?
    答:那灿如水晶的分级结果难道不就是光映下玉环玉手上的南国来的荔枝肉?

    TEXT 大文本窗体
    内容在前面的添加面板中已经叙述。这里无非就是对其滚动条的精心隐藏。就象西施无人知晓的一方去处。

    CCONTROL 应急窗体
    大量运用Map。看似许多按钮,其实没有一个按钮。虽然不是按钮,所到之处,却也事必暗示。
    外表就象一台真实的专业功放,算一种气氛。
    把杂项如切换播放模式、定位条、音量调整、计时器、频谱显示等集中起来,俨然一个扩展控制台。还从实用出发,预设一组DSP。比如单声道转立体声、六声道转二声道,跳单轨空白段、加载VST插件、Flat效果、分频应用等等。
    毫无疑问,这是王昭君的出使地,是昭君在安排应急事务吧?

    《插图 功放》



    ALBUMART 封面窗体
    绘写封面、封底、CD图、盒子图。主要用$gp_image(%_id%,%art8_img%,……)语句。$gp_circle、 $gp_roundrect配合。
    尽可以把它当百变貂蝉。貂蝉
    支持每音轨一图。
    支持通配符。
    支持不同的蒙片、相框。
    支持变幻形状、大小与位置。
    可以想一想,它们是怎么实现的?来龙去脉要理清楚。
    想啊:
    (1)相框、蒙片在哪处理?
    (2)形状、大小、位置又是从哪儿决定的?
    (3)每轨一图、通配符这些由来何方?
    不要限于该窗体,现在必须联想。不予联想,FUI就会没来由变得不好惹的。这也是我们突然改变写法,暂时中断解说代码的原因之一。
    这也是我们不吝笔墨试图叙述西施之忍辱、昭君之负重、貂蝉之可怜、玉环之可叹的原因之一。
    有关图片功能的进一步探讨请参与《FUI零件共享》。


    本节未有配图者,请参见主窗体事件之相关插图。

    5. 其他事件
    至此,这个FUI打造的Foobar2000已经固定成形,播放、转换、管理都已不成问题。不过,还是有些细节需要进一步完善。
    比如定位条,比如时间阀,比如音量,比如由选曲等带来的列表状态变化等等。

    ——例5.1
    On volume Change 当音量改变

    $removeobject(%volume_rect%,redraw:true)
    $hash(vW,$display_volume(112))
    $gp_rect(CCONTROL,$calc(153+%vW%),43,2,2,brush:255-255-20-147)
    $hash(volume_rect,%_result%)
    $setobjectzorder(%volume_rect%,top)
    $updateobject(%volume_rect%)

    解说:
    多言数穷,不如守中。

    ——例5.2
    On Playback Time 当播放进行中(每秒)

    $if($iswindowvisible(CCONTROL),
    $if($strcmp(%AtW_seek_state%,s_how),

    $if(%playback_can_seek%,
    $if(%SEEKBAR_RECT%,$removeobject(%SEEKBAR_RECT%,redraw:true))
    $gp_roundrect(CCONTROL,$calc(%SEEKBAR_X%+%SEEKBAR_B%+%SEEKBAR_BW%*{%playback_position%/%playback_length%}),%SEEKBAR_Y%,6,6,1,1,brush:%SEEKBAR_BC%,aa:false)
    $hash(SEEKBAR_RECT,%_result%)
    $setobjectzorder(%SEEKBAR_RECT%,top)
    $updateobject(%SEEKBAR_RECT%)

    $if(%time_TEXT%,$removeobject(%time_TEXT%,redraw:true))
    // $text(CCONTROL,$hms(%playback_position%),96,107,120,20,fg:55-255-55,bg:255-255-155,font-name:DS-Digital,font-size:16)
    // $gp_text(CCONTROL,%length%  $hms(%playback_position%),96,107,120,20,brush:91-55-255-55,pen:91-255-255-155-1,font-name:DS-Digital,font-size:16,glow:100-200-255-1-5,halign:center,valign:top,font-size:16,shadow:rightbottom-1-1)
    $gp_text(CCONTROL,$hms(%playback_position%),156,107,56,20,brush:91-55-255-55,pen:91-255-255-155-1,font-name:Consolas,font-size:12,halign:right,valign:top,font-size:12,shadow:rightbottom-1-1)
    $hash(time_TEXT,%_result%)
    $updateobject(%time_TEXT%)
    )))

    解说:
    第二段在于绘写一个自动推移的定位游标。它在“功放”的最上方(双顶:上方,前端)。要完善它,还需在功放上码上类似的代码,以达到支持人工定位的要求。
    第三段在于向功放的时间仪表定时发送数据。
    这两段代码在FUI作者的示例中有,这里已经经过“优化”处理,它看来效率会提高一些。
    时间数据也可以通过“提供参数”的方法来解决,但那时$gp_text这个函数会出点意外,我不明白这是Bug,还是没有正确地运用。只是用这种方法也不能提高每秒功能的运行效率。
    总的来说,这两段代码最让人不满意。但我们不能责怪代码,真要责怪,首先应当从码代码的人上来找原因。如果这些代码已经尽职尽力,我们就要上溯责任。
    但不管怎么不太满意,它们还是可以正常工作的。表面也看不出有多少异样。只是在某具体系统上发现有不够顺畅的蛛丝马迹。
    不过,对于要求高的同志,建议这个定位条采用WSHM来写。音量调整如果要模仿旋转钮建议也用WSHM。那样会更容易更完美。不过,与此同时,我遇到另外一个棘手的事情。每音轨都有闪一下,甚至不定什么时候会闪一下。参照高手的代码,还是会闪一下。再看看高手直接的作品,也是会闪的。当然,这都是先前版本遇到的事,后来的情况我就不知道了。
    没办法,思来想去,最后,终于全部只用FUI的函数来解决了。
    万幸的事,我个人的使用习惯正好绝少用到这些。一年下来,音量游标是一次也不会动的。我的遥控器上有音量调节,键盘上面也有专门的音量按钮。我还没有勤快到喜欢麻烦一点。定位条也只是在测试的时候用一下看行不行。我也不善于使用定位条,不明白为什么需要频繁地拉动它。但我知道人家总不可能吃饱了犯傻,他们必定有自己的用意。个人需要总是千差万别,所以才需要一人一个Foobar2000。所以,才有必要写出本讲义。
    《插图 功放 喔先前插过了,见上面》

    ——例5.3
    On Playback Edited 当数据更新

    解说:
    这个用于体现当可编辑信息产生变动时,及时通知相关信息的使用者。并让其做出适当的反映。
    比如要让分级结果在改变时同时变化一下显示的颜色。就需要将代码写在这里。你可以把先前在New Track中写过的代码复制过来,改一下有关颜色的代码就成了。真这么简单?是的,就这么简单。
    本规划中,分级变动显示要跟着变。编辑艺术家、专辑信息等,也要引起显示上的变化。此外,我发现,当计数器计数时也由这里自动发出数据更新指令。
    我们的用户脚本有个 tag_data
    New Track事件中我们用过一回了,现在再用一回。$tag_data()。就这样。放在前头,因为这小女子总爱当头。

    理同于上,暂停、音轨选择(焦点)等等小项就不再赘言。当然,对这个开发案是小项,对其他开发案来说也许会是大项。这是需要注意。

    ——例5.4
    On Quit 退出


    //--!--
    $hash_save(/Presets\hash.data,

    AtW_bg_image,
    AtW_bg_trans,
    AtW_body_trans,
    AtW_albumArt_frame,
    AtW_text_state,
    AtW_cfont_sate,
    AtW_seek_state,
    AtW_start_state,
    AtW_fg_glow,
    AtW_art1_PATH,
    AtW_art2_PATH,
    AtW_exe1_PATH,
    AtW_exe2_PATH,
    AtW_exe3_PATH,
    AtW_exe4_PATH,
    AtW_dsp_txt)

    解说:
    没有忘记吧,FUI初步时我们一起探讨过内部流程的,当主窗体关闭程序退出前的那一瞬间,On Quit是一定要回眸一撇的。没有忘记吧,在On Init中我们遇到的第一项是
    $hash_load(/Presets\hash.data)
    再回想一路过来我们遇到的无数AtW_x_X……明白了吧,张良Hash!

    6. 事件小结
    并没有按通常事件、用户事件、窗体事件三种事件类型来组织讲义结构的。我们从用户的角度,从开发者的角度,基本上顺着FUI内部运作流程,来组织代码组团的解释工作。
    在组织代码的同时,我们也谈到了开发中的代码检验方法,二R方法,即Run与Refresh。
    所有代码均来自于客观真实的应用实例,绝非道听途说,绝非为讲解而临时编纂。读者对其仅需根据自己的实际情况略作打磨就能顺利移植到自己的配置之中。如此,将给自己的开发带来精力和时间上的双节约。
    也由于代码来源于实例,该实例没有用到几个需要提一提的控件:
    按钮。FUI对按钮的处理与其他组件有十分明显的区别。其他组件当按钮设置通常就定居在那,更新也基本没它什么事。但FUI不同,它将按钮视同对象,级为次于窗体的中级。按钮可以刷新,也可以移动,不过其为字符按钮时字体及字体背景不能透明。这是本开发例没有用按钮的根本原因。事实上,FUI的图形按钮也可以雕琢得十分明艳性感。
    组合框。这控件被安排与按钮在同一组。可视为加强型的按钮组团。原名直译为康宝盒,很时尚的名称,却用来实现很古老的功用。如果用过Lotus套件,一定不会忘记那抽屉般的有配音的操作方式。康宝盒就是这样的,一点就象抽屉被拉开,抽屉里划好几格,比如中药柜那样,但这格要来得好看。因为这些格允许配色,要多美就可以多美。遗憾的是,这个抽屉的边框还处于系统风格,我也不知道怎么才能装修它。
    消息框。消息对话框?是的。$msgbox(msg,title,button)。MessageBox的返回值,列出如下供参考:

    (1)OK 确定:      1
    (2)Cance 取消:  2
    (3)Abort 终止:  3
    (4)Retry 重试:  4
    (5)Ignore 忽略: 5
    (6)Yes 是:        6
    (7)No 否:          7

    我想啊,都做到这儿,何不干脆再做个InputBox?
    除此之外,还有一些函数没有被用到。但相对已经很少,有了这些学习做基础,大概理解掌握并不会有难度了。

    $closewindow(六、起——组织代码之具体实例)
    $window(六、起)
    最后编辑kmpfor 最后编辑于 2009-11-07 11:49:37
    TOP

    六、起

    ——4.章小结
    本章从工作台出发,讲述了建立窗体、添加面板、组织代码三个部分的有关内容。建立窗体、添加面板还可以从Func菜单轻松地进行,子窗体也可以通过右键呼出用鼠标拉动于父窗体上定位,但这些我们没有讲,也不想再讲。由于前二者过于简单,我们把几乎全部的篇幅与精力都放在了组织代码上面。注意,是几乎全部。记得FUI初步的概述,我们也是这样表述的,FUI几乎……全靠代码怎么怎么样的。要记得,这回我是经过脑子才讲话的。原本想把代码全部都码上来,有需要的复制回去,就成一个可用的配置。不过,这样会很啰嗦,不好。所以,现在将整个开发结果附在附录,想试的朋友就可以实践了。

    干活不见影,酒宴会议保准来。好了,领导到场。下面请上级领导讲话。
    领导说:
    同志们好!今天我既然来了,就给讲两句,我就讲两点吧。先讲第一点。
    代码工作到今天为止总算全面结束了,今天就是庆功的好日子。在这举自己同庆的沸腾的气氛中,我们回想这些日子以来朝夕相处的点点点点滴滴,切身体会到全体代码同志无私奉献精神,亲眼目睹他们服从用户需要,毅然决然到最艰苦的地方去,到最危险的地方去,到人都不敢去的地方去。他们或单队或团队,一不怕苦二不怕死,以帕格尼尼的惊人速度,以霍洛维茨的惊人力度,象卡拉扬那样神勇奋战,攻克了一道又一道的艰难险阻。他们完成了人类过去现在乃至未来都不可能完成的任务。现在粗粗统计一下,创新成果有不少项,如:个人创新有类触摸操作法、节目预告、节目列表、透明通配符法、背景当场换、用户设置现场化、内外远近沟通法(比如读取文本类文件等等)等等。团体创新有中文长文本完美显示屏、媒体库通用软件管理方法,专辑分级功能,等等等等。这些内容到目前为止,还没有发现有什么组件可以实现。专辑分级可能有了。所以,是了不起的,是不得了的。
    实现替代功能有不少项,如:跳功能、找回节目功能、上网搜资源功能、启动本地程序或文件功能、艺术图片显示功能、曲目分级功能、自动分级、DSP预设功能、播放列表切换器、透明容器、透明背景下的信息字体宣染、直接写屏、全局变量、配置自动保存等等、等等。真是不胜枚举啊。
    所有这些,如果雇用DLL插件,需要牵涉到到:

    foo_uie_wsh_panel_mod (或foo_uie_wsh_panel)
    foo_uie_panel_splitter
    foo_uie_tabs
    foo_run
    foo_exvar
    foo_uie_trackinfo
    foo_uie_trackinfo_mod
    foo_skip
    foo_uie_playlists_dropdown
    foo_osd
    foo_uie_albumart
    Album Art Downloader XUI
    foo_dockable_panels
    foo_dock Dock
    foo_auto_rating
    DSP导出与保存,具体名得再找找
    设置自动保存,这个也是,大约象这样foo_jesus吧。

    肯定还有一些,一时也想不全。算了,就算只有这些。
    少说也有16、7项。想想,这得给用户节省多少资源啊。少了十尊佛,一年到头得少多少香火啊!请大家好好端详端详这些插件,要效果的都是需要代码俟候的,只是它们分散着写,各处都不是非常的多,但集合起来就可观了。我看,它们的代码总数一定大于我们,至少至少持平。而且他们插件多,代码语法五花八门,学起来相当零碎,不象我们这么统一,只要一种通。一种通,就象全国粮票,不论走到哪个省都可以吃饭没问题。所以,我首先是无比的激动,无比的感动,无比的冲动。代码同志们,辛苦了,谢谢,谢谢你们以一当十,少吃饭多办事。给你们致敬了。
    这是第一点,第二点,也是今天的第二个内容。根据上级布置,对本次代码工作做一个全面性的总结。(上级秘书写的),下面我给念一念:
    组织代码是项目规划的重点对象,是一项工程中轰轰烈烈的建筑施工,是一个战斗中你死我活的肉搏血拼,其重要性不言而喻。当然,同时也要看得到,它毕竟只是项目规划的一个具体实施部分——起中的一部分,是整个集成工作中的一道具体流程而已。
    码代码属小处着手的范畴,主要是靠细致耐心,但心中要片刻不离大处着眼。组织代码一定要服从规划方案,不可随兴指使代码去执行一些不相干的分外活。哪怕有时是那么的精美诱人也不可。
    也不要过于迷恋任何一个小战斗的完满漂亮,要注意全局形势的总把握,统一方向,协调运行,有序从而高效地去完成用户交给的每一项光荣任务。
    务必深刻知道,就象战争的胜败早在战争之前就已经分好,我们一定非常地警惕一种倾向,那就是单纯的代码主义。这种的单纯的代码主义看似实干忠厚,其实是不肯或者不善动大脑筋。他们眷恋在一个小圈圈里死命地勤奋死活地不肯自拨。他们总难免爱投机取巧,或者有时爱耍一耍小聪明,对上级明明正确的指示总是理解困难、缓慢,跟不上总形式的发展变化。所以,貌似一向冲在最前头,其实始终都在拖后腿。我们之所以这样痛下决心抨击,要抨击的并不是这种主义的积极性,而是他们一贯迷糊的方向性。
    作为码代码的总指挥,全世界每一位对自己负责任的开发者,都不应当把40%以上的精力放到码代码的繁琐的具体工作上面。这个40%科学地计算起来还是太多,不能这么宽裕,就给30%,这是死要求,不允许讨价还价,因为我们的作品形不成商品,它卖不成钱。就算再过几个世纪熬成了古不懂,依然如此。那万一本世纪就真有大傻瓜要来买?那样我们反而不卖了。这不是说我们跟傻瓜一个劲地傻瓜,那是因为这个从来就不能够成为我们的根本的主张。这一点任何时候都不能不小心给忘记,忘记了就等于失去了根本。当然,话说回来,从头到尾,码代码的总人手还是仅仅你自己一个人。没有人会有可能腾一手帮你。他们有他们的顾虑、承担和种种难以意料的牵挂。但就是在这种艰难困苦缺衣少食的恶劣情况下,也还是坚决要确保69%以上的精力出来,出来深入群众搞调查研究、出来倾听用户心声、出来搞深入细致的具体可行的完整的规划、出来后面还有许多必须的工作。活已经干到这份上,我们坚决不能够躺在过去的功劳簿睡不起来,坚决不能够半途而废,坚决不能够虎头蛇尾。只有这样,历经千辛万苦最终搞出来的作品,自己才会喜欢才会爱用,才能给自己带来无穷无尽的喜悦和欣慰。
    (领导话音未落尽,会场掌声雷动。其实大家是按惯例走程序式的一鼓。鼓完好散会,散完会好吃饭吃酒去啊!)

    七、调试

    为什么要调试?都要调试些什么?
    调试分两种,一种是开发过程中的调试,一种是开发结束后的调试。开发过程的调试已经在上一章中穿插讲了一些。
    此刻,房子是落成了,轮船是造好了,汽车是就要出厂了。但房子轮船交付前必经竣工验收、汽车需经检验。为保证今后稳定高效地使用,我自己的Foobar2000当然也是需要全面检验的。

    方法一,菜单法
    FUI窗体的右键菜单共有5项,去掉头尾,中间三项主要都是为检验服务的。其一Information信息,其二Embed内嵌,其三Refresh刷新。
    信息二级菜单有七项,从上往下依次为窗体ID,坐标,尺码、用户尺码、鼠标坐标、内嵌数量、对象。其中最后一条对象还有三级菜单,这最深层的菜单在我这里草算就有17条分3组。第一组是控件,第二组是图文,第三组是Mpa与全局性的组团。从这些分门别类、层次分明的信息条目中,我们可以清楚地明白在我们的窗体上到底都有些啥子内容。
    比较这些信息与我们的设计,比较这些信息前后的不同,都可以帮助我们发现Bug,我们在开发过程中产生的Bugs。举个例子,比如$tooltip我们的施工只做了7个,但信息却给14个这样的情报。这肯定是有问题的。一定是要追查到底的。后来,经进一步调试,发现原因出在重复绘写。后来我们采取必要的清除手段(记得具体方法吗?),问题就得以解决。

    再看内嵌,分窗体、面板。不但可以查户口,有的还可以调出本人来看看。

    刷新就是二R方法中的一R。

    方法二,Console法,控制台法
    在开发中调试我们讲过Run,Run还可以用,但现阶段主要用Console。其实$console也是个函数。
    程序一启动,就打开工具箱,密切关注Console显示屏。有没有不对劲的信息?如果有,就需要逐条落实,直到再度启动时一切正常为止。
    然后,是每轨信息。有没有异常?比如出现文件不存在的错误提示,我的情况就出在$files()上。换一个方法。解决了。还出现别的提示,分析分析,不是问题的就算了。
    还有啊要,对鼠标行为进行监控。你点,你看。正常不正常?

    《插图 信息观察、控制台观察》


    方法三,效率调试。
    对同一任务换不同代码实现方法进行比较,以效率高者为当选。

    方法四,主程序版本调试。
    从基于开发的版本向前推移,当新版本出来时,向后推移。比如,经此方法,本开发项目从0.9.6.9向前一直试到0.9.5.4。最终建议使用0.9.5.6或0.9.5.4。喜新者可以用0.9.6.9。

    方法五,组件适应性调试。
    换组件版本试试。此项调试结果与采用主程序版本有关,具体请见附录。

    方法六,你说呢?任务管理器法。对,还有呢?

    八、实地运行

    就象轮船试水要走几个不同的海域。
    我们的开发案总象船不太会移动着建造那样总是比较多地在一个相对固定的系统环境下进行。好了,现在弄好了。
    在原生环境下,运行通常不会有什么问题啦。

    换一个系统看看。
    原先在Vista下开发,
    搬到Windows 7来用用看,中文版的、英文版的,都看看,X86的,X64也都看看。
    也搬到Xp下去试一试。Linux、Mac当前肯定不行的啦。
    不同大环境下还各有小环境的问题。有的系统塞满不知道什么东西,有的系统却保持得相当干净。伊呀!里面有陈某人泄露的图图!别大惊小怪,也别管它,这不是我们该关心的。我们关心的是,不管它什么环境,都要试一下,都要看看表现。

    实地运行要视同投入生产。真刀真枪地加载媒体库,真刀真枪地让它处于平常处于极限工作状态。
    如果这些关都过了,我们还要记得记下用户的反应与反映。

    本开发实例实测结果
    结论是可以在Vista、Windows 7 X86 X64下运行。在Windows 7下运行效果更好。X64下运行也正常,但有ASIO出现过状况的记录,但这个状况的根源是硬件驱动程序引起的。Xp没有机子可试。

    九、改进

    一开发完就能尽善尽美的可能性,就算神仙也是没有把握的。而且神仙懂不懂当今的计算机技术还是个大问题。
    改进的工作是免不了的。刚愎自用要不得,一意孤行要不得,负气撂挑要不得,从善如流、精益求精才是根本出路。自己对自己也需要从善如流?对!自己不是多元化多面性的自己吗?自己不是摇摆间的自己吗?自己不是前进中的自己吗?

    改进方法。
    大的全盘性的改进,还是做个补充规划比较好。
    小的改进,可以按笔记进行。
    少的改进,可以凭记忆进行。

    改进结束,最好进行一次全面彻底的反思,把好的经验与好的教训都总结一下。总结完了,写一份用户操作指南好不好?言简意赅。让它被FUI帮助与设置窗体读出,看起来就象正规厂家出品的一样。

    《插图,帮助与设置》



    十、成品:导出或者打包

    ——导出
    导出操作就在导入的身旁。FUI初步我们都会导入了。

    ——打包
    主要是选择打包工具与打包程度。
    1.可以用Nullsoft Installation System、Inno Setup 等专门的安装制作工具,好处是具备完善的定制方法,包括安装过程中的注册行为。可以做得象原版那样。
    2.可以用7z等压缩工具。直接压缩;或做成自解压。自解压也可以做得象安装程序。不过脚本定制能力没法跟安装程序制作工具相提并论。
    我主张用7z自解压形式。即有简便的安装,也可以方便普通用户自主解压。
    问:没说明要打包哪几个文件?
    答:我晕。实在分不清,就全包了吧。反正又不是包二奶。又不花钱,要包几个你就包几个。

    ——总结
    成品已经可以出厂,告别的时刻来临。
    几句话最后说说,什么才是本讲义的重中重。本来讲义是本不该有轻重的,不信请把轻者全移走,看那重的还重不重。
    但是,读者多半总是带着问题来听讲的。比如他们最关心的是怎么弄代码。甚至他们会想,其实只要直截了当把代码的部分写出来,其余部分其实都可以省略,那些没用。
    我认为读者有这样的初衷很正常,我也曾经做过这样的读者。但是,要知道就象病症会转移一样,重点也是会转移的。就拿本讲义来说吧:
    在初读阶段,一般读者都觉得组织代码是重点是重中重。他们感觉不知怎么写出一行、一段、一群代码,他们把写完的代码不知放什么地方,不知什么地方好,也不知这些地方的关联关系,……所以代码是他们的难点,也是他们的重点。
    然后,随着学习和实践的深入,代码部分逐渐掌握起来逐渐熟能生巧起来,当代码不再成为难点,它的重点性也就值得重新评估。因为,在集成这个环节,代码只是平常的一种技术手段。真正比它重要,是指导代码工作的项目规划,那个规划才是我们集成工作中富有创意的施工蓝图。如果说码代码是建筑施工是劳动密集型劳动,那么,项目规划就是施工图设计是技术密集型劳动。显然项目规划比组织代码的劳动更为高级,也更为繁杂。项目规划直接对用户的需求负责,以用户需求为出发点,全面考察一切内外环境、现有技术手段,周到安排产品生成目标、过程、日程,从而生成一个即艺术又现实的行动方案。
    表面看来是起、调试、实地运行、改进、产品出厂这些步骤与行动实现了我的需求,其实决定这一连贯行动的成败的“命数”不是这些行动本身,而是指导他们的项目规划。
    是这个项目规划有效地满足了我(用户自己)的需求。要说谁最难,最难就是在这项目规划了,要说谁最重要,最重要也就这项目规划了。而项目规划中最难的地方只有一处,那就是自知之明。

    而今,我的需求已经得到贯彻落实,接下来该怎么办?
    问我啊,我就是一时茫然才写起这个讲义的啊!





    做一介蚍蜉撼一回大树
    做一头乳猪渡一趟沧海
    做一只菜鸟飞
                    一圈网络时空

    十一、附录(
    最后编辑kmpfor 最后编辑于 2009-11-07 18:08:11
    TOP

    十一、附录(

    4.FUI下插件的选择。
    作为集成讲义,插件的选择是必须的内容。放在附录只是为了不冲淡FUI的新鲜味。另外,插件选择是绝对非常个人性的东西,我也没有自信自己的选择可以波及别人。放在附录写,好像也不再那么拘束。
    总的还是一句老话,是我们根据应用需要根据项目规划来选择组件,而不能组件有什么功能我们就临时硬安上什么功能说以备来日需要。要真考虑来日需要也应当在项目规划中去考虑。
    到底是组件选我,还是我选组件?

    1)推荐(经脑子的,当主程序版本为0.9.5.X时,请注意组件的版本号):
    foo_uie_elplaylist
    foo_uie_library_tree (V3.1.1 这个版本主要是考虑稳定)
    foo_uie_playlist_tree (通常与上面那个选其一,两个都上也行)
    foo_uie_lyrics
    foo_uie_textbox
    foo_uie_quicksearch
    foo_uie_vis_channel_spectrum

    foo_customdb (也是kandata 的力作)
    foo_mouse_gesture
    foo_playlist_bind (当有foo_uie_playlist_tree可略,或当主程序版本大于0.9.5.6时迂回替代)
    foo_masstag
    foo_chacon
    foo_cuesheet_creator

    foo_input_monkey (V2.1.3)
    foo_input_dts (若无内嵌CUE请考虑foo_dts,各有优点)
    foo_ac3
    foo_input_dvda
    foo_out_asio (V1.2.6)

    foo_dsp_xover
    foo_dsp_resampler
    foo_dsp_vst

    flac.exe (怎么没有Mp3?我从来都没有压过Mp3,倒压过Mpc,也不会可能再把别的转成Mp3。Mp3正在迅速从硬盘中逃离。)

    foo_uie_playlist_tree 必须多说几句。这个组件无疑是值得大书特书的。它分带与不带Scheme两版,是俄国人cwbowron的作品。FUI从v0.0.5开始支持它。不带Scheme版功能就已经强于foo_uie_library_tree,而且定制更加灵活丰富,外观效果也更多姿多彩。不过,它所谓的列表其实是列表的“镜像”,不象foo_uie_library_tree的列表是真实的,是可操作的。foo_uie_playlist_tree与foo_uie_library_tree运行机制有些差别,foo_uie_library_tree在每次程序启动时对媒体库按用户设置进行清分,程序关闭后并不保存清分结果。而foo_uie_playlist_tree则必定在程序退出前保存用户设置到playlist-tree-0.pts文档以便下次启动时加载。这个文档扩展名有点奇怪,但内容却很平易近人,用一般的文本编辑软件就能正常打开。
    foo_uie_library_tree的筛选对象是媒体库,以对象命名,所以叫library_tree;foo_uie_playlist_tree筛选对象不仅有媒体库,还有播放列表,还有文件夹。对,文件夹,这也是为什么有它在就不需要foo_playlist_bind组件的原因。它以呈现结果为命名,所以叫playlist_tree。也正因为犯了以名取人的错,我曾误以为它与媒体库无关,差点永远无视它的存在。
    foo_uie_playlist_tree 之深不可测、神通广大,更在于它可以运用Scheme语言。这可是真正的有创新意义的程序语言。这个语言网上有非常详尽的教材,而且是英文的,看得懂的人就多了。
    是Theophile大侠指点我foo_uie_playlist_tree的强大,是Theophile大侠引我认识Scheme这门学问的。因为Scheme对我十分有用,所以就实际需要去钻研了一段时间,问题总算得以解决。也由此发觉自己所学到的部分仅仅是沧海之一粟。Scheme语言广袤得很,学习难度恐怕并不低于什么C++之类的。
    当然,Scheme语言不仅仅只支持Foobar2000,相反的,它之后的一个具体应用更是以VLC为播放引擎。我想,这也许并非一件坏事。
    PLT Scheme Latest release: 4.2.2, October 2009 更新于今年今月,支持多平台,分Windows、Linux、Mac等版本。
    cwbowron这家伙从去年开始不再更新foo_uie_playlist_tree,转而搞Schemep3:
    Schemep3 is a music playback and database program written in PLT Scheme. It can playback any audio format that libVLC supports and read tags in any format that TagLib understands. It uses Jay McCarthy's SQLite module for database access.
    赫赫然者有三:




    PLT Scheme
    SQLite
    libVLC

    所以,我现在用的foo_uie_playlist_tree其实是foo_uie_playlist_tree_mod。它由德国人fbuser基于foo_uie_playlist_tree去年的最后版本继续开发。当前版本为3.0.6.2,支持主程序版本为0.9.5.3及以上。
    foo_uie_playlist_tree 是空前绝后的强大,它的强大足以掩盖任何方面以致于令人看不到缺点,唯一的遗憾是不支持背景透明。对Foobar2000来说,cwbowron的离开,个人认为比PUI的离开更是难以估量的损失。在我看来,选择播放器的首要是对媒体库的管理能力及通用化管理。这是我一直以来始终的重点,也是今后永远的重点。我是跟着对媒体库的管理能力走而不是跟着Foobar2000走。

    借着这口劲,说一下主程序的版本选择
    本开发案选择了0.9.5.6,必定有人费解。为什么不用最新的?
    Foobar2000自0.9.5.3起开始杀伐PUI,0.9.6.X继续杀伐一大批历史功臣,比如神秘兔、乐辞等等,可恶的还远不在此,0.9.6.X居然强制扫瞄媒体库、居然强制监视媒体库、居然强制装载DUI,如果说第三个居然只是增加一点垃圾的话,那么第一、第二个居然简直已经到了令人忍无可忍的程度。说它智能吗?这是大愚若智!
    当然,0.9.6.X也不是没有优点,象音频转换就有改进,象标签编辑就有自动补充的进步。
    0.9.6.X对待黑名单的方式,我觉得是一种愚民政策。如果它能把强制抵制的黑名单以友情提醒的方式让用户自觉去回避,那样就民主了。
    总之,从前的那种开放的胸怀、那种博大的气量、那种自由的氛围在0.9.6.X这已经越来越看不见影子了。
    好啦,这些我们都忍了,那么请问0.9.6.X在音质上有提升吗?不能肯定对不对?那么再请问0.9.6.X在媒体库管理能力上有没有提升?只有刚刚提到的“智能”对不对?最后再请问0.9.6.X对系统的兼容性更好吗?有人在Windows 7上试验,说还是0.8.3最为稳定。从我的实践情况来说,0.9.5.X不论在Vista还是在Windows 7上都十分稳定健康,看不到0.9.6.X有什么实质性改进。
    就仅因为这一些,我还有必要选择最新版吗?


    2)一把牛刀
    foo_uie_wsh_panel_mod 几乎与FUI v0.0.1同一天出世(印象),始终处于迅猛发展中。与FUI自带的功能多有雷同,局部效果很好。曾用以播放模式选单、音量调节、定位条、时间显示、曲目分级等。但闪烁问题本人解决不了,怪自己水平太臭使不起来。
    JS代码高手可以用这个搞出非常完美的功能。比如可以比较容易的搞出与实际音量旋钮无比接近甚至更好的效果来(这个我做过一个,赶紧声明:我不是高手。我对JS还处于一版空白的程度,也许这个比如不恰当了)。这样的功能要FUI直接来做也可以,但十分困难。因为FUI的计算公式中没有三角函数,需要用抛物线或无数的二维座标点来营造(这个我也做过,表面还可以,效果与前者差距很大)。后来音量调节用平直法,这个问题也就不了了之了。这个例子说明WSHM的能力有时是FUI远远不及的。
    但是,如果在FUI中小小事动不动都用来WSHM来,就等于杀鸡用了牛刀,就等于炸碉堡用了原子弹。因为,对于大部分的小功能,FUI只要三言两语就可以搞定,而WSHM总是需要多些“准备动作”,代码要多出许多来,至于效率,对这样的小功能,常人根本就体会不到其差别。相反的,频频插入WSHM面板,消耗其实也不在小。表面看来,局部看来,效率也许真高了,但整体上,实际上总效率也许会是想当然的。而且,当FUI的效率已经令人满意,再谈效率问题就多少有些多此一举了,不知所云了。
    同时,有必要注意一点,就如人体医学的排斥现象。既然用FUI来集成了,相同效果下,还是选用FUI的方法比较科学一点。好东西滥用乱用其实不是尊重而亵渎。
    至于两者的代码实现方法,一个属于JS,一个更靠近于或说根本上还是TF。理论上JS的方法更规范,它属于解释性语言,比较接近通常意义上的程序语言。但实际情况要具体分析。就如国军的装备先进于共军,但共军却胜利了。我们要的是胜利地完成集成工作,而不是一味去计较取得胜利的工具是不是一定得要最先进。假如,思想都集中到这个方向去了,那么,为何不直接用程序语言直接来搞就爽快啦。直接用Java,直接用CDEFG……不然自己也给发明一个(我一位老哥们的太太学计算机专业,每次有东西,都问我用什么语言写的。她懂语言,却从不曾拿出一个应用产品出来。)……现实呢?现实用程序语言直接“组装”好的音频程序多如牛毛,但有一个我们喜欢、我们满意吗?要是喜欢,要是满意,又何必来折腾Foobar2000呢?
    所以,空谈误事,实干实在。
    WSHM是令人敬佩的Theophile大侠的杰作,是我们同胞的骄傲。我们祝愿WSHM越来越强大,也祝愿它有一天直接UI。那时,我们再结伴去学习WUI一体化设计。不过,我天生迂钝,到时不要嫌我学得慢跟不上。

    3)不推荐(不反对,鼓励多做尝试):
    曾经装了卸,卸又装,装又卸的插件有(以下纯属个人习惯 及用途所限,无褒贬之原意。无经脑子,随便举例的):
    foo_uie_wsh_panel 自有了WSHM,谁还在用这个?
    foo_uie_panel_splitter 在CUI中十分依靠它。其功能雷同在FUI中,并相形见拙,已无一用处。
    foo_uie_tabs 曾是CUI必备,快从记忆中消失了。
    foo_run 功能尽被FUI自身集成。
    foo_exvar 曾试图依靠它全屏化,未果。已无需再外加全局变量。
    foo_uie_trackinfo 用它做过整屏的信息。包括进度条。
    foo_uie_trackinfo_mod  感觉太小儿,历史使然。
    foo_uie_tagger_mod 弄了弄,不是所需。
    foo_skip 功能单一,用代码取代之。
    foo_texttools 紧急需要的时候用了它,结果没用。
    foo_utils 看似很多内容,个人均用不到。
    foo_quicktag 想看看是不是真很方便。感觉还是标签脚本加属性页用惯了。
    foo_uie_explorer 资源浏览器,一开始的最爱,好方便啊!几年没用了,好不方便啊!
    foo_uie_playlists_dropdown PUI时的宠物之一,感觉FUI不是其相宜的生存环境。其功能可由代码实现。
    foo_uie_bookmarks 折腾的最后结果是放弃。因为越来越主要靠媒体库筛选。
    foo_uie_albumlist  功能和显示效果不如Library Tree,更不能与Playlist Tree相提并论。效率相当。
    foo_osd 总感觉很多余。
    foo_Lyric_art 在找寻底座透明且支持通配符的过程中被推荐尝试。图片与歌词共在,还透明,换一曲,不动。定制能力特弱,当然也不支持通配符。
    AutoLyric 奥特歌词,显示效果奇好,但吸附入窗体时本身不被Foobar2000所调度;桌面显示时,无歌词状态下必须显示艺术家名及歌名。只好放下。期待其再度加强对Foobar2000的支持。
    乐辞,曾经的常配。可惜,对内嵌CUE支持欠佳。从未见过英文版,在曾经的配置中只有它一个面板名跟人家格格不入。久未更新,已为新版主程序所不容。
    foo_uie_albumart 不能透明底坐。支持通配符,设置相对简单。有较多的相关扩展功能。不过,所有这些,用FUI代码完全可以做到,可以做得更好。
    foo_uie_biography 自动图文信息,好迷人的功能。不过,还是对英文人比较有用。咱重在汉语。罗大佑、王菲知名度高的,信息是简单了些,图片还是有的。众多的不是那么响当当的歌手呢?恐怕就常常Sorry罗。此插件爱耗资源,目前暂时回避。
    Album Art Downloader XUI 还要额外的运行库,好给你装,结果那些图,不如用谷歌用百度。
    foo_uie_graphical_browser 对英文人还有点用,对中文人视如妲已。
    foo_chronflow 好眩啊!儿童之最爱。无关的图片一大堆,真要想挑节目却用它找如上蜀道。此插件巨耗资源,管理能力上差不多排长一级,少了它不爱管,多了它管不来。
    foo_dockable_panels 先关闭它,再关闭程序,下次就不见。得重新设置。弄两次就懒了。FUI下再去使用,傻了不是。
    foo_dock 菜单长长,版本越高越长,想无所不包,其实既然都Dock了,还有必要事事躬亲吗?不如自己弄一个简捷的。
    foo_input_mslive、foo_audioscrobbler之类 看来我比较落伍,总是几乎没听网络音乐,如果偶然听了,也觉得用浏览器的插件随便对付一下更直观一些。
    foo_playcount_sql 这个东西有一段时间更新很勤奋。号称SQL了,厂牌不小。但功能远远见不着只是SQLite的foo_customdb。
    foo_httpcontrol,积极更新中。试过了试,先卸下。可用手机遥控操作,因此可以将主机搬到储藏间,加个无线声卡,在客厅听音乐一点噪音都没了。有意思,将来还会再用到。
    foo_w7shell,好酷!好新潮!有Jumplist功能!任务栏上加图加按钮加设置项加列表,点非活动列表也许从当前的序号播放,也摸不清都些什么内容。所有功能貌似有用,其实都在舍本逐末。
    foo_playlist_attributes 功能好贴心!还每个列表分配Dsp、增益什么等等,选项很多的说。可惜啊,本人全部列表本来就不足两手手指。扣除大半的自动的,还有Bind掉的,哪还有列表需要它贴心?

    5.媒体库管理中对标签的灵活掌握
    零散的谈几个,供举一反三。

    1)Date。如果觉得没必要细致如此2009-10-23,而标签中已有类似值,请酌情取前4位2009。

    2)风格(流派)。这是一个很灵活的标签。从大派来讲,音乐基本可以分为流行与古典两大阵营。
    古典可以进一步分为文艺复兴、巴洛克、古典、浪漫、新古典,这基本是按古典音乐的发展历程划分。我们发现古典音乐的每一步跨越,都似乎在刻意对抗近亲而宏扬远亲,就算它在返祖吧。不过这样划分还不够,因为这些讲的是西方古典,我们还必须加一个中华古典。中华古典还应当再细分。可是,我不懂怎么分下去了。一讲到中华古典,眼前就只有高山流水、月儿高、胡笳十八拍、南音、以及所谓抢救出来的古乐编钟等等这样零散具体的印象,却怎么也形不成象西方古典那样的一个组团一个组团的块块来。这些意思用到我们的标签里来,就是要根据自己的音乐内容来取舍。比如,总古典量本来就不多,那么Classical一个就算了,如果古典量比较多,就看哪些细项也成群了,把成群的单独出来,比如可以分为巴洛克、古典、浪漫、中华古典。少量的文艺复兴和新古典就混在古典中或者再加一个其他古典。另外,也可以把美声、歌剧分离出来分成古典的两个细项。
    再另外,古典也可以从曲式或者演奏形式来划分,比如咏叹调、奏鸣曲、变奏曲……独奏、二重奏、五重奏、小协作、大协作、交响诗、交响乐……
    这样一来,风格中的古典这一项才能被更有效地管理起来,并在今后的曲目筛选中对我们有切实良好的帮助。
    同样的,流行也应当再细分,比如分到民谣、爵士、摇滚、流行等。如果曲目数量庞大,这样划分显然是不够用的。那么就要再对数量可观的那些类再开刀。比如把民谣再分为古民谣、流行性民谣、校园民谣、新民歌等,摇滚再分为摇滚、重金属、电子、朋克、甚至雷鬼等等,把流行再分为R&B、中国风、时代曲、民谣性流行曲、New-Age、World music等等等等。
    正如世上的事,往往不能都非此即彼。在音乐的世界里,还有一个流派两不靠。你靠它古典也不太融洽,你靠它流行也不太紧密。它就是轻音乐。一提起轻音乐,可能许多朋友脑子里已经不禁要浮现一个接一个的乐队来了,从曼托瓦尼……但是,又不是在上专业课,我们要始终很轻松。本来嘛,轻音乐就是为了我们的轻松而诞生的。不管它那么多,只要搞得自己明白、搞得自己方便就行了。所以,只要自己高兴,尽可以把轻音乐单独划一类。如果太多,就再细点,比如,朦胧啦、印象啦、气氛啦 、梦幻、乡野、SPA什么的……只要同类有了一定的量,归纳起来就有使用价值。
    总之,只有自己根据自己的特殊情况,加以提炼,风格这个标签才能有用好用。

    3)语言。这是本开发项目特地加进去的标签之一。
    语言,狭义来说,可分为本国语、外语,本国语再可分为普通话、闽南语、粤语、蒙语……其他本国语;外语再可分英语、意大利语、法语……其他外语。
    语言,广义地讲,可分为人声,器乐声,自然声。
    人声可分男声、女声、童声、口哨声,可分高、中、低音,可混合为男中音、女高音……
    器乐声,可分为民乐、西乐。
    民乐可再分为古琴、古筝、二胡、三弦、扬琴、琵琶、笛子、箫(包括尺八)、锣、鼓、箜篌、唢呐、葫芦丝、叶、……有公然将吉他划入民乐范畴的,我看不懂……但从远古看来,比如二胡很久很久之前是不是民乐?
    西乐可再分为钢琴、小提琴、大提琴、贝司、长笛、黑管、萨克斯、管风琴、竖琴、小号、大号、圆号……混合型的管弦乐……
    自然声可再分海潮声、风声、雨声、雷声、流水声、甚至不自然的车声、喧嚣声……
    与对风格的灵活对待一样,我们也需要对语言进行具体问题具体分析。分析的结果就可以拎出自己的所爱,把剩下的零碎再归纳一下,称它们为其他民乐、其他西乐、其他乐器、其他自然声……

    小结
    我们之所以说媒体库筛选有强大的管理能力,其根基就在标签,不怎么被重视的平平淡淡的标签!标签没弄好,再先进、再用心设置的媒体库管理工具都一样是徒劳而已。

    ——后语
    本讲义的根本作用就是帮助读者尽快摆脱本讲义的束缚。意思就是按自己的意志去行事,随心所欲,At Will。比如,一开始我们说窗体事件的重点在Load、Resize、Open,但要是您的开发案有许多移动行为,那么,Move也就成了重点,前面三个中的某个也许就不再是重点。共通事件的情形亦同此理。
    本讲义讲了一种方法甚或N种方法,但实际上实现的方法肯定还有更多,并且最佳的方法极可能不在讲述到的范围内。本讲义只是对探讨方法的鼓励与示范,而不是探讨方法本身及其终结。
    本讲义只是一种态度,一种努力方式,话讲得不老少,但真知灼见不多,甚至没有,不但没有,还可能错误连篇、漏洞百出。
    如果已经明白我的意思,敬请从此刻开始,理智地消除本讲义对自己或良或不良的影响。谢谢。


    1.规划文档实例——《AtWill Audio 开发无皮书》作者:W.T.F
    网址:

    2.代码来源—— AtWill Audio 6.1.1001 英文版 原作者:Wong 非全屏化作者:kmpfor
    原版无对外提供。下载网址:http://www.foobar2000.com.cn/showtopic-9047.aspx 一楼 (汉化作者:TpFoR)这是一个应用实例,直接可使用。

    3.FUI零件——《FUI零件共享》(可视为本讲义的实践篇,欢迎大家共同参与:我帮人,人帮我)
    网址:http://www.foobar2000.com.cn/showtopic-11165.html
    最后编辑kmpfor 最后编辑于 2009-12-10 11:17:32
    TOP

    强烈支持,期待中。。。
    TOP

    有些函数还是要说明一下,最好是结合例子来具体说明,把一些注意事项扩展开来说明。因为现在可用的FUI实例配置实在是太少了。
    楼主看来这次真要下决心了,希望能在两个月内看到你这个完善的教程,如果楼主做到,为了不辜负楼主的一片热心,我决定配置一个FUI的配置出来以飨观众,本人也是一直在寻找适合的配置,最近有了一点眉目,本来准备用CUI来写,如果两个月内楼主能完善此帖我就用FUI来写。
    最后互相鼓励一下!
    音乐知我心,我魂随律动
    TOP

    帖子先收藏了。。。

    我也占个楼

    等楼主更新。。。
    TOP

    此贴必火,首页留名。
    补充:
    foo_ui_func_readme.txt,
    foo_ui_func_variables.txt,
    foo_ui_func_functions.txt。
    这三个文档指定放在Foob根目录,打开palette可以有规则地阅读。
    注意:当你把乱码转码成日文,或翻译成中文,保存时还是ansi就好,忽略Unicode丢失提示。否则Palette不能打开。
    通过Palette阅读,可以双击字段或函数到,脚本编辑框的光标处。目前好像只有fui自带如此方便贴心的编辑器。可惜的是不能在线编辑。如果能在线编辑,你可以边看边翻译自己看的懂的部分了。
    最后编辑bense 最后编辑于 2009-10-10 14:18:30

                         

    不是所有时间久远的都可以成为经典,不是所有的人都可以重新演绎经典。

    在那片青色的山坡我要埋下所有的歌,等待着终于有一天成为世间的传说 。

    TOP

    路过 顺便 支持一下 虽然懒得去用FUI
    Asion's Blog

    .......哦 是这样? 嗯
    TOP

    回复 15# bense 的帖子

    我已经将F1,用FUI+WSHmod重写一遍。弱化FUI功能,加强WSHmod的应用。
    ========================================
    那你的这个修改后的版本发布了没有?现在的1.2a是不是修改后的?
    音乐知我心,我魂随律动
    TOP

    回复 17# gdzqj88 的帖子

    还没弄完。重点就是WSH的写设置的部分。有点繁琐,虽然设想都知道怎么做,但堆代码要时间,要反复调试。
    这次我几乎把所有的fui和wsh的代码都再堆过了,想法就是提高效率,和使代码工整,至于美工方面,想在完成功能后再说。

    其实,fui有两个难度:
    1、窗体刷新的技巧,不是bug。就是那么几个函数,正确使用,窗体刷新效率一点不差,很顺畅。技巧就那么一点点,掌握了就好。问题就在它没有中文说明,连英文也没有。日文只能猜。
    就算是不去掉窗体标题栏,fui的刷新还是好过cui+PSS。PSS实在恶心。
    2、有几个关键的bug,需要技巧来避免,这个我摸索的比较苦,现在我想要的东西都避免掉了。

    不知道什么时候完工。
    最后编辑bense 最后编辑于 2009-10-09 22:30:38

                         

    不是所有时间久远的都可以成为经典,不是所有的人都可以重新演绎经典。

    在那片青色的山坡我要埋下所有的歌,等待着终于有一天成为世间的传说 。

    TOP

    还是第一页不?
    TOP

    该用户帖子内容已被屏蔽
    TOP