objective-c – 如何获取NSStatusItem的屏幕位置

objective-c – 如何获取NSStatusItem的屏幕位置,第1张

概述我有一个问题关于NSStatusItem可可在mac osx.如果你看看被称为片段的mac应用程序(见 http://snippetsapp.com/的电影).你会看到,一旦你点击了状态栏图标,一个完全对齐的视图/面板,或者甚至窗口出现在图标的正下方. 我的问题是…如何计算这个位置,就像这个应用程序一样放置你的NSWindow的位置? 我已经尝试过以下内容: >子类NSMenu >设置菜单的第一个 我有一个问题关于NsstatusItem可可在mac osx.如果你看看被称为片段的mac应用程序(见 http://snippetsapp.com/的电影).你会看到,一旦你点击了状态栏图标,一个完全对齐的视图/面板,或者甚至窗口出现在图标的正下方.

我的问题是…如何计算这个位置,就像这个应用程序一样放置你的NSWindow的位置?

我已经尝试过以下内容:

>子类NSMenu
>设置菜单的第一个项目的视图poedy(工作但足够)
>使用addSubvIEw而不是NsstatusItem的图标这个工作,但不能高于20px

解决方法 如果您愿意使用图像分析来在菜单栏上查找状态项,那么NSScreen的类别就是这样做的.

以这种方式执行它可能看起来很疯狂,但是速度相对较小,这是找到没有未记录API的状态项的唯一方法.

如果您传递状态项目的当前图像,此方法应该找到它.

@implementation NSScreen (LTStatusItemLocator)// Find the location of img on the screen's status bar.// If the image is not found,returns NSZeroPoint- (NSPoint)originofStatusItemWithImage:(NSImage *)img{    CGcolorSpaceRef     csK = CGcolorSpaceCreateDeviceGray();    NSPoint             ret = NSZeroPoint;    CGDirectdisplayID   screenID = 0;    CGImageRef          displayimg = NulL;    CGImageRef          compareimg = NulL;    CGRect              screenRect = CGRectZero;    CGRect              barRect = CGRectZero;    uint8_t             *bm_bar = NulL;    uint8_t             *bm_bar_ptr;    uint8_t             *bm_compare = NulL;    uint8_t             *bm_compare_ptr;    size_t              bm_compare_w,bm_compare_h;    BOol                inverted = NO;    int                 numberOfScanlines = 0;    CGfloat             *meanValues = NulL;    int                 presumptiveMatchIDx = -1;    CGfloat             presumptiveMatchMeanVal = 999;    // If the computer is set to Dark Mode,set the "inverted" flag    NSDictionary *globalPrefs = [[NSUserDefaults standardUserDefaults] persistentDomainForname:NSGlobalDomain];    ID style = globalPrefs[@"AppleInterfaceStyle"];    if ([style isKindOfClass:[Nsstring class]]) {        inverted = (NSOrderedSame == [style caseInsensitiveCompare:@"dark"]);    }    screenID = (CGDirectdisplayID)[self.deviceDescription[@"NSScreenNumber"] integerValue];    screenRect = CGdisplayBounds(screenID);    // Get the menubar rect    barRect = CGRectMake(0,screenRect.size.wIDth,22);    displayimg = CGdisplayCreateImageForRect(screenID,barRect);    if (!displayimg) {        NSLog(@"Unable to create image from display");        CGcolorSpaceRelease(csK);        return ret; // I would normally use goto(bail) here,but this is public code so let's not ruffle any feathers    }    size_t bar_w = CGImageGetWIDth(displayimg);    size_t bar_h = CGImageGetHeight(displayimg);    // Determine scale factor based on the CGImageRef we got back from the display    CGfloat scaleFactor = (CGfloat)bar_h / (CGfloat)22;    // Greyscale bitmap for menu bar    bm_bar = malloc(1 * bar_w * bar_h);    {        CGContextRef bmCxt = NulL;        bmCxt = CGBitmapContextCreate(bm_bar,bar_w,bar_h,8,1 * bar_w,csK,kCGBitmapAlphaInfoMask&kCGImageAlphaNone);        // Draw the menu bar in grey        CGContextDrawImage(bmCxt,CGRectMake(0,bar_h),displayimg);        uint8_t minVal = 0xff;        uint8_t maxVal = 0x00;        // Walk the bitmap        uint64_t running = 0;        for (int yi = bar_h / 2; yi == bar_h / 2; yi++)        {            bm_bar_ptr = bm_bar + (bar_w * yi);            for (int xi = 0; xi < bar_w; xi++)            {                uint8_t v = *bm_bar_ptr++;                if (v < minVal) minVal = v;                if (v > maxVal) maxVal = v;                running += v;            }        }        running /= bar_w;        uint8_t threshold = minVal + ((maxVal - minVal) / 2);        //threshold = running;        // Walk the bitmap        bm_bar_ptr = bm_bar;        for (int yi = 0; yi < bar_h; yi++)        {            for (int xi = 0; xi < bar_w; xi++)            {                // Threshold all the pixels. Values > 50% go white,values <= 50% go black                // (opposite if Dark Mode)                // Could unroll this loop as an optimization,but probably not worthwhile                *bm_bar_ptr = (*bm_bar_ptr > threshold) ? (inverted?0x00:0xff) : (inverted?0xff:0x00);                bm_bar_ptr++;            }        }        CGImageRelease(displayimg);        displayimg = CGBitmapContextCreateImage(bmCxt);        CGContextRelease(bmCxt);    }    {        CGContextRef bmCxt = NulL;        CGImageRef img_cg = NulL;        bm_compare_w = scaleFactor * img.size.wIDth;        bm_compare_h = scaleFactor * 22;        // Create out comparison bitmap - the image that was passed in        bmCxt = CGBitmapContextCreate(NulL,bm_compare_w,bm_compare_h,1 * bm_compare_w,kCGBitmapAlphaInfoMask&kCGImageAlphaNone);        CGContextSetBlendMode(bmCxt,kCGBlendModenormal);        NSRect imgRect_og = NSMakeRect(0,img.size.wIDth,img.size.height);        NSRect imgRect = imgRect_og;        img_cg = [img CGImageForProposedRect:&imgRect context:nil hints:nil];        CGContextClearRect(bmCxt,imgRect);        CGContextSetFillcolorWithcolor(bmCxt,[NScolor whitecolor].CGcolor);        CGContextFillRect(bmCxt,9999,9999));        CGContextScaleCTM(bmCxt,scaleFactor,scaleFactor);        CGContextTranslateCTM(bmCxt,(22. - img.size.height) / 2.);        // Draw the image in grey        CGContextSetFillcolorWithcolor(bmCxt,[NScolor blackcolor].CGcolor);        CGContextDrawImage(bmCxt,imgRect,img_cg);        compareimg = CGBitmapContextCreateImage(bmCxt);        CGContextRelease(bmCxt);    }    {        // We start at the right of the menu bar,and scan left until we find a good match        int numberOfScanlines = barRect.size.wIDth - img.size.wIDth;        bm_compare = malloc(1 * bm_compare_w * bm_compare_h);        // We use the meanValues buffer to keep track of how well the image matched for each point in the scan        meanValues = calloc(sizeof(CGfloat),numberOfScanlines);        // Walk the menubar image from right to left,pixel by pixel        for (int scanx = 0; scanx < numberOfScanlines; scanx++)        {            // Optimization,if we recently found a really good match,bail on the loop and return it            if ((presumptiveMatchIDx >= 0) && (scanx > (presumptiveMatchIDx + 5))) {                break;            }            CGfloat xOffset = numberOfScanlines - scanx;            CGRect displayRect = CGRectMake(xOffset * scaleFactor,img.size.wIDth * scaleFactor,22. * scaleFactor);            CGImageRef displayCrop = CGImageCreateWithImageInRect(displayimg,displayRect);            CGContextRef compareCxt = CGBitmapContextCreate(bm_compare,kCGBitmapAlphaInfoMask&kCGImageAlphaNone);            CGContextSetBlendMode(compareCxt,kCGBlendModecopy);            // Draw the image from our menubar            CGContextDrawImage(compareCxt,22. * scaleFactor),displayCrop);            // Blend mode difference is like an XOR            CGContextSetBlendMode(compareCxt,kCGBlendModeDifference);            // Draw the test image. Because of blend mode,if we end up with a black image we matched perfectly            CGContextDrawImage(compareCxt,compareimg);            CGContextFlush(compareCxt);            // Walk through the result image,to determine overall blackness            bm_compare_ptr = bm_compare;            for (int i = 0; i < bm_compare_w * bm_compare_h; i++)            {                meanValues[scanx] += (CGfloat)(*bm_compare_ptr);                bm_compare_ptr++;            }            meanValues[scanx] /= (255. * (CGfloat)(bm_compare_w * bm_compare_h));            // If the image is very dark,it matched well. If the average pixel value is < 0.07,we consIDer this            // a presumptive match. Mark it as such,but continue looking to see if there's an even better match.            if (meanValues[scanx] < 0.07) {                if (meanValues[scanx] < presumptiveMatchMeanVal) {                    presumptiveMatchMeanVal = meanValues[scanx];                    presumptiveMatchIDx = scanx;                }            }            CGImageRelease(displayCrop);            CGContextRelease(compareCxt);        }    }    // After we're done scanning the whole menubar (or we bailed because we found a good match),// return the origin point.    // If we dIDn't match well enough,return NSZeroPoint    if (presumptiveMatchIDx >= 0) {        ret = CGPointMake(CGRectGetMaxX(self.frame),CGRectGetMaxY(self.frame));        ret.x -= (img.size.wIDth + presumptiveMatchIDx);        ret.y -= 22;    }    CGImageRelease(displayimg);    CGImageRelease(compareimg);    CGcolorSpaceRelease(csK);    if (bm_bar) free(bm_bar);    if (bm_compare) free(bm_compare);    if (meanValues) free(meanValues);    return ret;}@end
总结

以上是内存溢出为你收集整理的objective-c – 如何获取NSStatusItem的屏幕位置全部内容,希望文章能够帮你解决objective-c – 如何获取NSStatusItem的屏幕位置所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1026903.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存