So, it's a new week, and I've got new ideas for improving things. Part of what I do is send out reports to individual offices and departments all over the place; these offices in turn are supposed to go through the information and note inconsistencies. As with everything in life, this turns out to be more trouble than anything else. In an effort to make it a little bit more painless (I hope) I want to try somethinga little different for them. What I would like to do is set up something within the worksheet that the individuals receive that does two things:
First, I would like to set up the worksheet so that when the user
clicks on a cell the cell is highlighted;
Second, after the cell highlights then the activebox would
automatically transfer to a "comments" box at the end of the row
where the user would enter their comments as to why the cell in
question was highlighted; and
Third, assuming that someone will make a mistake and highlight
something by mistake I would like to add the additional function
that if a user selects a cell that is highlighted then it would
clear the highlight from the cell.
Possible? Suggestions? Thanks!
JMax is correct in identifying the flaw in that you cannot edit a cell if it changes color and selects a comments cell every time you click on it. The best way around this problem is to change the color only on double-click. I would also define the selected row/column and see if they fall within a table's range (instead of using Application.Intersect) but that's just personal preference
Something like...
Private Sub Worksheet_Beforedoubleclick(ByVal target As Range, cancel As Boolean)
Application.EnableEvents = False
Dim TargRow as Variant
Dim TargCol as Variant
TargRow = target.Row
TargCol = target.Column
'Define Header, FirstCol, CommentCol, LastCol as required to define your table/range where you wish these changes to be made. CommentCol is the cell in which comments should be made
If TargRow > Header And TargCol > FirstCol and TargCol < LastCol Then
If Cells(TargRow,TargCol).Interior.ColorIndex <> -4142 Then 'change color as required to match background
Cells(TargRow,TargCol).Interior.ColorIndex = 3 'change color as required; this makes them red
Cells(TargRow,CommentCol).Select
Else
Cells(TargRow,TargCol).Interior.ColorIndex = -4142 'match color from start of IF statement
End If
End If
Application.EnableEvents = True
End Sub
Note that we disable events so no other code can be triggered by us selecting a different cell. This is an absolute necessity when implementing the Worksheet_SelectionChange event, less so with the BeforeDoubleClick event
It's very important to consider how you trigger macros and how they give the user flexibility. This Excel help video provides a reasonable introduction
What you can (and probably have to) use is the Worksheet_SelectionChange event procedure:
See MSDN for how it works.
You also should have a look at Chip Pearson's page about events.
When the user changes the selection, you should check wheter you are in the right cells (using Intersect) and if so, change the Target background color and change the ActiveCell to the one where you should put comments.
Btw, you can check if the cell is aldreay highlighted before moving to another cell.
The main drawback of this method is that it will move the Excel Selection every time the user clicks on a corresponding cell. A solution would be to tell the user to use the Scroll Lock key and to navigate with arrows. See this link on how it works.
Related
I have a worksheet containing a column of numbers. The column is formatted with a background color, number formats, etc. The column is unlocked. I protect the sheet manually by right-clicking on the tab and selecting Protect. In the Protect Sheet dialog, 'format cells' is unchecked. I interpret to mean that the user should not be able to format cells. Yet when the user pastes into the column, formats are pasted along with values.
If I protect the sheet in VBA using
sh.Protect UserInterfaceOnly:=True
I get the same result: formats are pasted. I do not specify AllowFormattingCells:=False because the default is False.
I have seen posts suggesting that formats can be restored by copying and pasting them from a shadow area. I have used this solution before I started protecting worksheets and found it overly complex. I had hoped this was something protection would handle. If there is a way to handle it, I'd like to do it in VBA.
This question is a little old, but I had the same one, and so have many people in the past. With a bit of browsing I came up with a solution which seems quite clean and appears to work. Am I missing something?
Private Sub Worksheet_Change(ByVal rngTarget As Range)
Dim vPaste As Variant
With Application.CommandBars("Standard").Controls("&Undo")
If Not .Enabled Then Exit Sub
If .ListCount < 1 Then Exit Sub
If .List(1) <> "Paste" Then Exit Sub
End With
vPaste = rngTarget.Value2
On Error Resume Next
Application.EnableEvents = False
Application.Undo
rngTarget.Value2 = vPaste
Application.EnableEvents = True
On Error GoTo 0
End Sub
This could go in Workbook_SheetChange, but not if you already have code in Worksheet_Change, because the worksheet event handler gets called before the workbook event handler. But this code can go in a module to keep things tidy.
There is no built-in protection option you can use to achieve your desired result.
The only thing that works in this case is the clunky workaround that you mention, i.e. use a Worksheet_Change event that ensures the correct format after a cell has been modified.
Since there are many different ways to paste content, i.e. via various menus, ribbon commands, keyboard shortcuts, etc., any VBA solution that tries to intercept pasting will become very complex, much more complex than the change event that restores the format to its original state.
Another option might be user education and training (so they know to paste values only), although user behaviour may be the toughest element to change in the whole scenario.
We all know that Excel has some counter-intuitive behaviours and it is, I believe, one of them:
When you select a range of few cells, starting your selection with the cell with data validation list and choose value from drop-down list: only one cell changes (the one containing drop-down list) instead of all selected.
Sometimes a few magic keyboard shortcuts such as CTRL+d, or combination of CTRL+' and CTRL+ENTER can fix this behaviour, but from my experience clients doesn't like to learn some new hacks, they just want to work everything in as simple way as possible.
I found even similar questions on SO e.g. here:
Adding same drop-down value to multiple cells simultaneously
I know that this is very simple code, but following few lines of code make my life easier, and I am sure this will help somebody too. Code in Worksheet module of course:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
' MACRO FILLS THE WHOLE SELECTED RANGE
' WITH THE SAME VALUE USING DROP-DOWN LIST
' IN JUST ONE ACTIVE CELL
' change to false if all selected cells should be filled with value
Const FILL_VISIBLE_CELLS_ONLY As Boolean = True
' detecting if dropdown list was used
'
' I am using very clever solution by JvdV from SO
' ~~~~> stackoverflow.com/questions/56942551/
'
' If after edit we're in the same cell - drop-down list was used
' I know that may be also drag&drop or copy-paste
' but it seems no matters here.
' Warning! Should be add one more check if someone used
' 'accept OK character' next to formula bar, not implemented here.
'
If ActiveCell.Address <> Target.Address Then Exit Sub
' preventing error which sometimes occurs
If IsEmpty(ActiveCell.Value) Then Exit Sub
' fill a range or visible range with activeCell value
If FILL_VISIBLE_CELLS_ONLY Then
Selection.Cells.SpecialCells(xlCellTypeVisible) _
.Value = ActiveCell.Value
Else
Selection.Value = ActiveCell.Value
End If
End Sub
When you select a Range of more than one Cell, is is important to distinguish between the Active Cell (the single highlighted cell) and the Selection (the entire selected range, including the Active Cell).
Then:
Any Content (such as Values or Formulas) that you enter into the Formula bar is input into the Active Cell only, not the entire Selection.
Any Formatting changes you make are applied to the entire Selection, not just the Active Cell.
An exception is when entering an Array formula which applies to the Selection.
Since in this case you are making a change to content not formatting, it is applied to only the Active Cell.
When considering the above, it is not counterintuitive but entirely consistent with the design and operation of the software.
However, from a UX experience this may seem counterintuitive simply because it defies your expectation. This is kind of like a "customer is always right" type situation, which can be very frustrating for programmers, but is essential that it be understood. You can read more about the concept in a series of well-written articles on the topic at https://www.joelonsoftware.com/2000/04/10/controlling-your-environment-makes-you-happy/ (disclosure: the author of these articles happens to be integral to the development history of both Excel and SO, but it is linked here on merit). It was written more than 20 years ago and is still every bit as relevant today.
I have created a spreadsheet which uses the Worksheet_Change feature and the code associated with that works very well. I can stop it firing unnecessarily when inside the module by using Application.EnableEvents = False.
However, while I've created a form to enter data directly into the next available row (again, that works fine in terms of entry) it doesn't cause the formulae in the sheet to calculate (even though auto calculation is on and re-enabled within the module). If I manually place my cursor in the row, hit F2 and simply press enter, everything then fires up.
I have tried to enter data directly into the cells, but of course the Worksheet_Change feature then kicks in again and the cursor isn't simply moving to the next adjacent cell ....
I've tried to check firs for any direct entry with the code below and if it looks like the user isn't entering directly into the cell, the Worksheet_Change is disabled:
Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo eventhandler
Sheets(1).Range("a1").Select
LastCell2 = Sheets(1).Cells(Rows.Count, "A").End(xlUp).Row
Dim intersection As Range
Set intersection = Intersect(Target, Range("A3:F" & LastCell2))
If intersection.Row = LastCell + 1 Then
Exit Sub
End If
Application.EnableEvents = False
The code above is simply checking to see if data is being entered into the next empty cell and if that's the case I want it to just exit there but it isn't working.
So I actually have 2 problems :
the first is why this formula isn't triggering after entry via a vba form - I've used INDIRECT since there are other macros that delete rows by moving the remaining cells up and that was causing the count in the $A$3:$A$500 to reduce to $A$499 and then 498 etc - the addition is done depending on the system date and the transaction date so I get a current value and a future value using a standard sum statement:
=AD1-(SUMIF(INDIRECT("$A$3:$A$500"),"<="&TODAY(),INDIRECT("$E$3:$E$500")))+(SUMIF(INDIRECT("$A$3:$A$500"),"<="&TODAY(),INDIRECT("$F$3:$F$500")))
The second is why I can't enter data directly into the spreadsheet and trap the fact that I don't want it to do anything and simply allow the user to hit enter and move to the next adjacent cell to the one they just entered data into.
Is this a lost cause and am I trying to do too much here? I'm relatively new to coding and teaching myself so apologies if the standard and style isn't to everyone's taste.
Thanks in advance for any replies.
I have the following code to simulate some cells behave like buttons
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Application.ScreenUpdating = False
If Target.Cells.Count = 1 Then
'~~~~~~ pseudocode ~~~~~~
If {select cell is one of the chose ones}
{do some stuff}
End If
'~~~~~~ pseudocode ~~~~~~
End If
Range("A1").Select
'Application.ScreenUpdating = True
End Sub
It doesn't matter whereas I use the ScreenUpdating code, the "Selection box" is flying around from A1 to the selected cell and back and it make the sheet much slower.
Can this flying (animation) selection box be stoped?
So far I have found this, not possible to hide, but noting about the flying efect:
Hide the cell selection box in Excel
Edit:
I need (I think so) edit capabilities on the sheet, therefore the option of not changing selection cell is not applicable. Due to:
most of the sheet is informative, and should be available for copy (not edited)
some cells are input forms (free text thing), selection as usual
some cells should behave like buttons (plus/minus for a numeric value, sclaes, simple stuff, but thousand of then, so much easier do/maintain by code), and user must not edit them
grouping should be available, (so that's complicate protecting the sheet)
I am not closed to the option : Range("A1").Select after each (most) of user interaction, but no other method comes into mind to me now.
An example:
I know some would say: "you should make this out from excel", and I agree with you, but this is a mandatory thing, I do not have the power to raise this question
As you can see, I got the "flying selection" that I try to get rid off
cell A1 is already hodden, that will do most of the trick
final version sure will go with hidden gridlines and headlines
rows groups exist, and are important, so no protection possible
all the functionality, I can do easy with vba, just problem with the animation
Maybe this is not the answer that you have been waiting for, but as Mathieu mentioned in his comment, please try to avoid using Selection.
It does make things slower and often causes errors (in example try selecting cell from hidden sheet). Instead just do something with the range that you define with your if statements directly. Every property of Cell or Range can be accessed directly.
Hope it helps.
Not sure how you can achieve you "flying select box" problem, but at least you could add this code, so opening/closing groups are available on protected sheets:
'Password Protect Current Sheet
ActiveSheet.Protect Password:="Add_here_your_password", UserInterfaceOnly:=True
'Enable Group Collapse/Expand Capabilities
ActiveSheet.EnableOutlining = True
How about trying to remove the "back to A1" as much as possible?
Maybe do it only on absolutely necessary, or move back to the changed value (the 33 in your example), or to the question title (in your multi-option example)
Background Details
I have an excel spreadsheet with Activex dropdown (combobox) objects which help the user to know what options are available. I did this because the data validation list dropdowns are way too small in font size, and were gathering a lot of complaints.
So my solution was to add combobox objects which allow the user to select from a range of options. However, I have to link the comboboxes to a cell with the linkedcell property, so that both the user and various formulas can see what has been chosen. I also set up the combobox to disappear when it's not in use (much in the same way as the data validation dropdown button only appears when you select the relevant cell).
Here is the problem:
I don't want the users to edit the value in the linked cell, so I make sure the linked cell is locked whenever the combobox is not selected:
Private Sub comboBox1_GotFocus()
Call unlockComboBoxTargetCell(comboBox1)
End Sub
the procedure above does this:
If (targetComboBox.LinkedCell <> "") Then
Dim targetCell As Variant
Set targetCell = Range(targetComboBox.LinkedCell)
If Not targetCell Is Nothing And targetCell.Locked <> False Then
unlockSheet (activesheet.Name)
targetCell.MergeArea.Locked = False
lockSheet (activesheet.Name)
End If
End If
Equivalent procedures exist to lock the target cell.
However, whenever you do a "Save As" action on the workbook, it seems that the linked and locked cells create a problem: Excel gives this error out of the blue:
"The cell or chart you are trying to change is protected and therefore read-only..."
This error comes up about twice or three times for each cell that is locked and is the linkedcell for a combobox.
Is there a good way to overcome this problem? Right now my best solution is to leave the cells unlocked and place data validation on the cell, so that if the user edits the cell they will at least be refused when they type something invalid. I could make sure that the combobox covers up the linked cell whenever it is selected, but sometimes that means having a very large, annoying combo box with a very tiny dropdown button on its right side.
Perhaps I am being a bit too particular about the user interface?
Thanks in advance for reading this long and involved post.
In the "lockSheet" procedure you have created, the code to 'protect' the worksheet needs an additional parameter, UserInterfaceOnly, set to true.
I imagine the LockSheet sub is something like this;
sub lockSheet(strSheetName as string)
thisworkbook.sheets(strSheetName).Protect
end sub
Try this:
sub lockSheet(strSheetName as string)
thisworkbook.sheets(strSheetName).Protect, UserInterfaceOnly=True
end sub
UserInterfaceOnly allows programmatic changes to the protected sheet.
Bill