Prevent user from inserting row in table except using VBA - excel

I've created a table for data entering. However, as user use it, they insert rows in the middle of the table. That messes the formula up as the functions were designed only work forward. Also sometimes when the user add row manually (just by typing into the next row after the last row of the table), the function were filled automatically but the function is incorrect quite often.
So I added a button to add the rows to the table and that works without problems. Now I want to disable the ability for user to add rows manually, meaning rows can ONLY be added via clicking the button.
As far as I research, people all suggesting using protect sheet functionality. But it would remove all ability to add rows including via VBA. Other offer the VBA that only prevent inserting rows via right click at the Rows Column. I need to disable all user-accessible ways.
This is the code for the button (if it's of any relevant).
Sub InsertRow_Click()
Dim i As Integer
For i = 1 To 10
ActiveSheet.ListObjects("Invoice").ListRows.Add alwaysinsert:=True
Next i
End Sub

When using sheet protection, you could add Userinterfaceonly= true, this will prevent user interference, but VBA code will still work.
Private Sub Workbook_Open()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Protect Password:="secret", UserInterFaceOnly:=True
Next ws
End Sub
or if you want to protect just one sheet:
Private Sub Workbook_Open()
Worksheets("YourSheetName").Protect Password:="secret", UserInterFaceOnly:=True End Sub
Or just take protection off before running your macro and put it on afterwards:
Sub InsertRow_Click()
ActiveSheet.Unprotect Password:="secret"
Dim i As Integer
For i = 1 To 10
ActiveSheet.ListObjects("Invoice").ListRows.Add alwaysinsert:=True
Next i
ActiveSheet.protect Password:="secret"
End Sub
Userinterfaceonly and tables looks if it's no good match

Related

Excel using auto-generated hyperlinks to hide rows in a table

I have a table where I want to be able to hide individual rows at a mouse click. The (seemingly) easiest solution I've found is to have a column filled with hyperlinks that call a macro to hide the row that they're in.
There are two ways of calling macros from hyperlinks: using Worksheet_FollowHyperlink with manual hyperlinks, and using =HYPERLINK.
The former works fine, except there's no way (that I've found) to have them generate automatically when new rows are added to the table. I would have to either manually copy them down every time, which is unviable, or add them with VBA, which adds a bunch of complexity to an otherwise simple task.
The latter generates fine, being a formula, but it doesn't actually work. It doesn't trigger Worksheet_FollowHyperlink, and when using =HYPERLINK("#MyFunction()") it just doesn't hide rows (or do much other than editing cells contents).
Function MyFunction()
Set MyFunction = Selection
Selection.EntireRow.Hidden = True
End Function
Is there a good solution to this?
Rather than a Hyperlink, you could handle a Double Click event on the table column
Something like
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
Dim NameOfTableColumn As String
On Error GoTo EH:
NameOfTableColumn = "DblClickToHide" ' update to suit your table
If Not Application.Intersect(Target, Target.ListObject.ListColumns(NameOfTableColumn).DataBodyRange) Is Nothing Then
Target.EntireRow.Hidden = True
Cancel = True
End If
Exit Sub
EH:
End Sub
Please, copy the next code in the sheet code module where the table to be clicked exists. Clicking on each cell in its first column (dynamic to rows adding/insertions/deletions), the clicked row will be hidden:
Option Explicit
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim tbl As ListObject
If Target.cells.CountLarge > 1 Then Exit Sub
Set tbl = Me.ListObjects(1) 'you may use here the table name
If Not Intersect(Target, tbl.DataBodyRange.Columns(1)) Is Nothing Then
Application.EnableEvents = False
Target.EntireRow.Hidden = True
Application.EnableEvents = True
End If
End Sub
It would be good to think about a way to unhide the hidden row if/when necessary. If only a row should be hidden at a time, it is easy to unhide all the rest of column cells...

How to block cells when file opens?

I have some formulas set via vba to change the value in columns H, J, K, L and N. Those changes are based on G column value and a Submit button, this works fine.
When I do the process to lock them to avoid the user from editing, that says to unlock the whole sheet then lock the ones I need, after this I modify the G column and get:
"Autofit Method of Range Class Failed".
I use it on H column.
This get highlighted:
Sheet1.Range("H11:H50").Rows.EntireRow.AutoFit
You are trying to change protected cells using VBA while the protection is on. You can work around this various ways, however, the most simple solution is something like the following:
Sub Example()
Sheet1.Unprotect "YOURPASSWORD" 'if no password was used, you don't need to include it
Sheet1.Range("H11:H50").Rows.EntireRow.AutoFit
Sheet1.Protect "YOURPASSWORD"
End Sub
Alternative solution:
By using this in the on open procedure of your workbook. VBA can make changes on locked cells, but users can not.
One Caveat: if an error occurs in the code, this will reset and you need to close and reopen the worksheet in order for this to function again
Private Sub Workbook_Open()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Protect UserInterfaceOnly:=True
Next ws
End Sub

Excel VBA - random runtime errors

I’m very new to Excel VBA but managed to create three buttons in a staff timesheet. All buttons work as needed, however, one particular button is causing random issues – about 90% of the time it works, but from time to time it will crash Excel or give an error such as runtime error '-2147417848 (800 10 108)': Automation error The object invoked has disconnected from its clients. Other times it’s a similar message, saying Method ‘Insert’ of object ‘Range’ failed.
It’s happening in different versions of Excel on different computers. The task is not complex but I’m stumbling with my VBA knowledge.
The user clicks the button to set up each formatted row in the sheet called “Timesheet”, i.e. clicking the button in “Timesheet” copies a row from sheet4 (formatted and containing formulae) and inserts it into the “Timesheet” above the button.
I’d be very grateful if someone could suggest alternative code that won’t crash Excel - many thanks in advance!
Sub NewSlot()
' NewSlot Macro used in Timesheet
'
'turn protection off
Worksheets("Sheet4").Unprotect Password:="mypasswd"
Worksheets("Timesheet").Unprotect Password:=" mypasswd "
' select row 8 in sheet4
Sheets("Sheet4").Select
Rows("8").Select
Selection.Copy
' go back to timesheet
Sheets("Timesheet").Select
' insert copied row
Dim r As Range
Set r = ActiveSheet.Buttons(Application.Caller).TopLeftCell
Range(Cells(r.Row, r.Column), Cells(r.Row, r.Column)).Offset(0, 0).Select
Selection.Insert shift:=xlDown
Application.CutCopyMode = False
'turn protection on
Worksheets("Sheet4").Protect Password:=" mypasswd "
Worksheets("Timesheet").Protect Password:=" mypasswd"
End Sub
If you are going to use VBA to repeatedly modify a protected worksheet, unprotect it then protect it once with UserInterfaceOnly:=True.
sub protectOnce()
worksheets("Timesheet").unprotect password:="mypasswd"
worksheets("sheet4").unprotect password:="mypasswd"
worksheets("Timesheet").protect password:="mypasswd", UserInterfaceOnly:=True
worksheets("sheet4").protect password:="mypasswd", UserInterfaceOnly:=True
end sub
After that has been done once you will not have to unprotect to modify with VBA. If you have to unprotect it for another reason, reprotect it with with UserInterfaceOnly:=True.
This cuts your NewSlot code down significantly. It is considered 'best practise' to avoid using Select and Activate, particularly across worksheets.
Sub NewSlot()
' select row 8 in sheet4
workSheets("Sheet4").Rows("8").Copy
' go back to timesheet
with workSheets("Timesheet")
' insert copied row
Dim r As Range
Set r = .Buttons(Application.Caller).TopLeftCell
.Cells(r.Row, "A").entirerow.Insert shift:=xlDown
end with
End Sub

VBA Macro To Select Same Cell on all Worksheets

I'm somewhat newer to VBA, and this particular action seems like it may be out of my current scope of knowledge.
Is there a way to code VBA to have it actively select the same cell on all worksheets as the current cell selected? I have a model I've put together to allow my team to enter data simultaneously regarding product SKUs in Column A on Sheet1, but due to the large amount of information that we enter per item, I used multiple sheets
For example, if I have cell H4 selected on Sheet1, is it possible to have all other sheets active cell H4 upon switching to the other worksheets?
This is what I've come up with so far on a test workbook, but it does not seem to work:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Select Case LCase(Sh.Name)
Case Is = "sheet1", "sheet2", "sheet3"
If CurRow > 0 Then
With Application
.EnableEvents = False
.Goto Sh.Cells(CurRow, CurCol), Scroll:=True
Sh.Range(ActCellAddr).Select
.EnableEvents = True
End With
End If
End Select
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
Select Case LCase(Sh.Name)
Case Is = "sheet1", "sheet2", "sheet3"
CurRow = ActiveWindow.ScrollRow
CurCol = ActiveWindow.ScrollColumn
ActCellAddr = ActiveCell.Address
End Select
End Sub
I've located this code below:
Excel VBA code to allow the user to choose the same cell on every sheet
But this requires the user actually enter the cell they'd like to have selected. I am looking for it to be automatic.
Any tips or suggestions? Any help is greatly appreciated.
You can post the following to every sheet in your workbook.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Set CurrWS = ActiveSheet
For Each WS In ThisWorkbook.Worksheets
WS.Activate
WS.Range(Target.Address).Select
Next
CurrWS.Activate
End Sub
Every time you select a cell, it will cycle through all the worksheets and select the same cell there. The downside to this is obvious: if you have too many sheets, it's going to be tedious. The other problem is that it's going to cycle through everything. So it might mess up some other sheets if you're going to use this for data entry.
Otherwise, if it's just selecting the cell, then this is harmless though the flicker can be noticeable at times, based on how many sheets you have.
Not as elegant as one would want, but it works. Good luck and let us know if this helps.
Worth noting there is a workbook-level event handler which handles the same event, so you only need to add the code once to the ThisWorkbook code module:
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, _
ByVal Target As Range)
Sh represents the ActiveSheet.
Probably also worth disabling events while you're selecting the ranges on the other sheets, or that will re-trigger your event handler (don't forget to turn event handling back on before exiting your code!)
This approach will test for hidden sheets. It selects all non-hidden sheets, selects the target cell then returns to the original sheet. It works pretty fast even if you have many many tabs.
targetcell = ActiveCell.Address
OriginSheet = ActiveSheet.Name
Dim ws As Worksheet
For Each ws In Sheets
If ws.Visible = True Then ws.Select (False)
Next ws
range(targetcell).Select
Sheets(OriginSheet).Select

How to lock specific cells but allow filtering and sorting

I'm using the following code to lock the content of certain cells
Sub LockCell(ws As Worksheet, strCellRng As String)
With ws
.Unprotect
.Cells.Locked = False
.Range(strCellRng).Locked = True
.Protect Contents:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, AllowFormattingRows:=True, AllowInsertingColumns:=True, AllowInsertingRows:=True, AllowSorting:=True, AllowFiltering:=True, AllowUsingPivotTables:=True, DrawingObjects:=True
End With
End Sub
It locks the content of those specific columns. The problem is users cannot sort, neither filter, nor apply borders to the cells since those Excel menu items are disabled.
I thought the AllowSorting:=True, AllowFiltering:=True and DrawingObjects:=True would allow that the same way the AllowFormattingColumns:=True and AllowFormattingRows:=True allowed resizing.
There are a number of people with this difficulty. The prevailing answer is that you can't protect content from editing while allowing unhindered sorting. Your options are:
1) Allow editing and sorting :(
2) Apply protection and create buttons with code to sort using VBA. There are other posts explaining how to do this. I think there are two methods, either (1) get the code to unprotect the sheet, apply the sort, then re-protect the sheet, or (2) have the sheet protected using UserInterfaceOnly:=True.
3) Lorie's answer which does not allow users to select cells (https://stackoverflow.com/a/15390698/269953)
4) One solution that I haven't seen discussed is using VBA to provide some basic protection. For example, detect and revert changes using Worksheet_Change. It's far from an ideal solution however.
5) You could keep the sheet protected when the user is selecting the data and unprotected when the user has the header is selected. This leaves countless ways the users could mess up the data while also causing some usability issues, but at least reduces the odds of pesky co-workers thoughtlessly making unwanted changes.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If (Target.row = HEADER_ROW) Then
wsMainTable.Unprotect Password:=PROTECTION_PASSWORD
Else
wsMainTable.Protect Password:=PROTECTION_PASSWORD, UserInterfaceOnly:=True
End If
End Sub
This was a major problem for me and I found the following link with a relatively simple answer. Thanks Voyager!!!
Note that I named the range I wanted others to be able to sort
Unprotect worksheet
Go to "Protection"--- "Allow Users to Edit Ranges" (if Excel 2007, "Review" tab)
Add "New" range
Select the range you want allow users to sort
Click "Protect Sheet"
This time, *do not allow users to select "locked cells"**
OK
http://answers.yahoo.com/question/index?qid=20090419000032AAs5VRR
I just came up with a tricky way to get almost the same functionality. Instead of protecting the sheet the normal way, use an event handler to undo anything the user tries to do.
Add the following to the worksheet's module:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Locked = True Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
End If
End Sub
If the user does anything to change a cell that's locked, the action will get immediately undone. The temporary disabling of events is to keep the undoing itself from triggering this event, resulting in an infinite loop.
Sorting and filtering do not trigger the Change event, so those functions remain enabled.
Note that this solution prevents changing or clearing cell contents, but does not prevent changing formats. A determined user could get around it by simply setting the cells to be unlocked.
Here is an article that explains the problem and solution with alot more detail:
Sorting Locked Cells in Protected Worksheets
The thing to understand is that the purpose of locking cells is to prevent them from being changed, and sorting permanently changes cell values. You can write a macro, but a much better solution is to use the "Allow Users to Edit Ranges" feature. This makes the cells editable so sorting can work, but because the cells are still technically locked you can prevent users from selecting them.
I know this is super old, but comes up whenever I google this issue. You can unprotect the range as given in the above cells and then add data validation to the unprotected cells to reference something outrageous like "423fdgfdsg3254fer" and then if users try to edit any those cells, they will be unable to, but you're sorting and filtering will now work.
Lorie's answer is good, but if a user selects a range that contains locked and unlocked cells, the data in the locked/protected cells can be deleted.
Isaac's answer is great, but doesn't work if the user highlights a range that has both locked and unlocked cells.
I modified Isaac's code a bit to undo changes if ANY of the cells in the target range are locked. It also displays a message explaining why the action was undone. Combined with Lorie's answer, I was able to achieve the desired result of being able to sort/filter a protected sheet, while still allowing a user to make changes to an unprotected cell.
Follow the instructions in Lorie's answer, then put the following code in the worksheet module:
Private Sub Worksheet_Change(ByVal Target As Range)
For Each i In Target
If i.Locked = True Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
MsgBox "Your action was undone because it made changes to a locked cell.", , "Action Undone"
Exit For
End If
Next i
End Sub
If the autofiltering is part of a subroutine operation, you could use
BioSum.Unprotect "letmein"
'<Your function here>
BioSum.Cells(1, 1).Activate
BioSum.Protect "letmein"
to momentarily unprotect the sheet, filter the cells, and reprotect afterwards.
This is a very old, but still very useful thread. I came here recently with the same issue. I suggest protecting the sheet when appropriate and unprotecting it when the filter row (eg Row 1) is selected. My solution doesn't use password protection - I don't need it (its a safeguard, not a security feature). I can't find an event handler that recognizes selection of a filter button - so I gave the instruction to my users to first select the filter cell then click the filter button. Here's what I advocate, (I only change protection if it needs to be changed, that may or may not save time - I don't know, but it "feels" right):
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Const FilterRow = 1
Dim c As Range
Dim NotFilterRow As Boolean
Dim oldstate As Boolean
Dim ws As Worksheet
Set ws = ActiveSheet
oldstate = ws.ProtectContents
NotFilterRow = False
For Each c In Target.Cells
NotFilterRow = c.Row <> FilterRow
If NotFilterRow Then Exit For
Next c
If NotFilterRow <> oldstate Then
If NotFilterRow Then
ws.Protect
Else
ws.Unprotect
End If
End If
Set ws = Nothing
End Sub
In Excel 2007, unlock the cells that you want enter your data into. Go to Review
> Protect Sheet
> Select Locked Cells (already selected)
> Select unlocked Cells (already selected)
> (and either) select Sort (or) Auto Filter
No VB required
I had a simular problem. I wanted the user to be able to filter "Table3" in a
protected worksheet. But the user is not able to edit the table. I accomplished above,
using the vba code below:
Range("Table3").Select
Selection.Locked = True
Selection.FormulaHidden = False
ActiveSheet.Protect DrawingObjects:=True, Contents:=True, Scenarios:=True _
, allowfiltering:=True
In the following code I filtered the code using VBA:
Range("Table3[[#Headers],[Aantal4]]").Select
ActiveSheet.ListObjects("Table3").Range.AutoFilter Field:=8, Criteria1:= _
Array("1", "12", "2", "24", "4", "6"), Operator:=xlFilterValues

Resources