1

ユーザーが特定のフィールドを変更するのを止めようとしています。ただし、それらのフィールドがどの列に含まれるかはわかりません。最初に含まれる値のみです。

私の現在のアプローチはこれです:

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)    
    Dim columnHeaderRange As Range
Set shtData = Worksheets("Data")     
Set columnHeaderRange = Union(shtData.Columns(ColumnNumber(5, "example1")), _
                         shtData.Columns(ColumnNumber(5, "example2")), _
                         shtData.Columns(ColumnNumber(5, "example3")))    
Set columnHeaderRange = Application.Intersect(Target, columnHeaderRange)    
    ElseIf Not (columnHeaderRange Is Nothing) Then    
    With Application
        .EnableEvents = False
        .Undo
        MsgBox "Change is not possible.", 16
        .EnableEvents = True
    End With          
Else
    Exit Sub
End If

上記のコードの私の ColumnNumber 関数は、行とフィールドの値をパラメーターとして受け取り、列番号を返します。ただし、固定フィールド値を使用しているため、フィールドが変更されていると失敗し、ユニオン呼び出しが失敗します。

ユーザーがセルの値を変更しようとしたときに、セルの実際の値が変更される前にこのコードを実行する方法はありますか? あるいは、誰かがより良いアプローチを提案できますか?

4

2 に答える 2

2

私のコメントに加えて

例 1

List値を保存するというシートを作成します。この方法の最も良い点は、リストから項目を追加/削除するたびにコードを修正する必要がないことです。

スクリーンショットを見る

ここに画像の説明を入力

そして、これがあなたのメインシートだとしましょう

ここに画像の説明を入力

このコードをシート コード エリアに貼り付けます

Dim rngList As Range, aCell As Range
Dim RowAr() As Long

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim i As Long

    On Error GoTo Whoa

    Application.EnableEvents = False

    For Each aCell In Target
        If aCell.Row = 5 Then
            With Application
                For i = LBound(RowAr) To UBound(RowAr)
                    If RowAr(i) = aCell.Column Then
                        MsgBox "Change is not possible."
                        .Undo
                        GoTo Letscontinue
                    End If
                Next
            End With
        End If
    Next

Letscontinue:
    Application.EnableEvents = True
    Exit Sub
Whoa:
    MsgBox Err.Description
    Resume Letscontinue
End Sub

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Dim wsList As Worksheet
    Dim n As Long, lrow As Long

    Set wsList = ThisWorkbook.Sheets("list")

    With wsList
        lrow = .Range("A" & .Rows.Count).End(xlUp).Row
        Set rngList = .Range("A1:A" & lrow)
    End With

    n = 0
    ReDim RowAr(n)

    For Each aCell In Range("5:5")
        If Len(Trim(aCell.Value)) <> 0 Then
            If Application.WorksheetFunction.CountIf(rngList, aCell.Value) > 0 Then
                n = n + 1
                ReDim Preserve RowAr(n)
                RowAr(n) = aCell.Column
                Debug.Print aCell.Column
            End If
        End If
    Next
End Sub

ここに画像の説明を入力

コードの実行

ここに画像の説明を入力

例 2

これは、ハードコードされたリストを使用します。

Option Explicit

Dim RowAr() As Long, aCell As Range

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Dim MyList As String, MyAr() As String
    Dim n As Long, i As Long

    '~~> This is the list
    MyList = "Header 1,Header 2"
    MyAr = Split(MyList, ",")

    n = 0
    ReDim RowAr(n)

    For Each aCell In Range("5:5")
        If Len(Trim(aCell.Value)) <> 0 Then
            For i = LBound(MyAr) To UBound(MyAr)
                If aCell.Value = MyAr(i) Then
                    n = n + 1
                    ReDim Preserve RowAr(n)
                    RowAr(n) = aCell.Column
                End If
            Next
        End If
    Next
End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
    Dim i As Long

    On Error GoTo Whoa

    Application.EnableEvents = False

    For Each aCell In Target
        If aCell.Row = 5 Then
            With Application
                For i = LBound(RowAr) To UBound(RowAr)
                    If RowAr(i) = aCell.Column Then
                        MsgBox "Change is not possible."
                        .Undo
                        GoTo Letscontinue
                    End If
                Next
            End With
        End If
    Next

Letscontinue:
    Application.EnableEvents = True
    Exit Sub
Whoa:
    MsgBox Err.Description
    Resume Letscontinue
End Sub
于 2013-04-18T09:34:09.887 に答える
1

数式がセル内のユーザーに表示されないようにする場合は、非表示にチェックを入れることもできます。

VBA ソリューション

2 段階のスクリプトを使用できます。

  1. 最初の段階では、そのシートに変更が加えられた後、および段階 2 が実行された後に、参照用にシートのコピーを (非表示の) シートに保存します。

  2. Worksheet_Change(Target) のスクリプトを作成します。このスクリプトは、ワークTargetシート コピーのターゲット範囲内のすべてのセルの行/列座標を検索して、範囲に元々特別な値の 1 つが含まれていたかどうかを確認します。特別な値が含まれている場合は、その値をシート コピーから戻すだけです。これは主に、すでに持っているスクリプトです...

ワークシート保護ソリューション

ワークシートの保護 ( [レビュー] > [シートの保護] ) を使用して、ユーザーが変更できるセルのみの保護を解除することを検討しましたか? そうすれば、追加のコーディングなしでこれを制御できます...おそらく、これらのセルがどこにあるかには、事前に使用できるいくつかのロジックがありますか? または、スクリプトによる各変更の後、VBA スクリプトを実行してそれらの値を持つすべてのセルを検索し、ロックされたプロパティ = を設定してTrueから、ワークシート保護を再度適用します。

個々のセルまたは範囲の保護ロックを手動で設定するには、右クリック > セルの書式設定 > 保護 >ロックの横のボックスにチェックを入れます

于 2013-04-18T08:19:00.597 に答える