I have a problem concerning Pivot Tables. If you create a Pivot Table where you drag some variables to "Rows" and some to "Values", then it is not possible to change any of data concerning the values column. For example, if I try to change the value of "Average of Final Product Value" to something else I am thrown an error:
However, it is possible to change any of the data in the Row Labels but it is not possible to delete it completely. For an example, I changed "Cheeku" to "a".
Is there any way to make sure that you can't change the Row Labels in Excel? I made some VBA which does the job, i.e. it looks at a certain range and then by using Worksheet_Change I can undo what was just done. However, I would like to just do it in Excel - if it is possible. My code is
Sub Worksheet_Change(ByVal Target As Range)
Dim WatchRange As Range
Dim IntersectRange As Range
Dim nRow As Integer
Dim temp As Variant
With Sheets("Sektor")
nRow = .Cells(21, 1).End(xlDown).row
End With
Set WatchRange = Range("A21:D" & nRow)
Set IntersectRange = Intersect(Target, WatchRange)
If IntersectRange Is Nothing Then
'Do Nothing Spectacular
Else
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
End If
End Sub
To do it in Excel I tried to lock the rows, which did not work. Any suggestions?
Normally you can edit the name of the column headers in your pivot table.
I see that you have the yellow bar at the top. I don't speak the language but I assume that it's the usual yellow bar that appears when you can't edit the file and you actually have to press the button to go in "Edit mode".
Regarding stopping users from editing the row of the Pivot Table, your idea of locking the rows is correct.
The only issue is that you need to "Protect" the sheet for the locking to take effect.
Related
SETUP:
Start with a sheet that has 3 columns. "ID", "MyNote", "MyDate" headers. This sheet may have thousands of rows of data.
I need to "flag" any row where the user has made a change to anything on the row. In other code the flagged rows will be in turn be used to update a table on my SQL server.
Typically there will only be a few rows the user would change/update in a session. So I don't want to process every row in the sheet, particularly the ones with no changes.
WHAT I HAVE WORKING NOW:
I have done this successfully by writing a "x" to an additional "flag" column any time the user makes a change. Then later I can process any rows that were flagged with a "x" . I did this using:
Private Sub Worksheet_Change(ByVal Target As Range)
...
' Flag any lines with a change
If Not Intersect(Target, Me.Range(TestForChangeColRange)) Is Nothing Then
Application.EnableEvents = False
' Set the "Pending Write" Flag
Target.Worksheet.Range(PendingWriteCol & Target.Row).Value = "x"
Application.EnableEvents = True
...
PROBLEM:
That works great for individual cells being updated one at a time. The problem comes when a user either a) uses the drag and copy (drag the bottom right corner of a cell to replicate it where dragged), or b) with a paste from some other workbook, in either case more than one cell is changed at a time.
In those cases, the Worksheet_Change sees only the first cell and not any extra cells edited by dragging or pasting.
I tried to find other similar solutions for intercepting Copy/Paste, etc., but I can't see anyway to find that if a copy was made, which cells were affected.
NEED:
All I need to know is which row numbers were affected from a drag or a copy/paste. If I can accurately flag those rows as updated, I'm in business.
FOLLOW-UP
Using Tim's solution. Having trouble melding something back into it.
Additionally I need to be able to check if a particular column was edited and if it was, clear a different column. For example, if Col 2 is edited, clear the contents of Col 3.
I tried adding the test inside the For loop, but my colno for rw.Col is coming out off.
If Not rng Is Nothing Then
'expand the range so we can flag by row, and not cell-by-cell
Set rng = Application.Intersect(rng.EntireRow, rngTbl)
For Each rw In rng.Rows 'loop over affected rows
Me.Cells(rw.Row, PendingWriteCol).Value = "x"
If rw.Column = RequestTypeCol Then
Me.Cells(rw.Row, LastColToClear).ClearContents
End If
Next rw
End If
Can you show me what I've done wrong?
For example (following on from Scott's comment):
Private Sub Worksheet_Change(ByVal Target As Range)
Const PendingWriteCol As Long = 4
Const TestForChangeColRange = "A:C"
Dim rw As Range, rng As Range, rngTbl As Range
Set rngTbl = Me.Range(TestForChangeColRange)
Set rng = Application.Intersect(Target, rngTbl) 'any monitored cells affected?
If Not rng Is Nothing Then
'expand the range so we can flag by row, and not cell-by-cell
Set rng = Application.Intersect(rng.EntireRow, rngTbl)
For Each rw In rng.Rows 'loop over affected rows
Me.Cells(rw.Row, PendingWriteCol).Value = "x"
Next rw
End If
End Sub
I am working on a table in a spreadsheet that multiple users will be editing. We have had problems with people pasting over other entries accidentally or moving half of a row up several columns. I want to protect every cell with values in it, or alternatively allow every cell without values to be edited.
I have tried making the whole table editable, then locking the cells with values in it. This seemed to do nothing, as I was able to edit values anyway.
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Dim NewEditRange As Range
Dim ThisSheet As Worksheet
Dim DataTable As Range
Dim CurrentEditRange As AllowEditRange
Dim CurrentCell As Range
Set ThisSheet = ActiveWorkbook.Worksheets("Data")
Set DataTable = ThisSheet.Range("Table1")
Set NewEditRange = ThisSheet.Range("$A$1")
ThisSheet.Unprotect
For Each CurrentEditRange In ThisSheet.Protection.AllowEditRanges
CurrentEditRange.Delete
Next
For Each CurrentCell In DataTable
If CurrentCell.Value = "" Then
Set NewEditRange = Application.Union(NewEditRange, CurrentCell)
End If
If CurrentCell.Value = "0" Then
Set NewEditRange = Application.Union(NewEditRange, CurrentCell)
End If
Next
ThisSheet.Protection.AllowEditRanges.Add Title:="New Edit Range", Range:=NewEditRange
ThisSheet.Protect
End Sub
I expect this to unlock the sheet, delete all AllowEditRange objects, then add every blank cell in the table to the NewEditRange, then make a new AllowEditRange containing NewEditRange, then protect the sheet.
Instead it makes an AllowEditRange with the cells through row 14 or so, and I can still edit cells that are not in that range.
You should always use `Option Explicit
I have some doubt that Application.Union works on NewEditRange if it is still nothing. You should initialize it and may have to split the case of NewEditRange being nothing or not.
(Can't comment due to rep)
Okay, so it turns out the problem is that you can't protect cells in tables. Period. If you are interested in them adding this feature, go to https://excel.uservoice.com/forums/304921-excel-for-windows-desktop-application/suggestions/16452913-get-tables-working-on-protected-sheets-add-rows and vote.
I need to work on a range of cells that changes every day. I have decided that the best way to handle this might be to use an InputBox to get the range to work on. The macro massages the data and places it 1 column to the right of the range from the InputBox, but the data is not in adjacent cells (if that makes a difference.)
I would like to select the cells 1 column to the right of the selected range where the new data is located (this is the preferred solution) and format the new data. Or if I can't select the range, I could just select the entire column and then change the format of the entire column.
I can't figure out how to extract the range info to do the necessary math on it and then use it to change the format of the newly created data.
I have included a simplified sample of the problem area of the code.
I would appreciate your help with this.
Sub InputBox_Range_Test()
Dim rng As Range
Set rng = Application.InputBox(Prompt:=PromptString, Type:=8)
Debug.Print rng.Address
'
'*** Needs to select the range that is
'*** 1 column to the right of the input range
'
Columns(rng).Select
Selection.NumberFormat = "0.00%"
Range("I4").Select
End Sub
I finally figured it out. I was thinking about it the wrong way. I was trying to make it harder that it needed to be. I just had to use the offset property.
Here's what I came up with:
Private Sub CommandButton2_Click()
Dim rngTarget As Range
Set rngTarget = Application.InputBox(strPrompt, "Select the Range to work with", Type:=8)
Range(rngTarget.Address).Offset(, 1).Select
Selection.NumberFormat = "0.00%"
Range("P2").Select
End Sub
I can make one or the other of the below codes work, but need them both. The first locks cells in range upon data entry, the second inserts a date stamp when the final data entry in column D of each row is completed.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim xRg As Range
On Error Resume Next
Set xRg = Intersect(Range("A8:D5005"), Target)
If xRg Is Nothing Then Exit Sub
Target.Worksheet.Unprotect Password:="Midnight"
xRg.Locked = True
Target.Worksheet.Protect Password:="Midnight"
End Sub
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Set rng = Range("D8:D5005")
If Not Intersect(Target, rng) Is Nothing Then
Target.Offset(0, 1) = Now
Target.Offset.NumberFormat = "dd/mm/yyyy hh:mm:ss"
End If
End Sub
I'm still guessing a bit exactly what you're trying to do … but here is way to allow your users enter four data points ... and then to press button to add the data points to a protected list … and includes a time stamp.
First setup 4 data entry cells in A4 through to D4 by using the Format Cell option, make sure for these cells that Locked is unchecked on the Protection tab.
Next create a button and link the button to the following code:
Sub ButtonCode()
ActiveSheet.Unprotect Password:="A"
Range("A7:E7").Insert xlShiftDown
Range("A4:D4").Copy Range("A7:D7")
Range("E7") = Now()
Range("A7:E7").Interior.Color = rgbLightBlue
Range("A7:E7").Font.Color = rgbBlack
ActiveSheet.Protect Password:="A"
End Sub
As a once only step, protect the worksheet; my example consistently uses a password of "A". Note that your users will not need to enter the password at any time.
Once the sheet is setup, when the button is clicked, the code unlocks the sheet (allowing it to make edits), it move the existing data data down, copy the new data points to the top of the list, adds timestamp and some minimal formatting. It then re-enables protection so that the user can't overwrite the existing entries.
The screenshot below gives you an idea of what it might look like, including showing that A4:D4 need to be unlocked.
Maybe not the implementation direction you were thinking of … but the principles included in this example might work for you. All the best.
I'm not 100% sure of the structure of your worksheet, so here are the assumptions for my response. You only want the user to modify cells in the range "A8:D5005" … and somewhere on the sheet you want to record date/timestamp changes for cells changed.
So I would start by protecting the sheet by going to the Excel "Review" ribbon (not in VBA), and setting up an editable range as follows.
Before you close the dialog box, click on Protect Sheet so that the rest of the sheet is password protected.
Once you've done this … you can use something like the code below to record the date/timestamps. In this example … I record them in columns to the right of your editable range (given your editable data is only to Column D).
Private Sub Worksheet_Change(ByVal Target As Range)
Dim vIntersect As Variant
Set vIntersect = Application.Intersect(Target, Range("A8:D5005"))
If Not vIntersect Is Nothing Then
Application.EnableEvents = False
Target.Worksheet.Unprotect Password:="Midnight"
Target.Offset(0, 5) = Now
Target.Offset(0, 5).NumberFormat = "dd/mm/yyyy hh:mm:ss"
Target.Worksheet.Protect Password:="Midnight"
Application.EnableEvents = True
End If
End Sub
I have almost found the answer to this in previous post, but not quite.
The scenario is as follows.
Column A contains values, based on a drop down list.
When I change a value - on any row in column A - I want the current date to be written into to the corresponding row in column C. The date must not change when I save and re-open the file at a later point, i.e. the =TODAY() function won't do it.
The user might change a multiple values on different rows in column A before exiting and saving the file.
Thankful for any input.
Mårten.
This should meet your needs, paste this vba code into the Microsoft Excel Object for the worksheet you desire (so if this is for Sheet1, paste it into Sheet1):
Private Sub Worksheet_Change(ByVal Target As Range)
Dim controlRng, nRng As Range
'This will be the entire range of drop downs you have, I've set it to be the entire column A, if that's not suitable then change it to a set range
Set controlRng = Range("A:A")
Set nRng = Intersect(controlRng, Target)
If nRng Is Nothing Then Exit Sub
If Target.Value <> "" Then
Target.Offset(0, 2).Value = Now
End If
End Sub