Apache flex 在文本区域粘贴大量文本会导致脚本执行超时
(Flex 3)我有一个TextArea组件,它需要保存用户的剪贴板内容。TextArea在大多数情况下都做得比较好,但是当粘贴大量数据时,由于脚本执行超时,我似乎根本无法获取组件中的内容 我已经做了一个公平的调查,试图并希望找到如何使这项工作。 我发现TextArea正在使用一个IUITextField(在我的例子中,它是运行时TextField的一个实例)来处理获取粘贴数据的工作,然后在完成时抛出一个事件 我没有找到查看TextField源代码的方法,因为它是playerglobal.swc库中的一个类 有没有一种方法可以让我看到这个类的来源,或者在我的方法中,有没有什么我没有找到的方法来实现这个目标Apache flex 在文本区域粘贴大量文本会导致脚本执行超时,apache-flex,flash,performance,Apache Flex,Flash,Performance,(Flex 3)我有一个TextArea组件,它需要保存用户的剪贴板内容。TextArea在大多数情况下都做得比较好,但是当粘贴大量数据时,由于脚本执行超时,我似乎根本无法获取组件中的内容 我已经做了一个公平的调查,试图并希望找到如何使这项工作。 我发现TextArea正在使用一个IUITextField(在我的例子中,它是运行时TextField的一个实例)来处理获取粘贴数据的工作,然后在完成时抛出一个事件 我没有找到查看TextField源代码的方法,因为它是playerglobal.swc
注:我知道有其他方法可以实现我想要的结果,但我想让这个特定的解决方案起作用。当大量抗锯齿文本添加到显示列表时,这个问题经常会发生。文本渲染完成后,一切又恢复正常。如果要处理预定义的文本,可以绕过这个问题,方法是将大部分文本拆分为许多小文本,然后将它们逐段添加到后台(例如,一次添加20行文本),每段之间等待一帧,从而允许屏幕刷新 我还没有尝试过这个方法,但是我建议在文本区域中添加一个事件侦听器,如果文本被更改,则检查
event.RENDER
。如果这是真的,则可以删除自上次渲染事件以来添加的所有文本,然后逐帧重新添加,就像上面的示例中那样
此外,尝试使用本机字体而不是嵌入式字体,并关闭抗锯齿,或降低其质量 在Spark文本区域中,粘贴事件将正确触发。也许有一种更干净的方法可以做到这一点,但这就是我找到的解决方案 MXML:
不幸的是,我认为使用Flex3无法截获文本字段上所有类型的用户输入事件 如果您可以切换到Flex 4(因此使用新的FTE),那么您应该在
TextOperationEvent.CHANGING
事件上添加一个侦听器,这是一个可取消的事件。在处理程序中,您可以验证正在添加的文本量,如果文本量过大,则取消事件(event.preventDefault()
)并将其添加到多个帧中
此事件的好处在于,它也会为事件触发,例如“使用选定文本按delete键”,或剪切/复制/粘贴/删除操作。事实上,我用它来对某种文本字段应用早期验证,我用Flex3无法检测到这种情况
编辑
也许我找到了解决办法。。我注意到,“restrict”属性允许过滤文本字段中允许的字符,它在内置的TextField类中是受支持的,并且它不是包装Flex组件添加的一个特性:对我们的porpuse来说很有趣
因此,我尝试使用它,发现在TextArea上设置restrict=“
”可以防止在粘贴大量文本时阻塞UI,因为它在播放器级别“早期”应用。好的是,即使使用此设置,TextArea仍将调度textInput
事件,因此您可以监视粘贴事件并决定如何处理新文本:在一个步骤中更新text
属性,启动增量更新或忽略事件
复制并粘贴以下代码以查看示例(使用Flex 3.6和Flash Player 11进行测试):
棘手的部分是正确设置textInput事件上的文本,以及大文本的“增量”加载。由于TextField不希望接受我们的粘贴事件,我们将找到其他人。以下是mx:TextArea解决方案: MXML: 您还需要在画布的ContextMenu上启用剪贴板项目,并在粘贴完成后将焦点重置为TextArea
从以下位置获得粘贴阻止解决方案:对于如此大的文本(您提到的文本大约为7MB),这是不可能的 如果查看mx:TextArea的源代码,只需将其TextField text属性设置为您输入的字符串即可插入文本:
从第2050行附近的TextArea.as开始:
if (textChanged || htmlTextChanged)
{
// If the 'text' and 'htmlText' properties have both changed,
// the last one set wins.
if (isHTML)
textField.htmlText = explicitHTMLText;
else
textField.text = _text;
textFieldChanged(false, true)
textChanged = false;
htmlTextChanged = false;
}
如果您使用TextField制作一个示例应用程序,并尝试使用一个大字符串设置其text属性,则会出现脚本超时。(当我尝试使用1MB的字符串长度时,超时):
导入flash.text.TextField;
tf=新文本字段();
addChild(tf);
tf.multiline=true;
tf.wordWrap=true;
宽度=600
tf.高度=500
var-str:String=“”;
对于(VarI:int=0;i200)返回;
微量元素(cnt);
var-str:String=“”;
//一次粘贴大约50K看起来很理想。
对于(var i:int=0;i“大量数据”对于测试来说还不够具体,你想发布一个例子吗?它大约有7mb的文本。我测试了一个简单的文本区域,没有样式,没有处理程序的裸应用程序,我也遇到了同样的问题。也许我应该说,我可能更感兴趣的是一些指针来帮助我自己继续调试这个问题,而不是解决我的问题问题。仅仅从记事本文档中渲染5 mb的纯文本在5分钟内都不会渲染。我说5是因为那是我放弃并结束tast的时候。我强烈建议不要走这条路。你知道,当你设法将7 mb的文本放入文本区域时,整个应用程序会慢得太多,以至于你无法启动是否要执行任何操作?执行诸如输入单个字母或向下滚动之类的操作将导致脚本超时。Event.Render方法不起作用-在我按C键的那一刻之间不会启动任何事件
private var pastedText:String;
private var textPosition:int=0;
//Number of characters to read per frame
private var chunkSize:int=1000;
private function changeHandler(event:TextOperationEvent):void{
if(String(event.operation)=="[object PasteOperation]"){
event.preventDefault();
}
}
private function pasteHandler(event:Event):void{
pastedText = String(Clipboard.generalClipboard.getData(ClipboardFormats.TEXT_FORMAT));
this.addEventListener(Event.ENTER_FRAME,frameHandler);
}
private function frameHandler(event:Event):void{
if( textPosition + chunkSize > pastedText.length ){
chunkSize = pastedText.length - textPosition;
this.removeEventListener(Event.ENTER_FRAME,frameHandler);
}
textArea.text += pastedText.substr(textPosition,chunkSize);
textPosition += chunkSize;
}
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
minWidth="955" minHeight="600"
layout="vertical"
horizontalAlign="center">
<mx:Script>
<![CDATA[
protected function generateClipboard():void {
var largeData:String = "";
while (largeData.length < 1000000) {
largeData += "Lorem ipsum ... ";
}
System.setClipboard(largeData);
}
protected function ontextarea1_textInput(event:TextEvent):void {
if (event.text.length < 100) {
// NAIVE CODE: just to demonstrate that you can
// programmatically modify the text.. you should "merge"
// the new text with existing content here
textArea.text += event.text;
} else {
// do something here, like starting
// to add text block by block in
// multiple frames
}
}
]]>
</mx:Script>
<mx:TextArea id="textArea" width="100%" height="100%" restrict="" textInput="ontextarea1_textInput(event)"/>
<mx:Button click="generateClipboard()" label="Set clipboard"/>
</mx:Application>
<mx:Canvas id="canvas" paste="pasteHandler(event)">
<mx:TextArea id="textArea" textInput="if (event.text.length > 1) event.preventDefault();"
keyDown="keyDown(event)" mouseEnabled="false"/>
</mx:Canvas>
private function keyDown(event:KeyboardEvent):void{
//When CTRL-V is pressed set focus to canvas
if(event.keyCode==86 && event.ctrlKey)
canvas.setFocus();
}
if (textChanged || htmlTextChanged)
{
// If the 'text' and 'htmlText' properties have both changed,
// the last one set wins.
if (isHTML)
textField.htmlText = explicitHTMLText;
else
textField.text = _text;
textFieldChanged(false, true)
textChanged = false;
htmlTextChanged = false;
}
import flash.text.TextField;
tf = new TextField();
addChild(tf);
tf.multiline = true;
tf.wordWrap = true;
tf.width= 600
tf.height = 500
var str:String = "";
for (var i:int=0; i<100000; i++) {
str = str+"0123456789"
}
tf.text = str
import flash.text.TextField;
public function test(){
tf = new TextField();
addChild(tf);
tf.multiline = true;
tf.wordWrap = true;
tf.width= 600
tf.height = 500
addEventListener(Event.ENTER_FRAME,onEF);
}
private var cnt:int = 0;
private function onEF(event:Event):void{
if (cnt>200) return;
trace (cnt);
var str:String = "";
//pasting around 50K at once seems ideal.
for (var i:int=0; i<5000; i++) {
str = str+"0123456789"
}
tf.appendText(str);
cnt++;
}