2010年12月19日星期日

Cocoa runtime working directory

To specify a working directory of the application at runtime, we could use the 
changeCurrentDirectoryPath:(NSString*) of the NSFileManager

where the [NSBundle mainBundle] get the mainBundle and in my case I need the  "resourcePath" to get the path containing my stuffs.

2010年12月8日星期三

Export NSView to PNG

The following code is for exporting a NSView to PNG file.


And you can change the NSPNGFileType for other format, of course.

KVC for BOOL type not working

Recently I tried to read xml files by KVC in order to get rid of the frustrating hard-coded name matching.

However, by using the  -setValue:forKeyPath: function, I got a "-[NSCFString charValue]: unrecognized selector sent to instance XXXXXX" error when it comes to setting value of any property of BOOL type.

I could only found a few reference on Stackoverflow.

@try
    {
        [(NSObject*)retObj setValue:[[obj keyValuePairs] objectForKey:key]
                         forKeyPath:key];
    }
    @catch (NSException * e)
    {
        if ([[e name] isEqualToString:NSInvalidArgumentException])
        {
            NSNumber* boolVal = [NSNumber numberWithBool:[[[obj keyValuePairs] objectForKey:key] boolValue]];
            [(NSObject*)retObj setValue:boolVal
                             forKeyPath:key];
        }
    }

Since I am not knowing the type until runtime, I need to catch the exception before converting the data type. But I am not sure whether any other type would cause the same exception and lead to an incorrect casting.

I haven't met any problem yet, and hopefully it is safe

2010年12月4日星期六

NSImage Rotate at Image Centre

I have a much more clear concept of the coordinate system of Cocoa through these two days' work.

Firstly, the drawRect function of NSView doesnt simply draw on top of the context. The z-index couldn't be determined. Thus sometimes things that were drawn first may not covered by things drawn later. The reason behind, after googleing it, is that NSView is not for overlapping but subviewing to each other to form a view hierarchy.
So, in my case for a map editor, each component should not be regard as a subview in the main view representing the map. Instead they should be drawn directly on the drawRect function of the main view.

Secondly, here is the sample code of rotating a image.(not 100% complete as I not yet handle the case that the angle is 0, but should be pretty easy :p).

The concept would be better described by illustration but forgive my laziness.
Brief steps of rotating a image at its center:
1. create a NSBezierPath base on the original image bound
2. transform the NSBezierPath to get the bound after the image rotated
3. create an NSImage with the size equal to the size of the rotated bound
4. center the image in the rotated bound
5. set the NSAffineTransform: move to center of the bound > rotate > move back to the original position
6. lock the focus on the newly created image and draw the original image to its bound. done=]


In the drawRect function, calibrate the rect of the image. Otherwise the image will not be "anchored" on its center

Don't know whether there exists a better method (sth like simply putting the image in a NSImageView and rotate the view). But it at least works for me

2010年12月2日星期四

NSImage Transformation - Flip

Today a lot of time was wasted on deal with image transformation due to lack of investigation about the properties of drawing in Cocoa.

I can't make the transform context effect only on the image I want to transform but the whole NSView owning the image. After using "lockfocus", nothing is drawn becox of the wrong implementation of the coordination system.
The pain ended after I kw about the difference between "bounds" and "frame" on Stackoverflow

To make the "lock" function, it seems that the "frame" need to be set correctly and after the "lock" the drawing is easy.

Here is a simple sample of flipping a NSImage with the NSAffineTransform class. The image is drawn from its middle bottom.