dポイントプレゼントキャンペーン実施中!

師も走りまわる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だけ相対的に処理速度が速いです・・・。
なぜなんでしょう??

A 回答 (4件)

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

といったぐあいで …

この回答への補足

かなり開けてしまいましたが,あけましておめでとうございます♪
お礼が遅れましてすみません。

コードをみると,直接打ち込んでいらっしゃるのでしょうか。すごいです♪
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で良いでしょうか。。。
自助努力が足りなくてすみませんが,宜しくご教示下さい。

補足日時:2015/01/14 21:16
    • good
    • 0
この回答へのお礼

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

お礼日時:2015/01/24 22:17

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

noname#157639
    • good
    • 0
この回答へのお礼

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

お礼日時:2015/01/08 21:11

こんにちは。



>Application.EnableEventsで 制御できないんじゃないかな …

「排他的動作の際には,TrueなToggleButton#の動作をおこなってしまいます。」
というコメントから発想を考えたわけです。他の方法もありますが、一般的には、再帰的なイベントをEnableEventsはOn・Offで操作するのが定番のはずです。

#2さんのテクニック的には、面白いのですが、結果的には、再帰的に、別のActiveX Control オブジェクトに戻ってきてしまいますね。ActiveX Control オブジェクトが大量のある場合に、それでも同じだと言えるのかどうか、試してみないので、これは、答えようがありません。ただ、私は、それを嫌って解除しようとしたわけです。元のご質問をどのように解釈しているのかもよりますが……。
    • good
    • 0
この回答へのお礼

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

お礼日時:2015/01/08 21:16

こんにちは。



>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
'//

この回答への補足

あけましておめでとうございます。
御返答が遅れてすみません。
質問したコードに誤りがありました。
>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」に着目して頂いておりますが,質問の要領がよくなかった様ですみませんでした。(意図は汲み取って頂けていたとは思いますが。。。)

補足日時:2015/01/05 23:01
    • good
    • 0
この回答へのお礼

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

お礼日時:2015/01/08 21:33

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!