在將Cocoa中的狀態欄添加到狀態欄後,可以獲得NSStatusItem
的框架嗎?當我的應用程序啓動時,我將一個項目添加到系統狀態欄,並想知道它的位置,可能。如何獲取NSStatusItem的框架
回答
如果已設置自定義視圖上的狀態項:
NSRect statusRect = [[statusItem view] frame];
NSLog(@"%@", [NSString stringWithFormat:@"%.1fx%.1f",statusRect.size.width, statusRect.size.height]);
否則,我不認爲這是可能的使用可用的和記錄的API。
編輯:註冊意見。
你能砍窗口伊娃這樣的:
@interface NSStatusItem (Hack)
- (NSRect)hackFrame;
@end
@implementation NSStatusItem (Hack)
- (NSRect)hackFrame
{
int objSize = class_getInstanceSize([NSObject class]) ;
id * _ffWindow = (void *)self + objSize + sizeof(NSStatusBar*) + sizeof(CGFloat) ;
NSWindow * window = *_ffWindow ;
return [window frame] ;
}
@end
這是一個沒有自定義視圖狀態項很有用。
測試在獅子
以下似乎工作 - 我已經看到了iOS應用程序類似的解決方案,並推測他們,因爲你仍然在使用標準SDK方法允許提交給應用程序商店。
NSRect frame = [[statusBarItem valueForKey:@"window"] frame];
這可以工作,並且在您尚未設置狀態項目的自定義視圖時非常有用。 – Fabian 2013-11-10 01:21:15
這假設NSStatusItem(假設這是'statusBarItem'的)是KVC可以用作'window'屬性的東西。這並不保證是這種情況。如果/當這種情況消失,你會得到一個異常(不是KVC兼容的)。我也不會指望這個通過App Store審查,如果他們還沒有,他們可能有一天會開始檢查你如何使用KVC(尋找這樣的用法,你在哪裏訪問私有方法/ ivars)。 – 2014-07-01 04:07:45
這是一個私人的API調用,可能會讓你從App Store審查過程中被拒絕嗎? – 2014-07-28 01:04:50
隨着10.10,NSStatusItem
有用來獲取狀態項目位置不設置自定義視圖button
屬性。
NSStatusBarButton *statusBarButton = [myStatusItem button];
NSRect rectInWindow = [statusBarButton convertRect:[statusBarButton bounds] toView:nil];
NSRect screenRect = [[statusBarButton window] convertRectToScreen:rectInWindow];
NSLog(@"%@", NSStringFromRect(screenRect));
棒極了,但10.10還不是很受歡迎。 :( – 2014-07-28 01:02:46
沒有任何私人API可以做到這一點。這是NSScreen的一個類別。這使用圖像分析來查找菜單欄上的狀態項目圖像。幸運的是,電腦真的很快。 :)
只要你知道什麼狀態項的圖像看起來像,並可以作爲一個NSImage傳遞它,這種方法應該找到它。
適用於暗模式以及常規模式。請注意,您傳入的圖片必須是黑色的。彩色圖像可能效果不佳。
@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, 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, 0, bar_w, 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, 8, 1 * bm_compare_w, csK, kCGBitmapAlphaInfoMask&kCGImageAlphaNone);
CGContextSetBlendMode(bmCxt, kCGBlendModeNormal);
NSRect imgRect_og = NSMakeRect(0,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, CGRectMake(0,0,9999,9999));
CGContextScaleCTM(bmCxt, scaleFactor, scaleFactor);
CGContextTranslateCTM(bmCxt, 0, (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, 0, IMG.size.width * scaleFactor, 22. * scaleFactor);
CGImageRef displayCrop = CGImageCreateWithImageInRect(displayImg, displayRect);
CGContextRef compareCxt = CGBitmapContextCreate(bm_compare, bm_compare_w, bm_compare_h, 8, 1 * bm_compare_w, csK, kCGBitmapAlphaInfoMask&kCGImageAlphaNone);
CGContextSetBlendMode(compareCxt, kCGBlendModeCopy);
// Draw the image from our menubar
CGContextDrawImage(compareCxt, CGRectMake(0,0,IMG.size.width * scaleFactor, 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, CGRectMake(0,0,IMG.size.width * scaleFactor, 22. * scaleFactor), 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
- 1. 如何獲取NSStatusItem的屏幕位置
- 2. 獲取NSStatusItem的長度
- 3. 如何每秒獲取SurfaceView的框架?
- 4. 如何在頁面中獲取框架?
- 5. JDesktopPane - 如何獲取活動框架
- 6. 如何從框架中獲取網址?
- 7. 如何使用JavaScript從框架集框架中獲取元素?
- 8. 如何在OSX中獲取NSStatusBar的所有NSStatusItem元素?
- 9. 獲取SCNMaterial的框架
- 10. 從SurfaceTexture獲取框架(Android)
- 11. 與實體框架獲取
- 12. 獲取Angularjs /離子框架
- 13. 在框架中獲取ckeditor
- 14. 從SurfaceView獲取框架
- 15. Zend框架獲取URL
- 16. 獲取忍者框架
- 17. 獲取主框架窗口
- 18. 獲取BASE_URL到symfony3框架
- 19. 獲取框架集名稱
- 20. 組合框和實體框架,如何獲取ID? (WPF-MVVM)
- 21. 如何獲取價值形態複選框,離子框架
- 22. 如何獲得像zend框架舊版本的zend框架2.3
- 23. 如何改變NSStatusItem出
- 24. 從框架連接器獲取音頻的iOS框架
- 25. Javascript - 獲取框架元素到根父框架的協調
- 26. 如何獲取Tkinter中的主框架的名稱
- 27. 如何獲得的LINQ /實體框架
- 28. 如何獲得在Django的REST框架
- 29. 如何獲取一個框架的網址?
- 30. 如何在實體框架中獲取表的模式名稱?
沒有爲我工作。 NSStatusItem似乎沒有默認視圖,因此[statusItem視圖]返回null。 – blutfink 2013-01-07 00:35:41
正如文檔所述,「返回狀態欄中接收器位置顯示的自定義視圖」,而不是NSStatusItem的視圖。 – 2013-02-13 04:50:32
只有在狀態項目上設置了自定義視圖時,此功能纔有效。 – Fabian 2013-11-10 01:01:22