วันศุกร์ที่ 11 กุมภาพันธ์ พ.ศ. 2554

Create Chart with CorePlot (BarChart)

การสร้าง BarChart ด้วย CorePlot 

เริ่มจากการสร้าง Project ผมใช้ CorePlotBarChart
ทำการ Add Framework ดูวิธีจาก CorePlotPieChart นะครับ

สร้าง BarChartViewController
ใน BarChartViewController.h

#import <UIKit/UIKit.h>
#import "CorePlot-CocoaTouch.h"

@interface BarChartViewController : UIViewController <CPPlotDataSource, CPBarPlotDelegate , CPBarPlotDataSource> {
IBOutlet CPGraphHostingView *_barChartView;
CPXYGraph *_barChart;
NSMutableArray *_dataForBarChart;
}

-(void)constructBarChart;
-(void)genData;

@end



ใน BarChartViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
_barChartView = [[CPGraphHostingView alloc] initWithFrame:CGRectMake(0, 20, 350, 500)];

[self.view addSubview:_barChartView];
[self genData];
[self constructBarChart];
}



-(void)genData{
_dataForBarChart = [[NSMutableArray alloc] init];
for (int i = 0; i < 5; ++i) {
[_dataForBarChart addObject:[NSNumber numberWithInteger:10*i*i+50]];
}
}



-(void)constructBarChart{
//Create Bar Chart
    _barChart = [[CPXYGraph alloc] initWithFrame:CGRectZero];
//Select Theme
CPTheme *theme = [CPTheme themeNamed:kCPDarkGradientTheme];
    [_barChart applyTheme:theme];
    _barChartView.hostedGraph = _barChart;
    _barChart.plotAreaFrame.masksToBorder = NO;
    _barChart.paddingLeft = 70.0;
_barChart.paddingTop = 20.0;
_barChart.paddingRight = 20.0;
_barChart.paddingBottom = 80.0;
//Init Range of X axis (0 - 10) and Y axis (0 - 300)
    CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)_barChart.defaultPlotSpace;
    plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0.0f) length:CPDecimalFromFloat(300.0f)];
    plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0.0f) length:CPDecimalFromFloat(10.0f)];
    //Create X axis 
CPXYAxisSet *axisSet = (CPXYAxisSet *)_barChart.axisSet;
    CPXYAxis *x = axisSet.xAxis;
    x.axisLineStyle = nil;
    x.majorTickLineStyle = nil;
    x.minorTickLineStyle = nil;
    x.majorIntervalLength = CPDecimalFromString(@"5");
//Position of X Label on Y axis
    x.orthogonalCoordinateDecimal = CPDecimalFromString(@"0");
x.title = @"X Axis";
    x.titleLocation = CPDecimalFromFloat(5.0f);
x.titleOffset = 55.0f;
//Create Label for X axis
x.labelRotation = M_PI/4;
x.labelingPolicy = CPAxisLabelingPolicyNone;
NSArray *customTickLocations = [NSArray arrayWithObjects:[NSDecimalNumber numberWithInt:0], [NSDecimalNumber numberWithInt:1], 
[NSDecimalNumber numberWithInt:2], [NSDecimalNumber numberWithInt:3], [NSDecimalNumber numberWithInt:4], nil];
NSArray *xAxisLabels = [NSArray arrayWithObjects:@"Label A", @"Label B", @"Label C", @"Label D", @"Label E", nil];
NSUInteger labelLocation = 0;
NSMutableArray *customLabels = [NSMutableArray arrayWithCapacity:[xAxisLabels count]];
for (NSNumber *tickLocation in customTickLocations) {
CPAxisLabel *newLabel = [[CPAxisLabel alloc] initWithText: [xAxisLabels objectAtIndex:labelLocation++] textStyle:x.labelTextStyle];
newLabel.tickLocation = [tickLocation decimalValue];
newLabel.offset = x.labelOffset + x.majorTickLength;
newLabel.rotation = M_PI/4;
[customLabels addObject:newLabel];
[newLabel release];
}
x.axisLabels =  [NSSet setWithArray:customLabels];
//Create Y axis
CPXYAxis *y = axisSet.yAxis;
    y.axisLineStyle = nil;
    y.majorTickLineStyle = nil;
    y.minorTickLineStyle = nil;
    y.majorIntervalLength = CPDecimalFromString(@"50");
//Positionof Y Label on X axis
    y.orthogonalCoordinateDecimal = CPDecimalFromString(@"0");
y.title = @"Y Axis";
y.titleOffset = 45.0f;
    y.titleLocation = CPDecimalFromFloat(150.0f);
//Create Plot
    CPBarPlot *barPlot = [CPBarPlot tubularBarPlotWithColor:[CPColor darkGrayColor] horizontalBars:NO];
    barPlot.baseValue = CPDecimalFromString(@"0");
    barPlot.dataSource = self;
    barPlot.barOffset = 0.25;
    barPlot.identifier = @"Bar Plot";
    [_barChart addPlot:barPlot toPlotSpace:plotSpace];
}



Delegate and DataSource

-(void)barPlot:(CPBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)index{
NSLog(@"Select At Record Index %d", index);
}

-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot{
return [_dataForBarChart count];
}

-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index{
NSDecimalNumber *num = nil;

switch ( fieldEnum ) {
//Position of Plot
case CPBarPlotFieldBarLocation:
num = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:index];
break;
//Height of Plot
case CPBarPlotFieldBarLength:
num = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:[[_dataForBarChart objectAtIndex:index] intValue]];
break;
}
return num;
}



ใน CorePlotBarChartAppDelegate.h


#import <UIKit/UIKit.h>
#import "BarChartViewController.h"

@interface CorePlotBarChartAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
BarChartViewController *_barChartViewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end



ใน CorePlotBarChartAppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
    // Override point for customization after application launch.
    
_barChartViewController = [[BarChartViewController alloc] init];
[window addSubview:_barChartViewController.view];
    [self.window makeKeyAndVisible];
    
    return YES;
}



Build & Run

วันอาทิตย์ที่ 6 กุมภาพันธ์ พ.ศ. 2554

How to open .doc .xls .ppt in iPhone

ถ้าเราต้องการเขียนโปรแกรมเปิด .doc .xls .ppt ใร iPhone
เราสามารถใช้ UIWebView ได้ครับ

ก็เริ่มจากสร้าง Project ใหม่ (ผมใช้ชื่อ OpenDoc)
นำ File .doc ที่ต้องการเปิดใส่ไว้ใน Project (ผมใช้ sample.doc)


ใน OpenDocAppDelegate.m


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;


เพิ่ม Code สร้าง UIWebView


UIWebView *_webView = [[UIWebView alloc] initWithFrame:window.frame];


กำหนด Path ของ File ที่ต้องการเปิดและ Add Subview ลงใน Window


NSString *filePath = [[NSBundle mainBundle] pathForResource:@"sample.doc" ofType:nil];
NSURL *url = [NSURL fileURLWithPath:filePath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[_webView loadRequest:requestObj];
[window addSubview:_webView];



Build & Run

วันจันทร์ที่ 31 มกราคม พ.ศ. 2554

Create Chart with CorePlot (PieChart)

เป็นเรื่องของการทำ Chart นะครับ โดยเราจะใช้ Framework ที่ชื่อ CorePlot ครับ

การใช้ CorePlot ขอเริ่มจาก PieChart ก่อนนะครับ เพราะรู้สึกว่าจะง่ายที่สุดครับ
เริ่มจาก Download CorePlot 
Extract File จะได้ Folder ของ CorePlot (ผมใช้ CorePlot_0.2.2.zip ข้างในจะมีตัวอย่าง Code ให้ด้วยครับ)

สร้าง Project (ผมตั้งชื่อ CorePlotPieChart)
ทำการติดตั้ง Framework (ผมทำแบบที่ง่ายสำหรับผมนะครับ)
เริ่มจาก Copy CorePlot 0.2.2/Source/framework ไว้ใน Folder Project ของเราก่อนครับ



ลาก File CorePlot-CocoaTouch.xcodeproj ใส่ใน Project เปิดใน Project จะมี CorePlot-CocoaTouch.xcodeproj/libCorePlot-CocoaTouch.a อยู่
ลาก FIle libCorePlot-CocoaTouch.a ใส่ไว้ใน Targets/CorePlotPieChart/Link Binary With Libraries
ทำการ Add Framework QuartzCore.framework ใส่ใน Project



ทำการแก้ไข Project Setting
ไปที่ Project -> Edit Project Settings
เริ่มจากกำหนด Header Search Paths (Search คำว่า header se)



Double Click ที่ User Header Search Paths แล้วกดเพิ่ม
ใส่ค่า "${PROJECT_DIR}/framework" ใน Path และเลือก Recursive





ต่อไปทำการกำหนดค่าของ Other Linker Flags (Search คำว่า other link)



เพิ่ม -all_load -ObjC 



เลือก Project -> Edit Active Target "CorePlotPieChart" ที่ Tab General



ที่ Direct Dependencies เพิ่ม CorePlot-CocoaTouch



เสร็จขั้นตอนการ Add Framework
ต่อไปเป็นเรื่องของการใช้งาน
เริ่มจากสร้าง ViewController (ผมสร้าง ViewController ชื่อ PieChartViewController)

เปิด PieChartViewController.h 

#import <UIKit/UIKit.h>
#import "CorePlot-CocoaTouch.h"


@interface PieChartViewController : UIViewController <CPPieChartDataSource> {

IBOutlet CPGraphHostingView *_pieChartView;
CPXYGraph *_pieChart;
NSArray *_data;
}

-(void)constructPieChart;

@end



เปิด PieChartViewController.xib
ลาก View ใส่ใน MainView หลังจากนั้นไปที่ Inspector ที่ Tab identity
ใส่ชื่อ Class CPGraphHostingView ในส่วนของ Class
Link View ที่สร้างกับ Outlet _pieChartView



เปิด PieChartViewController.m
ที่ - (void)viewDidLoad; เพิ่ม [self constructPieChart];



Implement Datasource Protocol

//จำนวนข้อมูลที่จะแสดง
-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot{
return [_data count];
}

//ค่าที่จะนำไปใช้ในการสร้าง Chart แต่ละช่อง
-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index{
NSDecimalNumber *num = nil;
if (index >= [_data count]) {
return nil;
}
if (fieldEnum == CPPieChartFieldSliceWidth) {
num = [_data objectAtIndex:index];
}else {
num = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:index];
}
return num;
}

//Label ที่จะแสดงใน Chart
-(CPLayer *)dataLabelForPlot:(CPPlot *)plot recordIndex:(NSUInteger)index
{
CPTextLayer *newLayer = nil;
newLayer = [[[CPTextLayer alloc] initWithText:[NSString stringWithFormat:@"Data %lu", index+1] style:[CPTextStyle textStyle]] autorelease];
newLayer.textStyle.color = [CPColor darkGrayColor];
return newLayer;
}



Implement ส่วนของการสร้าง PieChart (-(void)constructPieChart;)

-(void)constructPieChart{
_pieChart = [[CPXYGraph alloc] initWithFrame:CGRectZero];
//เลือก Theme
CPTheme *theme = [CPTheme themeNamed:kCPDarkGradientTheme];
    [_pieChart applyTheme:theme];
//สร้างพื้นที่สำหรับแสดง Chart
    _pieChartView.hostedGraph = _pieChart;
    _pieChart.plotAreaFrame.masksToBorder = NO;
//ความหนาของกรอบ
    _pieChart.paddingLeft = 20.0;
_pieChart.paddingTop = 20.0;
_pieChart.paddingRight = 20.0;
_pieChart.paddingBottom = 20.0;
_pieChart.axisSet = nil;
//สร้าง Chart (รายละเอียดต่างๆ ของ Chart)
    CPPieChart *piePlot = [[CPPieChart alloc] init];
    piePlot.dataSource = self;
//ขนาด Chart
    piePlot.pieRadius = 120.0;
    piePlot.identifier = @"Pie Chart 1";
piePlot.startAngle = M_PI_4;
piePlot.sliceDirection = CPPieDirectionCounterClockwise;
piePlot.borderLineStyle = [CPLineStyle lineStyle];
//ตำแหน่งของ Label
piePlot.sliceLabelOffset = -35.0;
    [_pieChart addPlot:piePlot];
    [piePlot release];
//ข้อมูลที่จะแสดงใน Chart (อาจจะไปใส่ใน DataSource แทน)
_data = [NSArray arrayWithObjects:[NSNumber numberWithDouble:20.0], [NSNumber numberWithDouble:15.0], [NSNumber numberWithDouble:15.0], [NSNumber numberWithDouble:40.0], [NSNumber numberWithDouble:10.0], nil];
}



เปิด CorePlotPieChartAppDelegate.h

#import <UIKit/UIKit.h>
#import "PieChartViewController.h"

@interface CorePlotPieChartAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
PieChartViewController *_pieChartViewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end



ใน CorePlotPieChartAppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
    // Override point for customization after application launch.
    
_pieChartViewController = [[PieChartViewController alloc] init];
[window addSubview:_pieChartViewController.view];
    [self.window makeKeyAndVisible];
    
    return YES;
}



Build & Run





วันพฤหัสบดีที่ 27 มกราคม พ.ศ. 2554

การดึงข้อมูลของเครื่อง UIDevice

การดึงรายละเอียดเกี่ยวกับเครื่องที่ใช้งาน ชื่อเครื่อง UDID หรือ OS จะทำงานผ่าน UIDevice 

สร้าง Project ใหม่ (ผมใช้ชื่อ UIDeviceEx)

เปิดไฟล์ UIDeviceExAppDelegate.m 

ที่ Method 
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

เพิ่ม Code
UIDevice *myDevice = [[UIDevice alloc] init];
NSLog(@"Device Name : %@", myDevice.name);
NSLog(@"Device Model : %@", myDevice.model);
NSLog(@"OS Version : %@", myDevice.systemVersion);
NSLog(@"UDID : %@", myDevice.uniqueIdentifier);
if (myDevice.multitaskingSupported) {
NSLog(@"Multitask : YES");
}else {
NSLog(@"Multitask : NO");
}

วันศุกร์ที่ 14 มกราคม พ.ศ. 2554

XMLParser

สวัสดีครับ
สำหรับ Entry นี้จะเป็นเรื่องของ XML นะครับ
ซึ่งจริงๆ แล้ว XML Parser ก็มีคนทำให้ใช้อยู่หลายตัวนะครับ
และก็มีตัวของ Apple เองด้วย คือ NSXMLParser

การทำงานของ NSXMLParser หลังจากที่สร้าง NSXMLParser กำหนด Delegate แล้ว
เมื่อส่ง Message parse เข้าไปยัง Object ของ NSXMLParser จะเกิด Run loop ขึ้น
เราจะทำการกำหนดการทำงานต่างๆ จาก Event ที่เกิดขึ้น โดยผ่าน Delegate ของ NSXMLParser

เมื่อเริ่มทำการ Parser
– parserDidStartDocument:

เจอ Tag เปิดของ Element
– parser:didStartElement:namespaceURI:qualifiedName:attributes:

เจอ String ใน Element ปัจจุบัน
– parser:foundCharacters:

เจอ Tag ปิดของ Element
– parser:didEndElement:namespaceURI:qualifiedName:

เมื่อเกิด Error
– parser:parseErrorOccurred:

เมื่อทำการ Parser เสร็จสิ้น
– parserDidEndDocument:

และยังมี Delegate สำหรับ Event อื่นๆ ซึ่งดูได้จากใน Document
XML ที่ใช้ทดสอบจะใช้ XML จาก W3C 
ขั้นแรกก็มาดูโครงสร้างของ XML จาก File simple.xml
รูปแบบทั่วไปคือ

<breakfast_menu>
<food>
<name></name>
<price></price>
<description></description>
<calories></calories>
</food>
</breakfast_menu>



เปิด Xcode สร้าง Project ขึ้นมา (ผมใช้ชื่อ XMLParser)

Download File xml ใส่ใว้ใน Project (ไว้ใน Resources)

ไปที่ XMLParserAppDelegate.h (.h)
สร้างตัวแปรสำหรับเก็บค่าต่างๆ ตามรูปแบบทั่วไปของ XML (อาจสร้าง Class สำหรับมาใช้เก็บข้อมูล)
และ NSXMLParser ขึ้นมา

#import <UIKit/UIKit.h>

@interface XMLParserAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
NSMutableArray *_breakfast_menu;
NSMutableDictionary *_currentFood;
NSMutableString *_currentElement;
NSMutableString *_currentName;
NSMutableString *_currentPrice;
NSMutableString *_currentDescription;
NSMutableString *_currentCalories;
NSXMLParser *_xmlParser;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end



ไปที่ XMLParserAppDelegate.m (.m)

ใน - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

เราจะทำการสร้าง NSXMLParser ขึ้นมา (เมื่อเจอ [_xmlParser parse]; จะเริ่มทำการ Parser)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    // Override point for customization after application launch.
_breakfast_menu = [[NSMutableArray alloc] init];
NSURL *xmlURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"simple" ofType:@"xml"]];
_xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[_xmlParser setDelegate:self];
[_xmlParser parse];
    [window makeKeyAndVisible];
return YES;
}



ทำการ Implement Delegate method สำหรับ Event ต่างๆ

เมื่อเกิด Error ให้แสดง Error
- (void) parser: (NSXMLParser*) parser parseErrorOccurred: (NSError *) parseError{
NSLog(@"XML Parser Error : %@", parseError);
}

เริ่มการ Parser สร้าง Object สำหรับบอก Element ปัจจุบัน
-(void)parserDidStartDocument:(NSXMLParser *)parser{
_currentElement = [[NSMutableString alloc] init];
}

เจอ Tag เปิดกำหนดค่าของ _currentElement เพื่อนำไปตรวจสอบชนิดของ Element ที่ทำงานอยู่
ถ้าเป็น Tag food สร้าง Object สำหรับเก็บรายละเอียด
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
[_currentElement setString:elementName];
if([elementName isEqualToString: @"food"]){
_currentFood = [[NSMutableDictionary alloc] init];
_currentName = [[NSMutableString alloc] init];
_currentPrice = [[NSMutableString alloc] init];
_currentDescription = [[NSMutableString alloc] init];
_currentCalories = [[NSMutableString alloc] init];

}
}

เจอ Tag ปิดทำการเก็บค่าที่ได้
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if([elementName isEqualToString: @"food"]){
[_breakfast_menu addObject: _currentFood];
[_currentFood release];

}else if([elementName isEqualToString: @"name"]){
[_currentFood setObject: _currentName forKey: @"name"];
[_currentName release];
}else if([elementName isEqualToString: @"price"]){
[_currentFood setObject: _currentPrice forKey: @"price"];
[_currentPrice release];
}else if([elementName isEqualToString: @"description"]){
[_currentFood setObject: _currentDescription forKey: @"description"];
[_currentDescription release];
}else if([elementName isEqualToString: @"calories"]){
[_currentFood setObject: _currentCalories forKey: @"calories"];
[_currentCalories release];

}
}

เจอข้อมูลระหว่าง Tag
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if(![[string stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]] isEqualToString: @""]){
if([_currentElement isEqualToString: @"name"]){
[_currentName appendString: string];
}else if([_currentElement isEqualToString: @"price"]){
[_currentPrice appendString: string];
}else if([_currentElement isEqualToString: @"description"]){
[_currentDescription appendString: string];
}else if([_currentElement isEqualToString: @"calories"]){
[_currentCalories appendString: string];
}
}
}

จบการทำ Parser
- (void)parserDidEndDocument:(NSXMLParser *)parser {
for (NSMutableDictionary *food in _breakfast_menu){
NSLog(@"\n\n");
NSLog(@"Name        : %@", [food objectForKey: @"name"]);
NSLog(@"Price       : %@", [food objectForKey: @"price"]);
NSLog(@"Description : %@", [food objectForKey: @"description"]);
NSLog(@"Calories    : %@", [food objectForKey: @"calories"]);
}
[_currentElement release];
}



ลอง Build & Run ดูผลใน Debugger Console