21

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

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

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

我注意到NSToolbar,虽然在标题栏下方占据大致相同的空间量,但当光标在窗口上方时,它允许拖动窗口。如何实现这一点?

谢谢。

标签栏

4

9 回答 9

26

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

- (BOOL)isMovableByWindowBackground {
    return YES;
}

这就像一个魅力。

于 2013-10-20T17:46:35.173 回答
16

我在这里找到了这个:

-(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: 魔术,或者甚至可能只是使 mouseUp 上的 initialLocation 无效应该可以解决这个问题。

于 2010-12-30T17:10:11.130 回答
12

从 macOS 10.11 开始,最简单的方法是使用新-[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

在这里,-performWindowDragWithEvent:将处理不重叠菜单栏的正确行为,并且还将在 macOS 10.12 及更高版本上对齐边缘。确保在视图的私有接口中包含一个实例变量,这样一旦确定不想处理事件,BOOL movingWindow就可以避免事件。-mouseDragged:

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

于 2017-02-08T15:57:31.640 回答
11

您是否尝试过覆盖 NSView 方法mouseDownCanMoveWindow以返回YES

于 2010-12-30T16:07:25.060 回答
11

两个步骤后它对我有用:

  1. 子类 NSView,覆盖mouseDownCanMoveWindow返回 YES。
  2. 子类 NSWindow,重写isMovableByWindowBackground返回 YES。
于 2014-10-24T08:20:02.233 回答
4

这很容易:

覆盖mouseDownCanMoveWindow属性

override var mouseDownCanMoveWindow:Bool {
    return false
}
于 2014-11-22T14:26:45.657 回答
4

如果您NSTableView的窗口中有 a ,并且启用了选择,则覆盖该mouseDownCanMoveWindow属性将不起作用。

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

@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;
于 2018-02-17T17:21:50.517 回答
0

当您在 中设置属性isMovableByWindowBackgroundviewDidLoad,它可能不起作用,因为尚未设置的window属性。view在这种情况下,试试这个:

override func viewDidAppear() {
    self.view.window?.isMovableByWindowBackground = true
}
于 2019-11-17T10:29:00.363 回答
0

谢谢!Dimitris 的回答解决了我的问题,但我在 swift 5 中需要它。这就是我想出的。

final class BlahField: NSTextView {
    
    var movingWindow = false
    
    override func mouseDown(with event: NSEvent) {
        movingWindow = false
        let point = self.convert(event.locationInWindow, from: nil)
        if (self.window!.isMovableByWindowBackground && self.frame.contains(point)) {
            self.window?.performDrag(with: event)
            movingWindow = true
            return
        }
    
    }
    
    override func mouseDragged(with event: NSEvent) {
        if (movingWindow) {
            return
        }
    }
}
于 2021-09-14T20:21:36.103 回答