【问题标题】:How can I create a GUI and react to Cocoa events programmatically?如何以编程方式创建 GUI 并响应 Cocoa 事件?
【发布时间】:2009-03-17 21:35:54
【问题描述】:

我发现了如何以编程方式在 Cocoa 中创建一个窗口,但不知道如何对事件做出反应。窗口对退出请求或按钮单击没有反应。

我尝试添加以下控制器并使用 setDelegate/setTarget 没有运气:

    @interface AppController : NSObject {
    }
    - (IBAction)doSomething:(id)sender;
    @end

    @implementation AppController
    - (IBAction)doSomething:(id)sender;
    {
        printf("Button clicked!\n");
    }
    @end

    int main(int argc, char **args){
        NSRect frame = NSMakeRect(0, 0, 200, 200);

        AppController *controller = [[AppController alloc] init];

>       [[NSApplication sharedApplication] setDelegate:controller];
        NSWindow* window  = [[NSWindow alloc] initWithContentRect:frame
                                            styleMask:NSBorderlessWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask
                                            backing:NSBackingStoreBuffered
                                            defer:NO];
        [window setBackgroundColor:[NSColor blueColor]];

        NSButton *button = [ [ NSButton alloc ] initWithFrame: NSMakeRect( 30.0, 20.0, 80.0, 50.0 ) ];
        [ button setBezelStyle:NSRoundedBezelStyle];
        [ button setTitle: @"Click" ];
>       [ button setAction:@selector(doSomething:)];
>       [ button setTarget:controller];
        [ [ window contentView ] addSubview: button ];

        [window makeKeyAndOrderFront:NSApp];

        [[NSRunLoop currentRunLoop] run];
        return 0;
    }

【问题讨论】:

  • 一开始为什么要这样做?您通常应该使用 Interface Builder 来创建应用程序的人机界面。
  • 我正在创建另一个 GUI 工具包的端口。
  • @Chris Hanson:以编程方式构建用户界面的原因有很多。认为应该始终使用 Interface Builder 是幼稚的。要是我能拒绝这个没有经验的评论就好了。
  • @ctpenrose:评论不能没有经验,只有人才能。在 Apple 收购 NeXT 之前,我对 Cocoa 或 Objective-C 或 Mac 开发的经验并不陌生。我一次又一次地看到,习惯于其他工具包(Windows/Java)的开发人员会立即尝试用像 OP 的问题这样的代码来实现他们的整个 UI。正如我所说的一般你不应该那样做,你应该只使用IB。在需要它的情况下,使用代码,但要聪明,不要因为其他平台的工具很烂而下意识地使用它。
  • 从我阅读开发者论坛的经验来看,cmet 试图猜测开发者的意图而不是回答问题,往往无法为讨论增加价值。

标签: objective-c cocoa


【解决方案1】:

您需要调用 -[NSApplication run] 而不是 -[[NSRunLoop currentRunLoop] run]。如果你看一下方法的基本结构,原因应该就很清楚了:

- (void)run
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [self finishLaunching];

    shouldKeepRunning = YES;
    do
    {
        [pool release];
        pool = [[NSAutoreleasePool alloc] init];

        NSEvent *event =
            [self
                nextEventMatchingMask:NSAnyEventMask
                untilDate:[NSDate distantFuture]
                inMode:NSDefaultRunLoopMode
                dequeue:YES];

        [self sendEvent:event];
        [self updateWindows];
    } while (shouldKeepRunning);

    [pool release];
}

NSApplication 封装了很多关于如何获取事件、如何调度它们以及如何更新窗口的内容。

【讨论】:

  • 很好,谢谢。这解决了我的问题。你从哪里得到这个源代码?所以看来我什至可以在某个地方实现我自己的运行循环并使用这个提供的逻辑。
  • 我为我的博客文章创建了这段代码:cocoawithlove.com/2009/01/demystifying-nsapplication-by.html我通过仔细阅读 NSApplication 的文档并猜测所有隐含的步骤直到它起作用,重新构建了这个方法。
【解决方案2】:

我发现了如何以编程方式在 Cocoa 中创建一个窗口……

为什么?为什么不直接做一个笔尖?

窗口没有响应退出请求或按钮点击。

你会如何退出一个窗口?这不是 Windows 3;应用程序在 Mac OS X 上可以有多个窗口。因此,关闭窗口和退出应用程序是单独的操作。

[[NSRunLoop currentRunLoop] 运行];

除了在极少数情况下,运行运行循环是 NSApplication 的工作,你应该把它留给它。使用NSApplicationMain-[NSApplication run] 告诉应用程序运行。

【讨论】:

  • - 我正在将另一个 GUI 工具包(用另一种编程语言编写)移植到 Mac。所以 GUI 是非常动态的,我认为拥有一个 NIB 文件没有意义。 - 退出:通过应用程序菜单 - 在应用程序上调用运行就可以了,谢谢!谢谢。
【解决方案3】:

很好的问题。我认为 Matt Gallagher 已经回答了这个问题,但如果你想进一步了解这个问题,你必须深入研究 Apple 的 event-handling documentation。请记住,以编程方式执行所有操作都需要对cocoa fundamentals 有深入的了解。

【讨论】:

    【解决方案4】:

    我花了一整天的时间寻找这个问题的 GUI 和菜单部分的答案。对于这个问题,目前没有那么多简明扼要的答案。所以在为自己解决之后,我在 Stack 上发布了一个答案:Cocoa GUI Programmatically。我在此处添加了一个推荐,以帮助正在寻找相同答案的社区成员。

    【讨论】:

      猜你喜欢
      • 2010-09-25
      • 1970-01-01
      • 1970-01-01
      • 2012-04-17
      • 1970-01-01
      • 2021-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多