我正在尝试更改从NIB加载的窗口表中NSTextField
的鼠标光标。
根据文档,我已经将NSTextField
子类化并实施了resetCursorRects
。
- (void) resetCursorRects {
[self addCursorRect:[self bounds] cursor:[NSCursor pointingHandCursor]];
}
这从未被调用过。在NSWindowViewController
:
- (void) windowDidLoad {
[self.window invalidateCursorRectsForView:self.linkTextField];
}
我还通过在NSTextField
子类中添加以下内容来尝试跟踪区域:
- (void) awakeFromNib {
NSTrackingArea* trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds
options:(NSTrackingCursorUpdate | NSTrackingActiveAlways)
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}
- (void)cursorUpdate:(NSEvent *)theEvent {
[[NSCursor pointingHandCursor] set];
}
也没用。我做错了什么?
答案 0 :(得分:5)
Clickable links with NSTextField
我按照上面提到的NSTextField
进行子类化后得到了这个工作:
- (void)resetCursorRects {
[self addCursorRect:[self bounds] cursor:[NSCursor pointingHandCursor]];
}
答案 1 :(得分:1)
我在上面的答案中写了一个Swift 2.0版,并将其作为GitHub sample project found here提供。
即使它是为NSTextField设置的,这些概念也适用于NSResponder
(mouseEntered
和becomeFirstResponder
来自哪里)的子类。
以下是我写的代码的内容:
import Cocoa
class CCTextField: NSTextField {
var myColorCursor : NSCursor?
var mouseIn : Bool = false
var trackingArea : NSTrackingArea?
override func awakeFromNib()
{
myColorCursor = NSCursor.init(image: NSImage(named:"heart")!, hotSpot: NSMakePoint(0.0, 0.0))
}
override func resetCursorRects() {
if let colorCursor = myColorCursor {
self.addCursorRect(self.bounds, cursor: colorCursor)
}
}
override func mouseEntered(theEvent: NSEvent) {
super.mouseEntered(theEvent)
self.mouseIn = true
}
override func mouseExited(theEvent: NSEvent) {
super.mouseExited(theEvent)
self.mouseIn = false
}
override func mouseMoved(theEvent: NSEvent) {
if self.mouseIn {
myColorCursor?.set()
}
super.mouseMoved(theEvent)
}
func setArea(areaToSet: NSTrackingArea?)
{
if let formerArea = trackingArea {
self.removeTrackingArea(formerArea)
}
if let newArea = areaToSet {
self.addTrackingArea(newArea)
}
trackingArea = areaToSet
}
override func becomeFirstResponder() -> Bool {
let rect = self.bounds
let trackingArea = NSTrackingArea.init(rect: rect, options: [NSTrackingAreaOptions.MouseEnteredAndExited, NSTrackingAreaOptions.ActiveAlways], owner: self, userInfo: nil)
// keep track of where the mouse is within our text field
self.setArea(trackingArea)
if let ev = NSApp.currentEvent {
if NSPointInRect(self.convertPoint(ev.locationInWindow, fromView: nil), self.bounds) {
self.mouseIn = true
myColorCursor?.set()
}
}
return true
}
}
答案 2 :(得分:0)
我有同样的问题,每次光标进入跟踪区域时都会调用cursorUpdate方法,但是光标被放回到其他地方,可能是它的超级视图。
我设法通过覆盖mouseMoved方法来解决它。
// In the textfield subclass:
- (void)mouseEntered:(NSEvent *)theEvent {
[super mouseEntered:theEvent];
self.isMouseIn = YES;
}
- (void)mouseExited:(NSEvent *)theEvent {
[super mouseExited:theEvent];
self.isMouseIn = NO;
}
//In the superview of the textfield:
- (void)mouseMoved:(NSEvent *)theEvent {
if (self.hoverButton.isMouseIn) {
[[NSCursor pointingHandCursor] set];
}
[super mouseMoved:theEvent];
}
我在windowController类中覆盖了mouseMoved方法,但是覆盖superview应该可行。
答案 3 :(得分:0)
NSTextView似乎是通过其-(void)mouseMoved:(NSEvent*)theEvent
方法处理游标。此外,当NSTextView成为第一响应者时,RunLoop中的一些私有代码似乎强制光标到IBeamCursor而不给我们选择。这是一个可以解决这些限制的子类:
@interface MyTextView : NSTextView {
NSTrackingArea* area;
BOOL mouseInside;
}
@property(nonatomic, retain) NSTrackingArea* area;
@end
@implementation MyTextView
@synthesize area;
- (void)setArea:(NSTrackingArea *)newArea
{
[newArea retain];
if (area) {
[self removeTrackingArea:area];
[area release];
}
if (newArea) {
[self addTrackingArea:newArea];
}
area = newArea;
}
- (BOOL)becomeFirstResponder
{
NSRect rect = <insert the tracking rect where you want to have a special cursor>;
self.area = [[[NSTrackingArea alloc] initWithRect:rect options:NSTrackingMouseEnteredAndExited | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil] autorelease];
NSEvent* ev = [NSApp currentEvent];
if (NSPointInRect([self convertPoint:ev.locationInWindow fromView:nil], self.bounds)) {
mouseInside = YES;
// This is a workaround for the private call that resets the IBeamCursor
[[NSCursor arrowCursor] performSelector:@selector(set) withObject:nil afterDelay:0];
}
}
- (void)mouseEntered:(NSEvent *)theEvent
{
[super mouseEntered:theEvent];
[[NSCursor arrowCursor] set];
mouseInside = YES;
}
- (void)mouseExited:(NSEvent *)theEvent
{
[super mouseExited:theEvent];
mouseInside = NO;
}
- (void)mouseMoved:(NSEvent *)theEvent
{
si (!mouseInside) {
// We only forward the mouseMoved event when the mouse is outside the zone for which we control the cursor
[super mouseMoved:theEvent];
}
}
- (oneway void)dealloc
{
[area release];
[super dealloc];
}
@end
答案 4 :(得分:0)
这对我有用:
class TextField: NSTextField {
override func becomeFirstResponder() -> Bool {
addTrackingAreaIfNeeded()
return super.becomeFirstResponder()
}
override func mouseMoved(with event: NSEvent) {
super.mouseMoved(with: event)
NSCursor.pointingHand.set()
}
private func addTrackingAreaIfNeeded() {
if trackingAreas.isEmpty {
let area = NSTrackingArea(rect: bounds, options: [.mouseEnteredAndExited, .activeAlways], owner: self, userInfo: nil)
addTrackingArea(area)
}
}
}