当前位置:  开发笔记 > 前端 > 正文

我的应用如何检测到另一个应用窗口的更改?

如何解决《我的应用如何检测到另一个应用窗口的更改?》经验,为你挑选了1个好方法。

在Mac上的Cocoa中,我想检测何时移动,调整大小或重新绘制属于另一个应用程序的窗口.我怎样才能做到这一点?



1> Jim Dovey..:

您需要使用位于ApplicationServices框架内的可访问性API,它们是plain-C.例如:

首先创建一个应用程序对象:

AXUIElementRef app = AXUIElementCreateApplication( targetApplicationProcessID );

然后你从这里得到窗口.您可以请求窗口列表并枚举,或者您可以获取最前面的窗口(在AXAttributeConstants.h中查找您使用的所有属性名称).

AXUIElementRef frontWindow = NULL;
AXError err = AXUIElementCopyAttributeValue( app, kAXMainWindowAttribute, &frontWindow );
if ( err != kAXErrorSuccess )
    // it failed -- maybe no main window (yet)

现在,当此窗口的属性发生更改时,您可以通过C回调函数请求通知.这是一个分为四个步骤的过程:

首先,您需要一个回调函数来接收通知:

void MyAXObserverCallback( AXObserverRef observer, AXUIElementRef element,
                           CFStringRef notificationName, void * contextData )
{
    // handle the notification appropriately
    // when using ObjC, your contextData might be an object, therefore you can do:
    SomeObject * obj = (SomeObject *) contextData;
    // now do something with obj
}

接下来,您需要一个AXObserverRef来管理回调例程.这需要您用于创建上述"app"元素的相同进程ID:

AXObserverRef observer = NULL;
AXError err = AXObserverCreate( applicationProcessID, MyObserverCallback, &observer );
if ( err != kAXErrorSuccess )
    // handle the error

有了观察者,下一步就是要求通知某些事情.有关完整列表,请参阅AXNotificationConstants.h,但是对于窗口更改,您可能只需要这两个:

AXObserverAddNotification( observer, frontWindow, kAXMovedNotification, self );
AXObserverAddNotification( observer, frontWindow, kAXResizedNotification, self );

请注意,最后一个参数是将假定的"self"对象作为contextData传递.这不会保留,因此AXObserverRemoveNotification在此对象消失时调用很重要.

有了观察者并添加了通知请求,您现在想要将观察者附加到您的runloop,这样您就可以以异步方式(或者实际上)发送这些通知:

CFRunLoopAddSource( [[NSRunLoop currentRunLoop] getCFRunLoop],
                    AXObserverGetRunLoopSource(observer),
                    kCFRunLoopDefaultMode );

AXUIElementRefs是CoreFoundation风格的对象,因此您需要使用它CFRelease()来干净地处理它们.例如,为了清洁,您可以CFRelease(app)在获得frontWindow元素后使用,因为您将不再需要该应用程序.

关于垃圾收集的注意事项:要将AXUIElementRef保存为成员变量,请将其声明为:

__strong AXUIElementRef frontWindow;

这指示垃圾收集器跟踪对它的引用.分配时,为了与GC和非GC兼容,请使用:

frontWindow = (AXUIElementRef) CFMakeCollectable( CFRetain(theElement) );


UIElementInspector示例项目似乎也非常有用https://developer.apple.com/library/mac/#samplecode/UIElementInspector/Introduction/Intro.html
推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有