cocoa mouse nsview

Distinguir un solo clic de un doble clic en Cocoa en la Mac



mouse nsview (4)

Tengo un NSView personalizado (es uno de muchos y todos viven dentro de un NSCollectionView ; no creo que sea relevante, pero quién sabe). Cuando hago clic en la vista, quiero que cambie su estado de selección (y se vuelva a dibujar en consecuencia); cuando hago doble clic en la vista, quiero que aparezca una ventana de vista previa más grande para el objeto en el que se hizo doble clic.

Mi primera se veía así:

- (void)mouseUp: (NSEvent *)theEvent { if ([theEvent clickCount] == 1) [model setIsSelected: ![model isSelected]]; else if ([theEvent clickCount] == 2) if ([model hasBeenDownloaded]) [mainWindowController showPreviewWindowForPicture:model]; }

que en su mayoría funcionaba bien. Excepto, cuando hago doble clic en la vista, el estado de selección cambia y aparece la ventana emergente. Esto no es exactamente lo que quiero.

Parece que tengo dos opciones. Puedo revertir el estado de selección al responder a un doble clic (deshacer el error de un solo clic) o puedo encontrar algún tipo de solución NSTimer para generar un retraso antes de responder al solo clic. En otras palabras, puedo asegurarme de que no se reciba un segundo clic antes de cambiar el estado de selección.

Esto parecía más elegante, así que fue el enfoque que tomé al principio. La única guía real que encontré en Google estaba en un sitio sin nombre con un guión en su nombre. Este enfoque funciona principalmente con una gran advertencia.

La pregunta pendiente es "¿Cuánto tiempo debe esperar mi NSTimer ?". El sitio sin nombre sugiere utilizar la función Carbon GetDblTime() . Además de ser inutilizable en aplicaciones de 64 bits, la única documentación que puedo encontrar indica que está devolviendo los tics del reloj. Y no sé cómo convertirlos en segundos para NSTimer .

Entonces, ¿cuál es la respuesta "correcta" aquí? Fumble alrededor con GetDblTime() ? "Deshacer" la selección en un doble clic? No puedo entender el enfoque idiomático del cacao.


Agrega dos propiedades a tu vista personalizada.

// CustomView.h @interface CustomView : NSView { @protected id m_target; SEL m_doubleAction; } @property (readwrite) id target; @property (readwrite) SEL doubleAction; @end

Sobrescriba el método mouseUp: en su vista personalizada.

// CustomView.m #pragma mark - MouseEvents - (void)mouseUp:(NSEvent*)event { if (event.clickCount == 2) { if (m_target && m_doubleAction && [m_target respondsToSelector:m_doubleAction]) { [m_target performSelector:m_doubleAction]; } } }

Registre su controlador como el target con una doubleAction .

// CustomController.m - (id)init { self = [super init]; if (self) { // Register self for double click events. [(CustomView*)m_myView setTarget:self]; [(CustomView*)m_myView setDoubleAction:@selector(doubleClicked:)]; } return self; }

Implementar lo que se debe hacer cuando ocurre un doble clic.

// CustomController.m - (void)doubleClicked:(id)sender { // DO SOMETHING. }


Personalmente, creo que debe preguntarse por qué quiere este comportamiento no estándar.

¿Puede señalar cualquier otra aplicación que trate el primer clic en un doble clic como diferente de un solo clic? No puedo pensar en ninguna ...


Retrasar el cambio del estado de selección es (por lo que he visto) la forma recomendada de hacer esto.

Es bastante simple de implementar:

- (void)mouseUp:(NSEvent *)theEvent { if([theEvent clickCount] == 1) { [model performSelector:@selector(toggleSelectedState) afterDelay:[NSEvent doubleClickInterval]]; } else if([theEvent clickCount] == 2) { if([model hasBeenDownloaded]) { [NSRunLoop cancelPreviousPerformRequestsWithTarget: model]; [mainWindowController showPreviewWindowForPicture:model]; } } }

(Observe que en 10.6, se puede acceder al intervalo de doble clic como método de clase en NSEvent )


Si las operaciones de un solo clic y doble clic son realmente independientes y no están relacionadas, debe usar un temporizador en el primer clic y esperar para ver si se produce un doble clic. Eso es cierto en cualquier plataforma.

Pero eso introduce un retraso incómodo en la operación de un solo clic que a los usuarios normalmente no les gusta. Así que no ves que el enfoque se utiliza muy a menudo.

Un mejor enfoque es hacer que sus operaciones de un solo clic y doble clic estén relacionadas y sean complementarias. Por ejemplo, si hace clic en un icono en el Finder, se selecciona (inmediatamente), y si hace doble clic en un icono, se selecciona y se abre (inmediatamente). Ese es el comportamiento al que debes aspirar.

En otras palabras, las consecuencias de un solo clic deben estar relacionadas con su comando de doble clic. De esa manera, puede lidiar con los efectos de un solo clic en su controlador de doble clic sin tener que recurrir a un temporizador.