随笔 - 42  文章 - 3  trackbacks - 0
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿(2)

随笔档案

文章档案

网页收藏

搜索

  •  

最新评论

阅读排行榜

评论排行榜

From http://www.newsmth.net/nForum/#!article/Apple/136327
窗口
----
  
其实 Mac OS X 的老用户们都该熟悉了,和 Windows 不一样,这个系统里“窗口”并非
最重要的概念,一个程序的逻辑结构是:  
  
+---------------------------------------------+
| Application                                 |
| +-------------------------+  +-----------+  |
| | Window                  |  | Menu      |  |
| |   +----------------+    |  +-----------+  |
| |   | Control        |    |                 |
| |   | +---------+    |    |                 |
| |   | | Control |    |    |                 |
| |   | +---------+    |    |                 |
| |   +----------------+    |                 |
| +-------------------------+                 |
+---------------------------------------------+
  
也就是说,菜单是独立于窗口的存在,有窗口和控件的区别。这和 Windows 中一切的
本质都是窗口有很大的区别。  
  
虽然 Mac OS X 中区分 Window, Control 和 Menu 这几种概念,但并不代表其设计上
没有考虑到它们之间的一致性。在 Carbon 中,这些实体都是用 FooRef 的形式来表示
的,Ref 就有指针的意思,比如你创建了一个窗口之后,就会得到对应的  
WindowRef,其实这就是一个用来操纵这个窗口的指针,而你创建控件之后,对应的
是 ControlRef,创建菜单对应的自然是 MenuRef 了,还是很好理解的吧。  
  
我们这里先只谈窗口。很显然,要创建窗口,还得有些其他的属性,让我们看看  
Carbon 的 CreateNewWindow 这个函数的原形是怎么要求的:  
  
OSStatus CreateNewWindow (
    WindowClass windowClass,
    WindowAttributes attributes,
    const Rect *contentBounds,
    WindowRef *outWindow
);
  
WindowClass 是一个常量,我们最常见的一种是 kDocumentWindowClass (也是下面
打算要用的),还有 kDrawerWindowClass,这也很好理解:那种可以伸缩的 Drawer  
嘛,kAlertWindowClass 呢?就是我们常见的提示框了。  
  
WindowAttributes 则是针对具体 WindowClass 再作更仔细的属性定制了,这也是一个  
32 位的无符号整数,但和 WindowClass 只能 n 选 1 不同,你可以把属性用位或 (|) 组
合起来使用。反正一时也记不住那么多,就先设置为  
kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute 好了。前
者保证我们的窗口具有其他标准的文档窗口相同的特性,而后者给窗口加上系统提供的
标准 event handler,以自动处理一般的 event。下面是用于设置的代码:  
  
WindowAttributes windowAttrs;
  
windowAttrs = kWindowStandardDocumentAttributes |
               kWindowStandardHandlerAttribute;
  
直到这里,“event”都还是一个很模糊的概念,虽然我们前面多次提到了它,但为了避
免过多的讲理论,我拖到现在才来介绍它。  
  
Event (事件) 其实是 Carbon 编程的基础。鼠标点击、键盘输入、菜单命令都是以  
event 的形式发出的。窗口需要重绘、移动和放缩时,也会告知你的应用程序一个  
event。当你的程序切换到前端或者后端时,你也会收到 event 告知你这个信息。
Carbon 程序的工作就是通过回应 event 来实现与用户和系统交互。  
  
Carbon 的 event 处理是基于回调 (callback) 机制的。你可以定义针对不同 event 类型
的 event handler,然后在 Carbon Event Manager 中注册 (Install) 之。然后每当  
event 发生时,Carbon Event Manager 就会调用你注册的 handler 函数。每个 event  
handler 都必须与一个具体的 event target 对象关联起来,比如 target 是菜单、窗口或
整个程序。  
  
应用程序包含窗口和菜单,窗口包含控件,控件还能进一步包含控件。一旦 event 出
现,首先得到通知的是最里层的 target,比如点击 button 的 event 首先发到 button 控
件上。如果最里面的 target 没有相关的 handler,就把 event 传播到更外层的包含它的  
target 上。Carbon 给窗口和应用程序的 event target 提供了标准的 handler。标准  
handler 可以负责处理类似窗口针对鼠标的操作,比如拖拽,伸缩等等。这样一来,你
就只需要关心自己的程序里针对拖拽或伸缩的特殊反映,而不比费神于那些所有程序都
通用的部分了。  
  
当然,如果你愿意,也可以覆盖标准的 handler,比如有人可能会写个针对拉伸窗口的  
handler,给窗口的伸缩增加音效。我们这里没那么复杂,用标准的就好啦。  
  
第三个参数就更好理解了,是一个指向 Rect 这个结构体的指针,说明了窗口在屏幕坐
标系 [1] 中的位置和大小。这个东西其实还是 QuickDraw 中的概念,所以在程序中我
们也调用 QuickDraw 的 API 来完成设置:  
  
#define kWindowTop      100
#define kWindowLeft     50
#define kWindowRight    800
#define kWindowBottom   600
  
Rect contentRect;
  
SetRect(&contentRect, kWindowLeft, kWindowTop,
         kWindowRight, kWindowBottom);
  
设置的正是这个矩形四个点的坐标。  
  
[1]: 注意屏幕坐标系中左上角是 (0, 0)。
  
最后一个参数是一个输出,也就是我们最终创建出来的那个新窗口的指针了。所以,我
们一般是这样创建窗口的:  
  
WindowRef theWindow;
CreateNewWindow(kDocumentWindowClass, windowAttrs,  
                 &contentRect, &theWindow);
  
等等,窗口是创建好了,存在 theWindow 指针里,可窗口的标题呢?我们这样设置:  
  
SetWindowTitleWithCFString(theWindow, CFSTR("Hello Carbon"));
  
注意这里的 CFSTR 是一个宏,用于把 C 的 const char * 字符串转换为 Core  
Foundation 定义的 CFStringRef 字符串,对于 CFString 的详细介绍可以看 Strings  
Programming Guide for Core Foundation [2],不过其实现在我们知道它包括的是一个
数组和数组的长度,数组的元素都是 Unicode 字符 (UniChar),就行了,具体的转换细
节暂时不必考虑。
  
[2]: http://developer.apple.com/documentation/CoreFoundation/Conceptual/
CFStrings/CFStrings.html
  
一切完毕之后,我们就可以显示这个窗口了:  
  
ShowWindow(theWindow);
  
下面把完整的代码列出 (你也可以看附件里面的):  
  
/* hello.c: testing Carbon basics */
  
#include <Carbon/Carbon.h>
  
#define kWindowTop      100
#define kWindowLeft     50
#define kWindowRight    800
#define kWindowBottom   600
  
int main(int argc, char *argv[])
{
     WindowRef         theWindow;
     WindowAttributes  windowAttrs;
     Rect              contentRect;
      
     windowAttrs = kWindowStandardDocumentAttributes |
                   kWindowStandardHandlerAttribute;
  
     SetRect(&contentRect, kWindowLeft,  kWindowTop,
             kWindowRight, kWindowBottom);
  
     CreateNewWindow(kDocumentWindowClass, windowAttrs,
                     &contentRect, &theWindow);
  
     SetWindowTitleWithCFString(theWindow,  
                                CFSTR("Hello Carbon"));
     ShowWindow(theWindow);
     RunApplicationEventLoop();
     return 0;
}
  
这一节的内容,呃,还是超出了我的预计,你要是有兴趣不妨再看看 Carbon Event  
Manager Programming Guide,event 还是一个比较 tricky 的概念,而我们要到后面
用到的时候才会深谈。下一节讲菜单的创建。  
posted on 2012-07-04 10:39 鹰击长空 阅读(851) 评论(1)  编辑 收藏 引用

FeedBack:
# re: Carbon Window in OSX[未登录] 2013-05-28 11:15 jack
想问一下,我将上面那个测试例子放到cpp文件里去编译就会报编译错误,说找不到SetRect(), CreateNewWindow()...这些函数;而换成c文件就好了.

是不是carbon不支持cpp啊?  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理