2010-12-30 14 views
16

Sto usando una finestra con texture che ha una barra delle schede lungo la parte superiore, appena sotto la barra del titolo.Permetti di fare clic e trascinare una vista per trascinare la finestra stessa?

Ho usato -setContentBorderThickness:forEdge: sulla finestra per rendere il gradiente di destra e per assicurarsi che i fogli scivolino fuori dalla giusta posizione.

Ciò che non funziona, tuttavia, è il trascinamento della finestra. Funziona se faccio clic e trascino l'area che è in realtà la barra del titolo, ma dal momento che il gradiente della barra del titolo si rovescia in una barra delle schede (potenzialmente/spesso vuota), è davvero facile da selezionare troppo basso e sembra davvero frustrante quando provi trascinare e realizzare la finestra non si muove.

Noto NSToolbar, mentre occupa circa la stessa quantità di spazio sotto la barra del titolo, consente di trascinare la finestra quando il cursore si trova su di essa. Come si attua questo?

Grazie.

Tab Bar

risposta

16

ho trovato questo 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]; 
} 

Funziona bene, anche se sono sicuro al 100% che sto facendo in modo corretto. C'è un bug che ho trovato finora, e questo è se il trascinamento inizia all'interno di una sottoview (una scheda stessa) e poi entra nella superview (la barra delle schede). La finestra salta in giro. Alcuni -hitTest: magic, o forse anche solo invalidando initialLocation su mouseUp probabilmente lo risolveranno.

+0

Come sospettato, invalidando la variabile "initialLocation" in mouseUp: event (semplicemente impostando la posizione y su un numero negativo), quindi aggiungendo una clausola di guardia a mouseDragged: corregge il bug. – d11wtq

10

Hai provato l'override del metodo NSView mouseDownCanMoveWindow per tornare YES?

+0

Non avevo, dal momento che non sapevo che esistesse un tale metodo, grazie. Tuttavia, non sembra aver funzionato. La barra delle schede è una sottoview di una vista più ampia (quasi intera finestra), se fa la differenza. – d11wtq

+3

Il mio prossimo pensiero è stato quello di sovrascrivere 'mouseDown:' (metodo NSControl) per passare l'evento del mouse a '[self window]', e assicurarsi che la finestra 'isMovableByWindowBackground', ma che comunque non funzioni per me. Scusate. – Richard

+0

Nessun dramma. Eri sulla buona strada. Grazie per le indagini! :) – d11wtq

21

Ho provato la soluzione mouseDownCanMoveWindow (https://stackoverflow.com/a/4564146/901641) ma non ha funzionato per me. Mi sono liberato di quel metodo e invece aggiunto questo alla mia finestra sottoclasse:

- (BOOL)isMovableByWindowBackground { 
    return YES; 
} 

che ha lavorato come un fascino.

+9

In Swift: 'window.movableByWindowBackground = true'. – twe4ked

+3

@Odin - Immagino 'window.movableByWindowBackground = YES;' funziona in Obj-C, ma penso di essere andato a scavalcare il metodo perché stavo cercando di creare una sottoclasse di 'NSWindow' che mostrava sempre questa caratteristica. – ArtOfWarfare

+0

Probabilmente hai ragione, ho appena incollato ciò che ho trovato per chiunque visiti questa pagina usando Swift. Grazie per la risposta :) – twe4ked

10

Funziona per me dopo due fasi:

  1. sottoclasse NSView, eseguire l'override del mouseDownCanMoveWindow per tornare SI.
  2. Sottoclasse NSWindow, ignorare isMovableByWindowBackground per restituire SÌ.
+2

È possibile saltare il passaggio due se si rende la finestra" strutturata ". (C'è una casella di controllo in IB.) –

+5

Non hai bisogno di sottoclasse NSWindow, dato che puoi chiamare '[self.view.window setMovableByWindowBackground: YES]' nel controller della vista. Sembra che 'isMovableByWindowBackground' di NSWindow sia mutabile mentre' mouseDownCanMoveWindow' di NSView è di sola lettura. – VinceFior

4

E 'abbastanza facile:

esclusione mouseDownCanMoveWindow proprietà

override var mouseDownCanMoveWindow:Bool { 
    return false 
} 
6

Come di MacOS 10.11, il modo più semplice per farlo è quello di utilizzare il nuovo -[NSWindow performWindowDragWithEvent:] metodo:

@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 

Qui, -performWindowDragWithEvent: gestirà il comportamento corretto viore di non sovrapporre la barra dei menu, e scatterà anche ai bordi su macOS 10.12 e successivi. Assicurati di includere una variabile di istanza BOOL movingWindow con l'interfaccia privata della tua vista in modo da poter evitare gli eventi -mouseDragged: una volta stabilito che non vuoi elaborarli.

Qui, stiamo anche verificando che -[NSWindow movableByWindowBackground] sia impostato su YES in modo che questa vista possa essere utilizzata in finestre non mobili-per-finestre-sfondo, ma ciò è facoltativo.

+0

Questo metodo funziona per il mio progetto. ad eccezione del fatto che qualsiasi evento del mouse in movableRect eseguirà lo spostamento, anche se ci sono subviews sopra ** la vista **. – Lax

+0

@Lax Si consiglia di verificare che la vista che appare sopra la vista di trascinamento sia stata testata correttamente - entrambi stanno ottenendo gli eventi del mouse verso il basso? –

0

se hai un NSTableView nella finestra, con la selezione abilitato, sovrascrivendo la proprietà mouseDownCanMoveWindow non funzionerà.

È necessario invece creare una sottoclasse NSTableView e sovrascrivere i seguenti eventi del mouse (e utilizzare il performWindowDragWithEvent: menzionati nella 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 

Inoltre non dimenticate di impostare la proprietà finestra movableByWindowBackground corrispondente così:

self.window.movableByWindowBackground = YES; 
Problemi correlati