[Cocoa]处理消息的方法-Delegate

本文详细解析了Mac平台下GUI程序的退出机制,包括消息驱动循环原理及应用,重点介绍了如何通过实现Delegate对象来处理应用程序的退出事件。通过代码示例展示了如何在程序关闭最后一个窗口时,向应用程序发送退出请求。此外,还提到了如何在窗口关闭前弹出对话框以确认操作,确保程序的稳定性和用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接:http://www.cocoachina.com/b/?p=124

我们上次演示的程序在关掉了应用程序的窗口之后,应用程序并没有真正的退出,现在我们就来完成这个任务。

在 Mac,Windows 或者 Linux 平台上,所有的 GUI 程序都可以称作消息驱动的,
就是说整个应用程序就是在处理消息的循环中进行的,用户的操作或者系统发送的一些通知都会被送到应用程序的消息处理循环中,
比如用户通过键盘输入,用鼠标点击窗口等等,有些消息会直接派发给应用程序的对象,
比如鼠标按下(MouseDown)的消息就会直接被送给鼠标按下的那个窗口或者试图,
但是有些消息会被系统首先解释,然后在生成其他的消息,比如用户用鼠标单击窗口 Frame 上的关闭按钮,
这个时候 MouseDown 事件并没有被送给应用程序的内部对象,而是在应用程序的消息循环中被解释成了窗口将要关闭的消息。

我们这次要处理的这个消息就是 应用程序最后一个窗口关闭的时候, 通知应用程序退出。

Cocoa 中处理事件的方式有几种,其中一种是你可以重载类中的对应的事件处理方法,
比如 MouseDown 事件在 NSResponse 类中就被方法 mouseDown: 处理,
所以所有继承自 NSResponse 的类都可以重载 mouseDown: 方法来实现对 MouseDown 事件的处理。
另外一种处理方式就是使用 Delegate,当一个对象接受到某个事件或者通知的时候,
会向它的 Delegate 对象查询它是否能够响应这个事件或者通知,
如果可以这个对象就会给它的 Delegate 对象发送一个消息(执行一个方法调用),在代码中一般用如下的方式来实现。

if (delegate != nil && [delegate espondsToSelector:@selector(theEvent)]{
	[delegate performSelector:@selector(theEvent)];
}
所以如果我们想处理一个对象的事件的话,就可以实现它所要求的方法,
然后将实现了这个方法的类的实例作为 Delegate 对象赋值给发出事件的对象。
下面我们就用代码来说明。

#import 
@interface MyDelegate : NSObject {
	
}
-(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication;
-(BOOL) windowShouldClose:(id)window;
@end

@implementation MyDelegate
-(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
{
    return YES;
}

-(BOOL) windowShouldClose:(id)window
{
    NSAlert* alert = [[NSAlert alloc] init];
    [alert setAlertStyle:NSInformationalAlertStyle];
    [alert setMessageText:@"Are you sure you want to quit?"];
    [alert addButtonWithTitle:@"Yes"];
    [alert addButtonWithTitle:@"No"];
    NSInteger result = [alert runModal];
    if (result == NSAlertFirstButtonReturn)
    {
        [alert release];
        return YES;
    }
    [alert release];
    return NO;   
}
@end

int main(int argc, char* argv[])
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    [NSApplication sharedApplication];
	
    //Create the main window
    NSRect rc = NSMakeRect(0, 0, 800, 600);
    NSUInteger uiStyle = NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask;
    NSBackingStoreType backingStoreStyle = NSBackingStoreBuffered;
    NSWindow* win = [[NSWindow alloc] initWithContentRect:rc styleMask:uiStyle backing:backingStoreStyle defer:NO];
    [win setTitle:@"HelloWin Test"];
    [win center]; //Center main Window
    [win makeKeyAndOrderFront:win];
    [win makeMainWindow];
	
    //Set delegate to application object
    MyDelegate* myDelegate = [[MyDelegate alloc] init];
    //Use the same delegate object to window object
    [win setDelegate:myDelegate];
    [NSApp setDelegate:myDelegate];
    //Start the event loop by calling NSApp run
    [NSApp run];
    //Release the object
    [myDelegate release];
    [pool drain];
    return 0;
}
首先定义了一个类名字叫 MyDelegate,然后里面实现了两个方法,

这两个方法是分别对应 NSApplication 的一个消息和 NSWindow 的一 个消息,我们在实现 Delegate 对象的时候,
不比针对每个类的 Delegate 对象单独创建一个类,比如创建一个 MyAppDelegate 类,创建一个 MyWindowDelegate 对象,
我们也不需要将发出事件对象的所有的 Delegate 方法都实现,只选择我们需要的就可以了。
所以针对这个简单的应用程序,我定义了一个 Delegate 对象,并且响应了 2 个对象的两个事件。

这个 Delegate 类处理的针对 NSApplication 的事件是

-(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
这个事件是在应用程序的最后一个窗口被关闭之后发出的,NSApplication 中有一个窗口的列表,
当最后一个窗口关掉的时候,应用程序就会查询它的 Delegate 对象是否响应这个事件,如果响应这个事件,就调用这个方法,
然后查看这个方法的返回值来决定是否退出应用程序。

在这个 Delegate 类中,这个事件的响应很简单,直接返回 YES,告诉应用程序可以退出了,
当然在具体的程序中,我们可以在这个事件中处理一些其他的工作,比如保存应用的设置或者释放一些全局的资源等等。

针对 NSWindow 的事件是
-(BOOL) windowShouldClose:(id)window;
这个事件是在一个窗口将要关掉的时候发出的,我们可以在这个事件中来防止错误的操作关掉了正在进行的工作,
所以可以给用户弹出一个对话框,来确认是否真的要关闭这个窗口。

在这个事件的处理中,我使用 NSAlert 类来完成这个简单的对话框,
这演示了 NSAlert 类的强大功能,可以通过这个类来实现更多的这类对话框。
另外有些常用的对话框,比如 Critical Error, Information 对话框等,Cocoa中已经进行了包装,
我们可以直接调用这些方法,这样可以用更少的代码来完成这个工作。
比如 NSRunAlertPanel, NSRunInformationalAlertPanel 等等。

虽然我们的程序现在能够退出了,但是窗口上面什么也没有,实际上还是一个没有用的程序,如何来向窗口中增加内容呢?下次在说吧。
去讨论去讨论本文, http://www.cocoachina.com/bbs/read.php?tid-25.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值