Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the blinking cursor in textfield cause drawRect to be called?

I have the following view hierarchy setup in my program.

Window
+ContentView (Subview of Window)
++MyCustomView (Subview of ContentView)
++MyCustomOpaqueView (Subview of ContentView)
+++TextField (Subview of MyCustomOpaqueView)

When the user clicks the TextField the cursor inside of it starts to blink. On each blink drawRect is called on MyCustomView. Not a big deal, but I'm wondering why?

In MyCustomOpaqueView I implement isOpaque like so,

- (BOOL)isOpaque {return YES;}

I thought this would block messages to drawRect in MyCustomView if the NSRect passed to drawRect is entirely obscured by an opaque view, but when the cursor blinks MyCustomView still gets sent the drawRect message with an NSRect entirely behind an opaque view.

Am I missing a key concept or is this a quirk of the blinking cursor?


like image 597
Tobias Avatar asked Nov 05 '22 01:11

Tobias


1 Answers

Self-Resolving this answering, on recommendation by Josh Caswell.


I asked about this at a CocoaHeads meeting. I got a suggestion to look at the NSView's hitTest. So on both my custom views, I overrode the NSView's hittest function like so:

- (NSView*) hitTest:(NSPoint)aPoint {
    static int depth = 1;
    NSLog([NSString stringWithFormat:@"%%%dd ENTER %%@ - hitTest", depth], 
          depth, [[self class] description]);
    depth++;
    NSView *hitView = [super hitTest:aPoint];
    depth--;
    NSLog([NSString stringWithFormat:@"%%%dd EXIT %%@ - hitTest: %%@", depth], 
          depth, [[self class] description], [[hitView class] description]);
    return hitView;
}

Below is the output:

MyCustomView is subview of contentView.
MyOpaqueCustomView (OCV) is subview of contentView.

1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
MyCustomView - Dirty Rect: {{49, 189}, {127, 28} //!!Focus Ring Around Text Field
OCV - Dirty Rect: : {{49, 189}, {127, 28}}
testTextField isOpaque? Yes
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}}
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 ENTER MyCustomView - hitTest
1 EXIT MyCustomView - hitTest: MyCustomView
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}} //!!EVERY BLINK
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}}
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}}
MyCustomView - Dirty Rect: {{64, 194}, {1, 17}}

MyCustomView is subview of the contentView.
MyOpaqueCustomView (OCV) is subview of MyCustomView.

1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 EXIT MyCustomView - hitTest: NSTextField
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 EXIT MyCustomView - hitTest: NSTextField
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
1 EXIT MyCustomView - hitTest: NSTextView
OCV - Dirty Rect: : {{49, 189}, {127, 28}} //!!FOCUS RING
testTextField isOpaque? Yes
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
1 EXIT MyCustomView - hitTest: NSTextView
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextView
1 EXIT MyCustomView - hitTest: NSTextView
1 ENTER MyCustomView - hitTest
1 ENTER OCV - hitTest
1 EXIT OCV - hitTest: NSTextField
1 EXIT MyCustomView - hitTest: NSTextField
//!!BLINKING HERE - But no dirtyRects.

So it looks like the response to hitTest defines what views will get redrawn.

like image 116
Tobias Avatar answered Nov 10 '22 18:11

Tobias