2008-10-07 31 views
19

¿Hay alguna manera de capturar un clic en una celda en VBA con Excel? No me refiero al evento Worksheet_SelectionChange, ya que no se activará varias veces si se hace clic en la celda varias veces. BeforeDoubleClick tampoco resuelve mi problema, ya que no deseo que el usuario haga doble clic en eso con frecuencia.OnClick en Excel VBA

Mi solución actual funciona con el evento SelectionChange, pero parece requerir el uso de variables globales y otras prácticas de codificación subóptimas. También parece propenso al error.

Respuesta

18

Claramente, no hay una respuesta perfecta.Sin embargo, si desea permitir al usuario

  1. seleccionar ciertas células
  2. les permiten cambiar esas células, y
  3. trampa cada clic, incluso repetidos clics en la misma celda,

, entonces la manera más fácil parece ser mover el foco fuera de la celda seleccionada, de modo que al hacer clic se activará un evento Seleccionar.

Una opción es mover el foco como sugerí anteriormente, pero esto evita la edición de la celda. Otra opción es extender la selección por una celda (izquierda/derecha/arriba/abajo), porque esto permite la edición de la celda original, pero activará un evento Select si esa celda se vuelve a hacer clic por sí misma.

Si solo desea interceptar la selección de una sola columna de celdas, puede insertar una columna oculta a la derecha, ampliar la selección para incluir la celda oculta a la derecha cuando el usuario hizo clic, y esto le da un editable célula que puede quedar atrapada cada vez que se hace clic. El código es el siguiente

Private Sub Worksheet_SelectionChange(ByVal Target As Range) 
    'prevent Select event triggering again when we extend the selection below 
    Application.EnableEvents = False 
    Target.Resize(1, 2).Select 
    Application.EnableEvents = True 
End Sub 
+0

Perfecto, gracias :) – haslo

0

No lo creo. Pero puede crear un objeto de forma (o wordart o algo similar). Haga clic en evento y coloque el objeto en la posición de la celda especificada.

+0

Hm, el problema con eso es que quiero ver qué celda era, y tengo un número arbitrario de líneas en las que quiero capturarlo, junto con la línea en la que estaba atrapado (el SelectionChange me da un buen Rango para eso) ... – haslo

+0

Y el usuario debería ser capaz de editar fácilmente la hoja, también, sin restricciones como "tendrá que hacer clic en este botón, si agrega una nueva línea a mano, no funcionará". Pero estoy bastante seguro de que realmente no hay forma (VBA no me sorprende una vez más), también podría aceptar su respuesta formalmente ... – haslo

1

SelectionChange es el evento integrado en el modelo de objetos de Excel para esto. Debería hacer exactamente lo que quiera, disparando cada vez que el usuario haga clic en cualquier lugar ...

No estoy seguro de entender sus objeciones a las variables globales aquí, solo necesitaría 1 si usa el evento Application.SelectionChange . Sin embargo, no necesitaría ninguno si utiliza el código de clase Workbook (para atrapar el evento Workbook.SelectionChange) o el código de clase Worksheet detrás (para atrapar el evento Worksheet.SelectionChange). (A menos que su problema sea el problema de "reinicio global de variables" en VBA, para el cual solo hay una solución: manejo de errores en todas partes. No permita ningún error no controlado, en lugar de eso, inicie sesión y/o "informe suave" como mensaje cuadro para el usuario.)

Es posible que también necesite interceptar los eventos Worksheet.Activate() y Worksheet.Deactivate() (o su equivalente en la clase Workbook) y/o Workbook.Activate and Workbook.Deactivate () eventos para que sepa cuándo el usuario ha cambiado las hojas de cálculo y/o los libros de trabajo. Los eventos de activación y desactivación de ventana deben completar este enfoque. Todos pueden llamar el mismo procedimiento exacto, sin embargo, todos denotan lo mismo: el usuario cambió el "foco", si se quiere.

Si no te gusta VBA, por cierto, puedes hacer lo mismo usando VB.NET o C#.

[Editar: Dbb hace un muy buen punto sobre el evento SelectionChange no captando un clic cuando el usuario hace clic dentro de la celda seleccionada actualmente. Si necesita recoger eso, entonces necesitaría usar subclases.]

+0

Las variables globales son feos, eso es todo :) La razón por la que utilicé una aquí en particular, se debe a que también cambié la hoja de trabajo durante el manejo del evento, copiando y pegando filas en otra hoja. Es solo una pequeña aplicación, VB.NET o C# (aunque me gustan mucho más) son un poco exagerados. – haslo

+0

Aparte de eso, muy buena idea, ¡gracias! – haslo

5

Para atrapar clics repetidos en la misma celda, debe mover el foco a una celda diferente, de modo que cada vez que haga clic , de hecho estás moviendo la selección.

El código siguiente seleccionará la celda superior izquierda visible en la pantalla, cuando haga clic en cualquier celda. Obviamente, tiene el inconveniente de que no atrapará un clic en la celda superior izquierda, pero puede administrarse (por ejemplo, seleccionando la celda superior derecha si la celda activa está arriba a la izquierda).

Private Sub Worksheet_SelectionChange(ByVal Target As Range) 
    'put your code here to process the selection, then.. 
    ActiveWindow.VisibleRange.Cells(1, 1).Select 
End Sub 
+1

Esta es una muy buena idea, si todo lo que necesita hacer es recoger clics. Pero si el usuario también necesita poder editar un valor de celda, etc., esto sería un no-go. (Incluso si no, podría ser v. Confuso.) Excelente punto acerca de SelectionChange que no recoge un clic en "la misma celda", sin embargo; Me lo perdí. –

0

Esto ha funcionado para mí .....

Private Sub Worksheet_Change(ByVal Target As Range) 

    If Mid(Target.Address, 3, 1) = "$" And Mid(Target.Address, 2, 1) < "E" Then 
     ' The logic in the if condition will filter for a specific cell or block of cells 
     Application.ScreenUpdating = False 
     'MsgBox "You just changed " & Target.Address 

     'all conditions are true .... DO THE FUNCTION NEEDED 
     Application.ScreenUpdating = True 
    End If 
    ' if clicked cell is not in the range then do nothing (if condttion is not run) 
End Sub 

NOTA: esta función en el uso real vuelve a calcular una tabla dinámica si un usuario añade un elemento en un rango de datos de A4 a D500. El no fueron protegidos y secciones sin proteger de la hoja para la verificación real para el clic se si la columna es menor que "E" La lógica puede llegar tan complejo como el que desea incluir o excluir cualquier número de áreas

block1 = row > 3 and row < 5 and column column >"b" and < "d" 
block2 = row > 7 and row < 12 and column column >"b" and < "d" 
block3 = row > 10 and row < 15 and column column >"e" and < "g" 

If block1 or block2 or block 3 then 
    do function ..... 
end if