【发布时间】:2016-03-15 00:22:40
【问题描述】:
这可能类似于this question,但我相信它在复杂性方面更进了一步,这就是我问它的原因。
上下文:我正在构建一个预算电子表格,可以在表格中创建和删除行。在工作表中,我有两张桌子。一个包含基于类别的总计,而另一个表包含用户可以输入以填充另一个表中的总计的事务。我保护了工作表以防止用户破坏公式,并且只有他们应该编辑的单元格(即输入值)不受保护。我还有用于插入和删除表格上的一行或多行的宏(我对宏进行了编码以在宏运行完成之前和之后取消保护/保护工作表)。
问题:我的问题涉及first table。在该表中,我想确保不能删除“存款”行。问题是,在我的代码中,如何确保用户可以删除另一个包含“存款”的表中的所有其他行,同时防止删除该表中的“存款”行?我正在考虑以下伪代码,但请随时提出其他建议:
'If selected range contains cells in Column A
'and cell in selected range = Deposits
'Then pop error message
'Exit Sub
这是我的删除宏的代码
Sub DeleteRow()
'
' DeleteRow Macro
'
' Keyboard Shortcut: Ctrl+Shift+D
'
Dim loTtest As ListObject
Dim loSet As ListObject
Dim c As Range
Dim arrRows() As Variant
Dim arrTemp() As Variant
Dim xFind As Variant
Dim iCnt As Long
Dim sMsg As String
ActiveSheet.Unprotect Password:="PYS"
Erase arrRows()
iCnt = 1
For Each c In Selection.Cells
If Not c.ListObject Is Nothing Then
If loSet Is Nothing Then
Set loSet = c.ListObject
Else
If c.ListObject <> loSet Then
'different table
MsgBox "You have more than one table selected.", vbInformation, "ERROR!"
ActiveSheet.Protect Password:="PYS"
GoTo MyExit
End If
End If
If iCnt = 1 Then
ReDim arrRows(1 To iCnt)
arrRows(iCnt) = c.Row - loSet.HeaderRowRange.Row
iCnt = iCnt + 1
Else
On Error Resume Next
xFind = 0
xFind = WorksheetFunction.Match(c.Row - loSet.HeaderRowRange.Row, arrRows(), 0)
If xFind = 0 Then
ReDim Preserve arrRows(1 To iCnt)
arrRows(iCnt) = c.Row - loSet.HeaderRowRange.Row
iCnt = iCnt + 1
End If
Err.Clear
On Error GoTo 0
End If
Else
'a cell is not in a table
MsgBox "Your selection is all or partially outside of a table.", vbInformation, "ERROR!"
ActiveSheet.Protect Password:="PYS"
GoTo MyExit
End If
Next c
Call SortArray(arrRows())
sMsg = "Are you sure you want to delete " & UBound(arrRows) & " rows from from this table?"
If MsgBox(sMsg, vbYesNo + vbDefaultButton2, "CONTINUE?") <> vbYes Then
ActiveSheet.Protect Password:="PYS"
Exit Sub
End If
For iCnt = UBound(arrRows) To LBound(arrRows) Step -1
loSet.ListRows(arrRows(iCnt)).Delete
Next iCnt
ActiveSheet.Protect Password:="PYS"
Exit Sub
MyExit:
End Sub
Sub SortArray(MyArray() As Variant)
Dim iStart As Long
Dim iEnd As Long
Dim iStep As Long
Dim iMove As Long
Dim vTemp As Variant
iStart = LBound(MyArray)
iEnd = UBound(MyArray)
For iStep = iStart To iEnd - 1
For iMove = iStep + 1 To iEnd
If MyArray(iStep) > MyArray(iMove) Then
vTemp = MyArray(iMove)
MyArray(iMove) = MyArray(iStep)
MyArray(iStep) = vTemp
End If
Next iMove
Next iStep
End Sub
顺便说一句,这一切都不是我自己想出来的;我把大部分代码都拼凑了起来。 :) 如果您需要更多信息或上下文,请告诉我。提前致谢!
【问题讨论】:
-
上传示例工作簿会很有帮助。一个有用的建议是在使用受保护的工作表时使用 Workbook_Open 事件,该事件将遍历工作表并在将 UserInterfaceOnly 参数设置为 true 的情况下保护它们打开。这允许 vba 对受保护的工作表进行更改,而无需每次都取消保护和保护工作表,但仍会阻止用户进行编辑。这是一个示例语法
wbTCT.Sheets(i).Protect Password:="?CSandM!|", UserInterfaceOnly:=True循环是For i = 1 to thisworkbook.sheets.count Next i -
请删除“宏”标签,它在 StackOverflow 上用于其他内容。
-
只是为了您的考虑,我想指出 Excel 仅提供非常有限的安全性(如果有的话)。请注意,您选择的任何安全性仅与执行它的软件一样好。如果您使用 Microsoft Excel 打开 Excel 文件,则所有安全机制都将按预期实施。但是还有许多其他程序不这样做。还要考虑到并非所有计算机都运行宏。对于较新的 Excel 版本,大多数未签名的宏实际上都被阻止了(除非您按下按钮来启用它们)。
-
使用LibreOffice 打开 Excel 文件甚至可以让您在没有密码保护的情况下查看 VBA 代码(允许用户查看代码中的密码)。我想说的是,如果您允许某人打开它,Excel 只会为您的数据提供非常有限的安全性。如果您确实需要保护您的数据,您可能需要选择使用 SQL 后端。
-
感谢@Ralph,我并不真正关心人们查看密码以解除对单元格的保护,因为大多数普通用户无论如何都不知道该怎么做。密码保护只是为了防止用户破坏公式,而不是提高安全性。我还打算编写一个简单的用户指南,其中包括需要在此预算上启用宏才能使其工作。我意识到宏可能并不适合所有人,但这是我能做的最好的。