Frage

I'm writing some AppKit code in PyObjC on Lion, and I want to use the special KVC accessor style, e.g. obj._.field = value instead of obj.setField_(value).

I have success setting NSString- and NSDictionary-valued properties with KVC, but I'm having trouble with wrapped Objective-C structs, specifically NSSize and NSRect.

When I try to set a KVC property of type NSSize or NSRect, the Objective-C layer throws an NSInvalidArgumentException. Cocoa is trying to invoke sizeValue or rectValue on the Python object.

Here is a log at the interactive prompt that shows the issue:

% python
Python 2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from AppKit import *
>>> NSApplication.sharedApplication()
<NSApplication: 0x7fcf6ae071f0>
>>> w = NSWindow.alloc().init()
>>> w._.minSize = NSSize(100, 200)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC/objc/_convenience.py", line 141, in __setattr__
    return self.__object.setValue_forKey_(value, key)
ValueError: NSInvalidArgumentException - Class OC_PythonObject: no such selector: sizeValue
>>> r = NSMakeRect(100, 200, 300, 400)
>>> w._.frame=r
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC/objc/_convenience.py", line 141, in __setattr__
    return self.__object.setValue_forKey_(value, key)
ValueError: NSInvalidArgumentException - Class OC_PythonObject: no such selector: rectValue

PyObjC seems to be wrapping the structs in a OC_PythonObject proxy, which doesn't implement the expected KVC converter. The KVC code assumes that the value is like an NSValue and implements the struct accessor methods.

Is there a way to set struct-valued KVC properties in PyObjC?

War es hilfreich?

Lösung

This is quite simple. Even in plain ObjC, the structs would need to be wrapped in an NSValue before being passed through KVC. You can do the same in Python:

>>> w._.minSize = NSValue.valueWithSize_(NSSize(100,200))
>>> w.minSize()
<NSSize width=100.0 height=200.0>
>>> w._.frame = NSValue.valueWithRect_(NSMakeRect(100, 200, 300, 400))
>>> w.frame()
<NSRect origin=<NSPoint x=100.0 y=200.0> size=<NSSize width=300.0 height=400.0>>

See "Wrapping and Unwrapping Structs" in the KVC Programming Guide for more info. Also, don't forget when doing this that not all classes are KVC compliant for all attributes.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top