[Obj-C++] 19 NSWindowの重複 : 正攻法の解決手段 / 仕上げ

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

AppDelegateにDrag & Dropに関連する操作を集約させて仕上げました。異常終了についても修正しました。

NSWindow初期化, NSTextField・NSView作成をAppDelegateに移管しています。

初学者にはかなりきつい内容でしたが、それなりに基礎固めできたように思います。Objective-C++を学び始めて2週間ですから進度としてはまずまずです。

#import "AppDelegate.h"
#import "DragAndDropView.h"
#import "ConvertorWindow.h"

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

@implementation AppDelegate
- (void)applicationWillFinishLaunching:(NSNotification*)aNotification {

    // NSWindow
    _windowInit = [[ConvertorWindow alloc] init];
    [_windowInit autorelease];
    [_windowInit makeKeyAndOrderFront:NSApp];
	[_windowInit setTitle:@"Xlsx Convertor"];

    // NSTextField
    _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.delegateV = self;
    _windowInit.delegateW = self;
}

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

- (void)pasteFunction:(NSString *)fileURL;{
    NSLog(@"%s","pasteFunction kaishi");
    _textBox1.stringValue = fileURL;
    NSLog(@"%s","pasteFunction kanryou");
}

- (void)clearTextBox1;{
    _textBox1.stringValue = @"";
}

- (NSString*)getTextBox1;{
    NSString* path = [_textBox1 stringValue];
    NSLog(@"path %@",path);
    return path;
}

@end
#include <Cocoa/Cocoa.h>

@protocol ConvertorWindowDelegate <NSObject>
- (void)clearTextBox1;
- (NSString*)getTextBox1;
@end

@interface ConvertorWindow : NSWindow
@property(nonatomic, assign) id <ConvertorWindowDelegate> delegateW;
@end
<関連箇所のみ>

- (BOOL)windowShouldClose:(id)sender {
	[NSApp terminate:sender];
	return YES;
}

- (void) OnButton1Click:(id)sender {
	onoff_XlsxToList = radioButton_a1.state; 
	onoff_XlsxToCsv = radioButton_a2.state; 
	onoff_ListToXlsx = radioButton_b1.state; 
	onoff_ListToCsv = radioButton_b2.state; 
	onoff_CsvToXlsx = radioButton_c1.state; 
	onoff_CsvToList = radioButton_c2.state;

	if (radioButton_a1.state == 1){
		rbtn_num = 1;
	} else if (radioButton_a2.state == 1){
		rbtn_num = 2;
	} else if (radioButton_b1.state == 1){
		rbtn_num = 3;
	} else if (radioButton_b2.state == 1){
		rbtn_num = 4;
	} else if (radioButton_c1.state == 1){
		rbtn_num = 5;
	} else if (radioButton_c2.state == 1){
		rbtn_num = 6;
	}

	NSLog(@"case %d",rbtn_num);
	
	switch (rbtn_num){
		case 1:
		case 2:
		case 5:
		case 6:
			path = [_delegateW getTextBox1];
			convert = [[Convert alloc] init];
			result = [convert ConvertFunc:path number:rbtn_num];
			[textview setString:result];
			break;
		case 3:
		case 4:
			list = [textBox2 stringValue];
			convert = [[Convert alloc] init];
			result = [convert ConvertFunc:list number:rbtn_num];
			[textview setString:result];
			break;
	}
}

- (void) OnButton2Click:(id)sender {
	[_delegateW clearTextBox1];
	textBox2.stringValue = @"";
}

[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

参考サイト