AS3,如何仅显示最后一行动态文本(以及更多)?
Posted
技术标签:
【中文标题】AS3,如何仅显示最后一行动态文本(以及更多)?【英文标题】:AS3, How to show just the last line of dynamic text (and more)? 【发布时间】:2011-03-21 22:08:22 【问题描述】:我制作了一个加载外部文本文件并将其内容滚动到底部的动作脚本:
var myTextLoader:URLLoader = new URLLoader();
myTextLoader.addEventListener(Event.COMPLETE, onLoaded);
function onLoaded(e:Event):void
track_info.text = e.target.data;
addChild(track_info);
addEventListener(Event.ENTER_FRAME, scrollField);
function scrollField(e:Event):void
if(track_info.scrollV < track_info.maxScrollV)
track_info.scrollV++;
else
removeEventListener(Event.ENTER_FRAME, scrollField);
myTextLoader.load(new URLRequest("tracks.txt"));
tracks.txt 是来自软件的日志文件,它以这种格式(无法更改)实时从播放器中获取 mp3 艺术家和歌曲名称标签。当前歌曲位于列表底部。每首歌曲都以“[Day-Month-Year Hour:Min:Sec] *”(25 个字符前缀)开头:
[14-07-2010 20:21:33] Log file created for client.
[14-07-2010 20:21:33] Client connected.
[14-07-2010 20:26:21] * Artist 21 - Song 11
[14-07-2010 20:40:02] * Artist 42 - Song 02
[14-07-2010 20:45:04] * Artist 14 - Song 10
[14-07-2010 20:47:19] * Artist 46 - Song 04
[14-07-2010 20:51:09] * Artist 07 - Song 09
[14-07-2010 20:54:13] * Artist 54 - Song 01
[14-07-2010 20:57:32] * Artist 19 - Song 12
[14-07-2010 21:00:51] * Artist 35 - Song 06
[14-07-2010 21:04:02] * Artist 43 - Song 08
脚本有效,但我想知道这个问题是否可以解决:
我想在 Flash 电影中仅显示当前歌曲,即列表的最后一行(正在播放的歌曲),而不是 track.txt 文件中的所有数据。能做到吗?
为此,电影必须几乎实时地自动更新 .txt 中的内容,以将新歌曲信息显示到文本字段中,替换之前的内容。有没有办法做到这一点?
最后,是否可以在文本字段中隐藏“[Day-Month-Year Hour:Min:Sec] *” 25 个字符前缀,以仅显示 Flash 电影中的艺术家 - 歌曲名称部分?
提前感谢您的帮助。
编辑
var reload:Timer = new Timer(5000, 0);
reload.addEventListener(TimerEvent.TIMER, onTimer);
function onTimer(event:TimerEvent):void
var myTextLoader:URLLoader = new URLLoader();
myTextLoader.addEventListener(Event.COMPLETE, onLoaded);
function onLoaded(e:Event):void
var lines:Array = e.target.data.split("\n");
var lastLine:String = lines[lines.length - 1];
var artistAndSong:String = lastLine.substr(24);
track_info.text = artistAndSong;
addChild(track_info);
myTextLoader.load(new URLRequest("tracks.txt"));
reload.start();
编辑
也许 split() 不适用于真正的 .log 文件。显示所有文本,而不仅仅是最后一行。这是 .log 示例:
[30-07-2010 03:21:34] Log file created for client "127.0.0.1,55684".
[30-07-2010 03:21:34] Client "127.0.0.1,55684" connected and has been identified as Traktor (or a something close enough).
[30-07-2010 03:22:58] * The Bravery - An Honest Mistake
[30-07-2010 03:23:22] * The Waterboys - The Whole of the Moon
编辑
var reload:Timer = new Timer(5000, 1);
reload.addEventListener(TimerEvent.TIMER, onTimer);
var tracksLoader:URLLoader = new URLLoader();
tracksLoader.addEventListener(Event.COMPLETE,onTracksLoaded);
tracksLoader.addEventListener(IOErrorEvent.IO_ERROR,onTracksError);
tracksLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onTracksError);
loadTracks();
function onTracksLoaded(e:Event):void
trace("onTracksLoaded");
parseTracks(tracksLoader.data);
reload.start();
function onTimer(event:TimerEvent):void
loadTracks();
function onTracksError(e:Event):void
trace("onTracksError", e);
reload.start();
function loadTracks():void
tracksLoader.load(new URLRequest("127.0.0.1,55684.log"));
function parseTracks(data:String):void
try
debugChars(data);
var lines:Array = data.split("\r\n");
var lastLine:String = lines[lines.length - 1];
var artistAndSong:String = lastLine.substr(24).split(" - ").join("\n");
trace(artistAndSong);
track_info.text = artistAndSong;
addChild(track_info);
catch(e:Error)
function debugChars(str:String):void
var buffer:ByteArray = new ByteArray();
buffer.writeUTFBytes(str);
buffer.position = 0;
var result:String = "";
while(buffer.bytesAvailable)
result += "0x" + uint(buffer.readUnsignedByte()).toString(16) + ", ";
if(buffer.position % 16 == 0)
result += "\n";
// print this string...
trace(result);
编辑
请注意,“艺术家”和“歌曲名称”之间的换行符是由以下代码引起的:
.split(" - ").join("\n");
.log 实际上带有“艺术家 - 歌曲名称”。
onTracksLoaded
0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32, 0x30, 0x31, 0x30, 0x20, 0x30, 0x33, 0x3a, 0x32,
0x31, 0x3a, 0x33, 0x34, 0x5d, 0x20, 0x4c, 0x6f, 0x67, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x63,
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x20, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2c, 0x35, 0x35, 0x36,
0x38, 0x34, 0x22, 0x2e, 0xa, 0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32, 0x30, 0x31, 0x30,
0x20, 0x30, 0x33, 0x3a, 0x32, 0x31, 0x3a, 0x33, 0x34, 0x5d, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x20, 0x22, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x2c, 0x35, 0x35, 0x36,
0x38, 0x34, 0x22, 0x20, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x61, 0x6e,
0x64, 0x20, 0x68, 0x61, 0x73, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x69, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x54, 0x72, 0x61, 0x6b, 0x74, 0x6f, 0x72,
0x20, 0x28, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67,
0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x20, 0x65, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x29, 0x2e, 0xa,
0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32, 0x30, 0x31, 0x30, 0x20, 0x30, 0x33, 0x3a, 0x32,
0x32, 0x3a, 0x35, 0x38, 0x5d, 0x20, 0x2a, 0x20, 0x54, 0x68, 0x65, 0x20, 0x42, 0x72, 0x61, 0x76,
0x65, 0x72, 0x79, 0x20, 0x2d, 0x20, 0x41, 0x6e, 0x20, 0x48, 0x6f, 0x6e, 0x65, 0x73, 0x74, 0x20,
0x4d, 0x69, 0x73, 0x74, 0x61, 0x6b, 0x65, 0xa, 0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32,
0x30, 0x31, 0x30, 0x20, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x3a, 0x32, 0x32, 0x5d, 0x20, 0x2a, 0x20,
0x54, 0x68, 0x65, 0x20, 0x57, 0x61, 0x74, 0x65, 0x72, 0x62, 0x6f, 0x79, 0x73, 0x20, 0x2d, 0x20,
0x54, 0x68, 0x65, 0x20, 0x57, 0x68, 0x6f, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65,
0x20, 0x4d, 0x6f, 0x6f, 0x6e, 0xa, 0x5b, 0x33, 0x30, 0x2d, 0x30, 0x37, 0x2d, 0x32, 0x30, 0x31,
0x30, 0x20, 0x30, 0x33, 0x3a, 0x32, 0x37, 0x3a, 0x35, 0x36, 0x5d, 0x20, 0x2a, 0x20, 0x42, 0x61,
0x62, 0x61, 0x73, 0x6f, 0x6e, 0x69, 0x63, 0x6f, 0x73, 0x20, 0x2d, 0x20, 0x59, 0x65, 0x67, 0x75,
0x61, 0xa,
g file created for client "127.0.0.1,55684".
[30-07-2010 03:21:34] Client "127.0.0.1,55684" connected and has been identified as Traktor (or a something close enough).
[30-07-2010 03:22:58] * The Bravery
An Honest Mistake
[30-07-2010 03:23:22] * The Waterboys
The Whole of the Moon
[30-07-2010 03:27:56] * Babasonicos
Yegua
【问题讨论】:
【参考方案1】:对于 1) 和 3),String::split 会这样做。
应该是这样的:
/*
\n is the end of line character. Depending on the program that creates
the text file, you might need to change it to \r\n or \r
Note I'm not doing any error checking, you might want to add it...
*/
var lines:Array = e.target.data.split("\n");
var lastLine:String = lines[lines.length - 1];
如果格式是固定的,你可以在“*”上分割最后一行,甚至使用substr来获取艺术家和歌曲名称。
/*
Again, I'm not checking for any errors
*/
var songAndArtist:String = lastLine.split("*")[1];
或
var songAndArtist:String = lastLine.substr(25);
对于 2),只需以合理的时间间隔轮询服务器。有几种方法可以做到这一点。一种可能是,每当您加载文件时,启动一个Timer;当这个计时器完成时,停止计时器并重新加载文件。您也可以使用setTimeout 代替计时器。
编辑
不确定您发布的代码有什么问题,但解析日志的部分对我来说很好。我重新安排了一下,并在加载数据期间添加了错误检查。
您的代码存在一个问题:您在等待当前加载操作完成之前调用了计时器。这可能会导致问题。您不需要同时进行两次下载,因此您最好等待下载完成(成功与否),然后再尝试重新加载(您可能不想尝试重新加载错误;或者可能会限制您的重试到 2、3 或类似的东西,但这取决于你)。
另外,请注意,我将计时器的重复计数更改为 1,因此您不必停止它。这意味着它会运行一次,然后它会停止,直到你再次调用 start)。我对您的代码进行了一些结构化,以将其部分分成不同的函数,以便更容易理解。
在 parseTracks 函数中,我将所有代码包装在一个 try/catch 中,它几乎可以捕获所有错误。这有点快速和肮脏,所以我通常不推荐这种错误处理方式,但可能会在这里完成工作。
var reload:Timer = new Timer(5000, 1);
reload.addEventListener(TimerEvent.TIMER, onTimer);
var tracksLoader:URLLoader = new URLLoader();
tracksLoader.addEventListener(Event.COMPLETE,onTracksLoaded);
tracksLoader.addEventListener(IOErrorEvent.IO_ERROR,onTracksError);
tracksLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onTracksError);
loadTracks();
function onTracksLoaded(e:Event):void
trace("onTracksLoaded");
parseTracks(tracksLoader.data);
reload.start();
function onTimer(event:TimerEvent):void
loadTracks();
function onTracksError(e:Event):void
trace("onTracksError", e);
reload.start();
function loadTracks():void
tracksLoader.load(new URLRequest("tracks.txt"));
function parseTracks(data:String):void
try
var lines:Array = data.split("\n");
var lastLine:String = lines[lines.length - 1];
var artistAndSong:String = lastLine.substr(24);
trace(artistAndSong);
catch(e:Error)
编辑 2
添加此函数并打印其结果以尝试检测所涉及的字符是否存在问题...从 parseTracks 中调用它,如下所示:
debugChars(data);
function debugChars(str:String):void
var buffer:ByteArray = new ByteArray();
buffer.writeUTFBytes(str);
buffer.position = 0;
var result:String = "";
while(buffer.bytesAvailable)
result += "0x" + uint(buffer.readUnsignedByte()).toString(16) + ", ";
if(buffer.position % 16 == 0)
result += "\n";
// print this string...
trace(result);
【讨论】:
无法实时检测txt文件的变化。您所能做的就是每隔 X 秒调用一次加载程序并重新加载 txt 文件中的信息。至少您可以检查最后一个 txt 内容和当前内容的详细信息,如果这两个匹配,则什么也不做。这样一来,播放的歌曲和显示的信息之间最多会有 X 秒的延迟。 非常感谢,我会尝试在我的代码上实现它(我不确定我能不能) @Adrian Pirvulescu。是的,这就是我所说的,我认为 - 你必须每隔一段时间重新加载。尽管我不会费心检查是否有任何变化,因为在这种情况下没有任何区别。但是,说歌曲与其信息之间的最大延迟 X 秒是不准确的(充其量,X 是信息显示和重新加载开始之间经过的时间)。 @Pablo。没问题,尝试解决,如果您发现无法解决的问题,请随时发布。 @Juan 关于延迟。如果歌曲从 12:00:00 开始并且信息写入 txt 文件中,那么在最坏的情况下,文本将在最多 X 秒后刷新(考虑到最后一次重新加载是在 11:59:59:999)【参考方案2】:我建议使用一些正则表达式进行字符串匹配,而不是进行字符串拆分
var $lastLine:String = String(e.target.data).match(/.*$/);
你也可以得到最后一行减去括号 [^]]*$
中的任何内容 - 但如果艺术家的名称中有 ]
,这可能会中断,但无论如何我会使用表达式从 $lastLine
中获取艺术家
那么你可以使用
var $artistAndSong:String = $lastLine.match(/\*.*/);
这将匹配第一个 *
之后(包括)之后的任何内容
如果你更多地使用正则表达式,你可以摆脱它,但总是有助于使用像 http://regexpal.com/ 这样的东西
【讨论】:
嗨丹尼尔,我已经尝试过你的解决方案,但我不知道如何,我还没有找到让它工作的方法。我已将在我之前的评论中有效的解决方案发布到另一个答案。谢谢。以上是关于AS3,如何仅显示最后一行动态文本(以及更多)?的主要内容,如果未能解决你的问题,请参考以下文章