2012-09-07 110 views
8

我知道这不是一个受欢迎的问题,有些人不喜欢具有非标准外观的应用程序,但它对我的应用程序很有用。更改NSWindow标题文本的颜色

是否可以使用“标准”非私有API方式更改NSWindow标题栏文本的颜色?

我知道这是可能的,如果我使用私人API(as mentioned in this answer),但我认为它可以做到这一点没有私人的API,因为Pixelmator已经做到了,并没有被MAS拒绝,我知道也可以做到这一点无边界窗口并绘制所有内容,但我不认为这就是Pixelmator的做法,因为它们仍然获得标准NSWindow标题栏附带的所有附加位;可拖动图标,重命名窗口,文档修订的下拉菜单和。全屏按钮

基本上,我做了使用setBackgroundColor一个黑色窗口:但文本仍然出现黑色,不黑色背景上的工作

那么有没有人知道一种方法来做到这一点,或者Pixelmator如何做?

+0

我懒得试试这个,但我不知道你会得到什么,如果你有窗口的内容视图,并要求它的超级视图。也许你会得到零,或者你会得到一个包含其他隐藏事物的根视图。 – JWWalker

+0

你得到一个名为NSThemeView的私有NSView子类。它确实包含了一些关于窗口关闭,最小化和最大化按钮的私人视图,但是我没有看到如何在不使用私有API的情况下访问标题。 – iain

+0

有一篇由Matt Gallagher撰写的关于自定义窗口的文章,您应该能够在那里找到一些信息。 http://www.cocoawithlove.com/2008/12/drawing-custom-window-on-mac-os-x.html – Michael

回答

0

您可以使用一些私有API来解决这个问题,如您对问题的评论中所述 - 但是,您将无法将该应用程序提交给AppStore。

其他的解决办法是得到[[myWindow contentView] superview] - 这会得到你前面提到的NSThemeView实例。所有你需要做的就是搜索NSTextField的任何实例的视图的子视图(实际称为帧视图)子视图并修改它们。请注意,这些私有视图的层次结构可能随着每个OS X版本的不同而变化,可能会破坏您的代码。

的可能最好的解决办法是子类(只有类,无其他定制)NSWindow和实施-title-setTitle:方法 - 为每个窗口,你实际的标题设置为@""(通过调用[super setTitle:@""]),然后把你的自己的编程方式创建,NSTextField例如在框架视图(即[[[self contentView] superview] addSubview:myTextField],其中myTextField是文本字段,你需要找出确切位置等领域,但是这是最容易的部分。

1

这里是一个在Swift中的解决方案,它已经很晚了,我很累,所以这可能不是最优的,但它的工作原理是

首先,这是一个功能,可以在层次结构中查找视图,并可以跳过特定的视图。 (这是有用的,如果我们正在经历window.contentView.superview.subviews搜索,我们希望忽略contentView你自己的看法)

func findViewInSubview(subviews: [NSView], #ignoreView: NSView, test: (NSView) -> Bool) -> NSView? { 
    for v in subviews { 
     if test(v) { 
      return v 
     } else if v != ignoreView { 
      if let found = findViewInSubview(v.subviews as [NSView], ignoreView: ignoreView, test) { 
       return found 
      } 
     } 
    } 
    return nil 
} 

这里是你将如何使用它,例如从NSViewController子类。请注意,当窗口变得可见时,你需要做到这一点,所以你不能在viewDidLoad

override func viewDidAppear() { 
    if let windowContentView = view.window?.contentView as? NSView { 
     if let windowContentSuperView = windowContentView.superview { 
      let titleView = findViewInSubview(windowContentSuperView.subviews as [NSView], ignoreView: windowContentView) { (view) -> Bool in 
       // We find the title by looking for an NSTextField. You may 
       // want to make this test more strict and for example also 
       // check for the title string value to be sure. 
       return view is NSTextField 
      } 
      if let titleView = titleView as? NSTextField { 
       titleView.attributedStringValue = NSAttributedString(string: "Hello", attributes: [NSForegroundColorAttributeName: NSColor.redColor()]) 
      } 
     } 
    } 
} 

请注意您正在玩火。这样的内部没有具体说明是有原因的。

+0

这适用于我,但它似乎是它绘制文本两次。第一个文本正常绘制,就像通缉一样,但第二个文本有点偏离。这给了它一个非常奇怪的外观。任何想法如何解决这个问题? [链接](http://imgur.com/oYaoAeJ) –

8

由于OS X 10。10应该足够给窗口的外观更改为NSAppearanceNameVibrantDark

window.appearance = NSAppearance(named:NSAppearanceNameVibrantDark) 

以为这是值得一提,因为大多数你可以找到问题的答案已经过时了。

+0

不与面板工作...“无法识别的选择器'_backstoppedByDefaultAppearance'” –

+0

NSAppearanceNameVibrantDark看起来不错,但它似乎导致我的基于OpenGL的应用程序出现问题......它出现创建半透明窗口栏,并似乎使用CoreAnimation废话。我只想要一个简单的黑暗NSAppearance没有褶边! –

0

这是我做的方式:

#import <objc/runtime.h> 

@interface SOWindow : NSWindow 
@end 

@interface SOWindowFrameOverrides : NSView 
@end 

@implementation SOWindow 

+ (void)load 
{ 
    SEL selector = NSSelectorFromString(@"_currentTitleColor"); 
    SEL originalSelector = NSSelectorFromString(@"_original_currentTitleColor"); 
    Class frameClass = NSClassFromString(@"NSThemeFrame"); 

    Method m = class_getInstanceMethod(frameClass, selector); 
    Method m2 = class_getInstanceMethod([SOWindowFrameOverrides class], selector); 
    class_addMethod(frameClass, originalSelector, method_getImplementation(m), method_getTypeEncoding(m)); 
    method_exchangeImplementations(m, m2); 
} 

@end 

@implementation SOWindowFrameOverrides 

- (NSColor *)_currentTitleColor 
{ 
    if ([self.window isKindOfClass:[SOWindow class]]) { 
     return [NSColor redColor]; 
    } else { 
     return [self _original_currentTitleColor]; 
    } 
} 

- (NSColor *)_original_currentTitleColor 
{ 
    // will be filled in at runtime 
    return nil; 
} 

@end 

虽然视图层次结构发生了很大变化,从小牛到优胜美地,_currentTitleColor一直在API中很长一段时间,可能不会在近期改变未来。即使是强悍的方法混搭也是一种拙劣的做法,我发现它比遍历视图层次更优雅,但那只是我自己。

如果您想进一步自定义标题,您可以NSThemeFrame覆盖_titleTextField返回一个自定义的文本字段(我已经用它来改变backgroundStyle我F3X项目)。