Thursday, November 27, 2008

NSStepper


A common use of NSStepper is to control the value displayed in an adjacent text field. Here, I want to use this method to control text size in a simplified fashion. In IB, I set the stepper's minimum and maximum values and increment (all as floats).

One trick to steppers is that you should control drag from the stepper to the Text Field and then select takeIntValueFrom. This results in an action being sent to the TF to reflect changes in the stepper. Here, the stepper has been pre-set to have the values 12.0 and 14.0 with an increment of 2.0. These values can be changed in code, by making the stepper an outlet of the AD.

I also set the TextField as an outlet of the AppDelegate and get the stepper's value in awakeFromNib. Otherwise, the value is not displayed until the stepper is clicked for the first time.

To find out when the stepper has been clicked, just control drag from the stepper to the App Delegate in IB, the same as for any control. That's it.

class PyStepperAppDelegate(NSObject):
myStepper = objc.IBOutlet()
myStepperTF = objc.IBOutlet()

def awakeFromNib(self):
self.myStepper.setMaxValue_(24.0)
self.myStepperTF.takeIntValueFrom_(self.myStepper)
self.fontSize = self.myStepperTF.intValue()
print 'fontSize', self.fontSize

@objc.IBAction
def stepperChanged_(self,sender):
self.myStepperTF.takeIntValueFrom_(self.myStepper)
self.fontSize = self.myStepperTF.intValue()
print 'stepperChanged_, 'fontSize', self.fontSize

NSFontManager

Here is a minimal demonstration of an application that uses the FontPanel.
The application window contains a Custom View object (class set to MyView). The main menu contains a Font Menu Item (NSMenuItem), and there is a object called Font Manager (NSFontManager). The only connection that is needed is to make the Font Manager a target of the Show Fonts Menu Item, such that it receives the action "orderFrontFontPanel."

Now, when the User clicks on Font => Show Fonts, the Font Manager handles the interaction, and if the font changes, it calls "changeFont_" which is sent to the First Responder. To deal with a request to change the font, all we need is something like this:

class MyView(NSView):

def initWithFrame_(self, frame):
self = super(MyView, self).initWithFrame_(frame)
self.font = NSFont.fontWithName_size_(
'Helvetica', NSNumber.numberWithInt_(14))
return self

def acceptsFirstResponder(self):
return True

def changeFont_(self,sender):
print 'changeFont_', sender
font = sender.convertFont_(self.font)
print font.description()
self.font = font
self.setNeedsDisplay_(True)

def drawRect_(self, rect):
NSColor.whiteColor().set()
NSBezierPath.fillRect_(self.bounds())
D = { NSFontAttributeName: self.font }
g = 'just a purple string'
c = NSColor.purpleColor()
D[NSForegroundColorAttributeName] = c
s = NSString.stringWithString_(g)
s.drawAtPoint_withAttributes_(NSPoint(20,20), D)


I think what it does is so obvious that we don't need a screenshot. Of course, we could make things a lot more complicated. At the moment, none of the other items in the Font Menu is active.