【问题标题】:Why this TLFTextField code works only once?为什么这个 TLFTextField 代码只工作一次?
【发布时间】:2025-12-31 04:00:16
【问题描述】:

当用户更改它时,我需要修改输入 TLF 文本字段中的文本。例如,每次用户添加或删除字符时,我都会尝试将其设为大写:

import fl.text.TLFTextField;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.elements.TextFlow;

var myTLFTextField:TLFTextField = new TLFTextField();
addChild(myTLFTextField); 
myTLFTextField.x = 10;
myTLFTextField.y = 10;
myTLFTextField.width = 200
myTLFTextField.height = 100;
myTLFTextField.text = "This is my text";

var myFormat:TextLayoutFormat = new TextLayoutFormat();
myFormat.textIndent = 8;
myFormat.color = 0x336633;
myFormat.fontFamily = "Arial, Helvetica, _sans";
myFormat.fontSize = 24;

var myTextFlow:TextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
myTextFlow.flowComposer.updateAllControllers();

//--

myTLFTextField.addEventListener(Event.CHANGE, this.onTextFieldChange);
function onTextFieldChange(event:Event):void
{
    myTLFTextField.text = myTLFTextField.text.toUpperCase();
}

//-- 之前的代码取自页面上的第一个示例TLFTextField documentation

当我尝试编辑文本时,它确实变成了大写,但之后文本字段停止响应任何输入并且输出显示

TypeError:错误 #1009:无法访问 null 的属性或方法 对象引用。在 flashx.textLayout.container::TextContainerManager/getController() 在 flashx.textLayout.container::TextContainerManager/mouseDownHandler()

当我注释掉 addEventListener 行时,一切似乎都正常。

这是否意味着不能像经典文本字段那样在用户输入事件中对 TLF 文本字段中的文本进行更改?

【问题讨论】:

  • 可能是无限循环。尝试检查是否确实需要在回调中更改案例; if( myTLFTextField.text.toUpperCase() != myTLFTextField.text )
  • @Dave 我的问题不是关于大写(无论如何都有一个内置功能可以保持文本大写),而是更多关于在用户输入事件中更改文本。如果您尝试以其他方式进行更改,例如在文本末尾添加字母“A”而不是将其设为大写,则会遇到同样的问题。
  • 好吧,但我的观点仍然成立;可能是通过更改您触发回调的文本,这会更改文本(...)。我不确定是否是问题所在,但您可以通过打破该循环进行检查。如果事实证明是问题所在,您可以尝试更改您收听的事件或使用变量标记(例如,如果已经在回调中,则设置为 true)。
  • @Dave 那么打破循环的最佳方法是什么?对不起,如果我没有明白你所说的变量标记的意思..
  • @The_asMan 这不是真的。任何拥有 Flash CS6 的人都可以创建一个空的 AS3 文档,将代码复制/粘贴到第一帧中,并在输出面板中得到完全相同的错误。我已经尝试过FLOW_OPERATION_COMPLETE,问题仍然存在。

标签: actionscript-3 flash apache-flex text actionscript


【解决方案1】:

为什么?因为TLF有问题。正如其他人所指出的,在 Event.CHANGE 处理程序中更改 TLF 文本会导致再次调用更改处理程序。到那时,事情就崩溃了。

我想出了一个类似于@Abe 发布的解决方案,但它更通用——它不依赖于检查大写字符。您侦听 TextEvent.TEXT_INPUT,然后在文本输入处理程序中切换 Event.CHANGE 侦听器。

import fl.text.TLFTextField;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.elements.TextFlow;
import flash.text.TextFieldType;
import flash.events.TextEvent;

var myTLFTextField:TLFTextField = new TLFTextField();
addChild(myTLFTextField); 
myTLFTextField.x = 10;
myTLFTextField.y = 10;
myTLFTextField.width = 500
myTLFTextField.height = 100;
myTLFTextField.text = "This is my text";
myTLFTextField.border = true;
myTLFTextField.multiline = true;
myTLFTextField.type = TextFieldType.INPUT;

var myFormat:TextLayoutFormat = new TextLayoutFormat();
myFormat.textIndent = 8;
myFormat.color = 0x336633;
myFormat.fontFamily = "Arial, Helvetica, _sans";
myFormat.fontSize = 24;

var myTextFlow:TextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
myTextFlow.flowComposer.updateAllControllers();

myTLFTextField.addEventListener(TextEvent.TEXT_INPUT, onTextInput);

var selectionIndex:uint;
function onTextInput(e:TextEvent):void
{
    trace("onTextInput");
    selectionIndex = myTLFTextField.selectionEndIndex;
    myTLFTextField.addEventListener(Event.CHANGE, onTextChanged);
}

function onTextChanged(e:Event):void
{
    trace("onTextChanged");
    myTLFTextField.removeEventListener(Event.CHANGE, onTextChanged);

    // Do whatever you need to do here:
    myTLFTextField.text = myTLFTextField.text.toUpperCase();
    myTLFTextField.setSelection(selectionIndex + 1, selectionIndex + 1);
}

【讨论】:

  • 谢谢,但是,使用此代码,闪烁的插入符号会一直消失,当字符被删除时,更改将被忽略。
【解决方案2】:

现在无法尝试您的代码,所以这是一个疯狂的猜测,但是当您设置文本时,控制器似乎消失了。如果你愿意这样做会发生什么:

private var m_dontupdate:Boolean;
function onTextFieldChange(event:Event):void
{
  if(m_dontupdate) return;
  m_dontupdate = true;
  myTLFTextField.text = myTLFTextField.text.toUpperCase();
  myTLFTextField.textFlow.flowComposer.updateAllControllers();
  m_dontupdate = false;
}

? (我无法尝试,因为我使用的是 FB 4.7 并且找不到 TLFTextField)。

【讨论】:

  • 如果我是对的,您可能必须保留对 myFormat 的引用,并在 onTextFieldChange 中重新设置格式
  • 与原版不同的是,这似乎真的导致了无限循环和错误的瀑布。所以,它没有工作..
【解决方案3】:

首先 - 你在事件监听器中进行无限循环!您在事件处理程序中的代码会自行调用它! TLF.text = VALUE 产生事件,如 TLF.dispatch(new Event(Event.CHANGE));

所以将事件侦听器添加到用户操作而不是文本更改!对于 KEY_UP

第二个 - 正确的格式代码,以便将其应用于新文本:

myTLFTextField.text = NEW_VALUE;

myTextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;

编辑:为了更清楚,我添加了完整的代码:

import fl.text.TLFTextField;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.elements.TextFlow;
import flash.events.KeyboardEvent;

var myTLFTextField:TLFTextField = new TLFTextField();
addChild(myTLFTextField);
myTLFTextField.x = 10;
myTLFTextField.y = 10;
myTLFTextField.width = 400;
myTLFTextField.height = 100;
myTLFTextField.text = "This is my text";
myTLFTextField.type = "input";
//allow user to wirte in filed

var myFormat:TextLayoutFormat = new TextLayoutFormat();
myFormat.textIndent = 8;
myFormat.color = 0x336633;
myFormat.fontFamily = "Arial, Helvetica, _sans";
myFormat.fontSize = 24;

var myTextFlow:TextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
myTextFlow.flowComposer.updateAllControllers();

//--;

myTLFTextField.addEventListener(Event.CHANGE, wrongHandler);
myTLFTextField.addEventListener(KeyboardEvent.KEY_UP, goodHandler);
myTLFTextField.text = 'TEXT';
//this invoke CHANGE and trace '-' in console

setTimeout(function(){  myTLFTextField.text = 'text';}, 500);
//this invoke CHANGE and trace '-' in console

function wrongHandler(event:Event):void
{
    //myTLFTextField.text = myTLFTextField.text.toUpperCase();
    //myTextFlow = myTLFTextField.textFlow;
    //myTextFlow.hostFormat = myFormat;
    // above code will run infinity loop of changing text! test it by uncomment and comment KEY_UP listener!
    trace('-'); // to see in console when and how many event was triggered
}

function goodHandler(event:Event):void
{
    myTLFTextField.text = myTLFTextField.text.toUpperCase();
    myTextFlow = myTLFTextField.textFlow; // reasign formating
    myTextFlow.hostFormat = myFormat;
    var i:uint = myTLFTextField.text.length;
    myTLFTextField.setSelection(i,i); // move carret to last sign
    trace('+'); // to see in console when and how many event was triggered
}

输出:

  1. -
  2. -

在字段中写入'a'字符后的输出:

  1. -
  2. -
  3. -
  4. -
  5. +
  6. -

舞台成绩: 文本

【讨论】:

  • 它不会导致任何无限循环。这可以通过在为Event.CHANGE 事件添加侦听器后立即尝试更改文本字段的text 属性来轻松确认,onTextFieldChange 函数没有被调用,它仅在用户输入时调用。
  • 我认为你错了。查看我的答案的变化。代码已经过测试,所以不要说它不起作用。
  • @Pleo 如果您不同意,请显示证明您正确的测试代码。
  • 我刚刚测试过了。代码中的wrongHandler 函数被调用了两次,但我看不出被调用两次如何符合无限循环的条件。即使它是无限循环,它也不会是 wrongHandler 中的第一行导致它,因为即使该行被注释掉,wrongHandler 仍然在每个用户输入时被调用两次。顺便说一句,除了按键之外还有其他用户输入方式,这就是为什么需要使用 Event.CHANGE 事件,它不会导致经典文本字段出现问题。
  • 如果您想使用 Event.CHANGE,请在对文本应用更改时使用 stopImmediatePropagation。