Weitere ähnliche Inhalte Ähnlich wie Brew up a Rich Web Application with Cappuccino (20) Mehr von Howard Lewis Ship (16) Kürzlich hochgeladen (20) Brew up a Rich Web Application with Cappuccino1. Brew up a Rich
Web Application
with Cappuccino
Howard M. Lewis Ship
TWD Consulting
hlship@comcast.net
1 © 2009 Howard Lewis Ship
3. Agenda
• Why Cappuccino?
• Getting Started
• Objective-J
• Running as a Web App
• Window Resizing &
Remote Communication
• Cappuccino Pitfalls
3 © 2009 Howard Lewis Ship
5. 5 © 2009 Howard Lewis Ship
6. 6 © 2009 Howard Lewis Ship
7. ❝If you need web applications that offer
the same user experience as a desktop
app would, then Cappuccino is for you. If
you truly believe that the classic web
development "components" - the usual
HTML/CSS/Javascript horror shop -
simply stinks, then you are going to be
delighted about Cappuccino, too.❞
Holger Jahn
7 © 2009 Howard Lewis Ship
9. Download
http://cappuccino.org/download/
Click Here
9 © 2009 Howard Lewis Ship
10. Install Tools
sudo ./install-tools
10 © 2009 Howard Lewis Ship
11. Tools Install
• Pre-Requisites
• Mac or Linux Helps!
• Cygwin for Windows
• Ruby & Rake
•cd Tools ; sudo ./install-tools
• Tools & Frameworks installed to /usr/local/share
• Must add /usr/local/share/bin to $PATH
11 © 2009 Howard Lewis Ship
13. Generated Files
Info.plist Application startup information
main.j main() method for application
AppController.j Application controller (builds initial UI)
index.html Launches application
index-debug.html Launches application (debug mode)
Rakefile Rake build file
Frameworks Copy of /usr/local/share/objj/lib/Frameworks
Resources Resources (images, etc.) available to application
13 © 2009 Howard Lewis Ship
14. Configuration
/*
* AppController.j
* example
*
* Created by You on July 14, 2009.
* Copyright 2009, Your Company All rights
reserved.
*/
• capp config key value Stored in ~/.cappconfig
• user.name
• user.email
• organization.name
• organization.email
• organization.url
• organization.identifier
14 © 2009 Howard Lewis Ship
17. Lineage
17 © 2009 Howard Lewis Ship
18. Objective-C
+ =
Preprocessor
18 © 2009 Howard Lewis Ship
19. Objective-J Syntax
Java Syntax Objective-J Syntax
window.orderFront(); [window orderFront];
icon.moveToXY(100, 200); [icon moveToX:100 Y:200];
method moveToX:Y:
Java Syntax Objective-J Syntax
new JFrame(); [[CPWindow alloc] init];
new JFrame("Toolbox"); [[CPWindow alloc] initWithTitle:"Toolbox"];
Class name
Class method
Java Syntax Objective-J Syntax
this.setNeedsDisplay(true); [self setNeedsDisplay:YES];
Cheat Sheet: this ➠ self, true ➠ YES, false ➠ NO, null ➠ nil 19 © 2009 Howard Lewis Ship
20. Defining Classes
Base class
PageView.j
@import <AppKit/CPView.j>
@implementation PageView : CPView
{
CALayer _rootLayer;
}
// Methods defined here
@end
Convention: instance variables
start with underscore
20 © 2009 Howard Lewis Ship
21. Defining Methods
- for instance method type of parameter
+ for class method
PageView.j
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
Return type {
_rootLayer = [CALayer layer];
[self setWantsLayer:YES];
[self setLayer:_rootLayer];
[_rootLayer setBackgroundColor:[CPColor whiteColor]];
[_rootLayer setNeedsDisplay];
}
return self;
}
21 © 2009 Howard Lewis Ship
23. Cappuccino User Interfaces
M
ac
O
nl
y
UI Object properties and connections
+ =
Controller Class Interface Builder File Running User Interface
[CPBundle loadCibNamed:owner:loadDelegate:]
Instantiates & connects
23 © 2009 Howard Lewis Ship
24. Actions and Outlets
triggerClicked:
AppController
@implementation AppController : CPObject
{
CPWindow theWindow;
CPTextField outputField;
}
…
- (void)triggerClicked:(id)sender
{
[outputField setObjectValue:"You clicked it!"];
}
@end
24 © 2009 Howard Lewis Ship
26. 26 © 2009 Howard Lewis Ship
27. Be 1
N
ta 5
ov
http://280atlas.com/
27 © 2009 Howard Lewis Ship
28. Running as a Web App
Using Maven & Jetty
28 © 2009 Howard Lewis Ship
29. 29 © 2009 Howard Lewis Ship
30. Creating a Web App
• mvn archetype:generate
• #18 (basic web application)
• Edit pom.xml:
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<requestLog implementation="org.eclipse.jetty.server.NCSARequestLog">
<append>true</append>
</requestLog>
</configuration>
</plugin>
</plugins>
• capp gen src/main/webapp/app
• mvn jetty:run
• Open http://localhost:8080/app
30 © 2009 Howard Lewis Ship
32. Cappuccino Classes
CPObject
CPResponder
undoManager : CPUndoManager
menu : CPMenu
nextResponder : CPResponder
CPView CPWindow
hidden : BOOL fullBridge : BOOL
frame : CGRect
- addSubview:CPView : void
level : int
- display : void
visible : BOOL
contentView : CPView
backgroundColor : CPColor
hasShadow : BOOL
title : CPString
CPControl
CPPanel
32 © 2009 Howard Lewis Ship
33. Cappuccino Classes
CPControl
action : SEL
target: id
enabled : BOOL
highlighted : BOOL
objectValue : id
floatValue: float
doubleValue : double
intValue : int
- initWithFrame:CGFrame : CPControl
CPButton CPTextField
title : CPString editable : BOOL
secure: BOOL
- sizeToFit : void bezeled : BOOL
+ buttonWithTitle:CPString : CPButton
+ labelWithTitle:CPString : CPTextField
33 © 2009 Howard Lewis Ship
34. Adding Controls
AppController.j
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero()
styleMask:CPBorderlessBridgeWindowMask],
contentView = [theWindow contentView];
_display = [CPTextField labelWithTitle:"(placeholder)"];
[_display setBezeled:YES];
[_display sizeToFit];
[contentView addSubview:_display];
[theWindow orderFront:self];
}
34 © 2009 Howard Lewis Ship
35. Utility Methods
AppController.j
- (void)add:(CPView)subview
{
[_contentView addSubview:subview];
}
- (CPButton)makeButton:value at:(CGRect)frame
{
var button = [[CPButton alloc] initWithFrame:frame];
[button setTitle:value.toString()];
[self add:button];
return button;
}
35 © 2009 Howard Lewis Ship
36. More Controls
AppController.j
_display = [CPTextField labelWithTitle:"(placeholder)"];
[_display setFrame:CGRectMake(5, 5, 180, 30)]
[_display setBezeled:YES];
[self add:_display];
[self makeButton:7 at:CGRectMake(5, 35, 40, 25)];
[self makeButton:8 at:CGRectMake(50, 35, 40, 25)];
[self makeButton:9 at:CGRectMake(95, 35, 40, 25)];
[self makeButton:"*" at:CGRectMake(140, 35, 40, 25)];
[self makeButton:4 at:CGRectMake(5, 65, 40, 25)];
[self makeButton:5 at:CGRectMake(50, 65, 40, 25)];
[self makeButton:6 at:CGRectMake(95, 65, 40, 25)];
[self makeButton:"-" at:CGRectMake(140, 65, 40, 25)];
[self makeButton:1 at:CGRectMake(5, 95, 40, 25)];
[self makeButton:2 at:CGRectMake(50, 95, 40, 25)];
[self makeButton:3 at:CGRectMake(95, 95, 40, 25)];
[self makeButton:"+" at:CGRectMake(140, 95, 40, 25)];
[self makeButton:0 at:CGRectMake(5, 125, 85, 25)];
[self makeButton:"." at:CGRectMake(95, 125, 40, 25)];
[self makeButton:"=" at:CGRectMake(140, 125, 40, 25)];
36 © 2009 Howard Lewis Ship
37. Local vars have no type
- (CPButton)makeDigit:(int)value at:(CGRect)frame
{
Should be var CPButton button = [self makeButton:value at:frame
action:@selector(digit:)];
[button setTag:value];
return button;
}
37 © 2009 Howard Lewis Ship
38. Local vars have no type
- (CPButton)makeDigit:(int)value at:(CGRect)frame
{
Should be var CPButton button = [self makeButton:value at:frame
action:@selector(digit:)];
[button setTag:value];
return button;
}
Not helpful!
38 © 2009 Howard Lewis Ship
41. Fleshed-Out Calculator
AppController.j
_display = [CPTextField labelWithTitle:""];
[_display setAlignment:CPRightTextAlignment];
[_display setFrame:CGRectMake(1, 5, 183, 30)]
[_display setBezeled:YES];
[self add:_display];
[self makeButton:"C" atX:0 y:0 action:@selector(clear:)];
[self makeButton:"/" atX:3 y:0 action:@selector(div:)];
[self makeButton:"*" atX:3 y:1 action:@selector(mult:)];
[self makeButton:"-" atX:3 y:2 action:@selector(minus:)];
[self makeButton:"+" atX:3 y:3 action:@selector(plus:)];
[self makeDigit:7 atX:0 y:1];
[self makeDigit:8 atX:1 y:1];
[self makeDigit:9 atX:2 y:1];
…
[[self makeButton:"=" atX:3 y:4 action:@selector(compute:)]
setDefaultButton:YES];
41 © 2009 Howard Lewis Ship
42. Utility Methods
AppController.j
- (CPButton)makeButton:(id)value atX:(int)x y:(int)y action:(SEL)action
{
var frame = CGRectMake(45 * x + 5, 30 * y + 35, 40, 24);
var button = [[CPButton alloc] initWithFrame:frame];
[button setTitle:value.toString()];
[button setTarget:self];
[button setAction:action];
[self add:button];
return button;
}
- (CPButton)makeDigit:(id)value atX:(int)x y:(int)y
{
return [self makeButton:value atX:x y:y action:@selector(digit:)];
}
42 © 2009 Howard Lewis Ship
43. Action Methods
@selector(digit:)
AppController.j
- (void)digit:(CPButton)source
{
var digit = [source title];
if (_value == "" && digit == "0") return;
_value = _sign + _value + digit;
_sign = "";
[_display setStringValue:_value];
}
- (void)clear:(id)source
{
[self reset];
}
43 © 2009 Howard Lewis Ship
46. Main UI
Top level window
AppController.j
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
var window = [[CPWindow alloc] initWithContentRect:CGRectMakeZero()
styleMask:CPBorderlessBridgeWindowMask],
contentView = [window contentView];
var button = [CPButton buttonWithTitle:@"Calculator"];
[button setFrameOrigin:CGPointMake(60, 40)];
[contentView addSubview:button];
[button setTarget:self];
[button setAction:@selector(raiseCalculatorPanel:)];
[window orderFront:self];
}
46 © 2009 Howard Lewis Ship
47. Creating CalcController
AppController.j
…
@import "CalcController.j"
@implementation AppController : CPObject
{
CalcController _calcController;
}
…
- (void)raiseCalculatorPanel:(id)sender
{
if (_calcController == nil)
_calcController = [[CalcController alloc] init];
[_calcController show];
}
@end
47 © 2009 Howard Lewis Ship
48. CalcController UI
CalcController.j
- (id)init
{
self = [super init];
_panel = [[CPPanel alloc] initWithContentRect:CGRectMake(20, 30, 184, 184)
styleMask:CPHUDBackgroundWindowMask | CPClosableWindowMask];
_contentView = [_panel contentView];
[_panel setTitle:"Calculator"];
_display = [CPTextField labelWithTitle:""];
[_display setAlignment:CPRightTextAlignment];
[_display setFrame:CGRectMake(1, 5, 183, 30)]
[_display setBezeled:YES];
[self add:_display];
[self makeButton:"C" atX:0 y:0 action:@selector(clear:)];
…
return self;
}
48 © 2009 Howard Lewis Ship
50. 50 © 2009 Howard Lewis Ship
51. Twitter Panel UI
TwitterController.j
_panel = [[CPPanel alloc] initWithContentRect:CGRectMake(20, 30, 245, 184)
styleMask:CPHUDBackgroundWindowMask | CPClosableWindowMask | CPResizableWindowMask];
[_panel setTitle:@"Twitter"];
var label = [CPTextField labelWithTitle:"User:"];
[label setFrame:CGRectMake(3, 7, 50, 24)];
[label setTextColor:[CPColor whiteColor]];
_field = [CPTextField textFieldWithStringValue:"" placeholder:"Twitter User" width:200];
[_field setFrame:CGRectMake(40, 0, 200, 28)];
[_field setTarget:self];
[_field setAction:@selector(startSearch:)];
var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 32, 245, 160)];
[scrollView setAutohidesScrollers:YES];
var content = [_panel contentView];
[content addSubview:label];
[content addSubview:_field];
[content addSubview:scrollView];
51 © 2009 Howard Lewis Ship
52. 52 © 2009 Howard Lewis Ship
53. Autoresize Flags
Containing CPView
CPViewMinYMargin
CPView
HeightSizable
CPViewMinXMargin CPViewMaxXMargin
CPView
CPViewWidthSizable
CPViewMaxYMargin
53 © 2009 Howard Lewis Ship
54. Autoresizing
TwitterController.j
[_panel setTitle:@"Twitter"];
[_panel setMinSize:CGSizeMake(245, 184)];
var label = [CPTextField labelWithTitle:"User:"];
[label setFrame:CGRectMake(3, 7, 50, 24)];
[label setTextColor:[CPColor whiteColor]];
_field = [CPTextField textFieldWithStringValue:"" placeholder:"Twitter User" width:200];
[_field setFrame:CGRectMake(40, 0, 200, 28)];
[_field setTarget:self];
[_field setAction:@selector(startSearch:)];
[_field setAutoresizingMask:CPViewWidthSizable];
var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(0, 32, 245, 160)];
[scrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[scrollView setAutohidesScrollers:YES];
[scrollView setBackgroundColor:[CPColor whiteColor]];
Temporary
54 © 2009 Howard Lewis Ship
55. 55 © 2009 Howard Lewis Ship
56. CPCollectionView
TwitterController.j
var itemPrototype = [[CPCollectionViewItem alloc] init];
[itemPrototype setView:[[TwitView alloc] init]];
_timelineView = [[CPCollectionView alloc]
initWithFrame:CGRectMake(0, 0, CGRectGetWidth(scrollViewBounds) - 2, 0)];
[_timelineView setItemPrototype:itemPrototype];
[_timelineView setDelegate:self];
[_timelineView setMaxNumberOfColumns:1];
[_timelineView setAutoresizingMask:CPViewWidthSizable];
[_scrollView setDocumentView:_timelineView];
56 © 2009 Howard Lewis Ship
57. JSON ➠ Image & Label
{
"title" : "Mmm - biscuits and gravy, in my hometown, with the woman I love.",
…
"user" : {
"profile_image_url" :
"http://a3.twimg.com/profile_images/71386417/scott_davis_2009_normal.jpg",
…
}
}
TwitView.j
- (void)setRepresentedObject:(JSONObject)obj
{
if (!_label)
{
…
}
[_imageView setImage:[[CPImage alloc]
initByReferencingFile:obj.user.profile_image_url
size:CPSizeMake(55, 55)]];
[_label setStringValue:obj.text];
}
@end
57 © 2009 Howard Lewis Ship
58. Sending the Search Request
Cached file (to avoid authentication)
TwitterController.j
- (void)startSearch:(id)sender
{
var url = "twitter/statuses/friends_timeline/" + [_field stringValue] + ".json";
var request = [CPURLRequest requestWithURL:url];
[CPURLConnection connectionWithRequest:request delegate:self];
}
Who to notify when data arrives
58 © 2009 Howard Lewis Ship
59. Handling the Response
TwitterController.j
- (void)connection:(CPURLConnection)connection didReceiveData:(CPString)data
{
var timeline = JSON.parse(data);
[_timelineView setContent:timeline];
}
- (void)connection:(CPURLConnection)connection didFailWithError:(CPString)error
{
CPLog.error(error);
}
TwitView.j
- (void)setRepresentedObject:(JSONObject)obj
{
...
}
@end
59 © 2009 Howard Lewis Ship
65. Wrap Up
65 © 2009 Howard Lewis Ship
68. Image Credits
© 2008 nalungaard
http://www.flickr.com/photos/nalundgaard/2587677285/
© 2005 Michael Sarver
http://www.flickr.com/photos/michaelsarver/44302391/
© 2007 Till Krech
http://www.flickr.com/photos/extranoise/487179535/
© 2009 Phill Davison
http://www.flickr.com/photos/phill_dvsn/3771462059/
© 2007 Howard Gees
http://www.flickr.com/photos/cyberslayer/952153409/
© 2006 Tyler Hawkins
http://www.flickr.com/photos/m4m/279364376/
© 2009 Harald
http://www.flickr.com/photos/haarald/3227728698/
© 2006 Brittney Bush Bollay
http://www.flickr.com/photos/tzofia/247056173/
68 © 2009 Howard Lewis Ship