带有数字格式化程序的 NSTextField 不允许小数输入

发布于 2024-12-29 07:53:38 字数 930 浏览 4 评论 0原文

我正在尝试制作一个简单的 Cocoa 应用程序,其中将数字输入到文本字段中。当在一个文本字段中输入数字时,另一个文本字段将自动更新为另一个数字(反之亦然)。我拖到窗口中的文本字段是界面生成器中的“带有数字格式化程序的文本字段”。我将文本字段设置为委托,允许它们自动更新。但是,格式化似乎不起作用。我无法输入小数。请帮忙!!!

头文件在这里:

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate> {
    IBOutlet NSTextField *number1;
    IBOutlet NSTextField *number2;
}

@property (assign) IBOutlet NSWindow *window;

@end

实现文件在这里:

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;

-(void)controlTextDidChange:(NSNotification *) note {
    NSTextField *changedField = [note object];

    if (changedField == number1) {
        float num1 = [number1 floatValue];
        [number2 setFloatValue: (num1*2.0)];
    }

    if (changedField == number2) {
        float num2 = [number2 floatValue];
        [number1 setFloatValue: (num2/2.0)];
    }
}

@end

I'm trying to make a simple Cocoa application where a number is input into a textfield. When a number is typed into one textfield the other textfield will automatically update with another number (and vice versa). The textfield that I've dragged into the window is the "Text Field with Number Formatter" from interface builder. I have the textfields set as delegate which allows them to automatically update. However, the formatting does not seem to work. I can't input decimal numbers. Please help!!!

Header file here:

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate> {
    IBOutlet NSTextField *number1;
    IBOutlet NSTextField *number2;
}

@property (assign) IBOutlet NSWindow *window;

@end

Implementation file here:

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;

-(void)controlTextDidChange:(NSNotification *) note {
    NSTextField *changedField = [note object];

    if (changedField == number1) {
        float num1 = [number1 floatValue];
        [number2 setFloatValue: (num1*2.0)];
    }

    if (changedField == number2) {
        float num2 = [number2 floatValue];
        [number1 setFloatValue: (num2/2.0)];
    }
}

@end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你丑哭了我 2025-01-05 07:53:38

这有点晦涩,但你想做的事情实际上并不能奏效,但还有另一种选择。

在您的代码中,您有:

float num1 = [number1 floatValue];
[number2 setFloatValue: (num1*2.0)];

第一行请求 number1当前值。由于您在 number1 上附加了一个数字格式化程序,因此会调用它来格式化文本...如果您输入了 123。 此时格式化的结果是123...并且你的小数点消失了。您会注意到您也不能输入逗号(千位分隔符)。

因此,根本问题是,在输入每个字符后,您的代码会强制其成为此时的有效数字。

另一种方法是仅在用户输入完整数字时才执行操作。您可以自己编写代码来在键入每个字符时分析输入,也可以使用快速而简单的方法等待用户点击并响应操作。

要执行后者,请将代码更改为:

- (IBAction) textDidChange:(id)sender
{
   if (sender == number1)
   {
      float num1 = [number1 floatValue];
      [number2 setFloatValue: (num1*2.0)];
   }
   else if (sender == number2)
   {
      float num2 = [number2 floatValue];
      [number1 setFloatValue: (num2/2.0)];
   }
}

并将其作为“选择器”连接到控件,并删除已有的“委托”连接。

该解决方案不如您尝试的“动态”,但它确实有效。要获得动态响应,您需要编写更多涉及的代码,如上所述。

This is a bit obscure, but what you are trying to do cannot really work but there is an alternative.

In your code you have:

float num1 = [number1 floatValue];
[number2 setFloatValue: (num1*2.0)];

The first line requests the current value of number1. As you have a number formatter attached to number1 it is called to format the text... and if you've entered, say, 123. at this point the formatted result is 123... and your decimal point is vanished. You'll notice you cannot enter commas (thousands separators) either.

So the fundamental problem is that after every character is typed your code is forcing it to be a valid number at that point.

The alternative is to only do your action when the user has entered a complete number. You can either write code yourself to analyze the input as each character is typed, or you can use the quick and easy method of waiting until the user hits and responding to the action.

To do the latter change your code to:

- (IBAction) textDidChange:(id)sender
{
   if (sender == number1)
   {
      float num1 = [number1 floatValue];
      [number2 setFloatValue: (num1*2.0)];
   }
   else if (sender == number2)
   {
      float num2 = [number2 floatValue];
      [number1 setFloatValue: (num2/2.0)];
   }
}

and connect it to the control as the "selector" and remove the "delegate" connection you already have.

This solution is less "dynamic" than what you tried, but it does work. To get the dynamic response back you'll need to write more involved code as stated above.

再浓的妆也掩不了殇 2025-01-05 07:53:38

我知道我回答得很晚,但我刚刚遇到了完全相同的问题并找到了一个很好的解决方法。基于@CRD 的答案。

我如何解决这个问题是:

  • 存储格式化程序
  • 从文本字段中擦除格式化程序
  • 从文本字段中读取值
  • 将格式化程序重新应用到文本字段

我是如何做到这一点的示例如下:

-(void)controlTextDidChange:(NSNotification *)obj
{
    if ([obj object])
    {
        NSTextField *field = [obj object];
        NSNumberFormatter *formatter = [field formatter];
        [field setFormatter:nil];
        double data = [field doubleValue];
        [field setFormatter:formatter];
        // ...
        // Do other meaningful stuff now
    }
}

不确定这是否是正确的方法,但它对我来说效果很好。

I know I'm very late to answer but I just ran into the exact same problem and found a nice workaround. Building upon @CRD's answer.

How I accomplished the problem is:

  • Store the formatter
  • Wipe the formatter from the textfield
  • read the value from the textfield
  • Reapply the formatter to the textfield

An example of how I did it is below:

-(void)controlTextDidChange:(NSNotification *)obj
{
    if ([obj object])
    {
        NSTextField *field = [obj object];
        NSNumberFormatter *formatter = [field formatter];
        [field setFormatter:nil];
        double data = [field doubleValue];
        [field setFormatter:formatter];
        // ...
        // Do other meaningful stuff now
    }
}

Not sure if it's the proper way to do it but it worked well for me.

属性 2025-01-05 07:53:38

聚会有点晚了,但我自己也遇到了这个问题,我想我找到了一个简洁的解决方案,可以保持动态更新,但又避免格式化程序过早启动,从而阻止用户输入分数:(

- (void)controlTextDidChange:(NSNotification *)aNotification
{
    NSTextView *fieldEditor = [aNotification.userInfo valueForKey:@"NSFieldEditor"];
    CGFloat floatValue = fieldEditor.textStorage.string.floatValue;
    // Getting the new value from the field editor avoids the formatter kicking in here.
    // You can now use the value as you wish. Probably something like:
   if (sender == number1)
   {
      [number2 setFloatValue: (floatValue*2.0)];
   }
   else if (sender == number2)
   {
      [number1 setFloatValue: (floatValue/2.0)];
   }
}

我输入了这个进入浏览器,所以它可能不完全正确,但应该足够接近,基本部分是前两行:提取字段编辑器并从中提取新值。

A bit late to the party, but I just ran into this issue myself, and I think I found a concise solution that maintains dynamic updating, yet avoids the formatter kicking in too early, thus preventing the user from entering fractions:

- (void)controlTextDidChange:(NSNotification *)aNotification
{
    NSTextView *fieldEditor = [aNotification.userInfo valueForKey:@"NSFieldEditor"];
    CGFloat floatValue = fieldEditor.textStorage.string.floatValue;
    // Getting the new value from the field editor avoids the formatter kicking in here.
    // You can now use the value as you wish. Probably something like:
   if (sender == number1)
   {
      [number2 setFloatValue: (floatValue*2.0)];
   }
   else if (sender == number2)
   {
      [number1 setFloatValue: (floatValue/2.0)];
   }
}

(I typed this into the browser, so it may not be completely correct, but should be close enough. The essential parts are the first two lines: extract the field editor and extract the new value from it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文