使圆形 NSSlide 的外观和行为与 GarageBand 中类似

发布于 2024-09-05 02:38:08 字数 398 浏览 13 评论 0原文

我是用 Cocoa 绘图的新手,我正在制作一些软件,其中的滑块与 GarageBand 中的滑块类似:

GB 滑块 http://img33.imageshack.us/img33/2668/schermafbeelding2010061r.png

这些看起来很漂亮,可以通过上下移动鼠标来控制。

您能否帮助我通过子类化 NSSlider 来自定义它们,以便我可以使它们的外观和行为与 GarageBand 中完全相同?谢谢。


我有一张旋钮图像,应该旋转该旋钮,因为它们不需要是 3D 的。

I am new to drawing with Cocoa, and I am making some software which will have sliders similar to these found in GarageBand:

GB Sliders http://img33.imageshack.us/img33/2668/schermafbeelding2010061r.png

These look beautiful and can be controld by moving the mouse up and down.

Can you help me with customizing NSSliders by subclassing them, so I can make them look and behave exactly as in GarageBand? Thanks.


I have one image for the knob which should be rotated as they do not need to be in 3D .

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浅唱ヾ落雨殇 2024-09-12 02:38:08

最简单的方法是创建一个 NSView 子类来处理鼠标管理和绘图。

有一个示例代码可以帮助您启动名为“TLayer”的代码。它是 XCode 3.1.4 示例的一部分。它包含一个圆形自定义视图,用于控制为图层绘制的阴影的偏移和半径。它易于理解且易于扩展。

注:由于Apple网站上似乎没有,所以我将来源粘贴在下面。


ShadowOffsetView.h

#import <AppKit/AppKit.h>

extern NSString *ShadowOffsetChanged;

@interface ShadowOffsetView : NSView
{
    CGSize _offset;
    float _scale;
}

- (float)scale;
- (void)setScale:(float)scale;

- (CGSize)offset;
- (void)setOffset:(CGSize)offset;

@end

ShadowOffsetView.m

#import "ShadowOffsetView.h"

NSString *ShadowOffsetChanged = @"ShadowOffsetChanged";

@interface ShadowOffsetView (Internal)
- (NSCell *)cell;
@end

@implementation ShadowOffsetView

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self == nil)
    return nil;

    _offset = CGSizeZero;

    return self;
}

- (void)dealloc
{
    [super dealloc];
}

- (float)scale
{
    return _scale;
}

- (void)setScale:(float)scale
{
    _scale = scale;
}

- (CGSize)offset
{
    return CGSizeMake(_offset.width * _scale, _offset.height * _scale);
}

- (void)setOffset:(CGSize)offset
{
    offset = CGSizeMake(offset.width / _scale, offset.height / _scale);
    if (!CGSizeEqualToSize(_offset, offset)) {
    _offset = offset;
    [self setNeedsDisplay:YES];
    }
}

- (BOOL)isOpaque
{
    return NO;
}

- (void)setOffsetFromPoint:(NSPoint)point
{
    float radius;
    CGSize offset;
    NSRect bounds;
    
    bounds = [self bounds];
    offset.width = (point.x - NSMidX(bounds)) / (NSWidth(bounds) / 2);
    offset.height = (point.y - NSMidY(bounds)) / (NSHeight(bounds) / 2);
    radius = sqrt(offset.width * offset.width + offset.height * offset.height);
    if (radius > 1) {
    offset.width /= radius;
    offset.height /= radius;
    }
    if (!CGSizeEqualToSize(_offset, offset)) {
    _offset = offset;
    [self setNeedsDisplay:YES];
    [(NSNotificationCenter *)[NSNotificationCenter defaultCenter]
        postNotificationName:ShadowOffsetChanged object:self];
    }
}

- (void)mouseDown:(NSEvent *)event
{
    NSPoint point;

    point = [self convertPoint:[event locationInWindow] fromView:nil];
    [self setOffsetFromPoint:point];
}

- (void)mouseDragged:(NSEvent *)event
{
    NSPoint point;

    point = [self convertPoint:[event locationInWindow] fromView:nil];
    [self setOffsetFromPoint:point];
}

- (void)drawRect:(NSRect)rect
{
    NSRect bounds;
    CGContextRef context;
    float x, y, w, h, r;

    bounds = [self bounds];
    x = NSMinX(bounds);
    y = NSMinY(bounds);
    w = NSWidth(bounds);
    h = NSHeight(bounds);
    r = MIN(w / 2, h / 2);
    
    context = [[NSGraphicsContext currentContext] graphicsPort];

    CGContextTranslateCTM(context, x + w/2, y + h/2);

    CGContextAddArc(context, 0, 0, r, 0, 2*M_PI, true);
    CGContextClip(context);

    CGContextSetGrayFillColor(context, 0.910, 1);
    CGContextFillRect(context, CGRectMake(-w/2, -h/2, w, h));

    CGContextAddArc(context, 0, 0, r, 0, 2*M_PI, true);
    CGContextSetGrayStrokeColor(context, 0.616, 1);
    CGContextStrokePath(context);

    CGContextAddArc(context, 0, -2, r, 0, 2*M_PI, true);
    CGContextSetGrayStrokeColor(context, 0.784, 1);
    CGContextStrokePath(context);

    CGContextMoveToPoint(context, 0, 0);
    CGContextAddLineToPoint(context, r * _offset.width, r * _offset.height);

    CGContextSetLineWidth(context, 2);
    CGContextSetGrayStrokeColor(context, 0.33, 1);
    CGContextStrokePath(context);
}

@end

The simplest way is to create a NSView subclass that handles both the mouse management and the drawing.

There is a sample code that can help you to start named "TLayer". It is part of the Examples of the XCode 3.1.4. It contains a circular custom view that controls the offset and the radius of the shadow drawn for layers. It is easy to understand and easy to extend.

Note: as it does not seems to be available on the Apple website, so I have pasted the sources below.


ShadowOffsetView.h

#import <AppKit/AppKit.h>

extern NSString *ShadowOffsetChanged;

@interface ShadowOffsetView : NSView
{
    CGSize _offset;
    float _scale;
}

- (float)scale;
- (void)setScale:(float)scale;

- (CGSize)offset;
- (void)setOffset:(CGSize)offset;

@end

ShadowOffsetView.m

#import "ShadowOffsetView.h"

NSString *ShadowOffsetChanged = @"ShadowOffsetChanged";

@interface ShadowOffsetView (Internal)
- (NSCell *)cell;
@end

@implementation ShadowOffsetView

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self == nil)
    return nil;

    _offset = CGSizeZero;

    return self;
}

- (void)dealloc
{
    [super dealloc];
}

- (float)scale
{
    return _scale;
}

- (void)setScale:(float)scale
{
    _scale = scale;
}

- (CGSize)offset
{
    return CGSizeMake(_offset.width * _scale, _offset.height * _scale);
}

- (void)setOffset:(CGSize)offset
{
    offset = CGSizeMake(offset.width / _scale, offset.height / _scale);
    if (!CGSizeEqualToSize(_offset, offset)) {
    _offset = offset;
    [self setNeedsDisplay:YES];
    }
}

- (BOOL)isOpaque
{
    return NO;
}

- (void)setOffsetFromPoint:(NSPoint)point
{
    float radius;
    CGSize offset;
    NSRect bounds;
    
    bounds = [self bounds];
    offset.width = (point.x - NSMidX(bounds)) / (NSWidth(bounds) / 2);
    offset.height = (point.y - NSMidY(bounds)) / (NSHeight(bounds) / 2);
    radius = sqrt(offset.width * offset.width + offset.height * offset.height);
    if (radius > 1) {
    offset.width /= radius;
    offset.height /= radius;
    }
    if (!CGSizeEqualToSize(_offset, offset)) {
    _offset = offset;
    [self setNeedsDisplay:YES];
    [(NSNotificationCenter *)[NSNotificationCenter defaultCenter]
        postNotificationName:ShadowOffsetChanged object:self];
    }
}

- (void)mouseDown:(NSEvent *)event
{
    NSPoint point;

    point = [self convertPoint:[event locationInWindow] fromView:nil];
    [self setOffsetFromPoint:point];
}

- (void)mouseDragged:(NSEvent *)event
{
    NSPoint point;

    point = [self convertPoint:[event locationInWindow] fromView:nil];
    [self setOffsetFromPoint:point];
}

- (void)drawRect:(NSRect)rect
{
    NSRect bounds;
    CGContextRef context;
    float x, y, w, h, r;

    bounds = [self bounds];
    x = NSMinX(bounds);
    y = NSMinY(bounds);
    w = NSWidth(bounds);
    h = NSHeight(bounds);
    r = MIN(w / 2, h / 2);
    
    context = [[NSGraphicsContext currentContext] graphicsPort];

    CGContextTranslateCTM(context, x + w/2, y + h/2);

    CGContextAddArc(context, 0, 0, r, 0, 2*M_PI, true);
    CGContextClip(context);

    CGContextSetGrayFillColor(context, 0.910, 1);
    CGContextFillRect(context, CGRectMake(-w/2, -h/2, w, h));

    CGContextAddArc(context, 0, 0, r, 0, 2*M_PI, true);
    CGContextSetGrayStrokeColor(context, 0.616, 1);
    CGContextStrokePath(context);

    CGContextAddArc(context, 0, -2, r, 0, 2*M_PI, true);
    CGContextSetGrayStrokeColor(context, 0.784, 1);
    CGContextStrokePath(context);

    CGContextMoveToPoint(context, 0, 0);
    CGContextAddLineToPoint(context, r * _offset.width, r * _offset.height);

    CGContextSetLineWidth(context, 2);
    CGContextSetGrayStrokeColor(context, 0.33, 1);
    CGContextStrokePath(context);
}

@end
挽容 2024-09-12 02:38:08

好吧,对于实际绘图,您要么必须拥有旋钮每个旋转角度的图像(更容易实现),然后绘制正确的图像。

(我想,对于真正逼真的 3D 外观,即使可能,编程绘图也不值得花时间。)

或者通过代码绘制旋钮。我认为这篇文章应该给你一个想法:
http://katidev .com/blog/2008/03/07/how-to-create-a-custom-control-with-nsview/
(对于这两者,鼠标事件处理和圆形和旋转旋钮状元素的基本 NSBezerPath 绘制)

Well, for the actual drawing you'd either have to have images for each rotation angle of the knob (easier to implement) and then just draw the proper one.

(While for a real realistic 3d look—even if possible—programmatic drawing wouldn't be worth its time, I guess.)

Or draw the knob by code. This article should give you an idea I think:
http://katidev.com/blog/2008/03/07/how-to-create-a-custom-control-with-nsview/
(For both, the mouse event handling and basic NSBezerPath drawing of circular and rotating knob-like elements)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文