NSTextField + NSTimer

Posted

技术标签:

【中文标题】NSTextField + NSTimer【英文标题】: 【发布时间】:2014-07-15 08:51:20 【问题描述】:

我正在寻找一种在我的应用程序空闲时以NSTextField 的间隔显示字符串的方法。我知道使用sleep 的一种方法,尽管我认为这不是处理这个问题的最佳方法。我在想NSTimerscheduledTimerWithTimeInterval 可能是一个不错的方法,但我不知道该怎么做。

这是我的代码:

- (void)showTextAtInterval 

NSTextField *textLabel;

[textLabel setStringValue:[NSString stringWithFormat:@"06/01/14"]];
sleep(5);
[textLabel setStringValue:[NSString stringWithFormat:@"Headlines"]];
....


编辑:试过了,但只静态显示“标题”。

[self startTimer];

- (void)startTimer 

    [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(showTextAtInterval) userInfo:nil repeats:YES];
    return;


- (void)showTextAtInterval 

    NSTextField *textLabel;

    [textLabel setStringValue:[NSString stringWithFormat:@"06/01/14"]];
    [textLabel setStringValue:[NSString stringWithFormat:@"Headlines"]];


【问题讨论】:

问题中显示的代码不会显示任何内容,但您说它显示“标题”。你的实际代码是什么? (编辑您的问题,不要将其作为评论发布。) @CRD,这是实际代码,here's the XCode project。当您运行项目时,它会显示“标题”。 在上面的代码中,textLabel 是一个未初始化的局部变量 showTextAtInterval - 该代码不起作用。在您的实际代码中,textLabel 是该类的 IBOutlet 实例变量。像这样的细节问题。我将在下面添加一个答案。 不是玩魔鬼的拥护者,但是即使您将实例变量更改为 NSTextView *textLabel 而没有 IBOutlet 它仍然会做同样的事情。 关键是您的代码正在调用未初始化变量的方法,任何试图帮助您的人都会看到并指出问题所在。只是因为你写了它产生了输出,我才知道那不是你的代码。当您缩写代码以适应问题时,您必须小心不要引入错误或遗漏关键内容。 HTH 【参考方案1】:

您的代码有正确的想法,只是需要一些更改。

首先你发现不要使用sleep - 这会完全停止当前线程,如果你从主线程调用它,就像你做的那样,基本上是你的应用程序。

有很多方法可以做到这一点。您选择的NSTimer 是一个不错的选择,因为您说您只想在程序空闲时显示消息,NSTimer 有一个invalidate 消息,您可以使用它来停止计时器当您的代码不再空闲时调用。

UI 更新必须在主线程上发生,并且不一定是同步的 - 从更新 UI 的方法返回时,UI 可能尚未反映更改。这就是为什么您只看到“标题”的原因,您在另一个之后有两个 UI 更新调用,第二个在您看到第一个效果之前完成。

您需要做的是:暂停,显示第一条消息,暂停,显示第二条消息,根据需要重复。因此,请更改您的代码,以便在第一次计时器触发时显示第一条消息,第二次触发时显示第二条消息,等等。您可以使用实例变量来跟踪应首先显示哪条消息。最好创建一个“空闲消息”类,其中包含启动和停止消息的方法,并将所有消息选择和显示逻辑保留在该类中,您的计时器和其他状态应该是该类的实例变量。确保所有 UI 更新都发生在主线程上,您可以通过确保在该线程上安排 NSTimer 来做到这一点(并将确保该逻辑的逻辑放在 start 方法中)。

HTH

【讨论】:

你能告诉我为什么它必须保留在主线程上吗?我并不质疑它的有效性,但是在使用使用动画的子视图时遇到了类似的问题。那种东西不能在后台运行似乎有点奇怪。 您提到的暂停计时器的标准方法是什么?谢谢 所有 UI 更新本身必须在主线程上,这是 Apple 的规则。您可以在其他线程上运行代码来确定 UI 应该如何更改、绘制到屏幕外缓冲区等,只是更新本身需要在主线程上。 您已经设置了正确的计时器,它是一个重复计时器。您不会暂停计时器,但是当您不再需要显示空闲消息时会使其无效(如果需要重新启动显示,请创建一个新计时器)。【参考方案2】:

为了更正,我认为您应该添加一个私有变量并在showTextAtInterval 中进行切换。

- (void)showTextAtInterval 

NSTextField *textLabel;
switch(iTimer)



case 0:

[textLabel setStringValue:[NSString stringWithFormat:@"06/01/14"]];

break;

case 1:

[textLabel setStringValue:[NSString stringWithFormat:@"Headlines"]];

break;

....



iTimer ++;


【讨论】:

私有变量,你的意思是这样的 > ***.com/a/844670/3257552?以及我将如何准确使用它。谢谢【参考方案3】:

初始化你的计时器

-(void)awakeFromNib
    [super awakeFromNib];
     NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(showTextAtInterval) userInfo:nil repeats:YES];


并使用您的选择器:

- (void)showTextAtInterval 

NSTextField *textLabel;

[textLabel setStringValue:[NSString stringWithFormat:@"06/01/14"]];

[textLabel setStringValue:[NSString stringWithFormat:@"Headlines"]];
....


【讨论】:

这项工作不会出现在awakeFromNib 中吗?我做了类似[self startTimer]; 的操作,然后将NSTimer 放入-(void)startTimer,但textLabel 只显示一个标签(最后一个标签,在本例中为“标题”)并且不会循环或任何其他内容。谢谢 @ctfd 然后你应该把[self startTimer]放在awakeFromNib 请注意选择器不正确,来自 Apple 文档:“选择器应具有以下 签名:timerFireMethod:(包括一个冒号,表示该方法需要一个参数). 计时器将自身作为参数传递”。 @nicael,将函数放在awakeFromNib 中的问题是我不想立即显示文本,而是根据需要显示。

以上是关于NSTextField + NSTimer的主要内容,如果未能解决你的问题,请参考以下文章

根据 Font/Size 改变 NSTextField 的高度

NSTextField 文本的系统颜色是啥?

NSTextField 光标位置

NSTextField,在 Swift 中更改文本

根据 NSPopupButton 中的选择更新 NSTextField

NSTextField(标签)属性文本:选择