Demonstrates how to use Cocoa Bindings to simplify storing and retrieving user preferences. Also demonstrates how to use an NSValueTransformer to archive/unarchive a non-property-list type automatically (NSColor, in this case).
Originally from “Cocoa Bindings Examples and Hints”, converted to PyObjC by u.fiedler.
#
# ControlledPreferences
#
#
from PyObjCTools import AppHelper
# import classes required to start application
import PreferencesPanelController
import FontNameToDisplayNameTransformer
import FontSampleDisplayView
# start the event loop
AppHelper.runEventLoop()
#
# FontNameToDisplayNameTransformer.py
# ControlledPreferences
#
# Converted by u.fiedler on 04.02.05.
# with great help from Bob Ippolito - Thank you Bob!
#
# The original version was written in Objective-C by Malcolm Crawford
# at http://homepage.mac.com/mmalc/CocoaExamples/controllers.html
from Foundation import *
from AppKit import *
class FontNameToDisplayNameTransformer(NSValueTransformer):
"""
Takes as input the fontName of a font as stored in user defaults,
returns the displayed font name of the font to show to the user.
"""
def transformedValueClass(cls):
return NSString
transformedValueClass = classmethod(transformedValueClass)
def allowsReverseTransformation(cls):
return False
allowsReverseTransformation = classmethod(allowsReverseTransformation)
def transformedValue_(self, aValue):
font = NSFont.fontWithName_size_(aValue, 12)
return font.displayName()
#
# FontSampleDisplayView.py
# ControlledPreferences
#
# Converted by u.fiedler on 04.02.05.
# with great help from Bob Ippolito - Thank you Bob!
#
# The original version was written in Objective-C by Malcolm Crawford
# at http://homepage.mac.com/mmalc/CocoaExamples/controllers.html
from Foundation import *
from AppKit import *
from PyObjCTools.KeyValueCoding import *
class FontSampleDisplayView(NSView):
"""
Display WordOfTheDay with the preferred font and color
"""
def drawRect_(self, rect):
defaults = NSUserDefaultsController.sharedUserDefaultsController().values()
favoriteColor = NSUnarchiver.unarchiveObjectWithData_(getKey(defaults, u'FavoriteColor'))
fontName = getKey(defaults, u'FontName')
fontSize = getKey(defaults, u'FontSize')
favoriteFont = NSFont.fontWithName_size_(fontName, fontSize)
wordOfTheDay = getKey(defaults, u'WordOfTheDay')
# Do the actual drawing
myBounds = self.bounds() # = (x, y), (bw, bh)
NSDrawLightBezel(myBounds, myBounds)
favoriteColor.set()
NSRectFill(NSInsetRect(myBounds, 2, 2))
attrsDictionary = {NSFontAttributeName: favoriteFont}
attrString = NSAttributedString.alloc().initWithString_attributes_(wordOfTheDay, attrsDictionary)
attrSize = attrString.size() # = (bw, bh)
attrString.drawAtPoint_(
NSMakePoint(
(attrSize.width / -2) + (myBounds.size.width / 2),
(attrSize.height / -2) + (myBounds.size.height / 2),
),
)
def initWithFrame_(self, frameRect):
self = super(FontSampleDisplayView, self).initWithFrame_(frameRect)
dnc = NSNotificationCenter.defaultCenter()
dnc.addObserver_selector_name_object_(self, "redisplay:", NSUserDefaultsDidChangeNotification, None)
return self
def redisplay_(self, sender):
self.setNeedsDisplay_(True)
#
# PreferencesPanelController.py
# ControlledPreferences
#
# Converted by u.fiedler on 04.02.05.
# with great help from Bob Ippolito - Thank you Bob!
#
# The original version was written in Objective-C by Malcolm Crawford
# at http://homepage.mac.com/mmalc/CocoaExamples/controllers.html
from FontNameToDisplayNameTransformer import FontNameToDisplayNameTransformer
from Foundation import *
from AppKit import *
from PyObjCTools.KeyValueCoding import *
class PreferencesPanelController (NSWindowController):
@objc.IBAction
def changeTextFont_(self, sender):
"The user changed the current font selection, so update the default font"
# Get font name and size from user defaults
defaults = NSUserDefaultsController.sharedUserDefaultsController().values()
fontName = getKey(defaults, u'FontName')
fontSize = getKey(defaults, u'FontSize')
# Create font from name and size; initialize font panel
font = NSFont.fontWithName_size_(fontName, fontSize)
if font is None:
font = NSFont.systemFontOfSize_(NSFont.systemFontSize())
NSFontManager.sharedFontManager().setSelectedFont_isMultiple_(font, False)
NSFontManager.sharedFontManager().orderFrontFontPanel_(self)
# Set window as firstResponder so we get changeFont: messages
self.window().makeFirstResponder_(self.window())
@objc.IBAction
def changeFont_(self, sender):
"This is the message the font panel sends when a new font is selected"
# Get selected font
fontManager = NSFontManager.sharedFontManager()
selectedFont = fontManager.selectedFont()
if selectedFont is None:
selectedFont = NSFont.systemFontOfSize_(NSFont.systemFontSize())
panelFont = fontManager.convertFont_(selectedFont)
# Get and store details of selected font
# Note: use fontName, not displayName. The font name identifies the font to
# the system, we use a value transformer to show the user the display name
fontSize = panelFont.pointSize()
defaults = NSUserDefaultsController.sharedUserDefaultsController().values()
defaults.setValue_forKey_(panelFont.fontName(), u"FontName")
defaults.setValue_forKey_(fontSize, u"FontSize")
"""
Set up initial values for defaults:
Create dictionary with keys and values for WordOfTheDay, FontName,
FontSize, and FavoriteColor. Mostly straightforward, but:
Store the fontName of the font as the default; the textfield displays
the font's displayName using a value transformer.
The color must be archived -- you can't store NSColors directly in NSUserDefaults.
"""
dictionary = {}
dictionary[u'WordOfTheDay'] = u'Today'
systemFont = NSFont.systemFontOfSize_(NSFont.systemFontSize())
dictionary[u"FontName"] = systemFont.fontName()
dictionary[u"FontSize"] = systemFont.pointSize()
archivedColor = NSArchiver.archivedDataWithRootObject_(NSColor.greenColor())
dictionary[u'FavoriteColor'] = archivedColor
NSUserDefaultsController.sharedUserDefaultsController().setInitialValues_(dictionary)
# Create and register font name value transformer
transformer = FontNameToDisplayNameTransformer.alloc().init()
NSValueTransformer.setValueTransformer_forName_(transformer, u'FontNameToDisplayNameTransformer')
"""
Script for building the example:
Usage:
python setup.py py2app
"""
from distutils.core import setup
import py2app
setup(
name="ControlledPreferences",
app=["ControlledPreferences.py"],
data_files=["English.lproj"],
)