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
이 사용자 정의보기가없는 상태 항목에 유용합니다.
사자에서 테스트 다음은 작동하는 것 같다 - 나는 아이폰 OS 애플리케이션을위한 유사한 솔루션을 본 당신은 여전히 표준 SDK 방법을 사용하고 있기 때문에 아마도 그들은 앱 스토어에 제출을 허용합니다.
NSRect frame = [[statusBarItem valueForKey:@"window"] frame];
이 기능은 상태 항목에 대한 사용자 정의보기를 설정하지 않은 경우에 유용합니다. – Fabian
이것은 NSStatusItem ('statusBarItem'이 무엇인지 가정)이 KVC가'window' 속성으로 사용할 수있는 것을 가지고 있다고 가정합니다. 그 경우는 보장되지 않습니다. 이 키에 대해 KVC와 호환되지 않는 예외가 발생합니다. 또한이 앱 스토어 검토를 통과하지 않을 것입니다. 이미없는 경우 KVC 사용 방법을 확인하기 시작할 수도 있습니다 (이 방법을 사용하여 개인 방법/ivars에 액세스하는 경우). –
App Store 리뷰 프로세스에서 거부 될 수있는 비공개 API 호출입니까? –
는 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은 아직 널리 사용되지 않습니다. :( –
개인용 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. 이미지 주위의 프레임을 얻는 방법
- 2. NSStatusItem의 애니메이션
- 3. NSStatusItem의 이미지 업데이트
- 4. C++ 빌더에서 초당 플래시 무비의 프레임을 얻는 방법
- 5. NSStatusItem의 이미지로 불확정 상태 표시기를 사용하려면 어떻게해야합니까?
- 6. UIButton에 프레임을 추가하는 방법
- 7. UIImage 프레임을 설정하는 방법
- 8. UIImageView에서 표시된 이미지 프레임을 얻는 방법은 무엇입니까?
- 9. DirectShow.net을 사용하여 비디오 프레임을 얻는 방법은 무엇입니까?
- 10. 비 뷰 기반 NSStatusItem의 화면 위치 얻기
- 11. 이전 프레임을 파괴하는 방법 새 프레임을 여는 새 프레임
- 12. Animtion, 런타임에 프레임을 추가하는 방법?
- 13. 중첩 데이터 프레임을 만드는 방법
- 14. 프록시를 통해 프레임을 다시로드하는 방법?
- 15. cocos2d에서 애니메이션 프레임을 설정하는 방법
- 16. UIImagePickerController 자르기 프레임을 변경하는 방법
- 17. Cocoa2d에서 CCsprite의 프레임을 설정하는 방법
- 18. 웹 프레임을 사용하여 웹 페이지에서 플래시 URL을 얻는 방법은 무엇입니까?
- 19. 현재 재생중인 동영상 파일의 현재 프레임을 얻는 방법은 무엇입니까?
- 20. 프레임을 닫고 새 프레임을 열려면 어떻게해야합니까? (revisited)
- 21. 아직 웹캠 이미지를 얻는 방법
- 22. DirectShow로 RGB의 라이브 카메라 프레임을 캡쳐하는 방법
- 23. 보기에서 각 UIButton에 대한 프레임을 변경하는 방법
- 24. Android : 미리보기 프레임을 jpeg 이미지로 저장하는 방법?
- 25. 내 메뉴 막대에서 프레임을 여는 방법
- 26. Java : 압축되지 않은 프레임을 재생하는 방법
- 27. 메뉴 옵션 창에서 프레임을 표시하는 방법
- 28. stopPreview 후 서페이스에서 미리보기 프레임을 지우는 방법
- 29. 프로그래밍 방식으로 플래시 프레임을 추출하는 방법
- 30. R 목록의 데이터 프레임을 다시 포맷하는 방법
나를 위해 작동하지 않았습니다. NSStatusItem에는 기본보기가 없어서 [statusItem view]는 null을 반환합니다. – blutfink
문서에서 "상태 표시 줄의 수신자 위치에 표시되는 사용자 정의보기를 반환합니다."이며 NSStatusItem의보기가 아닙니다. –
상태 항목에 대한 사용자 정의보기를 설정 한 경우에만 작동합니다. – Fabian