tags:

views:

9629

answers:

5

Apart from being horribly annoyed with Excel VBA ... I have this question:

Is there a way to catch a click on a cell in VBA with Excel? I'm not talking about the Worksheet_SelectionChange event, as that won't trigger multiple times if the cell is clicked multiple times. BeforeDoubleClick doesn't solve my problem either, I don't want to require the user to double click all the time.

I'm fairly convinced there isn't, but I'm also fairly desperate. My current solution does work with that SelectionChange thing, but it brings along all kinds of problems and makes me use global variables and other horrible things.

A: 

I don't think so. But you can create a shape object ( or wordart or something similiar ) hook Click event and place the object to position of the specified cell.

TcKs
Hm, the trouble with that is that I want to catch on what cell it was, and have an arbitrary number of lines that I want to catch it in, along with the line that it was caught in (the SelectionChange hands me a nice Range for that)...
haslo
And the user should be able to easily edit the sheet, too, without restrictions like "you'll have to click this button, if you add a new line by hand it won't work". But I'm fairly certain there's really no way (VBA doesn't surprise me yet again), I might as well formally accept your answer...
haslo
+1  A: 

SelectionChange is the event built into the Excel Object model for this. It should do exactly as you want, firing any time the user clicks anywhere...

I'm not sure that I understand your objections to global variables here, you would only need 1 if you use the Application.SelectionChange event. However, you wouldn't need any if you utilize the Workbook class code behind (to trap the Workbook.SelectionChange event) or the Worksheet class code behind (to trap the Worksheet.SelectionChange) event. (Unless your issue is the "global variable reset" problem in VBA, for which there is only one solution: error handling everywhere. Do not allow any unhandled errors, instead log them and/or "soft-report" an error as a message box to the user.)

You might also need to trap the Worksheet.Activate() and Worksheet.Deactivate() events (or the equivalent in the Workbook class) and/or the Workbook.Activate and Workbook.Deactivate() events so that you know when the user has switched worksheets and/or workbooks. The Window activate and deactivate events should make this approach complete. They could all call the same exact procedure, however, they all denote the same thing: the user changed the "focus", if you will.

If you don't like VBA, btw, you can do the same using VB.NET or C#.

[Edit: Dbb makes a very good point about the SelectionChange event not picking up a click when the user clicks within the currently selected cell. If you need to pick that up, then you would need to use subclassing.]

Mike Rosenblum
Global Variables are just ugly, that's all :) The reason why I used one here in particular is because I also changed worksheet during the event handling, copy-pasting rows into another sheet.It's really just a tiny application, VB.NET or C# (while I like them a lot better) are a bit over the top.
haslo
Other than that, very good insight, thanks!
haslo
+1  A: 

In order to trap repeated clicks on the same cell, you need to move the focus to a different cell, so that each time you click, you are in fact moving the selection.

The code below will select the top left cell visible on the screen, when you click on any cell. Obviously, it has the flaw that it won't trap a click on the top left cell, but that can be managed (eg by selecting the top right cell if the activecell is the top left).

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
This is a VERY nice idea, if all you need to do is pick up clicks. But if the user also needs to be able to edit a cell value, etc. then this would be a no-go. (Even if not, it could be v. confusing.) Excellent point about SelectionChange not picking up a "same cell" click, however; I missed that.
Mike Rosenblum
+1  A: 

Clearly, there is no perfect answer. However, if you want to allow the user to

  1. select certain cells
  2. allow them to change those cells, and
  3. trap each click,even repeated clicks on the same cell,

then the easiest way seems to be to move the focus off the selected cell, so that clicking it will trigger a Select event.

One option is to move the focus as I suggested above, but this prevents cell editing. Another option is to extend the selection by one cell (left/right/up/down),because this permits editing of the original cell, but will trigger a Select event if that cell is clicked again on its own.

If you only wanted to trap selection of a single column of cells, you could insert a hidden column to the right, extend the selection to include the hidden cell to the right when the user clicked,and this gives you an editable cell which can be trapped every time it is clicked. The code is as follows

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
dbb
Perfect, thanks :)
haslo
A: 

This has worked for me.....

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

NOTE: this function in actual use recalculated a pivot table if a user added a item in a data range of A4 to D500. The there were protected and unprotected sections in the sheet so the actual check for the click is if the column is less that "E" The logic can get as complex as you want to include or exclude any number of areas

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

Joe