2009-09-30 8 views
5

El mini reproductor de iTunes (para dar solo un ejemplo) admite el clic donde la aplicación no se lleva al frente cuando se utilizan los controles de reproducción/pausa y volumen.Botones de clic y sin abrir la ventana

¿Cómo se hace esto?

He estado buscando a través de documentación de Apple y tengo un poco para seguir adelante, en Cocoa Event-Handling Guide, Event Dispatch afirma:

Algunos eventos, muchos de los cuales son definidos por el Kit de Aplicación (tipo NSAppKitDefined), que hacer con acciones controladas por una ventana o el objeto de la aplicación en sí. Ejemplos de estos eventos son aquellos relacionados con activar, desactivar, ocultar y mostrar la aplicación. NSApp filtra estos eventos al principio de su rutina de envío y los maneja por sí mismo.

Por lo tanto, desde mi comprensión limitada (How an Event Enters a Cocoa, Application) subclases NSApplication y primordial - (void)sendEvent:(NSEvent *)theEvent deberían atrapar cada evento ratón y el teclado, pero aún así, la ventana se eleva al hacer clic. Entonces, o bien la ventana se levanta antes de que NSA vea el evento o me falta algo más.

He visto el Demystifying NSApplication by recreating it de Matt Gallagher, desafortunadamente Matt no cubrió la cola de eventos, así que aparte de eso, estoy perplejo.

Cualquier ayuda sería apreciada, gracias.

Editado para agregar: Encontrado un puesto en Lloyd's Lounge en la que habla sobre el mismo problema y enlaces a un puesto en CocoaBuilder, capture first right mouse down. Actualmente estoy probando el código proporcionado allí, después de algunos cambios y reactivación del NSLog para [el tipo de evento], la actividad del botón izquierdo del mouse está siendo atrapada.

Ahora, al hacer clic con el botón izquierdo en la ventana para traerlo hacia delante se produce una secuencia de tipos de eventos, 13, 1, 13, estos son NSAppKitDefined, NSLeftMouseDown y NSAppKitDefined nuevamente. ¿Puedo filtrar estos o encontrar dónde van?

Respuesta

2

Esta no es exactamente la respuesta que estaba buscando, pero por ahora funciona bastante bien. Al crear subclases NSView e implementar los siguientes métodos, esa vista puede actuar como un botón.

- (void)mouseDown:(NSEvent *)theEvent { 
    [NSApp preventWindowOrdering]; 
// [self setNeedsDisplay:YES]; 
} 

- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { 
    return YES; 
} 

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent { 
    return YES; 
} 

No se requiere nada más, eso es todo. Por supuesto, esto pasa por alto todas las bondades de NSButton que quería conservar, tengo que diseñar y luego ocuparme de dibujar y actualizar los estados de los botones, pero estoy contento de tener una respuesta.

1

¿Has echado acceptsFirstMouse:? Cualquier NSView puede devolver YES a este evento para decir que la vista debe manejar el evento en lugar de llevar la ventana al primer plano. Presumiblemente, al interceptar el evento, no se usará para poner la ventana en primer plano, pero no puedo responder por eso.

Obviamente deberá subclase cualquier control que desee que tenga este comportamiento para anular acceptsFirstMouse:.

+0

acceptsFirstMouse: and acceptsFirstResponder: no tiene ningún efecto, fue (y debería haber notado) mi primer intento de este problema. Gracias sin embargo. –

3

Esto se puede lograr con un NSPanel que se ha configurado para que no se oculte al desactivar y para convertirse en clave solo cuando sea necesario. Esto también supone que los controles que utilizará devolverán YES a -acceptsFirstMouse:; NSButton s hacerlo de forma predeterminada.

Puede desactivar el indicador de ocultar al desactivar a través de IB para el panel, pero deberá enviar el mensaje -setBecomesKeyOnlyIfNeeded:YES al panel para evitar que la aplicación y el clic de botón se cierren.

+0

Quiero creer que esta es la respuesta, pero al leer la referencia de clase NSView (donde se define el método 'acceptsFirstMouse:') dice que está establecido en 'NO'. Y finalmente subclases 'NSView' no hace ninguna diferencia de todos modos. –

+0

Acabo de encontrar una breve discusión sobre CocoaDev, http://www.cocoadev.com/index.pl?PreventWindowOrdering, esto hace lo que quiero, aunque parece una mala manera de hacerlo. –

+0

Los documentos para 'acceptsFirstMouse:' llama específicamente a 'NSButton' como' SÍ 'a la vez: "Sin embargo, muchos objetos de control, como instancias de' NSButton' y 'NSSlider', los aceptan, por lo que el usuario puede manipular el control sin tener que soltar el botón del mouse ". –

2

Es posible hacer una NSButton responder a eventos de clics sin cambiar su comportamiento cuando la aplicación está activa:

Interface (ClickThroughButton.h):

#import <AppKit/AppKit.h> 

@interface ClickThroughButton : NSButton 

@end 

implementación (ClickThroughButton.m) :

#import "ClickThroughButton.h" 

@implementation ClickThroughButton 

- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent { 
    return ![NSApp isActive];  
} 

- (void)mouseDown:(NSEvent *)theEvent {  
    if (![NSApp isActive]) { 
     [NSApp preventWindowOrdering];   

     [self highlight:YES]; 

     NSEvent *mouseUpEvent = [[self window] nextEventMatchingMask:NSLeftMouseUpMask 
                untilDate:[NSDate distantFuture] 
                inMode:NSEventTrackingRunLoopMode 
                dequeue:YES]; 
     NSPoint mouseLocation = [self convertPoint:[mouseUpEvent locationInWindow] fromView:nil]; 
     BOOL mouseUpInside = [self mouse:mouseLocation inRect:[self bounds]]; 

     if (mouseUpInside) { 
      if ([self target]) 
       [[self target] performSelector:[self action] withObject:self]; 
     } 

     [self highlight:NO];    

    } else { 
     [super mouseDown:theEvent];   
    } 
} 

@end 
+0

Funciona, pero ¿cómo mantener el diálogo en la parte superior? Estoy desarrollando una aplicación como Keyboard Viewer. –

Cuestiones relacionadas