Category Archives: Cocoa

How to write a full screen cocoa progam

最近正好要写一个全屏的cocoa程序,所以就研究了一些用cocoa怎么写全屏的程序。 说起来全屏程序很简单,就是首先要拿到你要全屏的显示设备的ID,然后获取这个设备。接着建立一个无边界的窗口,将其大小设置为屏幕的大小,然后显示就可以了,这个窗口里面可以显示你需要的任何东东,包括按钮,滚动条等等,不过一般全屏要么显示图片,要么显示视频,再就是3D程序,所以也不会放上很丑的这些按钮什么的。 首先是获得显示设备的ID,你可以使用 CGDisplayErr CGGetActiveDisplayList ( CGDisplayCount maxDisplays, CGDirectDisplayID *activeDspys, CGDisplayCount *dspyCnt ); 去获得所有的可用的显示设备,然后用设备ID调用函数 CGDisplayErr CGDisplayCapture ( CGDirectDisplayID display ); 去获得这个设备。接着,我们建立一个无边界的窗口: – (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen 其中参数windowStyle设置为NSBorderlessWindowMask就是无边界窗口,screen要设置成为屏幕大小。我的程序里面完整的调用如下: [[YLFullScreenWindow alloc] initWithContentRect:screenRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO screen:[NSScreen mainScreen]]; 然后显示这个窗口就可以了。 我的程序中之所以使用YLFullScreenWindow,是因为要想全屏窗口响应鼠标事件,必须自己重载NSWindow这个类,重写一下函数- (BOOL)canBecomeKeyWindow,使其总是返回YES: – (BOOL)canBecomeKeyWindow { return YES; } 好了,全屏程序就这样建立了。

How to write an IM using Cocoa (3)

解决UIbug 从开始到现在,我遇到了两个UI方面的bug: 在resize一个window的时候,总是出现不及时刷新,留下白茫茫的一块一块的,很难看 在接收到消息的时候要显示在对话框中的输出窗口,可是当我聊着聊着,程序就死掉了,肯定是有bug,我查了半天,发现每次死掉的地方都不一样,不是内存访问问题,就是多线程互锁了 这两个bug困扰了我好几天,最终我在Cocoabuilder上面找到了答案,就在这里,两个问题一起解决了。 简而言之一句话:所有关于UI绘制的工作,都应该交给主线程去做!

How to write an IM using Cocoa (2)

解决刷新问题和使用NSToolbar、NSPopupButton、NSMenu 上一篇文章说到使用NSOutlineView来管理跟组的用户,但是存在一个小问题,就是在用户改变整个窗口大小的时候,NSOutlineView的每个Cell不会及时刷新,我自己考虑应该是没能及时把redraw的消息传递过去,可是找了半天没能找到方法把消息传过去,只好请教jjgod了,他给出了方法来解决这个问题。 这应该是一个Cocoa的bug,消息没有传过去,我们只能自己动手了,所以我们需要在自己继承NSOutlineView的myOutlineView中重载drawRect:(NSRect)rect或者是inLiveResize,代码如下: – (void)drawRect:(NSRect)rect { [super drawRect:rect]; }   – (BOOL)inLiveResize { return NO; }   IM中要显示用户自己的信息,比如说头像或者状态、签名等信息,这些信息一般都显示在窗口的最上方,怎么显示这些信息呢?只看位置,最直观的想法就是使用Toolbar了,由于Cocoa提供了很方便的Toolbar接口,所以也就很容易实现这一功能了。 我们要让NSToolbar显示自己定义的信息,那么我们必须自己定义一个NSView作为NSToolbarItem,这个很容易做到: 首先在Interface Builder中建立一个NSView 然后加入自己需要的一些控件,比如Image,NSPopupButton等 然后实现NSToolbar的delegate函数:toolbar:itemForItemIdentifier: willBeInsertedIntoToolbar:、toolbarDefaultItemIdentifiers:和toolbarAllowedItemIdentifiers: 在函数toolbar:itemForItemIdentifier: willBeInsertedIntoToolbar:中,按照需要,如果需要返回自定义的NSToolbarItem,那么就把这我们自定义的View传给NSToolbarItem的setView:消息 这样,程序就可以显示我们自定义的用户信息了。 在我们自定义的显示用户信息视图中,我们需要用到NSPopupButton,这个控件使我们用来调整用户状态的,很有用途,这个控件实际上就是一个NSButton加一个NSMenu,我们需要做的就是自己定义NSMenu: 首先,我们定义一个NSMenu,可以使用Interface Builder,也可以使用程序控制生成 然后为每一个NSMenuItem加入Image属性,这样有比较好的视觉效果 然后为每一个NSMenuItem设置响应函数,把要响应的函数传递给setAction:消息,注意在传递这个消息之前,先要设置Target 好了,来看看最终的结果吧!

How to write an IM using Cocoa (1)

使用NSOutlineView和MouseTracking 要做一个IM当然首要就是能够管理用户了,所以,要求具有显示分组用户的需求,就像Adium和iChat。我开始想用NSTableView,但是这个类不具有分组的功能,后来看到了NSOutlineView就解决了分组的问题。 分组问题解决方案: 要使用分组功能,就必须为NSOutlineView实现datasource和delegate的一些函数: outlineView:child:ofItem:、outlineView:numberOfChildrenOfItem:和outlineView:objectValueForTableColumn:byItem:告诉了NSOutlineView它的每行每列应该显示怎样的数据。如果你想要编辑某一行的内容,比如说你想要编辑IM中某个好友的昵称,就可以实现outlineView:setObjectValue:forTableColumn:byItem:这个方法。 只要上述方法能够正确返回你自己定义的结构,那么就可以正确分组显示用户了。 现在的问题是,你不能显示头像,不能显示状态,只能显示用户名,因为现在NSOutlineView默认的显示单元是NSTextfieldCell,如果想显示更为丰富的内容,那么你就要定义自己的NSCell子类。 自定义行的内容解决方案 定义自己的NSCell子类,比如myCell。 在myCell中实现方法drawInteriorWithFrame:inView:,这个方法定义了NSOutlineView中某行的显示内容,你可以在这个方法中绘制上用户的头像,用户的状态,或者用自定义的信息。这个方法一定要实现,否则还是只能显示文本。 调用setDataCell:或者在Interface Builder中直接指定NSOutlineView的显示单元为myCell。 又有问题了myCell怎么知道用户的状态、头像呢? 还记得前面实现的outlineView:objectValueForTableColumn:方法吗,这个方法的返回值是一个指针(id),我们可以返回任何值,一般只需要返回NSString就可以了,因为这个返回值的接收方就是NSOutlineView的显示单元,我们想要让myCell知道用户的头像等信息,我的解决方法: 就是将这些信息全部包含到outlineView:objectValueForTableColumn:的返回值中,定义一个自己的数据结构,比如FriendInfo类。记住FriendInfo类一定要实现方法copyWithZone:方法,否则myCell无法接收。 在myCell中调用方法objectValue:函数,得到之前传递过来的FriendInfo指针,这样,我们就可以在myCell中绘制想要的信息了。 我们现在已经很好实现了用户列表的功能了,不过似乎还是没有iChat中那么明显的分组功能,想要明显一些,那么实现这个方法吧,还是NSOutlineView的degelate方法:outlineView:isGroupItem:,这样看起来就比较像iChat了。效果参见下面图片: ==================== 上面说了怎么去建立一个看起来不错的用户列表,下面说说迷人的按钮是怎么做出来的,就像lumaqq中这个迷人的+号按钮,这里就用到了我前面提到的MouseTracking 其实说起来,这个+按钮就是两张图片,当没有事请发生的时候显示一张,当鼠标进入 图片区域的时候显示另一张,鼠标在这个图片区域按下就相应一些事件,很多mac下面的程序都用这个方法去实现按钮,确实可以做的很漂亮,也很方便。要想实现这个功能,我们要做下面几步: 定义一个跟踪区域,使用初始化函数initWithRect:options:owner:userInfo:定义一个NSTrackingArea跟踪区域。 把这个区域使用addTrackingArea:方法添加到某一个NSView对象中。 有必要的话,实现updateTrackingAreas方法来更新这个区域,一般在窗口大小改变的时候会调用这个方法。 调用mouseEntered:、mouseMoved:、mouseExited:等方法来响应鼠标事件,实现按钮的模拟。 还可以调用cursorUpdate:方法来改变鼠标的外观。 通过这些,我们就可以非常好的做出漂亮的按钮了。

How to write an IM using Cocoa (0)

开始学Cocoa已经有一段时间了,准备开发一个IM,具体是什么IM就不透露了,其实对于我来说,底层数据结构很简单,最难的就是UI了。所以我就决定写个系列文章,把我遇到的问题和解决方法都记录下来。这里第0篇就算是目录吧,以后我会陆续写其他篇,同时也会更新这篇来进行索引,敬请关注了XD。 目录: How to write an IM using Cocoa (1) How to write an IM using Cocoa (2) How to write an IM using Cocoa (3)