Reputation: 33
I am somewhat of a newbie, working on my first Mac app, an element of the functionality of which is that it allows users to drop an image into an image well, the app then needs to perform certain actions on the dropped image.
I have created my image well, and have made it editable, as such I can drop an image onto my image well, and it appears within my app.
Where I'm running into trouble is implementing event handlers so that I carry out actions when an image is dropped onto the image well. Specifically I need to load the image into an NSImage object.
I have had a read through this Mac Developer Library article: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DragandDrop/DragandDrop.html but can't quite get my head around it.
I would very much appreciate if someone could give me an example of how I would go about achieving this.
Many thanks in anticipation.
Upvotes: 2
Views: 2918
Reputation: 771
Hook up the 'selected' sent action on the outlets panel. This will send the action to your associated controller.
If you hook up the imagewell as an outlet on the controller, you can access the image that it was switched to. Alternatively, you can access the 'sender' parameter of the generated method, which will be the NSImageView.
- (IBAction)selector:(id)sender {
}
Then you will need create a subclass of NSImageView like in this gist
header:
#import <Cocoa/Cocoa.h>
@interface KSImageView : NSImageView
@end
implementation:
#import "KSImageView.h"
@implementation KSImageView
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
BOOL acceptsDrag = [super performDragOperation:sender];
if (acceptsDrag) {
NSPasteboard *pboard = [sender draggingPasteboard];
NSString *plist = [pboard stringForType:NSFilenamesPboardType];
if (plist) {
NSArray *files = [NSPropertyListSerialization propertyListFromData:[plist dataUsingEncoding:NSUTF8StringEncoding]
mutabilityOption:NSPropertyListImmutable
format:nil
errorDescription:nil];
if ([files count] == 1) {
NSDictionary *userInfo = @{@"imageFileName" : [[files objectAtIndex: 0] lastPathComponent]};
[[NSNotificationCenter defaultCenter] postNotificationName:@"KSImageDroppedNotification"
object:nil
userInfo:userInfo];
}
}
}
return acceptsDrag;
}
- (void) delete:(id)sender {
}
- (void) cut:(id)sender {
}
@end
Register for the notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(imageSelected:) name:@"KSImageDroppedNotification" object:nil];
Handle it here:
- (void)imageSelected:(NSNotification *)notification {
}
Upvotes: 2
Reputation: 1385
(This solves the problem that seanmakesgames addresses above, only in Swift 4.2 and more directly.)
import Cocoa
class PathImageWell: NSImageView {
var draggedFileURL: URL? = nil
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
let dragSucceeded = super.performDragOperation(sender)
if dragSucceeded == true {
let filenameURL = NSURL(from: sender.draggingPasteboard) as URL?
draggedFileURL = filenameURL
return true
}
return false
}
}
It's important to go via NSURL since URL does not have an init(NSPasteboard) method; you can retrieve the filename from the URL with
func imageNameFromURL(_ url: URL) -> String {
return url.deletingPathExtension().lastPathComponent
}
If you want to store the image name along with the image, you need to wrap it into a different struct/class with a 'name' property: do not attempt to use NSImage.name, which is a property strictly for use with NSImage(named:) and which shows peculiar behaviours.
Upvotes: 0
Reputation: 664
In Your nib init function, such as awakeFromNib or windowControllerDidLoadNib, add an Observer:
[self.imageView addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil];
And Implement a delegate function:
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if(object == self.imageView && [keyPath isEqualToString:@"image"])
{
// image changed, do anything your want
}
}
That's it.
Upvotes: 1