Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


795 / 13645 ツリー ←次へ | 前へ→

【78254】貼り付け禁止のマクロ ささ 16/6/10(金) 16:34 質問[未読]
【78257】Re:貼り付け禁止のマクロ マナ 16/6/10(金) 21:02 発言[未読]
【78259】Re:貼り付け禁止のマクロ マナ 16/6/11(土) 22:59 発言[未読]
【78260】Re:貼り付け禁止のマクロ sy 16/6/12(日) 3:05 回答[未読]
【78261】Re:貼り付け禁止のマクロ マナ 16/6/12(日) 18:23 発言[未読]
【78262】Re:貼り付け禁止のマクロ sy 16/6/12(日) 21:16 発言[未読]

【78254】貼り付け禁止のマクロ
質問  ささ  - 16/6/10(金) 16:34 -

引用なし
パスワード
   いつもありがとうございます。

早速ですが、表題の通りのマクロを組みたいと考えています。
ネットで色々調べましたが意図する着地点へと到達できません。

現在は、単セルの貼り付け禁止まではできていますが、
結合したセルや複数のセルを選択した場合には
適応出来ていません。

どちらかというと、複数セルを選択した場合の貼付けを禁止としたいです。

現状は以下のとおりです。

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)

 Dim Ans As Integer

 If Target.Count = 1 Then
   If Application.CutCopyMode Then
     Ans = MsgBox("本当に貼り付けますか?", vbYesNo, "確認")
     If Ans = vbNo Then
       MsgBox "正しいデータを貼り付けてください"
       With Application
        .EnableEvents = False
        .Undo
        .EnableEvents = True
       End With
     End If
     Application.CutCopyMode = False
   End If
 End If
End Sub

よろしくお願いいたします。

【78257】Re:貼り付け禁止のマクロ
発言  マナ  - 16/6/10(金) 21:02 -

引用なし
パスワード
   ▼ささ さん:

> If Target.Count = 1 Then

この行の意味を教えて下さい

【78259】Re:貼り付け禁止のマクロ
発言  マナ  - 16/6/11(土) 22:59 -

引用なし
パスワード
   ▼ささ さん:

> If Target.Count = 1 Then

を見なおせば、

>結合したセルや複数のセルを選択した場合には
>適応出来ていません。

これは解決できるのですが
実際は、単セルの場合でも、気がついていないだけで、
貼り付けできちゃう可能性があります。

他板ですが、類似の質問がありましたので紹介します。
タイトルからは、全然関係なさそうに見えますが、そんなことありません。
わたしのおすすめは、syさんの回答です。
よろしければ試してみてください。

ht tp://www.excel.studio-kazu.jp/kw/20160611090857.html

【78260】Re:貼り付け禁止のマクロ
回答  sy  - 16/6/12(日) 3:05 -

引用なし
パスワード
   こんばんわ。

マナさんが言ってた案件はこちらですね。

> If Target.Count = 1 Then
に関してはマナさんのアドバイス通りと思います。

>   If Application.CutCopyMode Then
こちらの判定部分ですが、セルに貼り付けれるデータでCutCopyMode が有効になるのは、セルを選択した時だけです。
文字を直接選択してコピーした時や、他のアプリからのデータコピーには対応できません。
そう言うデータも禁止にするなら、以下のようにクリップボードの中にデータがあるかを判定した方が良いです。
    If Application.ClipboardFormats(1) > -1 Then

ただこちらの案件ではMsgBoxで貼付を選択するようになっているので、消去した時との区別が出来ないので、かなり難しいですね。
多少妥協してもらう部分はありますがIF分岐で考えてみました。

ThisWorkbookモジュールに以下を記述して下さい。

Private Declare Function OpenClipboard Lib "User32" (ByVal hwnd As Long) As Long
Private Declare Function CloseClipboard Lib "User32" () As Long
Private Declare Function EmptyClipboard Lib "User32" () As Long


Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
  Dim Ans As Integer, cb As Object, val As String

  Application.EnableEvents = False
  If Target.Address = Selection.Address Then
    If Application.ClipboardFormats(1) > -1 Then
      Set cb = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
      cb.GetFromClipboard
      val = cb.GetText
      If (Len(val) = 0 And Application.CutCopyMode = 0) Or _
          (Len(val) = 2 And Application.CutCopyMode > 0) Then
        Application.Undo
        OpenClipboard (0&)
        EmptyClipboard
        CloseClipboard
      Else
        If Not IsEmpty(Target.Value) Then
          Ans = MsgBox("本当に貼り付けますか?", vbYesNo, "確認")
          If Ans = vbNo Then
            MsgBox "正しいデータを貼り付けてください"
            Application.Undo
            OpenClipboard (0&)
            EmptyClipboard
            CloseClipboard
          End If
        End If
      End If
    End If
  End If
  Application.EnableEvents = True

End Sub

上記コードは値の消去やDelete・BackSpaceなどでは反応しません。
代わりに空白セルや長さ0の文字列をコピーした場合にUndoが働き貼付出来ません。
それと文字選択状態(f2を押した時)での貼付はメッセージも出ず貼付出来てしまいます。
上の2つは消去との区別が出来ませんでした。

【78261】Re:貼り付け禁止のマクロ
発言  マナ  - 16/6/12(日) 18:23 -

引用なし
パスワード
   ▼sy さん:
>
>ただこちらの案件ではMsgBoxで貼付を選択するようになっているので、消去した時との区別が出来ないので、かなり難しいですね。
>多少妥協してもらう部分はありますがIF分岐で考えてみました。
>
syさん、コメントありがとうございます。
すごいですね。わたしには、とうてい考えられません。
途中で考えるのが、いやになっちゃいます。

質問者さんに確認しないとわかりませんが
おそらく、MsgBoxによる選択は不要かもしれません。
たまたま、ネットで見つけたサンプルがそうなっていただけで。

選択制にしたい場合は、変数を用意して、必要に応じて、
コピペ禁止モードを解除する運用でもよいかもしれません。

If IsCopyOK then exit sub

みたいな感じにすれば、学校のコードが使えるかなと思います。

【78262】Re:貼り付け禁止のマクロ
発言  sy  - 16/6/12(日) 21:16 -

引用なし
パスワード
   ▼ささ さん:

初めのコードは切取に反応しませんでした。
条件分岐が複雑なので、修正を繰り返してたら、切取の確認を忘れてました。

修正コードを提示します。
一応コピペ、カット&ペースト、値のみコピペの基本的な使い方では不具合は無いと思いますが(全部は検証しきれてないので絶対大丈夫とは言い切れないですが)、カットモードにして直接入力など、ユーザーはどんな使い方するか分からないので、意図しない動きをする可能性はあります。
もし不具合が起きたら、また質問して下さい。
(対処可能かどうかは保証できませんが)

後Undoした時は都度MsgBoxが出てくると思いますが、これはVBAでは対処不可能です。
多分全て「はい」で良いと思いますが、逆のパターンもありうるので、そこは使用者に慣れてもらうしかないです。

VBAではMsgBoxとの併用は限界があります。
APIでキーのクリックの常時監視などをすれば、大抵の事は対処できますが、Undoが効かなくなるのと、Undoをクリックした時の処置はAPIでも不可能と思います。

もう複雑すぎて説明は無理です。
ThisWorkbookモジュールに丸ごとコピペして下さい。

Private Declare Function OpenClipboard Lib "User32" (ByVal hwnd As Long) As Long
Private Declare Function CloseClipboard Lib "User32" () As Long
Private Declare Function EmptyClipboard Lib "User32" () As Long


Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
  Dim Ans As Integer
  Dim cb As Object, cbID As Integer, val
  Dim val1, cnt As Long
  Dim v, str1 As String
  Dim flg As Boolean, mode1 As Variant

  Application.EnableEvents = False
  mode1 = modeID(0, Target)
  If mode1(1) > 0 Then
    cbID = Application.ClipboardFormats(1)
    If cbID > -1 Or mode1(0) > 0 Then
      If Application.CutCopyMode Then
        flg = True
      Else
        val1 = Target.Value
        cnt = Selection.Count
        If cbID > -1 Then
          Set cb = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
          cb.GetFromClipboard
          val = cb.GetText
          If cnt = 1 Then
            If InStr(val1, val) > 0 Then flg = True
          Else
            flg = True
            For Each v In val1
              If v <> "" Then
                If InStr(val, v) = 0 Then
                  flg = False
                  Exit For
                End If
              End If
            Next v
          End If
        Else
          If mode1(0) = 2 Then flg = True
        End If
      End If

      If Selection.Address <> mode1(2) And mode1(0) <> 2 Then flg = False

      If flg Then
        Ans = MsgBox("本当に貼り付けますか?", vbYesNo, "確認")
        If Ans = vbNo Then
          MsgBox "正しいデータを貼り付けてください"
          Application.Undo
          OpenClipboard (0&)
          EmptyClipboard
          CloseClipboard
        End If
      End If
    End If
  End If
  If mode1(0) < 2 Then Call modeID(2, Target)
  Application.EnableEvents = True

End Sub

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

  Call modeID(1, Target)

End Sub

Function modeID(ID As Integer, rng As Range) As Variant
  Static CopyMode As Integer, i As Integer, tgt As String

  tgt = ""
  Select Case ID
    Case 0
      If i = 0 Then
        i = 1
      Else
        i = 0
        CopyMode = 0
      End If
    Case 1
      CopyMode = Application.CutCopyMode
      tgt = rng.Address
      i = 0
    Case 2
      i = 0
      CopyMode = 0
  End Select
  If tgt = "" Then tgt = rng.Address
  modeID = Array(CopyMode, i, tgt)

End Function


▼マナ さん:

>途中で考えるのが、いやになっちゃいます。

同感です。
途中で訳わからなくなってきました。


>選択制にしたい場合は、変数を用意して、必要に応じて、
>コピペ禁止モードを解除する運用でもよいかもしれません。
>If IsCopyOK then exit sub
>みたいな感じにすれば、学校のコードが使えるかなと思います。

完全禁止なら対処も簡単ですね。
不具合も出ないでしょうし、私も選択制をお勧めします。

795 / 13645 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free