【发布时间】:2012-12-28 23:59:36
【问题描述】:
我按照一些示例将NSButton 子类作为NSColorWell 工作(因为我们的NSButton 子类已经为我们提供了我们需要的外观行为),但是我注意到在使用按钮调用面板和改变颜色,它也改变了我们文档中选定文本的颜色。如果我改为使用我们的外观自定义子类化NSColorWell,它不会有这个问题吗?
但是,我仍然希望有一种解决方法可以避免这种情况,并且仍然可以让我们使用我们的按钮子类。我已经看到讨论线程建议让按钮本身成为第一响应者,但是由于按钮位于单独的调色板中,我无法使其正常工作。此外,我不希望更改响应者链或让调色板成为关键窗口。 NSColorPanel 上的类别会被覆盖 setColor:,使其发布预期的通知但不触及第一响应者,这有多邪恶?
(注意,我目前正在使用 DrummerB 的BFColorPickerPopover https://github.com/DrummerB/BFColorPickerPopover,而不是简单地打开颜色面板。但是我不认为这很复杂。我有同样的NSColorPanel /集成之前的第一响应者问题)。
被要求发布源代码,所以这是我的 NSButton 子类中的相关位(注意,使用上面提到的选择器弹出框,而不是直接使用 NSColorPanel):
.h:
@interface ...
@property (nonatomic, strong) NSColor *color;
@property (nonatomic, assign) BOOL active;
@property (nonatomic, strong) NSColor *buttonColor;
@property (nonatomic, weak) BFColorPickerPopover *popover;
- (void)activate:(BOOL)exclusive; // param ignored, always exclusive
- (void)activate;
- (void)deactivate;
- (void)takeColorFrom:(id)sender;
@end
.m:
@implementation ...
@dynamic color;
- (NSColor *)color
{
return self.buttonColor;
}
- (void)setColor:(NSColor *)newColor
{
self.buttonColor = newColor;
[self generateSwatch];
self.needsDisplay = YES;
self.popover.color = newColor;
}
- (void)activate:(BOOL)exclusive
{
[self activate]; // always exclusive
}
- (void)activate
{
self.popover = [BFColorPickerPopover sharedPopover];
self.popover.color = self.buttonColor;
[self.popover showRelativeToRect:self.frame ofView:self.superview
preferredEdge:self.preferredEdgeForPopover];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(popoverDidClose:)
name:NSPopoverDidCloseNotification
object:self.popover];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(colorDidChange:)
name:NSColorPanelColorDidChangeNotification
object:self.popover.colorPanel];
activeButton = self;
self.active = YES;
}
- (void)deactivate
{
if (self.popover)
{
[self.popover close];
self.popover = nil;
}
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSPopoverDidCloseNotification object:self.popover];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSColorPanelColorDidChangeNotification
object:self.popover.colorPanel];
if (activeButton == self) activeButton = nil;
self.active = NO;
}
- (void)popoverDidClose:(NSNotification *)notification
{
self.popover = nil; // don't let deactivate ask it to close again
[self deactivate];
}
- (void)colorDidChange:(NSNotification *)notification
{
self.buttonColor = self.popover.colorPanel.color;
[self generateSwatch];
self.needsDisplay = YES;
[self sendAction:self.action to:self.target];
}
- (void)mouseDown:(NSEvent *)theEvent
{
if (self.isEnabled && !self.active)
[self activate];
else if (self.active)
[self deactivate];
}
- (void)takeColorFrom:(id)sender
{
if ([sender respondsToSelector:@selector(color)])
self.color = [sender color];
}
@end
附录:
我尝试使用普通的NSColorWell 代替我的 NSButton 子类,但同样的问题。除了调用操作方法外,面板中选择的颜色还会调用第一响应者的changeColor:。所以在我的问题中忘记了关于NSButton 的所有内容,一般来说,一个人如何使用NSColorWell,它的颜色也不能被推送给第一响应者?必须求助于自定义预期的第一响应者以选择性地忽略changeColor:,还是让NSColorWell 成为真正的第一响应者,还是别的什么?
【问题讨论】:
标签: objective-c cocoa nsbutton first-responder nscolorpanel