允许单击并拖动视图以拖动窗口本身?

时间:2010-12-30 15:34:38

标签: objective-c macos cocoa nswindow appkit

我正在使用一个带纹理的窗口,它的顶部有一个标签栏,位于标题栏的下方。

我在窗口上使用-setContentBorderThickness:forEdge:使渐变看起来正确,并确保纸张从正确位置滑出。

然而,什么不起作用,是拖动窗口。如果我点击并拖动实际上是标题栏的区域,但是由于标题栏渐变溢出到(可能/通常是空的)标签栏,它的真的 很容易点击太低而且感觉很棒当你试图拖动并意识到窗口没有移动时真的很令人沮丧。

我注意到NSToolbar,虽然在标题栏下方占据的空间大致相同,但当光标悬停在窗口上时,可以拖动窗口。如何实现这个?

感谢。

Tab Bar

8 个答案:

答案 0 :(得分:25)

我尝试了mouseDownCanMoveWindow解决方案(https://stackoverflow.com/a/4564146/901641),但它对我不起作用。我摆脱了那个方法,而是将它添加到我的窗口子类中:

- (BOOL)isMovableByWindowBackground {
    return YES;
}

就像魅力一样。

答案 1 :(得分:16)

我发现了here

-(void)mouseDown:(NSEvent *)theEvent {    
    NSRect  windowFrame = [[self window] frame];

    initialLocation = [NSEvent mouseLocation];

    initialLocation.x -= windowFrame.origin.x;
    initialLocation.y -= windowFrame.origin.y;
}

- (void)mouseDragged:(NSEvent *)theEvent {
    NSPoint currentLocation;
    NSPoint newOrigin;

    NSRect  screenFrame = [[NSScreen mainScreen] frame];
    NSRect  windowFrame = [self frame];

    currentLocation = [NSEvent mouseLocation];
    newOrigin.x = currentLocation.x - initialLocation.x;
    newOrigin.y = currentLocation.y - initialLocation.y;

    // Don't let window get dragged up under the menu bar
    if( (newOrigin.y+windowFrame.size.height) > (screenFrame.origin.y+screenFrame.size.height) ){
        newOrigin.y=screenFrame.origin.y + (screenFrame.size.height-windowFrame.size.height);
    }

    //go ahead and move the window to the new location
    [[self window] setFrameOrigin:newOrigin];
}

它工作正常,但我不是100%确定我正确地做到了。到目前为止我发现了一个错误,如果拖动开始在子视图(标签本身)内,然后进入超级视图(标签栏)。窗户跳了起来。一些-hitTest:magic,或者甚至可能只是使mouseUp上的initialLocation无效应该可以解决这个问题。

答案 2 :(得分:11)

您是否尝试重写NSView方法mouseDownCanMoveWindow以返回YES

答案 3 :(得分:10)

经过两个步骤后,它对我有用:

  1. 子类NSView,覆盖mouseDownCanMoveWindow以返回YES。
  2. 子类NSWindow,覆盖isMovableByWindowBackground以返回YES。

答案 4 :(得分:7)

从macOS 10.11开始,最简单的方法是使用新的VoiceActivity方法:

-[NSWindow performWindowDragWithEvent:]

此处,@interface MyView () { BOOL movingWindow; } @end @implementation MyView ... - (BOOL)mouseDownCanMoveWindow { return NO; } - (void)mouseDown:(NSEvent *)event { movingWindow = NO; CGPoint point = [self convertPoint:event.locationInWindow fromView:nil]; // The area in your view where you want the window to move: CGRect movableRect = CGRectMake(0, 0, 100, 100); if (self.window.movableByWindowBackground && CGRectContainsPoint(movableRect, point)) { [self.window performWindowDragWithEvent:event]; movingWindow = YES; return; } // Handle the -mouseDown: as usual } - (void)mouseDragged:(NSEvent *)event { if (movingWindow) return; // Handle the -mouseDragged: as usual } @end 将处理不重叠菜单栏的正确行为,并且还会捕捉到macOS 10.12及更高版本的边缘。请务必在您的视图的私人界面中加入-performWindowDragWithEvent:实例变量,这样一旦您确定不想处理它们,就可以避免BOOL movingWindow个事件。

在这里,我们还检查-mouseDragged:是否设置为-[NSWindow movableByWindowBackground],以便此视图可用于不可移动的窗口背景窗口,但这是可选的。

答案 5 :(得分:4)

这很容易:

覆盖 mouseDownCanMoveWindow 属性

override var mouseDownCanMoveWindow:Bool {
    return false
}

答案 6 :(得分:3)

如果您的窗口中有NSTableView,并且选择已启用,则覆盖mouseDownCanMoveWindow属性将无效。

您需要创建一个NSTableView子类并覆盖以下鼠标事件(并使用performWindowDragWithEvent:中提到的Dimitri answer):

@interface WindowDraggableTableView : NSTableView
@end

@implementation WindowDraggableTableView 
{
    BOOL _draggingWindow;
    NSEvent *_mouseDownEvent;
}

- (void)mouseDown:(NSEvent *)event
{
    if (self.window.movableByWindowBackground == NO) {
        [super mouseDown:event]; // Normal behavior.
        return;
    }

    _draggingWindow = NO;
    _mouseDownEvent = event;
}

- (void)mouseDragged:(NSEvent *)event
{
    if (self.window.movableByWindowBackground == NO) {
        [super mouseDragged:event]; // Normal behavior.
        return;
    }

    assert(_mouseDownEvent);
    _draggingWindow = YES;
    [self.window performWindowDragWithEvent:_mouseDownEvent];
}

- (void)mouseUp:(NSEvent *)event
{
    if (self.window.movableByWindowBackground == NO) {
        [super mouseUp:event]; // Normal behavior.
        return;
    }

    if (_draggingWindow == YES) {
        _draggingWindow = NO;
        return; // Event already handled by `performWindowDragWithEvent`.
    }

    // Triggers regular table selection.
    NSPoint locationInWindow = event.locationInWindow;
    NSPoint locationInTable = [self convertPoint:locationInWindow fromView:nil];
    NSInteger row = [self rowAtPoint:locationInTable];
    if (row >= 0 && [self.delegate tableView:self shouldSelectRow:row])
    {
        NSIndexSet *rowIndex = [NSIndexSet indexSetWithIndex:row];
        [self selectRowIndexes:rowIndex byExtendingSelection:NO];
    }
}

@end

另外,不要忘记设置相应的窗口movableByWindowBackground属性:

self.window.movableByWindowBackground = YES;

答案 7 :(得分:0)

isMovableByWindowBackground中设置属性viewDidLoad时,它可能无法工作,因为window的{​​{1}}属性尚未设置。在这种情况下,请尝试以下操作:

view