Tôi không chắc chắn mình đang làm đúng cách, hoặc nếu tôi có tất cả bị tấn công.Làm thế nào để hiển thị và quản lý một hộp thoại ứng dụng đơn giản trong Cocoa
Tôi có một ứng dụng thử nghiệm thực sự đơn giản (không dựa trên tài liệu) mà tôi đã tạo để tìm hiểu cách làm việc với các hộp thoại ứng dụng theo phương thức trong các ứng dụng Cocoa.
Với dự án ứng dụng "TestModalDialog", tôi có một MainMenu.xib đơn giản với chế độ xem mặc định và nút "Hiển thị hộp thoại", tôi đã thêm. Tôi tạo ra một XIB thứ hai được gọi là TheDialog.xib có nút "Cancel" và "OK". Xib đó là chủ sở hữu của nó một lớp học có nguồn gốc từ NSWindowController gọi là "TheDialogController"; cửa sổ và đại biểu được kết nối với bộ điều khiển.
Chọn "Hiển thị hộp thoại" trên giao diện chính sẽ khởi chạy hộp thoại. Lựa chọn "Hủy" hoặc "OK" sẽ loại bỏ hộp thoại. Đây là mã khá đơn giản:
// TestModalDialogAppDelegate.h
// TestModalDialog
#import <Cocoa/Cocoa.h>
@class TheDialogController;
@interface TestModalDialogAppDelegate : NSObject <NSApplicationDelegate>
{
NSWindow *window;
TheDialogController* theDialogController;
}
@property (assign) IBOutlet NSWindow *window;
- (IBAction)showDialog:(id)sender;
@end
// TestModalDialogAppDelegate.m
// TestModalDialog
#import "TestModalDialogAppDelegate.h"
#import "TheDialogController.h"
@implementation TestModalDialogAppDelegate
@synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
theDialogController= [[TheDialogController alloc] init];
}
- (void)dealloc
{
if(nil != theDialogController)
[theDialogController release];
[super dealloc];
}
- (IBAction)showDialog:(id)sender
{
if(nil == theDialogController)
{
NSAlert* alert= [NSAlert alertWithMessageText:@"Dialog Error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"The dialog controller was not allocated."];
[alert runModal];
return;
}
NSInteger result= [NSApp runModalForWindow:[theDialogController window]];
// Do something with result....
}
@end
// TheDialogController.h
// TestModalDialog
#import <Cocoa/Cocoa.h>
@interface TheDialogController : NSWindowController
{
// BOOL userClickedCloseOrOk; // Removed based on answer.
// Should declare a common define - just being lazy.
NSInteger userClickedOk; // Added based on answer.
UInt16 timesShown;
}
- (IBAction)showWindow:(id)sender;
- (IBAction)closeDialog:(id)sender;
- (IBAction)okDialog:(id)sender;
//- (BOOL)windowShouldClose:(id)sender; // Removed based on answer.
- (void)windowWillClose:(NSNotification*)notification; // Added based on answer.
- (void)windowDidBecomeKey:(NSNotification*)notification; // To set title when modal.
@end
// TheDialogController.m
// TestModalDialog
#import "TheDialogController.h"
@implementation TheDialogController
- (id)init
{
self = [super initWithWindowNibName:@"TheDialog"];
userClickedOk= 0; // Added based on answer.
// userClickedCloseOrOk= FALSE; // Removed based on answer.
return self;
}
-(void)dealloc
{
// Do member cleanup if needed.
[super dealloc];
}
- (void)windowDidLoad
{
[super windowDidLoad];
// Initialize as needed....
[[self window] center]; // Center the window.
}
// Does not show with runModalForWindow.
- (IBAction)showWindow:(id)sender
{
// Just playing with the window title....
++timesShown;
NSString* newTitle= [NSString stringWithFormat:@"Shown %d Times", timesShown];
[[self window] setTitle:newTitle];
return [super showWindow:sender];
}
// This method no longer used for this solution based on the answer.
//- (BOOL)windowShouldClose:(id)sender
//{
// if(!userClickedCloseOrOk) // The user did not click one of our buttons.
// [NSApp abortModal];
// else
// userClickedCloseOrOk= FALSE; // Clear for next time.
//
// return TRUE;
//}
// Added based on answer.
- (void)windowWillClose:(NSNotification*)notification
{
[NSApp stopModalWithCode:userClickedOk];
userClickedOk= 0; // Reset for next time.
}
// Note - the title will update every time the window becomes key. To do the
// update only once per modal session, a flag can be added. There might be a better
// notification to catch.
- (void)windowDidBecomeKey:(NSNotification*)notification
{
++timesShown;
NSString* newTitle= [NSString stringWithFormat:@"Shown %d Times", timesShown];
[[self window] setTitle:newTitle];
}
- (IBAction)closeDialog:(id)sender
{
//userClickedCloseOrOk= TRUE; // Removed based on answer.
//[NSApp abortModal]; // Removed based on answer.
//[[self window] performClose:self]; // Removed based on answer.
[[self window] close]; // Know we want to close - based on answer.
}
- (IBAction)okDialog:(id)sender
{
userClickedOk= 1; // Added based on answer.
//userClickedCloseOrOk= TRUE; // Removed based on answer.
//[NSApp stopModal]; // Removed based on answer.
//[[self window] performClose:self]; // Removed based on answer.
[[self window] close]; // Know we want to close - based on answer.
}
@end
tôi đã gặp rắc rối với các phương thức - trước khi tôi đặt trong userClickedCloseOrOk và kiểm tra, nếu người dùng nhấn vào nút close (góc trên bên trái dấu chấm màu đỏ), hộp thoại sẽ đóng nhưng phiên phương thức vẫn đang chạy.
Tôi nhận ra rằng tôi chỉ có thể rời khỏi nút tắt khỏi hộp thoại để bắt đầu, nhưng với nó ở đó, là những gì tôi đã chứng minh một cách tốt để nắm bắt kịch bản đó, hoặc có cách nào tốt hơn không? Hoặc, tôi đang làm điều gì đó sai trái để bắt đầu, điều đó tạo ra vấn đề đó cho tôi?
Mọi lời khuyên sẽ được đánh giá cao.
LƯU Ý - Mã từ ví dụ ban đầu đã nhận xét và được thay thế bằng mã dựa trên câu trả lời. Cũng đã thêm một trình xử lý thông báo mới.
Có cách nào tốt hơn so với windowDidBecomeKey: hoặc windowDidBecomeMain: để biết khi nào cửa sổ đã được hiển thị trong một phiên phương thức? Tôi hỏi vì tôi muốn biết khi nào phiên thực sự bắt đầu. Tôi có thể tạo/phá hủy cửa sổ mỗi lần, và sau đó sử dụng windowDidLoad, nhưng điều đó có vẻ không hiệu quả lắm. Tôi cũng có thể gửi một lá cờ để nói với cửa sổ sắp xuất hiện trong một phiên làm việc, và quản lý nó từ một trong các thông báo - một lần nữa, nó giống như một hack. Hoặc, tôi chỉ nên sử dụng một tờ thay thế? – GTAE86