问题
I am using a NSColorWell which is set to continuously update. I need to know when the user is done editing the control (mouse up) from the color picker in the color panel.
I installed an event monitor and am successfully receiving mouse down and mouse moved messages, however NSColorPanel appears to block mouse up.
The bottom line is that I want to add the final selected color to my undo stack without all the intermediate colors generated while the user is choosing their selection.
Is there a way of creating a custom NSColorPanel and replacing the shared panel with the thought of overriding its mouseUp and sending a message?
In my research this issue has been broached on a few occasions, however I have not read a successful resolution.
Regards, - George Lawrence Storm, Keencoyote Invention Services
回答1:
I discovered that if we observe color
keypath of NSColorPanel
we get called one extra time on mouse up events. This allows us to ignore action messages from NSColorWell
when the left mouse button is down and to get the final color from keypath observer.
In this application delegate example code colorChanged:
is a NSColorWell
action method.
void* const ColorPanelColorContext = (void*)1001;
@interface AppDelegate()
@property (weak) NSColorWell *updatingColorWell;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel];
[colorPanel addObserver:self forKeyPath:@"color"
options:0 context:ColorPanelColorContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if (context == ColorPanelColorContext) {
if (![self isLeftMouseButtonDown]) {
if (self.updatingColorWell) {
NSColorWell *colorWell = self.updatingColorWell;
[colorWell sendAction:[colorWell action] to:[colorWell target]];
}
self.updatingColorWell = nil;
}
}
}
- (IBAction)colorChanged:(id)sender {
if ([self isLeftMouseButtonDown]) {
self.updatingColorWell = sender;
} else {
NSColorWell *colorWell = sender;
[self updateFinalColor:[colorWell color]];
self.updatingColorWell = nil;
}
}
- (void)updateFinalColor:(NSColor*)color {
// Do something with the final color...
}
- (BOOL)isLeftMouseButtonDown {
return ([NSEvent pressedMouseButtons] & 1) == 1;
}
@end
回答2:
In the Interface Builder, select your color well, and then uncheck the Continuous checkbox in the Attributes Inspector. Additionally, add the following line of code somewhere appropriate like in the applicationDidFinishLaunching:
method or awakeFromNib
method:
[[NSColorPanel sharedColorPanel] setContinuous:NO];
In other words, both the shared color panel and your color well need to have continuous set to NO
in order for this to work properly.
回答3:
The proper way to do what you want is to use NSUndoManager
's -begin/endUndoGrouping. So you'd do something like this
[undoManager beginUndoGrouping];
// ... whatever code you need to show the color picker
// ...then when the color has been chosen
[undoManager endUndoGrouping];
The purpose of undo groups is exactly what you're trying to accomplish - to make all changes into a single undo.
来源:https://stackoverflow.com/questions/14138852/nscolorpanel-blocking-mouse-up-events