ExcelのToggleButtonを排他的に使う方法

このQ&Aのポイント
  • ExcelのVBAを使用してToggleButtonを排他的に使う方法を教えてください。
  • ワークシート上にToggleButton1~3があり、各ボタンを押すと異なる処理が行われます。しかし、現在のコードでは排他的な動作がうまく働いていません。Excel2007とWindows7を使用しています。改善策を教えてください。
  • ToggleButton1を押すと処理A、ToggleButton2を押すと処理B、ToggleButton3を押すと処理Cが行われるようにしたいのですが、現在のコードでは必ずしも排他的に動作しません。Excel2007とWindows7で動作する改善策を教えてください。
回答を見る
  • ベストアンサー

ExcelのToggleButtonを排他的に。。

師も走りまわる12月。。皆様(師)も走りまわっていることでしょう。 私は。。。走りません、はい。 本題です。 ExcelのVBAでToggleButtonを排他的に使いたいのです。 調べるとオプションボタンになさいと書かれてはいるのですが・・・。 ワークシート上にToggleButton1~3があります。 1を押す(凹)と“処理A”,もう一度押す(凸)と“処理Z” 2  同上    “処理B”,  同上 3  同上    “処理C”,  同上 以下のコードでなんとなく動くのですが,排他的動作の際には,TrueなToggleButton#の動作をおこなってしまいます。 Excel2007,Windows7です。 師の皆様の良い御提案が御座いましたら御教示下さい。 ----ボタンがあるシートモジュールに記載---------------------------------------- Option Explicit Dim strCode As Variant Private Sub ToggleButton1_Click() If ToggleButton1.Value = False Then strCode = "処理中Z" ' Debug.Print "AからZに戻します。" Else strCode = "処理中A" ' Debug.Print "Aを押しました。" ToggleButton2.Value = False ToggleButton3.Value = False End If 'Debug.Print "Aでの処理をします。" Call 処理(strCode) 'Debug.Print "Aから処理をしました。" End Sub Private Sub ToggleButton2_Click() If ToggleButton2.Value = False Then strCode = "処理中Z" ' Debug.Print "BからZに戻します。" Else strCode = "処理中B" ' Debug.Print "Bを押しました。" ToggleButton1.Value = False ToggleButton3.Value = False End If 'Debug.Print "Bでの処理をします。" Call 処理(strCode) 'Debug.Print "Bから処理をしました。" End Sub Private Sub ToggleButton3_Click() If ToggleButton3.Value = False Then strCode = "処理中Z" Else strCode = "処理中C" ToggleButton1.Value = False ToggleButton2.Value = False End If Call 処理(strCode) End Sub Sub 処理(strCode) Dim i As Long Dim Start As Single Dim Finish As Single Start = timer i = 0 'Application.ScreenUpdating = False Application.Calculation = xlCalculationManual For i = 1 To 1000 i = i + 1 Cells(2, 1).Value = strCode & i Next i Application.Calculation = xlCalculationAutomatic 'Application.ScreenUpdating = True Cells(1, 1).Value = strCode Finish = timer Cells(3, 1).Value = Format$(Int((Finish - Start) * 10 ^ 4 + 0.5) / 10 ^ 4) End Sub --------------------------------------------------------------------------- おまけ:  上記サンプルを作ってみましたが,ToggleButton1だけ相対的に処理速度が速いです・・・。 なぜなんでしょう??

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

  • ベストアンサー
  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

Application.EnableEventsで 制御できないんじゃないかな … わたしなら モジュールレベルの変数として dim toggle, bFlag を定義 ボタンの制御プロシージャを定義 Sub ClickProc(ctl as Object)   ' フラグが Trueなら そのまま戻る   if bFlag then Exit Sub   if IsEmpty(toggle) then     toggle = Array(ToggleButton1, ToggleButton2, ToggleButton3)   end if   Dim ss as String   bFlag = True   ss = "処理Z"   select case ctl.Name     case "ToggleButton1"       if ctl.Value then ss = "処理A"       toggle(1).Value = False       toggle(2).Value = False     case "ToggleButton2"       if ctl.Value then ss = "処理B"       toggle(0).Value = False       toggle(2).Value = False     case "ToggleButton3"       if ctl.Value then ss = "処理C"       toggle(0).Value = False       toggle(1).Value = False   End Select   処理 ss   ' 処理終了のためフラグをFalseに   bFlag = False End Sub 各トグルボタンのクリックを Sub ToggleButton1_Click()   ClickProc ToggleButton1 End Sub Sub ToggleButton2_Click()   ClickProc ToggleButton2 End Sub Sub ToggleButton3_Click()   ClickProc ToggleButton3 End Sub といったぐあいで …

mayu1992
質問者

お礼

こんばんは♪ お礼が遅れてすみません。 callは省略できるのがわかりました!!! 制限がある様でいまひとつ難解でしたが,希望通り良いぐあいです(^^) 誠にありがとうございました♪

mayu1992
質問者

補足

かなり開けてしまいましたが,あけましておめでとうございます♪ お礼が遅れましてすみません。 コードをみると,直接打ち込んでいらっしゃるのでしょうか。すごいです♪ Private SubとSubの違いが解っていないといいましょうか,ボタンを作ってコードを表示させると 必ずPrivate Subなので,「Sub」でもいいのですね。。。 WindFaller様はテクニカルで面白いとの事ですが,私にはなんとも言えない程解らない所で御座います。 もう少し教えて頂きたいのですが・・・ 1.ボタンに登録しているClickProc ToggleButton#は,ClickProc(ctl as Object)とどの様に関係しているのでしょうか? 2.ss = "処理Z" ,処理 ss ・・・ssに文字列の"処理Z"を入れて,最後に「処理 ss」を行う。  この「処理 ss」というのは,どういったぐわいで使えばよろしいのでしょうか?? 3.トグルボタンは5つ使用予定ですので,toggle = Arrayに1~5, toggle(#).Valueに0~4で良いでしょうか。。。 自助努力が足りなくてすみませんが,宜しくご教示下さい。

その他の回答 (3)

回答No.4

EnableEventsはOn,Offの操作でするのがよさそうですね。noname#157639

mayu1992
質問者

お礼

こんばんは。 ご助言ありがとうございました。

回答No.3

こんにちは。 >Application.EnableEventsで 制御できないんじゃないかな … 「排他的動作の際には,TrueなToggleButton#の動作をおこなってしまいます。」 というコメントから発想を考えたわけです。他の方法もありますが、一般的には、再帰的なイベントをEnableEventsはOn・Offで操作するのが定番のはずです。 #2さんのテクニック的には、面白いのですが、結果的には、再帰的に、別のActiveX Control オブジェクトに戻ってきてしまいますね。ActiveX Control オブジェクトが大量のある場合に、それでも同じだと言えるのかどうか、試してみないので、これは、答えようがありません。ただ、私は、それを嫌って解除しようとしたわけです。元のご質問をどのように解釈しているのかもよりますが……。

mayu1992
質問者

お礼

こんばんは。 定番ってところにWindFaller様の凄さが伺えました。 他の場面でも活用したいと思います。 ありがとうございました♪

回答No.1

こんにちは。 >ToggleButton1だけ相対的に処理速度が速いです これ自体は、私の環境では実現できません。ほぼ同じでしたから、実際は、もっと数が多いのではないでしょうか。もしくは、バッファに入っていることぐらいでしょうか。 今のスタイルで、ActiveX コントロールで使う分には、しょうがないという所だと思います。 ご質問は、関係のない所のトグルボタンは、Call 処理(strCode)に飛ばないようにするということと同じ意味ではありませんか? 他にも方法としては、数が多い場合に、コードを全部インスタンスに換えて、クラスで設定すれば、イベントの発生した部分を特定化できるはずです。 とりあえず、これで、イベントのオンオフをしてやればどうでしょうか。  Application.EnableEvents = False  Application.EnableEvents = True '// Private Sub ToggleButton1_Click() Application.EnableEvents = False '全てのトグルボタンのコードに、これを入れて、 If ToggleButton1.Value = False Then   strCode = "処理中Z" '  Debug.Print "AからZに戻します。" Else   strCode = "処理中A" '  Debug.Print "Aを押しました。"   ToggleButton2.Value = False '←ここにイベント発生源   ToggleButton3.Value = False '←   〃 End If 'Debug.Print "Aでの処理をします。" Call 処理(strCode) 'Debug.Print "Aから処理をしました。" End Sub Sub 処理(strCode) Dim i As Long Dim Start As Single Dim Finish As Single Start = timer  '中略 Cells(3, 1).Value = Format$(Int((Finish - Start) * 10 ^ 4 + 0.5) / 10 ^ 4)  Application.EnableEvents = True 'ここで戻す End Sub '//

mayu1992
質問者

お礼

こんばんは♪ おまけの方なのですが,画面更新する状態で動作を確認しておりました。 トグルボタンを初めて使用したのですが,ワークシート上に上・中・下とボタン配置をしました。 なんとなくボタン配置を変えた所,一番上(垂直方向)にあるボタンの動作が速い事が解りました。 「中ボタンの上辺」が少しでも「上ボタンの下辺」に重なると両方とも遅くなる。(水平方向にずれていても) 画面更新をしない状態にすると,全て同程度で速い動作になりました。 パソコンの環境かも知れませんがご報告までに。。。 誠にありがとう御座いました♪

mayu1992
質問者

補足

あけましておめでとうございます。 御返答が遅れてすみません。 質問したコードに誤りがありました。 >strCode = "処理中A" >ToggleButton2.Value = False >ToggleButton3.Value = False ↓ ToggleButton2.Value = False ToggleButton3.Value = False strCode = "処理中A" >>ToggleButton1だけ相対的に処理速度が速いです > これ自体は、私の環境では実現できません。ほぼ同じでしたから、実際は、もっと数が多いのではないでしょうか。もしくは、バッファに入っていることぐらいでしょうか。 上記修正したコードでi=1000になるまで,トグルボタン1のON/OFFで約0.3秒 トグルボタン2,3のON/OFFで約1.5秒です。 (サンプルというよりも、この状態で停滞しております。。。) ちなみに,パソコンのスペックは以下です。 プロセッサ:Intel Core2Duo P8700@2.53GHz,RAM:2.00GB >ご質問は、関係のない所のトグルボタンは、Call 処理(strCode)に飛ばないようにするということと同じ意味ではありませんか? 現状ですと,ToggleButton1(ON)状態でToggleButton2(ON)にすると,ToggleButton1(OFF)の処理を行った後ToggleButton2(ON)の処理を行ってしまっています。 A→Z→B を A→B としたいのです。そして,ON/OFFではA→Zとしたいのです。 WindFaller様,noname157639様ご両名とも「Application.EnableEvents」に着目して頂いておりますが,質問の要領がよくなかった様ですみませんでした。(意図は汲み取って頂けていたとは思いますが。。。)

関連するQ&A

  • エクセルでセルの値がTRUEかFALSEか判定

    Q3:R19の表があります。 Q列にはTRUEかFALSEが入りますが、空白や文字列の場合もあります。 R列には文字列です。 Q列でFALSEのセルだけ、同じ行のとなりのR列の文字列を順に抜き出し、メッセージボックスに表示したいのです。 下記のようなVBAを書いてみましたが、Q列が空白や文字列の場合まで抽出されてしまいます。 これを排除するいい方法はないでしょうか? Sub test01()   Dim msg As String   Dim i As Long   With Sheets("LOG")     For i = 3 To 19       If .Range("Q" & i).Value = False Then '        Debug.Print  i & "-" & .Range("R" & i).Value         msg = msg & .Range("R" & i).Value & vbCrLf       End If     Next i   End With   If msg <> "" Then     MsgBox msg & vbCrLf & "上記により不可です。", vbCritical   End If End Sub

  • エクセルVBAでPDFを1枚目のみ印刷したい

    下記のVBAに複数PDFが重なっている場合は、一枚目のみ印刷する文面を 挿入したいのですがうまくいきません Sub Test() Dim z As Object Dim i As Long Dim f, p As String Application.ScreenUpdating = False Set z = CreateObject("WScript.Shell") p = Application.ActivePrinter For i = 1 To Range("A1").End(xlDown).Row f = "h:\hozei\" & Cells(i, 1).Value & ".pdf" If Dir(f) <> "" Then z.Run ("AcroRd32.exe /t " & f) Else Cells(i, 2).Value = Cells(i, 1).Value Cells(i, 1).Value = "" End If Next i Set z = Nothing End Sub お忙しいところ申し訳ございません どなたかご教示願います。

  • 「Debug.Print i = i + 1」がFalseになる。

    Sub test() Dim i As Long i = 0 Debug.Print i = i + 1 End Sub を実行すると False がイミディエイトウインドウに表示されます。 理由が知りたいです。 よろしくお願いします。

  • エクセルのマクロについて

    お手数ですが誰か教えてください! BのデーターをAに集計するマクロを作ったのですが 処理速度とっても遅いのです。 高速で処理する方法はありませんでしょうか? 私が作ったマクロ Sub 集計() Dim Z As Integer Dim i As Integer Dim X As Integer For Z = 2 To 2000 For i = 2 To 2000 For X = 3 To 20 If Worksheets("A").cells(Z, 1) = Worksheets("B").cells(i, 1) And       Worksheets("A").cells(1, X) = Worksheets("B").cells(i, 14) Then Worksheets("A").cells(Z, X) = Worksheets("B").cells(i, 16) End If Next X Next i Next Z End Sub       どこかが間違っている気がしますがマクロ初心者のため       先に進めません。       どうかご教授よろしくお願い致します。

  • 【エクセル】ActiveCellはなぜNullではないのでしょうか?

    私は今まで新規のシートを挿入した際のActiveCellは、Nullだと思っていたのですが Sub Empty空白なら() If ActiveCell.Value = Empty Then Debug.Print "空白セルです" End Sub Sub Null空白なら() If ActiveCell.Value = Null Then Debug.Print "空白セルです" End Sub Sub Null空白なら2() If IsNull(ActiveCell.Value) = True Then Debug.Print "空白セルです" End Sub VBAでこのコードを実行すると Emptyの方だけ「空白セルです」となりました。 (1)なぜ空白でもNullだと反応しないのでしょうか? (2)NullとEmptyの違いはなんですか? ご教授よろしくお願い致します。

  • VB.NET 2008 Eventステートメント

    VB.NET 2008 以下の実装で実行したところ、GC強制実行後のメモリ状態に疑問を持ち質問しました。 Eventを所持したクラスの生成、削除を繰り返し、GCを強制実行したところ、 16バイトごと増加していきます。 Class1で定義したm_eventをイベントから別のタイプ、例えばIntegerやString型に変更して、 同様に実行したところ、メモリの増加は見受けられません。 なぜでしょうか? またこの現象はメモリリークといえるのでしょうか? Public Class Class1 Public Sub New() End Sub Private Event m_event() End Class Sub Main() GC.Collect() Debug.Print("####") Debug.Print(GC.GetTotalMemory(False)) Dim cls As Class1 For i As Integer = 0 To 1000 cls = New Class1 cls = Nothing If i = 0 Then GC.Collect() Debug.Print(GC.GetTotalMemory(False)) End If Next GC.Collect() Debug.Print(GC.GetTotalMemory(False)) Debug.Print("@@@@") End Sub

  • エクセルVBAのイベントで質問です。

    ダブルクリックイベントで、G12:G31の範囲の文字列をB10:B27の範囲(最下行)に入れていくものを使っていますが、新たにH12:H31にある文字列もダブルクリックするとC10:C27の範囲(最下行)に入れていけるようにしたいと思います。 どのようにすればいいでしょうか。 ご存知の方いらっしゃればお教えいただけると助かります。 Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Excel.Range, _ Cancel As Boolean) Dim i As Long Dim flg As Boolean If Intersect(Target, Range("G12:G31")) Is Nothing Then Exit Sub If IsEmpty(Target.Value) Then Exit Sub With Worksheets("シートA") For i = 10 To 27 If .Range("B" & i).Value = "" Then .Range("B" & i).Value = Target.Value flg = True Exit For End If Next i If flg = False Then MsgBox .Name & " がいっぱいです。" End If End With Cancel = True End Sub

  • excel vba

    VBAに不慣れなので教えてください。 今下記のプログラム(A1セルで青色以外の文字を消去する)はA1セルのみを対象にしているのですが、 (1)セルをA1からA3までにする。 (2)処理対象をA1のある列を対象とするようにしたい。 各々どう手直しすればいいか。 プログラムtest Public Sub test() Dim r As Range Dim i, wk As String Set r = Range("A1") wk = "" For i = 1 To Len(r.Value) Debug.Print r.Characters(i, 1).Font.ColorIndex If r.Characters(i, 1).Font.Color = vbBlue Then wk = wk + r.Characters(i, 1).Text End If Next r.Value = wk r.Characters.Font.Color = vbBlue End Sub

  • エクセルVBA

    A列を基準にBC列が空白ならAの数値を入れて、A>BならB列を更新、A<CならC列を更新 A列が数値以外ならその行をスキップ、という処理をしたいのですが Option Explicit Dim A As Range, B As Range, C As Range Dim i As Long Sub test() For i = 1 To 10 Set A = Cells(i, 1) Set B = A.Offset(0, 1) Set C = A.Offset(0, 2) If IsNumeric(A) Then Else Exit Sub End If If B.Value = "" Then B.Value = A.Value If C.Value = "" Then C.Value = A.Value If A.Value > B.Value Then B.Value = A.Value If A.Value < C.Value Then C.Value = A.Value Next i End Sub とすると数値以外の行の時点で停止してしまいます。 その行を飛ばして次の行に進むにはどうしたらいいのでしょうか?

  • エクセルのマクロで

    お世話になります 下記のマクロで実行した所 100まで書式設定で保護、ロックしたいのですが b3:l3はロックするものの 4行目以降はロックしません どうしたらいいでしょうか もう1つ、このシートはいつもc3からはじめたいのですが If ActiveCell.Value >= "" Then の部分はどうしたらいいでしょうか よろしくおねがいいたします 初心者でバカな質問ですみません Sub マクロ1() Dim i As Integer For i = 1 To 100 If ActiveCell.Value >= "" Then Range("B3:l3").Select Selection.Locked = True Selection.FormulaHidden = False End If ActiveCell.Offset(1, 0).Select Next End Sub

専門家に質問してみよう