禁用按钮循环(NStimer 或 MouseMove)XCode Objective-C MacOS
Disable Button Loop (NStimer or MouseMove) XCode Objective-C MacOS
我只是尝试在 XCode MacOS(不是 iOS)上使用各种方法禁用按钮 Cocoa Objective-C.
在这种情况下,我有一个帮助按钮 (m_btHelp),当 g_bEnableHelpButton = NO 时该按钮被禁用;但只有在鼠标移动时才会检查
-(void)mouseMoved:(NSEvent *)theEvent
{
if(g_bEnableHelpButton) {
[m_btHelp setEnabled:YES];
} else {
[m_btHelp setEnabled:NO];
}
我宁愿连续检查而不是只在鼠标移动时检查。我已经用这样的东西尝试过 NSTimer,但它似乎不起作用(m_btHelp 在 g_bEnableHelpButton = NO 时不会被禁用;就像在 mouseMoved 事件中一样:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(Timerloop) userInfo:nil repeats:YES];
}
- (void)Timerloop
{
if(g_bEnableHelpButton) {
[m_btHelp setEnabled:YES];
} else {
[m_btHelp setEnabled:NO];
}
}
g_bEnableHelpButton
是全局变量吧?不要使用全局变量。最好创建一个 class 来保存您的状态(可以是视图模型,...)。我将在下面的所有示例中跳过状态 class 并将在同一视图控制器上使用 BOOL helpButtonEnabled
属性 (这不是强制性的,它只是使所有这些示例更短).你可以把这个属性移到别处,它可以是一个状态class,它基本上可以是任何对象。
另一件事是 NSTimer
、NSTrackingArea
、...所有这些都在浪费 CPU 周期、电池寿命... Cocoa & Objective-C 提供了多种方式来监控 属性 值并对其做出反应。你可以覆盖 属性 setter,你可以使用 KVO 或绑定。以下示例涵盖了所有三种方法。
肯定还有其他方法(比如 ReactiveCocoa),但我想演示三种方法如何在没有依赖项的情况下实现它。
初始状态
假设你有这样的观点:
实施如下:
#import "ViewController.h"
@interface ViewController ()
// Help button from the Main.storyboard
// Imagine it's your m_btHelp
@property (nonatomic, strong) IBOutlet NSButton *helpButton;
// Property driving helpButton enabled/disabled state
// Imagine it's your g_bEnableHelpButton
@property (nonatomic, getter=isHelpButtonEnabled) BOOL helpButtonEnabled;
@end
@implementation ViewController
// Just another button action coming from the Main.storyboard which toggles
// our helpButtonEnabled property value
- (IBAction)toggleHelpButtonEnabled:(id)sender {
self.helpButtonEnabled = !self.helpButtonEnabled;
}
@end
有帮助按钮和切换按钮,它只切换 helpButtonEnabled
值(YES
-> NO
,NO
-> YES
)。
如何在没有计时器、跟踪区域、...以更新帮助按钮状态的情况下进行监视?
覆盖setter
@implementation ViewController
// This is setter for the helpButtonEnabled property.
- (void)setHelpButtonEnabled:(BOOL)helpButtonEnabled {
// If the new value equals, do nothing
if (helpButtonEnabled == _helpButtonEnabled) {
return;
}
// Update instance variable
_helpButtonEnabled = helpButtonEnabled;
// Update button state
_helpButton.enabled = helpButtonEnabled;
}
- (void)viewDidLoad {
[super viewDidLoad];
// When the view loads update button state to the initial value
_helpButton.enabled = _helpButtonEnabled;
}
// Just another button action coming from the Main.storyboard which toggles
// our helpButtonEnabled property value
- (IBAction)toggleHelpButtonEnabled:(id)sender {
self.helpButtonEnabled = !self.helpButtonEnabled;
}
@end
KVO
Introduction to Key-Value Observing Programming Guide.
static void * const ViewControllerHelpButtonEnabledContext = (void*)&ViewControllerHelpButtonEnabledContext;
@implementation ViewController
- (void)dealloc {
// Remove previously registered observer when the view controller goes away
[self removeObserver:self forKeyPath:@"helpButtonEnabled" context:ViewControllerHelpButtonEnabledContext];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Register observer for the helpButtonEnabled key path
// - it fires immeditately with the current value (NSKeyValueObservingOptionInitial)
// - it fires later every single time new value is assigned (NSKeyValueObservingOptionNew)
// - context is used to quickly distinguish why the observeValueForKeyPath:... was called
[self addObserver:self
forKeyPath:@"helpButtonEnabled"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:ViewControllerHelpButtonEnabledContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (context == ViewControllerHelpButtonEnabledContext) {
// It's our observer, let's update button state
_helpButton.enabled = _helpButtonEnabled;
} else {
// It's not our observer, just forward it to super implementation
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
// Just another button action coming from the Main.storyboard which toggles
// our helpButtonEnabled property value
- (IBAction)toggleHelpButtonEnabled:(id)sender {
self.helpButtonEnabled = !self.helpButtonEnabled;
}
@end
绑定
Introduction to Cocoa Bindings Programming Topics.
@implementation ViewController
- (void)dealloc {
// Remove binding when the view controller goes away
[self.helpButton unbind:NSEnabledBinding];
}
- (void)viewDidLoad {
[super viewDidLoad];
// self.helpButton.enabled is binded to self.helpButtonEnabled
[self.helpButton bind:NSEnabledBinding
toObject:self
withKeyPath:@"helpButtonEnabled"
options:nil];
}
// Just another button action coming from the Main.storyboard which toggles
// our helpButtonEnabled property value
- (IBAction)toggleHelpButtonEnabled:(id)sender {
self.helpButtonEnabled = !self.helpButtonEnabled;
}
@end
我只是尝试在 XCode MacOS(不是 iOS)上使用各种方法禁用按钮 Cocoa Objective-C.
在这种情况下,我有一个帮助按钮 (m_btHelp),当 g_bEnableHelpButton = NO 时该按钮被禁用;但只有在鼠标移动时才会检查
-(void)mouseMoved:(NSEvent *)theEvent
{
if(g_bEnableHelpButton) {
[m_btHelp setEnabled:YES];
} else {
[m_btHelp setEnabled:NO];
}
我宁愿连续检查而不是只在鼠标移动时检查。我已经用这样的东西尝试过 NSTimer,但它似乎不起作用(m_btHelp 在 g_bEnableHelpButton = NO 时不会被禁用;就像在 mouseMoved 事件中一样:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(Timerloop) userInfo:nil repeats:YES];
}
- (void)Timerloop
{
if(g_bEnableHelpButton) {
[m_btHelp setEnabled:YES];
} else {
[m_btHelp setEnabled:NO];
}
}
g_bEnableHelpButton
是全局变量吧?不要使用全局变量。最好创建一个 class 来保存您的状态(可以是视图模型,...)。我将在下面的所有示例中跳过状态 class 并将在同一视图控制器上使用 BOOL helpButtonEnabled
属性 (这不是强制性的,它只是使所有这些示例更短).你可以把这个属性移到别处,它可以是一个状态class,它基本上可以是任何对象。
另一件事是 NSTimer
、NSTrackingArea
、...所有这些都在浪费 CPU 周期、电池寿命... Cocoa & Objective-C 提供了多种方式来监控 属性 值并对其做出反应。你可以覆盖 属性 setter,你可以使用 KVO 或绑定。以下示例涵盖了所有三种方法。
肯定还有其他方法(比如 ReactiveCocoa),但我想演示三种方法如何在没有依赖项的情况下实现它。
初始状态
假设你有这样的观点:
实施如下:
#import "ViewController.h"
@interface ViewController ()
// Help button from the Main.storyboard
// Imagine it's your m_btHelp
@property (nonatomic, strong) IBOutlet NSButton *helpButton;
// Property driving helpButton enabled/disabled state
// Imagine it's your g_bEnableHelpButton
@property (nonatomic, getter=isHelpButtonEnabled) BOOL helpButtonEnabled;
@end
@implementation ViewController
// Just another button action coming from the Main.storyboard which toggles
// our helpButtonEnabled property value
- (IBAction)toggleHelpButtonEnabled:(id)sender {
self.helpButtonEnabled = !self.helpButtonEnabled;
}
@end
有帮助按钮和切换按钮,它只切换 helpButtonEnabled
值(YES
-> NO
,NO
-> YES
)。
如何在没有计时器、跟踪区域、...以更新帮助按钮状态的情况下进行监视?
覆盖setter
@implementation ViewController
// This is setter for the helpButtonEnabled property.
- (void)setHelpButtonEnabled:(BOOL)helpButtonEnabled {
// If the new value equals, do nothing
if (helpButtonEnabled == _helpButtonEnabled) {
return;
}
// Update instance variable
_helpButtonEnabled = helpButtonEnabled;
// Update button state
_helpButton.enabled = helpButtonEnabled;
}
- (void)viewDidLoad {
[super viewDidLoad];
// When the view loads update button state to the initial value
_helpButton.enabled = _helpButtonEnabled;
}
// Just another button action coming from the Main.storyboard which toggles
// our helpButtonEnabled property value
- (IBAction)toggleHelpButtonEnabled:(id)sender {
self.helpButtonEnabled = !self.helpButtonEnabled;
}
@end
KVO
Introduction to Key-Value Observing Programming Guide.
static void * const ViewControllerHelpButtonEnabledContext = (void*)&ViewControllerHelpButtonEnabledContext;
@implementation ViewController
- (void)dealloc {
// Remove previously registered observer when the view controller goes away
[self removeObserver:self forKeyPath:@"helpButtonEnabled" context:ViewControllerHelpButtonEnabledContext];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Register observer for the helpButtonEnabled key path
// - it fires immeditately with the current value (NSKeyValueObservingOptionInitial)
// - it fires later every single time new value is assigned (NSKeyValueObservingOptionNew)
// - context is used to quickly distinguish why the observeValueForKeyPath:... was called
[self addObserver:self
forKeyPath:@"helpButtonEnabled"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:ViewControllerHelpButtonEnabledContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (context == ViewControllerHelpButtonEnabledContext) {
// It's our observer, let's update button state
_helpButton.enabled = _helpButtonEnabled;
} else {
// It's not our observer, just forward it to super implementation
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
// Just another button action coming from the Main.storyboard which toggles
// our helpButtonEnabled property value
- (IBAction)toggleHelpButtonEnabled:(id)sender {
self.helpButtonEnabled = !self.helpButtonEnabled;
}
@end
绑定
Introduction to Cocoa Bindings Programming Topics.
@implementation ViewController
- (void)dealloc {
// Remove binding when the view controller goes away
[self.helpButton unbind:NSEnabledBinding];
}
- (void)viewDidLoad {
[super viewDidLoad];
// self.helpButton.enabled is binded to self.helpButtonEnabled
[self.helpButton bind:NSEnabledBinding
toObject:self
withKeyPath:@"helpButtonEnabled"
options:nil];
}
// Just another button action coming from the Main.storyboard which toggles
// our helpButtonEnabled property value
- (IBAction)toggleHelpButtonEnabled:(id)sender {
self.helpButtonEnabled = !self.helpButtonEnabled;
}
@end