如何在Objective-C中自定义绘制窗口标题栏?

时间:2022-09-07 11:12:50

I'd like to customize the way I draw the window title bar on OS X. Specifically, I'd like to do something like the Twitterrific app where there is a custom close button, no min/max buttons, and the window title text is right-justified. Unlike Twitterrific, I'm not looking to custom draw the entire window (though I'm not completely opposed to that either).

我想自定义我在OS X上绘制窗口标题栏的方式。具体来说,我想做一些像Twitterrific应用程序,其中有自定义关闭按钮,没有最小/最大按钮,窗口标题文本是对的。与Twitterrific不同,我不打算自定义绘制整个窗口(尽管我并不完全反对)。

I've already seen the RoundWindow sample on Cocoa With Love as well as the RoundTransparentWindow example Apple provides, but neither seems appropriate.

我已经在Cocoa With Love以及Apple提供的RoundTransparentWindow示例中看到了RoundWindow示例,但似乎都不合适。

3 个解决方案

#1


6  

If you don't want to use a borderless window class then you can do a couple of things.

如果您不想使用无边界窗口类,那么您可以做一些事情。

First, you can customize the close/min/max buttons buy using -[NSWindow standardWindowButton:]. Once you get the button you can position it/remove it/etc...

首先,您可以使用 - [NSWindow standardWindowButton:]自定义关闭/最小/最大按钮。一旦你得到按钮,你可以定位/删除/等...

You can customize the title by setting the title to @"". Then you can add a NSTextField to draw your own title by doing the following [[[NSWindow contentView] superview] addSubview:textField].

您可以通过将标题设置为@“”来自定义标题。然后,您可以通过执行以下[[[NSWindow contentView] superview] addSubview:textField]添加NSTextField来绘制您自己的标题。

This is probably the easiest way to do things.

这可能是最简单的做事方式。

Another way to do this is to customize the view that draws all the window title bar, etc...

另一种方法是自定义绘制所有窗口标题栏的视图等...

NSWindow's content view's is inside a "theme view". You can subclass the theme view and do your own drawing. The only problem is that the theme view is a private class so you'll have to be careful.

NSWindow的内容视图位于“主题视图”中。您可以子类化主题视图并执行自己的绘图。唯一的问题是主题视图是一个私人类,所以你必须要小心。

#2


5  

cocoadev provides some more detail on how best to implement your own NSWindow subclass, complete with a description of most of the common pitfalls.

cocoadev提供了有关如何最好地实现自己的NSWindow子类的更多细节,并描述了大多数常见的陷阱。

The gist of it is to create a subclass of NSWindow, and set its styleMask to NSBorderlessWindowMask in the init method:

它的要点是创建NSWindow的子类,并在init方法中将其styleMask设置为NSBorderlessWindowMask:

- (id) initWithContentRect: (NSRect) contentRect
                 styleMask: (unsigned int) aStyle
                   backing: (NSBackingStoreType) bufferingType
                     defer: (BOOL) flag
{
    if ((self = [super initWithContentRect: contentRect
                                 styleMask: NSBorderlessWindowMask
                                   backing: bufferingType
                                     defer: flag]) == nil) { return nil; }

    [super setMovableByWindowBackground:YES];
    [super setLevel:NSNormalWindowLevel];
    [super setHasShadow:YES];
    // etc.

    return self;
}

Note that you should probably return YES for canbecomeKeyWindow in order to make your window behave like a normal window.

请注意,您应该为canbecomeKeyWindow返回YES,以使您的窗口像普通窗口一样运行。

- (BOOL) canBecomeKeyWindow
{
    return YES;
}

You can then create a custom NSView subclass, fill the entire window with an instance of said class, and then perform all of the appropriate window drawing from within that custom view.

然后,您可以创建自定义NSView子类,使用所述类的实例填充整个窗口,然后在该自定义视图中执行所有适当的窗口绘制。

The whole thing can get a bit painful. You will have to re-implement most of the normal window behaviours such as resizing by dragging the bottom right corner.

整件事情可能会有点痛苦。您将不得不重新实现大多数常规窗口行为,例如通过拖动右下角来调整大小。

#3


2  

There's an example of a custom window implementation in the CoreData Stickies sample project.

CoreData Stickies示例项目中有一个自定义窗口实现的示例。

#1


6  

If you don't want to use a borderless window class then you can do a couple of things.

如果您不想使用无边界窗口类,那么您可以做一些事情。

First, you can customize the close/min/max buttons buy using -[NSWindow standardWindowButton:]. Once you get the button you can position it/remove it/etc...

首先,您可以使用 - [NSWindow standardWindowButton:]自定义关闭/最小/最大按钮。一旦你得到按钮,你可以定位/删除/等...

You can customize the title by setting the title to @"". Then you can add a NSTextField to draw your own title by doing the following [[[NSWindow contentView] superview] addSubview:textField].

您可以通过将标题设置为@“”来自定义标题。然后,您可以通过执行以下[[[NSWindow contentView] superview] addSubview:textField]添加NSTextField来绘制您自己的标题。

This is probably the easiest way to do things.

这可能是最简单的做事方式。

Another way to do this is to customize the view that draws all the window title bar, etc...

另一种方法是自定义绘制所有窗口标题栏的视图等...

NSWindow's content view's is inside a "theme view". You can subclass the theme view and do your own drawing. The only problem is that the theme view is a private class so you'll have to be careful.

NSWindow的内容视图位于“主题视图”中。您可以子类化主题视图并执行自己的绘图。唯一的问题是主题视图是一个私人类,所以你必须要小心。

#2


5  

cocoadev provides some more detail on how best to implement your own NSWindow subclass, complete with a description of most of the common pitfalls.

cocoadev提供了有关如何最好地实现自己的NSWindow子类的更多细节,并描述了大多数常见的陷阱。

The gist of it is to create a subclass of NSWindow, and set its styleMask to NSBorderlessWindowMask in the init method:

它的要点是创建NSWindow的子类,并在init方法中将其styleMask设置为NSBorderlessWindowMask:

- (id) initWithContentRect: (NSRect) contentRect
                 styleMask: (unsigned int) aStyle
                   backing: (NSBackingStoreType) bufferingType
                     defer: (BOOL) flag
{
    if ((self = [super initWithContentRect: contentRect
                                 styleMask: NSBorderlessWindowMask
                                   backing: bufferingType
                                     defer: flag]) == nil) { return nil; }

    [super setMovableByWindowBackground:YES];
    [super setLevel:NSNormalWindowLevel];
    [super setHasShadow:YES];
    // etc.

    return self;
}

Note that you should probably return YES for canbecomeKeyWindow in order to make your window behave like a normal window.

请注意,您应该为canbecomeKeyWindow返回YES,以使您的窗口像普通窗口一样运行。

- (BOOL) canBecomeKeyWindow
{
    return YES;
}

You can then create a custom NSView subclass, fill the entire window with an instance of said class, and then perform all of the appropriate window drawing from within that custom view.

然后,您可以创建自定义NSView子类,使用所述类的实例填充整个窗口,然后在该自定义视图中执行所有适当的窗口绘制。

The whole thing can get a bit painful. You will have to re-implement most of the normal window behaviours such as resizing by dragging the bottom right corner.

整件事情可能会有点痛苦。您将不得不重新实现大多数常规窗口行为,例如通过拖动右下角来调整大小。

#3


2  

There's an example of a custom window implementation in the CoreData Stickies sample project.

CoreData Stickies示例项目中有一个自定义窗口实现的示例。