Разрешить перетаскивать вид и перетаскивать само окно? - PullRequest
17 голосов
/ 30 декабря 2010

Я использую текстурированное окно, в верхней части которого расположена панель вкладок, чуть ниже строки заголовка.

Я использовал -setContentBorderThickness:forEdge: в окне, чтобы градиент выглядел правильно и чтобы листы выдвигались из правильного положения.

Что не работает, так это перетаскивание окна. Это работает, если я щелкаю и перетаскиваю область, которая фактически является строкой заголовка, но поскольку градиент строки заголовка перетекает в (потенциально / часто пустую) панель вкладок, действительно легко щелкнуть слишком низко, и это действительно разочарование при попытке перетащить и понять, что окно не движется.

Я заметил, что NSToolbar, занимая примерно столько же места под строкой заголовка, позволяет перетаскивать окно, когда курсор находится над ним. Как это реализовать?

Спасибо.

Tab Bar

Ответы [ 7 ]

25 голосов
/ 20 октября 2013

Я попробовал решение mouseDownCanMoveWindow (https://stackoverflow.com/a/4564146/901641), но оно у меня не сработало. Я избавился от этого метода и вместо этого добавил его в мой подкласс окна:

- (BOOL)isMovableByWindowBackground {
    return YES;
}

который работал как шарм.

16 голосов
/ 30 декабря 2010

Я нашел это здесь :

-(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, или, возможно, даже просто аннулирование initialLocation на mouseUp, вероятно, должно это исправить.

11 голосов
/ 30 декабря 2010

Вы пытались переопределить метод NSView mouseDownCanMoveWindow для возврата YES?

10 голосов
/ 24 октября 2014

Это работает для меня после ДВУХ шагов:

  1. Подкласс NSView, переопределите mouseDownCanMoveWindow для возврата YES.
  2. Подкласс NSWindow, переопределите isMovableByWindowBackground для возврата YES.
7 голосов
/ 08 февраля 2017

Начиная с 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, чтобы этот вид можно было использовать в фоновых окнах с неподвижным окном, но это необязательно.

4 голосов
/ 22 ноября 2014

Это довольно просто:

переопределить mouseDownCanMoveWindow свойство

override var mouseDownCanMoveWindow:Bool {
    return false
}
3 голосов
/ 17 февраля 2018

Если у вас есть 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;
...