• ベストアンサー

ExcelのVBAでGoToの代わりに…

お世話になっています よく、gotoは悪名高いとか、使わないほうが良いとか言われていますが、何故なのでしょう?? 使わないようにしようと思っても、別の方法がわからず使ってしまっています。 例えば、「aaa」というシートがあるかどうか調べ、なければ作成するとした場合、 Dim myWS As Object For Each myWS In Worksheets If myWS.Name = "aaa" Then GoTo 1 Next Worksheets.Add ActiveSheet.Name = "aaa" 1 次の処理 というように書いていますが、これをgotoを使わないで…となるとどのように書いたら良いのでしょうか?

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

  • ベストアンサー
  • taocat
  • ベストアンサー率61% (191/310)
回答No.5

こんばんは。 こんなんでも出来るよということで。。。 -------------------------------------------- Sub Test()  On Error Resume Next  Sheets("aaa").Select    If Err.Number > 0 Then      Err.Clear      Worksheets.Add      ActiveSheet.Name = "aaa"    End If End Sub ------------------------------------------ それから質問者のコードの変数myWSの宣言ですが、今回のような場合にはちゃんと型宣言もすべきです。  Dim myWS As Object → Dim myWS As Worksheet 以上です。  

-yellowtail-
質問者

お礼

!!!なるほど~!!!! エラーを逆手に取るわけですね!!なんか感動しました。 これなら変数も増えず(むしろ減り)シンプルですね! エラーをこういう風に使ったことはないので、今後活用できるよう調べてみます。 型宣言もするようにしてみます! ありがとうございました。

その他の回答 (5)

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

こんばんは。 確かに、あるレベルぐらいまでは、コーディングの際に、Goto は、なるべく使わない方法で考えるべきだと思います。しかし、Excelの場合、他人とチームを組むということもあまりないし、まして、自分のコードをどのように書いたところで、半年も経てば他人のコードのように化してしまうわけで、あまり、それに縛られる必要はないと思います。 あえて言うと、いくつかのVBのルールがありますが、それををそのまま、短絡的にVBAに持ち込むことは出来ません。 気になる人は、マイクロソフトが提示したVBAの『最適化』をMSDNライブラリで、チェックしておいたほうがよいと思います。簡単に言うと、VBAのルールは、可読性を犠牲にしてでも、文字数を減らす方向にあるということです。 ですから、私は、実際のVBAコードと、掲示板に書くマクロとでは、その書法には違いがある時があります。 ちなみに、私の場合は、記録マクロのような定番ですが、以下のように書きます。 全体の流れを失わないで済みます。 '--------------------------------------------------- Sub Test()  Dim myWS As Worksheet  On Error GoTo ErrHandler  'エラーを吐くものなら何でも可   Set myWS = Worksheets("aaa")   'Next_Procedure  '次のコード    Set myWS = Nothing Exit Sub ErrHandler:   Worksheets.Add   ActiveSheet.Name = "aaa"   Resume End Sub '--------------------------------------------------- 例えば、オブジェクトを作らないなら、  Set myWS = Worksheets("aaa")  これでも可。#5のtaocat さんの Select でも可  Application.Goto Worksheets("aaa").Range("A1")

-yellowtail-
質問者

お礼

今回、gotoを使わなくても方法があると分かり、感動しました。 まだまだ勉強中の身であり、なるべくgotoを使わずにいろいろな方法を考えたいと思います。 確かに半年前のコードは自分でももうわかりません。 (今より知識がないため、より一層難解です) エラーコードを最後にまとめておくと流れが見やすいですね。 参考にしたいと思います。ありがとうございました!!

  • zap35
  • ベストアンサー率44% (1383/3079)
回答No.4

構造化プログラミングがはやった頃は「GOTO文を使うな」とか「上から下へ飛ぶときにしか使うな」と良く言われました。(1970年代後半ころ) 下から上へGOTO文で飛ばすと、プログラムのロジックが追いにくくなる → デバッグしにくい。ループしやすい。→ プログラム品質が落ちる という理由からです。 質問のループを抜けるGOTO文はまだ許される範囲だと思いますが、構造化プログラミングではこのような場合はフラグを使用するのが一般的です。でも行数が増えるとか、余分な変数が必要になるという理由で好まない人も多いと思います。 (コード自体は#01さん、#03さんも書かれているので記載しません) なお構造化プログラミングではEnd IfのないIf文も嫌われますね。

-yellowtail-
質問者

お礼

たしかに、gotoで飛ばされると、デバッグしにくいですね! 行数が増えたり、変数が増えるのもスマートでない気もしますが、フラグを使う処理を利用して行こうと思います。 End Ifも合ったほうがいいとは初耳でした。 どうも、作ったプログラムが他のPCで上手く動かなかったりするので、なるべく基本に忠実に作ろうと思います。 ありがとうございました!

noname#187541
noname#187541
回答No.3

こんばんは。 その程度の使い方であればいいと思いますよ。 多用すると処理が繁雑になるというか分かりにくくなるので、多用はするなと言うことだと思います。 とりあえずGotoを使わないとすれば、フラグを立てて判断するくらいでしょうか。 Dim myWS As Object Dim flg As Boolean flg = False For Each myWS In Worksheets If myWS.Name = "aaa" Then flg = True Next If flg = False Then Worksheets.Add ActiveSheet.Name = "aaa" End If 次の処理

-yellowtail-
質問者

お礼

ありがとうございます gotoが良くない、というより使い方に気をつけろということなのですね~。 参考になりました!

noname#20377
noname#20377
回答No.2

構造化プログラミングと言った話の流れからのようですが、 残念ながら私は詳しくないです。 構造化プログラミング-Wikipedia http://ja.wikipedia.org/wiki/構造化プログラミング Gotoを「むやみに使いすぎると」【何のプログラムだか把握できなくなる】から、気をつけよう、ということのようです 参考までに以下の文章を読んでみるとどーなるか判るかと http://www.algolab.co.jp/~lum/pcnyumon/hosoku06.htm

-yellowtail-
質問者

お礼

なるほど、こういった背景があったのですね。 スパゲッティーテキスト、たしかに読む気が起こりません(笑) ありがとうございました。

  • TAK_999
  • ベストアンサー率43% (42/96)
回答No.1

こんな感じではどうでしょうか? Dim myWS As Object Dim bExistFlg As Boolean bExistFlg=False For Each myWS In Worksheets If myWS.Name = "aaa" Then bExistFlg=True Exit For Next If Not bExistFlg Then WorkSheets.Add ActiveSheet.Name = "aaa" End If フラグを多用することもソースコードを難解にする要因ではありますが、 多少はしょうがないと思います。

-yellowtail-
質問者

お礼

ありがとうございます フラグを使えばいいのですね。 行は増えても、コードが上に戻るよりは良いということでしょうか。 参考になりました!

関連するQ&A

  • Excel VBA 指定シートの有無確認

    指定した名前のシートがあるかないか判断させてますが、 以下のやりかたでは、 グラフ作成したシートを認識してくれません。 そのようにすれば良いでしょうか? Dim ws As Worksheet, flag As Boolean For Each ws In Worksheets If ws.Name = "シート" Then flag = True  Next ws If flag = True Then  msgbox "あります  Else  Sheets.Add  ActiveSheet.Name = "シート" End If

  • Excel VBA チェックボックスの一括オン、オ

    1.2.のように2つマクロを作成し、それぞれチェックボックスのオン、オフが一括でできるようになったのですが、1つにまとめることはできますでしょうか? 1回クリックすると、一括オン、もう一度クリックすると一括オフを繰り返すようにしたいです。 1.チェックオフ Dim myobj As OLEObject For Each myobj In ActiveSheet.OLEObjects If TypeName(myobj.Object) = "CheckBox" Then _ myobj.Object.Value = False Next 2.チェックオン Dim myobj As OLEObject For Each myobj In ActiveSheet.OLEObjects If TypeName(myobj.Object) = "CheckBox" Then _ myobj.Object.Value = True Next

  • エクセルVBA・完全一致の情報

    既に出ているかもしれませんが… 文字列の完全一致で、セルの座標を取得が上手くいきません。 現在は完全一致した場所を塗りつぶしています。 A B C 1 2 AAA 3 Sub Find_moji() Dim a As Integer Dim b As Integer Dim c As Object For Each c In Worksheets("特産品素材").Range("a1:a3") If c.Value Like "AAA" Then c.Interior.ColorIndex = 3 '赤 End If Next c End Sub 求めたい結果としては、AAAが入っているA2を塗りつぶして、AAAの座標(X座標1、Y座標)の情報を取得したいのです。 お願い致します。

  • VBAの表からシートを作成したい

    現在の構文は以下のようになっています。 Dim ws As Range For Each ws In Worksheets("ユーザー情報").Range("C2:C201") On Error GoTo myError If Not ws Is Nothing Then Worksheets("雛形").Copy After:=Worksheets(Worksheets.Count) ActiveSheet.name = ws.Value End If Next ws Exit Sub myError: nm = "雛形 (2)" For Each sh In Worksheets If sh.name = nm Then Application.DisplayAlerts = False Worksheets(nm).Delete Application.DisplayAlerts = True End If Next 「ユーザー情報」シートのC列に氏名を記入して上記マクロを実行すれば、その氏名ごとに「雛形」を元にしたシートが連続でコピーされる形になっています。 しかし、1度実行した後、あらたにC列に氏名を追加してもその分のコピーを作ってくれなくなります。 どのようにすればよいでしょうか。アドバイスをいただければと思います。

  • エクセルVBAで xlOn xlOff の切替

    エクセル2000です。 ワークシート上に配置したオブジェクトのVisibleのTrue Falseについては、test01の方法で切り替えることが出来ます。 では、Test02でIfで判定している、xlOn xlOff の切替についても同様にNOTを使って簡単に記述することはできないでしょうか?xlOn xlOff はTrue False ではないから無理なのでしょうか? Sub test01() Dim o As Object For Each o In ActiveSheet.Buttons o.Visible = Not o.Visible Next o End Sub Sub test02() Dim o As Object For Each o In ActiveSheet.CheckBoxes If o.Value = xlOn Then o.Value = xlOff Else o.Value = xlOn End If Next o End Sub

  • Excel VBA でExecuteExcel4Macro("GET.OBJECT(48,

    エクセル2000です。 以前、ワークシートに配置したフォームツールのラベルの参照元を取得するマクロをご教示いただき、以下のTest01は問題なく作動しています。 Sub test01() Dim obj As Object Dim i As Integer Dim obj_n As String 'オブジェクトの名前 With ActiveSheet For Each obj In .Labels i = i + 1 .Cells(i, 2) = obj.Name: obj_n = obj.Name .Cells(i, 3) = obj.TopLeftCell.Address 'GET.OBJECT で、リンクがないものを取ると、False になる .Cells(i, 5) = ExecuteExcel4Macro("GET.OBJECT(48,""" & obj_n & """)") .Cells(i, 6) = obj.OnAction Next End With End Sub 今回、同一シートではなく別シートに表示させようと以下のTest02を書いたのですが、やってみると .Cells(i, 5) はすべて#VALUE!エラーになってしまいました。 ExecuteExcel4Macro("GET.OBJECT(48~がどのようなものかわからずやっているので応用がききません。(そもそも48って?) どのようになおしたらよいのかご教示いただければ幸いです。 Sub test02() Dim obj As Object Dim i As Integer Dim obj_n As String Dim ws As Worksheet, ns As Worksheet Set ws = ActiveSheet Set ns = Worksheets.Add With ns For Each obj In ws.Labels i = i + 1 .Cells(i, 2) = obj.Name: obj_n = obj.Name .Cells(i, 3) = obj.TopLeftCell.Address .Cells(i, 5) = ExecuteExcel4Macro("GET.OBJECT(48,""" & obj_n & """)") .Cells(i, 6) = obj.OnAction Next End With End Sub

  • VBA 同じ場所に保存する

    部署ごとに分割し、ブックで保存するコードです。 保存場所がデスクトップになっています。 これを同じ場所に保存する方法をお知らせください。 よろしくお願いします。 Sub macro1() Dim w As Worksheet Dim n As Long Dim r As Long Dim s As String Dim WSH As Variant Dim myPath As String Set w = ActiveSheet n = Worksheets.Count Application.ScreenUpdating = False On Error GoTo errhandle For r = 2 To w.Range("A65536").End(xlUp).Row s = w.Cells(r, "A") w.Rows(r).Copy Worksheets(s).Range("A65536").End(xlUp).Offset(1) Next r On Error GoTo 0 Set WSH = CreateObject("Wscript.Shell") myPath = WSH.specialfolders("Desktop") & "\" For r = Worksheets.Count To n + 1 Step -1 Worksheets(Worksheets.Count).Copy ActiveSheet.Columns.AutoFit ActiveWorkbook.SaveAs Filename:=myPath & ActiveSheet.Name ActiveWorkbook.Close False Application.DisplayAlerts = False Worksheets(Worksheets.Count).Delete Application.DisplayAlerts = True Next r w.Select Exit Sub errhandle: Worksheets.Add after:=Worksheets(Worksheets.Count) ActiveSheet.Name = s w.Rows(1).Copy Range("A1") Resume Application.ScreenUpdating = True End Sub

  • セルの値をシート名にするエクセルVBA

    件名のVBAを以下のように書きました B列の4からずっと下までのセルの値を次々とシート「ひな型」をコピーし増やしていくものです。 Sub テスト() ' ' Macro ' ' Dim target As Range Dim h As Range '見えてるセルを取得する。「全部隠れていた」場合も考える。 On Error Resume Next Set target = Worksheets("Sheet1").Range("B4:B" & Worksheets("Sheet1").Range("B65536").End(xlUp).Row).SpecialCells(xlCellTypeVisible) If target Is Nothing Then Exit Sub 'シートを増やしていく For Each h In target On Error GoTo errhandle Worksheets(CStr(h.Value)).Select On Error GoTo 0 Next Sheets("Sheet1").Select Exit Sub errhandle: Worksheets("ひな型").Copy after:=Worksheets(Worksheets.Count) ActiveSheet.Name = h.Value Resume End Sub これだと、一応思った通りにはなるのですが B列のセルに複数同じ名前があった時に、既に作ったシートの名前がある場合 それは無視するという風に実行したいです お知恵をお貸しくださいませ

  • Excel VBA セルの値をシート名にしたいのです。

    こんばんは 新しくシートを挿入させて、「シート2」の値のみをコピーさせたいと考えています。 その新しく挿入させたシート名を「シート1」のせるA3とA4の文字列をあわせたものにしたいのですが、どうしたらよいのでしょうか。 途中まで考えたところでいきずまってしまいました。 どうか英知をお貸しください。 宜しくお願い致します。 A3には日付、A4には名前が入力されています。 Dim sheetName As String Worksheets("月度集計").Activate Sheets.Add After:=Sheets(Sheets.Count) ActiveSheet.Name = Worksheets("Sheet1").Cells(3, 3).Value On Error Resume Next Worksheets(1).Name = sheetName On Error GoTo 0 Range("f2").Select

  • VBA なんですが

    VBA なんですが すべてのワークシートを順番に選択して 指定した範囲をコピーし『まとめ』と言う別のシートに貼り付けたいのですが どうしたらいいのかわかりません。 それらしいのは考えたのですが Set sh = Worksheets(sh.Name)でエラーになります。 頭がいいかた教えてください。   Dim sh3 As Worksheet Dim sh As Worksheet Dim en As Long Set sh3 = Worksheets("まとめ") For Each sh In ActiveWorkbook.Worksheets If sh.Name <> "まとめ" Then en = sh.UsedRange.Rows.Count Set sh = Worksheets(sh.Name) sh.Range(Cells(2, 1), Cells(en, 10)).Copy

専門家に質問してみよう