gpt4 book ai didi

cocoa - 如何使自定义 View 中的 NSTextField 成为第一响应者?

转载 作者:行者123 更新时间:2023-12-03 17:31:24 24 4
gpt4 key购买 nike

据我了解,将文本字段设置为第一响应者意味着您可以在文本字段中输入文本,而无需先单击文本字段。

我制作了一个简单的应用程序来演示该问题。以下是文件:

//
// AppDelegate.m
// MyFirstResponderApp
//

#import "AppDelegate.h"
#import "MyViewController.h"

@interface AppDelegate ()

@property (weak) IBOutlet NSWindow *window;
@property(strong) MyViewController* viewCtrl;

@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application

MyViewController* myViewCtrl = [[MyViewController alloc]
initWithNibName:@"MyView" bundle:nil];

[self setViewCtrl:myViewCtrl];

[[self window] setContentSize:[[myViewCtrl view] bounds].size];
[[self window] setContentView:[myViewCtrl view]];



}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}

@end

...

//
// MyViewController.h
// MyFirstResponderApp
//

#import <Cocoa/Cocoa.h>

@interface MyViewController : NSViewController

@property IBOutlet NSTextField* textField;

@end

...

//
// MyViewController.m
// MyFirstResponderApp
//

#import "MyViewController.h"

@interface MyViewController ()

@end

@implementation MyViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.

[[self textField] becomeFirstResponder]; //I tried here...
}

//And overriding initWithNibName:bundle: and setting it here:
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {

if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
[[self textField] becomeFirstResponder];
}

return self;
}

@end

MyView.xib 的文件所有者是 MyViewController,以下是文件所有者导出:

enter image description here

对答案的回应:

1)这对我有用:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application

MyViewController* myViewCtrl = [[MyViewController alloc]
initWithNibName:@"MyView" bundle:nil];

[self setViewCtrl:myViewCtrl];

[[self window] setContentSize:[[myViewCtrl view] bounds].size];
[[self window] setContentView:[myViewCtrl view]];


if ([[myViewCtrl textField] acceptsFirstResponder]) {
[[[myViewCtrl textField] window] makeFirstResponder:[myViewCtrl textField]];

}

}

3)是的,我正在尝试为窗口的初始显示进行第一响应者舞蹈,但这对我不起作用:

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application

MyViewController* myViewCtrl = [[MyViewController alloc]
initWithNibName:@"MyView" bundle:nil];

[self setViewCtrl:myViewCtrl];

[[self window] setContentSize:[[myViewCtrl view] bounds].size];
[[self window] setContentView:[myViewCtrl view]];

/*
if ([myViewCtrl acceptsFirstResponder]) {
[[[myViewCtrl textField] window] makeFirstResponder:[myViewCtrl textField]];

}
*/

[[self window] setInitialFirstResponder:[myViewCtrl textField]];



}

窗口显示正常,但我必须单击文本字段才能输入文本。如果我使用 makeFirstResponder: 来代替,那么文本字段将按照我想要的方式运行:

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application

MyViewController* myViewCtrl = [[MyViewController alloc]
initWithNibName:@"MyView" bundle:nil];

[self setViewCtrl:myViewCtrl];

[[self window] setContentSize:[[myViewCtrl view] bounds].size];
[[self window] setContentView:[myViewCtrl view]];

/*
if ([[myViewCtrl textField] acceptsFirstResponder]) {
[[[myViewCtrl textField] window] makeFirstResponder:[myViewCtrl textField]];

}
*/

[[self window] makeFirstResponder:[myViewCtrl textField]];



}

我在 Apple Developer's Event Handling Basics 找到了该建议,设置第一响应者部分。

对答案下评论的回复:

在我的应用中,如果我选择 MainMenu.xib,然后取消选中在启动时可见,下面的代码会成功使文本字段显示在“查看第一响应者”中:

//
// AppDelegate.m
// MyFirstResponderApp
//

#import "AppDelegate.h"
#import "MyViewController.h"

@interface AppDelegate ()

@property(weak)IBOutlet NSWindow* window;
@property(strong) MyViewController* viewCtrl;

@end

@implementation AppDelegate



- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application

MyViewController* myViewCtrl = [[MyViewController alloc]
initWithNibName:@"MyView" bundle:nil];


[self setViewCtrl:myViewCtrl];

[[self window] setContentSize:[[myViewCtrl view] bounds].size];
[[self window] setContentView:[myViewCtrl view]];

[[self window] setInitialFirstResponder:[myViewCtrl textField] ];
[self.window makeKeyAndOrderFront:self];

}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}

@end

如果我创建一个 WindowController(以及 .xib,并删除 MainMenu.xib 中的窗口),那么对我来说,像这样组织配置/初始化是最有意义的:

//
// AppDelegate.m
// MyFirstResponderApp
//

#import "AppDelegate.h"
#import "MyViewController.h"
#import "MyWindowController.h"

@interface AppDelegate ()

@property(strong) MyWindowController* windowCtrl;

@end

@implementation AppDelegate



- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application

[self setWindowCtrl:[[MyWindowController alloc]
initWithWindowNibName:@"MyWindow"]];

}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}

@end

然后通过覆盖 WindowController 中的 initWithWindowNibName 来设置 View :

//
// MyWindowController.h
// MyFirstResponderApp
//

#import <Cocoa/Cocoa.h>

@interface MyWindowController : NSWindowController

-(instancetype)initWithWindowNibName:(NSString *)windowNibName;

@end

...

//
// MyWindowController.m
// MyFirstResponderApp
//


#import "MyWindowController.h"
#import "MyViewController.h"

@interface MyWindowController ()

@property(strong) MyViewController* viewCtrl;

@end

@implementation MyWindowController

-(id)initWithWindowNibName:(NSString *)windowNibName {

if (self = [super initWithWindowNibName:windowNibName]) {
MyViewController* myViewCtrl = [[MyViewController alloc]
initWithNibName:@"MyView" bundle:nil];


[self setViewCtrl:myViewCtrl];

[[self window] setContentSize:[[myViewCtrl view] bounds].size];
[[self window] setContentView:[myViewCtrl view]];

[[self window] setInitialFirstResponder:[myViewCtrl textField] ];

[self showWindow:self]; //I had to uncheck 'Visible at Launch' for the WindowController's window in the Attributes inspector


}

return self;
}
- (void)windowDidLoad {
[super windowDidLoad];

// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.


}

@end

...

//
// MyViewController.h
// MyFirstResponderApp
//

#import <Cocoa/Cocoa.h>

@interface MyViewController : NSViewController

@property(weak) IBOutlet NSTextField* textField;

@end

最佳答案

有几件事:

  1. 您永远不应该自己调用 -becomeFirstResponder(除非在覆盖中调用 super)。它就在 docs 中说:

    Never invoke this method directly.

    该方法是系统通知一个对象它将成为第一响应者并给它一个拒绝的机会。它实际上并没有使对象成为第一响应者。

    使 View 成为第一响应者的方法是首先检查它是否接受该状态,然后告诉窗口使其成为第一响应者:

    if ([self.textField acceptsFirstResponder])
    [self.textField.window makeFirstResponder:self.textField];
  2. 您当前正在尝试在包含 View 的 View Controller 初始化期间使文本字段成为第一响应者。这还为时过早。此时 View 不能位于窗口中。因此,它还不能成为窗口的第一响应者。您应该在将 View 添加到窗口后执行此操作。

    该作业理应属于窗口 Controller ,而不是 View Controller 。毕竟,只有窗口 Controller 具有必要的概述来决定其哪个(可能是许多) View 应该是第一响应者。您在这个简单的应用程序中没有使用单独的窗口 Controller ,因此责任将由 AppDelegate 类承担。 (根据您发布的代码,它实际上充当窗口的 Controller 。)

  3. 如果这种情况发生在窗口显示之前,您应该考虑设置窗口的 initialFirstResponder,而不是强制 View 立即成为第一响应者。窗口首次显示时会将其 initialFirstResponder 设为第一响应者。

    最好保留 -makeFirstResponder: 以便在窗口显示后以编程方式更改第一响应者。

关于cocoa - 如何使自定义 View 中的 NSTextField 成为第一响应者?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30315840/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com