[Obj-C++] 18 NSWindowの重複 : 正攻法の解決手段

[M1 Mac, Big Sur 11.6.5, clang 13.0.0, no Xcode]

ここまで書いておきながら恐縮ですが、前回以前の解決方法は率直に言って邪道だと思います。そもそもDrag & Dropする度にNSWindowを初期化するというのはどう考えても不健全です。筋悪なコードを修正しても傷口が広がるだけですから根本的な対策が必要になります。

そこでNSWindowを再初期化せずにDrag & Dropしたファイルのパスをセットする方法を考えました。

ただこのコードのままではNSWindowを閉じた時に異常終了するので何らかの修正が必要です。

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>{
}
@end
#import "AppDelegate.h"
#import "DragAndDropView.h"

@interface AppDelegate () <DragAndDropViewDelegate>
@property (nonatomic, assign) DragAndDropView* view_dad;
@property (nonatomic, assign) NSWindow* windowInit;
@property (nonatomic, assign) NSTextField* textBox1;
@end

@implementation AppDelegate
- (void)applicationWillFinishLaunching:(NSNotification*)notification {
    int height = [[NSScreen mainScreen] frame].size.height;

    _windowInit = [[NSWindow alloc] initWithContentRect:NSMakeRect(100, height-265-100, 360, 265) 
        styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | 
        NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:NO];
    [_windowInit autorelease];
    [_windowInit makeKeyAndOrderFront:NSApp];
	[_windowInit setTitle:@"Xlsx Convertor"];

    // FILE
	NSTextField* label1 = [[[NSTextField alloc] initWithFrame:NSMakeRect(10, 265-16-15, 34, 16)] autorelease];
	[label1 setFont:[NSFont fontWithName:@"Arial" size:14]];
	[label1 setStringValue:@"FILE"];
	[label1 setBezeled:NO];
	[label1 setDrawsBackground:NO];
	[label1 setEditable:NO];
	[label1 setSelectable:NO];
    [[_windowInit contentView] addSubview:label1];

    _textBox1 = [[[NSTextField alloc] initWithFrame:NSMakeRect(50, 265-25-10, 220, 25)] autorelease];
	[_textBox1 setStringValue:@""];
	[_textBox1 setEditable:YES];
	[[_textBox1 window] makeFirstResponder:nil];
	[[_textBox1 currentEditor] moveToEndOfLine:nil];
    [[_windowInit contentView] addSubview:_textBox1];

    // NSView
	_view_dad = [[DragAndDropView alloc] initWithFrame:NSMakeRect(0, 0, 360, 265)];
	[_view_dad setWantsLayer:NO];
	_view_dad.layer.backgroundColor = [[NSColor orangeColor] CGColor];
    [[_windowInit contentView] addSubview:_view_dad];

    NSLog(@"%s","applicationWillFinishLaunching");
}
    
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    _view_dad.delegate = self;
}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
}

- (void)testFunction:(NSString *)fileURL;{
    NSLog(@"%s","testFunction kaishi");
    _textBox1.stringValue = fileURL;
    NSLog(@"%s","testFunction kanryou");
}
@end
#import <Cocoa/Cocoa.h>

@protocol DragAndDropViewDelegate <NSObject>
- (void)testFunction:(NSString *)fileURL;
@end

@interface DragAndDropView : NSView
@property(nonatomic, assign) id <DragAndDropViewDelegate> delegate;
@end
#import "AppDelegate.h"
#import "DragAndDropView.h"

@interface DragAndDropView()
@property (nonatomic) BOOL highlight;
@end

@implementation DragAndDropView
// 初期化
- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setHighlight:NO];
        [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]];
    }
    return self;
}

// Viewの描画処理
- (void)drawRect:(NSRect)rect{
    [super drawRect:rect];
    if (_highlight) {
        [[NSColor systemBlueColor] set];
        [NSBezierPath setDefaultLineWidth: 3];
        [NSBezierPath strokeRect: [self bounds]];
    }
}

// viewの境界にファイルがドラッグされた時の処理
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender{
    [self setHighlight:YES];
    [self setNeedsDisplay: YES];
    NSLog(@"%s","draggingEntered");

    return NSDragOperationCopy;
}

// ドラッグ中の処理
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender{
    [self setHighlight:YES];
    [self setNeedsDisplay: YES];

    return NSDragOperationCopy;
}

// ドラッグ中止時の処理
- (void)draggingExited:(id <NSDraggingInfo>)sender{
    [self setHighlight:NO];
    [self setNeedsDisplay: YES];
    NSLog(@"%s","draggingExited");
}

// ドロップ時の処理
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender {
    [self setHighlight:NO];
    [self setNeedsDisplay: YES];
    NSLog(@"%s","prepareForDragOperation");

    return YES;
}

// ドロップ後の処理
- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender {
    NSLog(@"%s","performDragOperation kaishi");
    NSArray *draggedFilenames = [[sender draggingPasteboard] propertyListForType:NSPasteboardTypeFileURL];
    NSLog(@"draggedFilenames %@",draggedFilenames);

    return YES;
}

// ドロップ完了後の処理
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender{
    NSPasteboard *pboard = [sender draggingPasteboard];
    NSString *fileURL = [[NSURL URLFromPasteboard:pboard] path];
    NSLog(@"fileURL %@",fileURL);

    [_delegate testFunction:fileURL];

    NSLog(@"%s","concludeDragOperation kanryou");
}
@end

参考サイト