質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

3回答

4313閲覧

Select - Case - If のループが同じところを繰り返してしまう 問題

vitabrevisarsl1

総合スコア57

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2017/11/09 06:01

編集2017/11/09 08:28

イメージ説明
B列に「▲」と「▼」ボタンが並んでいます。この内一番上と一番下のボタンを非アクティブにしたいです。
非アクティブにするために無動作マクロを割り当てるのですが、TopLeftCellを使い各ボタンのRow番取得がうまく行きません。
F8で検証するに、上図のように同じ「▲」と「▼」ボタンのループだけで終了してしまう場合があります。

VBA

1Sub 最上最下ボタン無効() 2Dim q As Integer 3Dim r As Integer 4Dim btn As Shape 5 6Application.ScreenUpdating = False 'チラついて五月蝿いのを防止 7 8Worksheets("年間集計_出勤簿").Activate 9 10Worksheets("年間集計_出勤簿").Unprotect 11 12'シート内のすべてのオブジェクト(シェイプ)をループ処理 13For Each btn In ActiveSheet.Shapes 14 Select Case btn.AlternativeText '取得したオブジェクトを表示名で判別 15 Case "▲" 16 q = ActiveSheet.Shapes(btn.Name).TopLeftCell.Row 17 If q = 8 Then 18 ActiveSheet.Shapes(btn.Name).Select 19 Debug.Print "無効ボタンアクション▲ q = 8" 20 With Selection 21 .OnAction = "無効ボタンアクション" 22 .Font.ColorIndex = 15 23 End With 24 Else 25 Debug.Print q & ":" & ActiveSheet.Shapes(btn.Name).TopLeftCell.Row 26 ActiveSheet.Shapes(btn.Name).Select 27 With Selection 28 .OnAction = "上に行移動" 29 .Font.ColorIndex = 56 30 End With 31 End If 32 Case "▼" 33 r = btn.TopLeftCell.Row 34 If r + 4 = ActiveSheet.Range("a8:a" & Cells(Rows.Count, 1).End(xlUp).Row).Count + 7 Then 35 ActiveSheet.Shapes(btn.Name).Select 36 Debug.Print "無効ボタンアクション▼ r + 4 =" & r & " // " & ActiveSheet.Range("a8:a" & Cells(Rows.Count, 1).End(xlUp).Row).Count + 7 37 ActiveSheet.Shapes(btn.Name).OnAction = "無効ボタンアクション" 38 With Selection 39 .OnAction = "無効ボタンアクション" 40 .Font.ColorIndex = 15 41 End With 42 Else 43 Debug.Print r + 4 & ":" & ActiveSheet.Range("A8:A" & Cells(Rows.Count, 1).End(xlUp).Row).Count + 7 44 ActiveSheet.Shapes(btn.Name).Select 45 With Selection 46 .OnAction = "下に行移動" 47 .Font.ColorIndex = 56 48 End With 49 End If 50 51 End Select 52Next 53 54Worksheets("年間集計_出勤簿").Protect UserInterfaceOnly:=True 55Worksheets("年間集計_出勤簿").Range("C3:D3").Locked = False 56 57ActiveSheet.Range("C3").Select 58Application.ScreenUpdating = True 59 60End Sub

カウンタ変数をiから他の文字に変えると順番に全部ループにかかりますが、一旦ファイル保存した後開いて再検証すると再発します。
Case - if の実行の中身をdebug.print等にすると問題ないことから、With Selection 以下がおかしいのかと思いdebug.print等より単純なものに替えてみると問題ありません。
OnActionとFont.Color.Indexについても検証しましたが、解消が見いだせません。

何かヒントでもご教授いただけますと幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hihijiji

2017/11/09 07:33

コードは画像を貼らずに Markdown で書いてください。
h.horikoshi

2017/11/10 01:12

Excelのバージョン(20xx)は何ですか? 2007以降、AlternativeTextでは表示名が採取できないように思いますが...
guest

回答3

0

今回の原因であるかは分かりませんが、ActiveSheet は変動することを留意してください。
MDIだった Excel 2010 以前から不変ではありませんでしたが、SDIになってから顕著に変わるようです。
ActiveSheet を使うと必ずいつかはトラブりますので、使わないようにしてください。

C#

1Dim yearlyAttendanceSheet As Worksheet 2Set yearlyAttendanceSheet = Worksheets("年間集計_出勤簿")

こんな風に解り易い?名前を付けて操作してください。

投稿2017/11/10 03:19

hihijiji

総合スコア4150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

質問のほうに「AlternativeTextでは表示名が採取できないように思いますが...」
などと書いてしまいましたが、AlternativeTextで値が採取できているということは、ボタンはフォームボタンで作成されていると考えてよいですか?

その前提でプログラムを書き直してみました。

Dim topIx As Long: topIx = 1 ' 最も上にあるボタンのIndex。デフォルト=1 Dim btmIx As Long: btmIx = 1 ' 最も下にあるボタンのIndex。デフォルト=1 Dim ss As Object: Set ss = ActiveSheet.Shapes ' 面倒なので変数に入れる Dim ix As Long For ix = 1 To ss.Count ' (1)とりあえず▲▼ボタンは全て有効にする。 ' (2)最も上のボタンと最も下のボタンのIndexを求める。 Select Case (ss(ix).AlternativeText) Case "▲": '--------------------------------------------------------------- ss(ix).OnAction = "上に行移動" ss(ix).TextFrame.Characters.Font.ColorIndex = 56 ' ※ If (ss(ix).TopLeftCell.Row < ss(topIx).TopLeftCell.Row) Then topIx = ix Case "▼": '--------------------------------------------------------------- ss(ix).OnAction = "下に行移動" ss(ix).TextFrame.Characters.Font.ColorIndex = 56 ' ※ If (ss(ix).TopLeftCell.Row > ss(btmIx).TopLeftCell.Row) Then btmIx = ix End Select Next ix ' 最も上のボタンと最も下のボタンを無効に書き替える。 ss(topIx).OnAction = "無効ボタンアクション" ss(topIx).TextFrame.Characters.Font.ColorIndex = 15 ' ※ ss(btmIx).OnAction = "無効ボタンアクション" ss(btmIx).TextFrame.Characters.Font.ColorIndex = 15 ' ※

【注】「※」の部分はExcel2010版用の記述です。非互換があるようですので
2013版用の記述に変更してください。

なお、フォームボタンはバージョン間でかなり非互換があるようですし、自由度も小さいため、ボタンはActiveXボタンあるいはシェイプ(図形)で作られたほう無難だと思います。

投稿2017/11/10 04:03

h.horikoshi

総合スコア505

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

For Each btn In ActiveSheet.Shapes ~ Nextで同じボタンを複数回してしまうとはちょっと考えにくいですね。
こちらの環境でも提示いただいたコードを数回試してみましたが、同じボタンが複数回取得されてしまうような現象は発生しませんでした。

本当に同じボタンが複数回取得されてしまっているのか、はたまたそれ以外の箇所に問題があるのか、見極めるためにもまずは簡単なコードで動作を確認してみることをオススメします。
例えば以下のような簡潔なコードで試してみてください。

Sub test() For Each btn In ActiveSheet.Shapes Debug.Print btn.AlternativeText & " " & CStr(btn.TopLeftCell.Row) Next End Sub

これでも同じ行番号のボタンが複数回取得されるのであれば、For Eachに問題があるのかもしれません。
この処理では同じボタンが複数回処理されないのであれば、それ以外の処理に問題があるのだと思います。
おそらくActiveSheet.Shapes(btn.Name)でボタンを特定しようとしている箇所がうまく機能していないのではないかとと推測しています。
といってもこちらでは現象が出ていないので野生の勘なのですが。

まずはコードをお試しください。

投稿2017/11/09 09:17

jawa

総合スコア3013

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問