• ベストアンサー

エクセルVBAで DirectPrecedentsプロパティ

DirectPrecedentsプロパティが同一シート内しかトレースできないことを利用して、他シートを参照しているセルを判定できないかと思い、下記のマクロを書いてみました。 残念ながら他シートを参照しているセルでエラーになってしまいます。 どのよに修正すればよいでしょうか? なお、他シート参照の判定に"!"の存在を使わないのは、「名前定義」されたセルを参照している場合を想定しているためです。 Sub TEST01() With ActiveSheet On Error GoTo line For Each c In .UsedRange.SpecialCells(xlCellTypeFormulas, 23) On Error GoTo 0 c.Select If c.DirectPrecedents.Address = "" Then'ここでエラー MsgBox c.Address & "は他シート参照" Else MsgBox c.Address & "は" & c.DirectPrecedents.Address & "参照" End If Next End With line: MsgBox "数式がありません。" End Sub

質問者が選んだベストアンサー

  • ベストアンサー
  • okormazd
  • ベストアンサー率50% (1224/2412)
回答No.5

このエラーはプログラムのエラーだから、IsError()では取れない。 IsError()は、引数を評価して、その評価の結果がエラー値かどうか判定してtrueとかfalseを返す。引数には有効な任意の式を指定する。 IsError(c.DirectPrecedents.Address)は、c.DirectPrecedents.Address が、他シート参照のセルのAddressをとろうとしたエラーだ(有効ではない)から、評価のしようが無いということではないか。 ところで、目的は、どうしてもc.DirectPrecedents.Addresを使いたいということですか。参照のアドレスを取りたいだけなら、単にc.Formulaとすればとれるけど・・・。

merlionXX
質問者

お礼

ありがとうございます。 > 目的は、どうしてもc.DirectPrecedents.Addresを使いたいということですか。 いいえ、アクティブなシートに他のシートを参照しているセルがあるかどうかの判定をしたいだけです。 最初はc.Formulaに"!"があれば他のシート参照としてたのですが、それでは他シートにある名前を定義されたセルを参照した場合、シート名の!が出ないので、逆に他のシートの参照元をトレースしたらエラーになるDirectPrecedentsが使えないかと考えたのです。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (5)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.6

こんばんは。 #4 のお礼側の件ですが、 >では、他シートを参照しているセルのDirectPrecedentsは何を返すのでしょうか? 重複しますが、プログラムとしてのエラー=実行時エラーですね。 そうすると、コード全体がとまってしまいます。 たぶん、お分かりにはなっているとは思いますが、値自体も取れませんので、そういう場合は、 On Error Resume Next  '実行時エラーの可能性のあるコード  buf = Empty  buf= c.DirectPrecedents.Address On Error Goto 0 変数 buf は、Variant 型としたら、Empty ですが、エラーが発生すると、変数の中がクリアされませんので、前の値が残っています。だから、一旦、その変数は、Empty にしてあげないといけませんね。文字型なら、「""」 ということになります。 この件は、確かに、#5さんの c.Formula もご指摘の通りなのですが、このマクロの発展型としては、ツールの中の[ワークシート分析]と同じことをしてもしょうがないので、数式自体を分解し、再構築して、参照先を明示するということを考えたほうがよいのかもしれません。出来る出来ないは別として。

merlionXX
質問者

お礼

そうか、何も返さないわけですね。 変数の使い方も大変勉強になりました。 ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.4

こんばんは。 >たとえば、IsError(c.DirectPrecedents.Address)  それ自体に、エラーを吐くわけではありません。 例えば、Application.Sum(...) というのは、エラー値を返すような仕組みが出来ていますが、c.DirectPrecedents.Address 自身の内部でエラーが起きるので、IsError では囲えません。エラー値は、一つの型の値なのです。 それと、#3のコードは今回の質問内容とは違うコードでしたので、もう少し言い訳させていただきたいのですが、この件に関しては、過去2度行っていて、昨年だったと思いますが、数式の参照先にジャンプでそこに飛ぶというものだったので、その記憶が強く残っていました。改めて訂正させていただきます。

merlionXX
質問者

お礼

>#3のコードは今回の質問内容とは違うコードでしたので、 今回のわたしの質問と直接の関係はないですが、すばらしいユーザー定義関数です。勉強させていただきます。ありがとうございました。 >> たとえば、IsError(c.DirectPrecedents.Address)  > それ自体に、エラーを吐くわけではありません。 では、他シートを参照しているセルのDirectPrecedentsは何を返すのでしょうか? "" でも Nothing でもないようです。どうやったらしらべられるのでしょうか?

全文を見る
すると、全ての回答が全文表示されます。
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.3

#2 のことわりを入れておきますが、 #2のコードのユーザー定義のアドレスの切り分けは、そのままでは、まったく意味がありません。取れたアドレスは、そのまま、表示すればよいだけのことです。ただ、それをVBAで再利用するときにだけ、「[ブック名]シート名! セル座標」の切り分けが必要になるというものです。 だから、そのユーザー定義関数は、今回の内容からすれば無意味です。

merlionXX
質問者

お礼

Wendy02さま、いつもありがとうございます。 Sub TEST03() Dim c As Range Dim buf As Variant With ActiveSheet On Error GoTo line For Each c In .UsedRange.SpecialCells(xlCellTypeFormulas, 23) On Error GoTo 0 On Error Resume Next buf = Empty buf = c.DirectPrecedents.Address On Error GoTo 0 If IsEmpty(buf) Then MsgBox c.Address & "は他シート参照" Else MsgBox c.Address & "は" & c.DirectPrecedents.Address & "参照" End If Next End With Exit Sub line: MsgBox "数式がありません。" End Sub いったんBufに取り込むようにしたことでできました。 ただ、たとえば、IsError(c.DirectPrecedents.Address) というような感じでなぜエラーを判定できないのが腑に落ちないのです。

全文を見る
すると、全ての回答が全文表示されます。
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.2

こんにちは。 うーん、今の状態では、基本的に無理があるかなって思います。 私の作ったものでも、名前定義とか関係なく、数式が複合的になると、うまくいきません。数式を切り分けする必要があるようです。 '------------------------------------------- Sub FindReferencesMacro() 'DirectPrecednts を使ったマクロ   Dim c As Variant   Dim buf As Variant   Dim pAddr As String      With ActiveSheet     On Error GoTo ErrHandler     For Each c In .UsedRange.SpecialCells(xlCellTypeFormulas, 23)       On Error Resume Next       buf = Empty       buf = c.DirectPrecedents.Address       On Error GoTo 0       If IsEmpty(buf) Then         FindPrecedent c.FormulaLocal, pAddr       Else         pAddr = c.DirectPrecedents.Address       End If       MsgBox c.Address & " は " & pAddr & " を参照"       pAddr = ""     Next   End With   Exit Sub ErrHandler:   MsgBox Err.Number & ": " & Err.Description End Sub Function FindPrecedent(ByVal strForml As String, ByRef strAdd As String)   Dim Matches As Object   Dim Match As Object   Dim w As String, s As String, c As String   If Not strForml Like "=?*" Then Exit Function   If InStr(strForml, "!") > 0 Then     With CreateObject("VBScript.RegExp")       .Pattern = "=(\[.*\])?(.*)\!(.*)"       .Global = True       Set Matches = .Execute(strForml)       If Not Matches Is Nothing Then         On Error Resume Next         w = Matches(0).SubMatches(0)         s = Matches(0).SubMatches(1)         c = Matches(0).SubMatches(2)         On Error GoTo 0       End If     End With   Else     FindPrecedent Application.Names(Mid$(strForml, 2)), strAdd   End If   If strAdd = "" Then     strAdd = w & s & "!" & c   End If End Function '-------------------------------------------

全文を見る
すると、全ての回答が全文表示されます。
  • okormazd
  • ベストアンサー率50% (1224/2412)
回答No.1

基本的には直っていないだろうが、目的の動作はするけど。 こういう姑息なことではない? アクティブ シートでしかできないといっているのを使うのだからこうなっても・・・。 Sub TEST01() With ActiveSheet On Error GoTo line For Each c In .UsedRange.SpecialCells(xlCellTypeFormulas, 23) 'On Error GoTo 0 c.Select Debug.Print Selection.Row, Selection.Column 'Debug.Print c.DirectPrecedents.Address If c.DirectPrecedents.Address = "" Then 'ここでエラー 'MsgBox c.Address & "は他シート参照" Else MsgBox c.Address & "は" & c.DirectPrecedents.Address & "参照" End If Next End With Exit Sub line: MsgBox c.Address & "は他シート参照" Resume Next End Sub

merlionXX
質問者

お礼

ありがとうございます。 姑息だなんてとんでもない。エラーハンドラーからResume NextでまたFor Nextの続きに戻れるとは知りませんでした。 ということはこれでいけますね。↓ Sub TEST02() With ActiveSheet On Error GoTo line1 For Each c In .UsedRange.SpecialCells(xlCellTypeFormulas, 23) On Error GoTo line2 MsgBox c.Address & "は" & c.DirectPrecedents.Address & "参照" Next End With Exit Sub line1: MsgBox "数式がありません。" Exit Sub line2: MsgBox c.Address & "は他シート参照" Resume Next End Sub ただ、たとえば、IsError(c.DirectPrecedents.Address) というような感じでなぜエラーを判定できないのが腑に落ちないのです。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • EXCEL VBAについて教えてください

    はじめまして。 過去ログに私のやりたいような内容を探していたらこのような下記のエクセルVBAがあったので、教えて頂きたいです。 Private Sub Worksheet_Change(ByVal Target As Range) If Target.Address <> "$A$1" Then Exit Sub If Target.Value = "" Then Exit Sub x = Target.Value With Application .ScreenUpdating = False .EnableEvents = False .Undo y = Target.Value Target.Value = x + y .EnableEvents = True .ScreenUpdating = True End With With Cells(ActiveSheet.Rows.Count, "C").End(xlUp) .Offset(1, 0).Value = x .Offset(1, 1).Value = Time() End With End Sub A1に入力するたびに同一セルに加算。 A1をクリアできる。 C列に入力履歴、D列に入力時間を記録。 If Target.Address <> "$A$1" Then Exit Sub の$A$1を変えることによって他のセルにも設定できる。 と、いう内容なのですが、これをたとえば同一シートのA1~E10のセルとA12~E22にも同じよう別々に処理できるように設定したいのですが、どのようにすればいいのでしょうか?ちなみにA11~E11とA23~E23は合計を表示するセルにしたいです。 Excelのバージョンは2003です。 よろしくお願い致します

  • セルの値をワークシート名にする(エクセル2013)

    インストラクターのネタ帳さんより http://www.relief.jp/itnote/archives/003382.php 下記「セルの値をワークシート名にする?Worksheet_Change」 を拝借し利用させていただこうと思いましたが ---------------------- Option Explicit Private Sub Worksheet_Change(ByVal Target As Range) On Error GoTo ERR_HANDLER If Target.Address(False, False) = "H1" Then ActiveSheet.Name = Range("H1").Value End If Exit Sub ERR_HANDLER: MsgBox "現在のH1セルの値はシート名にできません。" End Sub ---------------------- はそのまま出来るのですが、 H1セルにデータの入力規則:リストを指定しますと エラーとなりシート名が変わりません sheet1のリストA1:A50をsheet2のH1セルにリスト表示させ その表示名をそのままシート名に出来ませんでしょうか? ---------------------- Sub copy Range("H1").Copy Range("P1") End Sub ---------------------- Option Explicit Private Sub Worksheet_Change(ByVal Target As Range) On Error GoTo ERR_HANDLER If Target.Address(False, False) = "P1" Then ActiveSheet.Name = Range("P1").Value End If Exit Sub ERR_HANDLER: MsgBox "現在のP41セルの値はシート名にできません。" End Sub ---------------------- としてH1のセルをP1にコピーしたものを指定して試しましたがやはりエラーとなり うまくいきませんでした。 全くの素人で恐縮ですがよろしくお願いいたします

  • エクセルVBAについて教えてください

    エクセル2003です。 Sheet1     A    B    C     D 1 種類1 商品1 商品A  商品あ 2 種類2 商品2 商品B  商品い 3 種類3 商品3 商品C  商品う  4      商品4 商品D  商品え 5  商品5 商品E  商品お Sheet2   AB CDF     G    H     I 1         種類表示     商品表示  2         種類表示     商品表示  3         種類表示     商品表示  4         種類表示     商品表示  5         種類表示     商品表示  *Sheet2のG1をダブルクリックでSheet1のA列をユーザーフォームのコンボボックス1にてセルに表示  の上挿入 *コンボ1の選択によりコンボ2(Sheet2のI1をダブルクリック)の表示を変更する *コンボ1 種類1 → コンボ2 Sheet1のB列を表示の上セルに挿入 *コンボ1 種類2 → コンボ2 Sheet1のC列を表示の上セルに挿入 *コンボ1 種類3 → コンボ2 Sheet1のD列を表示の上セルに挿入 までは、出来きたのですが、Sheet2の2行目以降も同作業をしたいのですが、、、 Offset等を使用するのでしょうか? あまりわかっていないので詳しく教えて頂ければ幸いです コード Sheet2のコード Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) Cancel = True With Target If .Address = "$F$1" Then UserForm1.Show ElseIf .Address = "$H$1" Then Dim k As Long, myFlg As Boolean, myArray myArray = Array("種類1", "種類2", "種類3") myFlg = False For k = 0 To UBound(myArray) If Range("F1") = myArray(k) Then myFlg = True End If Next k If myFlg = False Or Range("F1") = "" Then MsgBox "種類を選択して", vbOKOnly Range("F1").Select Exit Sub End If UserForm2.Show End If End With End Sub ユーザーフォーム1のコード Private Sub UserForm_Initialize() ComboBox1.RowSource = "sHEET1!A1:A3" End Sub コンボ1のコード Private Sub ComboBox1_Change() Worksheets("Sheet2").Range("F1") = UserForm1.ComboBox1.Text Worksheets("Sheet2").Range("H1") = "" Unload Me End Sub ユーザーフォーム2のコード Private Sub UserForm_Initialize() With UserForm2.ComboBox1 Select Case Worksheets("Sheet2").Range("F1") Case "種類1" .RowSource = "Sheet1!B1:B5" Case "種類2" .RowSource = "Sheet1!C1:C5" Case "種類3" .RowSource = "Sheet1!D2:D5" End Select End With End Sub コンボ2のコード Private Sub ComboBox1_Change() Worksheets("Sheet2").Range("H1") = UserForm2.ComboBox1.Text Unload Me End Sub このコードをいじくってSheet2以降も同作業できるようにお願いします

  • EXCEL VBA 複数シート選択の方法

    エクセルVBAのシート選択方法について教えてください。 選択対象シート数は4つで、シート名は、「101」「102」「103追加工」「104」とします。 シート名「表紙」のセルは A1:101 A2:102 A3:103追加工 A4:104となっており、 使用者はB1~B4セルに「○」「×」を入力し、 「○」となっているシートのみ選択出来るようにしたい。 下記マクロの場合、シート名が全角文字だと使えるのですが、 シート名が「101」のように半角数字だけの場合コピーできません。 どこを修正すればよいのでしょうか? Sub TestSample2() Dim c As Range Dim flg As Boolean On Error Resume Next flg = True ThisWorkbook.Activate  With Worksheets("表紙")  For Each c In .Range("B1:B4")   If c.Value Like "○*" Then     Worksheets(c.Offset(, -1).Value).Select flg     flg = False   End If  Next c End With  With ActiveWindow.SelectedSheets  If .Count > 0 Then    .Copy  End If  End With  '元のシートに戻る場合  'Application.Goto ThisWorkbook.Worksheets("表紙").Range("A1") End Sub

  • VBAのinputboxで何もいれずに[OK]を押した時エラーになります

    よろしくお願い致します。 EXCELのVBAで「inputbox」を使ってセルを選択させたいと考えております。 下記のコードだと「キャンセル」や「×」で閉じられた時はmsgbox「キャンセル」が出てExit subするのですが、何も入力しないで「OK」を押した場合がどうしてもエラー(入力した数式は正しくありません)になります。 いろいろ調べて試したのですがどうしてもできず困っています。 どなたか教えてください。 Sub test() Dim myAns As Range On Error Resume Next Set myAns = Application.InputBox(Prompt:="セルを選択してください。", Title:="セル選択", Type:=8) On Error GoTo 0 If myAns Is Nothing Then MsgBox "キャンセル" Exit Sub ElseIf myAns = "" Then MsgBox "最低1つは選択してください" Exit Sub Else MsgBox myAns.Address(0, 0) End If End sub

  • excel vbaについてです

    VBA初心者で、暇な時にいろいろためしています。 以下のマクロを組んだのですが、エラーがでてうまくいきません。 どこがいけないのかご指摘願います。 Sub ather() Dim A As Range Dim B As Range Dim i As Integer With ThisWorkbook.Worksheets("Sheet1") For i = 1 To 30 Set A = Cells(i, 1) Set B = Cells(1, i) If Not .Range(A).Interior.ColorIndex = vbYellow Then GoTo port10 If Not .Range(B).Interior.ColorIndex = vbRed Then GoTo port10 .Range(B).Offset(, 1).Value = "○" port10: Next i End With End Sub イメージとしてはセルの塗りつぶしが黄色で、かつ右隣のセルの塗りつぶしが赤の時に、 赤色セルの右隣のセルに○を表示させようとしているのですが。。。 こうしたらいいんじゃない?といったアドバイスもお願いします(-人-)

  • エクセルでセルに文字が入力されたらマクロを実行

    前回どなたかが質問されて回答を見せてもらったら私のやりたいことと同じだったので実行してみましたが出来なかったのでもう一度質問をさせてください。 1.実行したのですが、なにも実行されません。 2.実行したらメッセジBOXだけは実行するのですが、後のコマンドが実行されずにエラーになります。 もう一度詳しく教えてください。 マクロ初心者ですよろしくお願いします。 1.【シートモジュールで条件判定し、マクロを起動する】 通常はこちらの方法が使われます。 Private Sub Worksheet_Change(ByVal Target As Range)   '変化のあったセルがA1セルか?   If Target.Address = "$A$1" Then      '条件判定:A1セルの値は 1 か?     If Target.Value = 1 Then       MsgBox "A1セルは条件を満たしました"     End If   End If End Sub 2.【ワークシート上で条件判定し、マクロを起動する】 処理内容にもよっては不向きな場合もありますが、こんな方法も あります。 マクロを Sub ではなく、Function 、、つまり関数にしてしまいます。 Function TestMacro() '<-- Sub を Function に替える   MsgBox "A1セルは条件を満たしました"   TestMacro = "" '戻り値はなし End Function そして、ワークシートの B1 セルに次の式を入力します。()は必須 です。  =IF(A1=1,TestMacro(),"")

  • VBAエクセル2003での下記の命令文の作成2

    命令文: シート名:商品売上げのセルB16に入っている数字と シート名:売り上げのセルC16に入っている数字が同じなら メッセージBOXに○を表示させる そうでなければ メッセージBOXに×を表示させる ↓ Sub 売り上げ() Set WS1 = Worksheets("売上") Set WS2 = Worksheets("商品売上") If WS1.Range("C16") = WS2.Range("B16") Then MsgBox "○" Else MsgBox "×" End If End Sub この作業をマクロの実行を押さずにショートカットキーで 作業を可能にするには どういった命令文または操作でショートカットキーでの表示がかのでしょうか。 (ショートカットキーを押すことで○×の表示を出すにはどうしたらいいでしょうか?) また、同じシート内でB16のセルとC16のセル、D15が同じ場合は メッセージボックスに○そうでない場合は×の場合は Sub 売り上げ2() Worksheets("商品売上") If Range("B16") = Range("C16") =Range("D15") Then MsgBox "○" Else MsgBox "×" End If End Sub だけでいいんでしょうか? 詳しい方教えてください。 今、仕事でミスが多くプログラミングでどうにか ミスを防げないか工夫したいのですが まだ、習いたてでよくわかりません。 お手数が教えていただけませんでしょうか。 よろしくお願いいたします。

  • エクセルVBA初心者です。

    エクセルVBA初心者です。 「テキストボックスとコマンドボタンを使って、シートのA列にあるセルの文字列を左から検索する」という事をやりたいのですが、うまくいきません。お教えください。ちなみにCtrl+Fではなく、VBAで。 Private Sub TextBox1_Change() Dim R As Range With ActiveWorkbook.Worksheets("Sheet名") Set R = .Columns(3).Find(Me.TextBox1.Value) End With If R Is Nothing Then MsgBox "該当セルなし" Else R.Activate End If Set R = Nothing End Sub としましたが、テキストボックス入力+Enterで出来てしまい、コマンドボタンが機能しません。また、BackSpaceやDelをすると、他のセルに飛んでしまいます。????

  • VBA コンボボックスの条件分岐

    コンボボックスの条件分岐のコードが間違っているみたいで 調べても分からなかったので質問します。 やりたいこと 『マスタ』という名前のシート内のセルを参照し マスタシートには C2セル『A』C3セル『B』C4セル『C』と それぞれアルファベットがあります。 そこでコンボボックスを使用し コンボボックス22にC2~C4セルを選択できるようにし 例えばC2セルを選択したら コンボボックス21の参照範囲をマスタシート内の D2~D13セルを選択できるようにし C3セルを選択したら コンボボックス21の参照範囲をマスタシート内の E2~E13セルを選択できるようにしたいのです。 すいませんがコードを記載して頂けますと 助かります。 Private Sub UserForm_Activate() '----------------------- With ComboBox22 .ColumnCount = 2 .ColumnWidths = "90;10" .RowSource = "マスタ!C2:C4" End With '↑こうすればコンボボックス22のマスタシートのC2からC4まで値を選択できるようになります。 '------------------------わかりやすく区切っています。 '--------------------------------------- If UserForm1.ComboBox22 = "A" Then With ComboBox21 .ColumnCount = 2 .ColumnWidths = "90;10" .RowSource = "マスタ!D2:D13" End With End If '↑コンボボックス22の値が(C2セルの値がAなら)コンボボックス21をマスタシートのD2からD13までを選択できるようにしたい If UserForm1.ComboBox22 = "B" Then With ComboBox21 .ColumnCount = 2 .ColumnWidths = "90;10" .RowSource = "マスタ!E2:E13" End With End If '↑コンボボックス22の値が(C3セルの値がBなら)コンボボックス21をマスタシートのE2からE13までを選択できるようにしたい '----------------------------------------区切っています。 End Sub

専門家に質問してみよう