• ベストアンサー

Excel VBA:コントロールボタンのEnabledプロパティーについての質問

コマンドボタンのEnabledプロパティーを変更したときの挙動が良くわからず 困っており、お教えいただけると幸いです。 Excelのワークシート上にCommandButtonを作り(名前をCommandButton1とします)、 module1に以下のプロシージャを書き、Enabledプロパティーを変化させます。 Sub test() ActiveSheet.CommandButton1.Enabled = Not ActiveSheet.CommandButton1.Enabled MsgBox "here" End Sub 上記のプロシージャに期待したのは、Enabeldの状態が反転した後、 hereの文字が表示されると言うものですが、 実際は先にhereの文字が表示されてしまいます。 また、不思議なことにDoEventsを二つ連続でMsgBoxの前に入れると きちんと動きます。 (ステップ実行でもきちんと動きます。) 最終的には、もっと長いプログラムの中で使う予定なので、 全てのEnabled文の後にDoEventsを二連続で書くという対症療法以外で、 良い解決方法が無いか、お教えいただけると幸いです。 なお、環境はwindowsXP、excel2003です。 よろしくお願いいたします。

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

  • ベストアンサー
  • piyo2000
  • ベストアンサー率49% (144/293)
回答No.1

>良い解決方法が無いか、お教えいただけると幸いです。 VB6でもそうなんですが、VBAのコマンドボタン(いわゆるForms2.0)はこういう仕様になっています。 少し難しい話になってしまいますが Enabledプロパティの状態が即座に反映されるようになるには、 コマンドボタンの再描画の結果を待つことが必要になります。 そしてこの現象は、再描画が完了する前にMsgBox(モーダルなフォーム)が出現してしまい、 再描画が待たされている状態なんですね。 (基本的にメッセージボックスが出てしまったら、その親は画面の再描画が出来なくなる) で、VB6/VBAでは再描画を待つということがDoEventsでしか(ほぼ)出来ないのです。 >全てのEnabled文の後にDoEventsを二連続で書くという対症療法 ですので、これは対症療法ではありません。 もっとも、元々のコードが酷いからこのような結論になってしまうのですが(^^; test()では、「アクティブシートのCommandButton1」の状態しか変えることが出来ませんよね。 アクティブシートにコマンドボタンが無ければ、 いや「CommnandButton1」というオブジェクトが無ければエラーになってしまいます。 このようなコードを私は書かないわけでは決してないんですが、 「全てのEnabled文の後に・・・」という愚痴は、絶対に言いません。だって、それは分かりきって書いていますから。 だったらこうするべきでしょう。 'MSForms.CommandButtonでエラーになる場合は"object"で Sub ChangeStatus(oCmd As MSForms.CommandButton) DoEvents oCmd.Enabled = Not oCmd.Enabled DoEvents 'MsgBox "here" End Sub Sub test() call ChangeStatus(ActiveSheet.CommandButton1) MsgBox "here" End Sub '-------------------------------- つまり、「コマンドボタンの状態を変え、Doeventsを発行する」という一連の作業を関数にしてしまえばいいんですよ。 ちなみにDoEventsは状態を変える前と後で発行してもうまく行きます。

sirakura3
質問者

お礼

ご回答、ありがとうございます。 自分でも散々調べたのですが、理由がわからず困っておりました。 しかし、piyo2000様の明快な回答を拝見させていただき、スッキリいたしました! また、作業を関数にして解決する案、目から鱗が落ちた感じです。 こういう解決方法があったんですね。大変参考になりました。 本当にありがとうございました。

その他の回答 (1)

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

CommandButtonなどはUserFormで使うことが前提のためのように思います ご質問と同様のことをUserForm上で実現すると Enabledを変更した後にDoEventsを一度実行すればMsgBoxを表示する前に状態は変化するようです Worksheet上の場合は2度の実行が必要なようですが …

sirakura3
質問者

お礼

ご回答ありがとうございます。 恥ずかしながらCommandButtonなどはUserFormで使うと言う前提も知らずに 使っておりました。 勉強になります。 しかし、worksheet上の場合は二回実行しないと動かないと言うのも、 面白いものですね。困ったときのDoEventsと言う感じですね。 ありがとうございました。

関連するQ&A

  • EXCEL VBAのRangeプロパティについて

    EXCEL VBAのRangeプロパティについて 下の2つのプログラムで表示されるメッセージは、 プロシージャAは"$B$1" プロシージャBは"$A$1" なのですが、Rangeプロパティはどういう使われ方をしているのでしょうか? お教えくださいませ。 ・プロシージャA Sub test1() Cells(1, 2).Activate MsgBox ActiveCell.Range("A1").Address End Sub ・プロシージャB Sub test2() Cells(1, 2).Activate MsgBox ActiveSheet.Range("A1").Address End Sub

  • エクセルVBAでフォームのボタンとコントロールツールボックスのコマンドボタン

    エクセルVBAでフォームのボタンとコントロールツールボックスのコマンドボタンについて教えてください。 実はこれまでフォームしか使ったことがないのですが、フォームのボタンですと、下記のように一つのプロシージャを多数のボタンから呼び出し、呼び出したボタンにより異なった指示が出来ます。 Sub test() x = Application.Caller Select Case x Case "ボタン 1" MsgBox 1 Case "ボタン 2" MsgBox 2 Case "ボタン 3" MsgBox 3 Case "ボタン 4" MsgBox 4 End Select End Sub コントロールツールボックスは Private Sub CommandButton1_Click() MsgBox 1 End Sub Private Sub CommandButton2_Click() MsgBox 2 End Sub のようにコマンドボタンごとにひとつずつ書くしかないのでしょうか?

  • オブジェクトのプロパティーをVBAで操作する方法

    今、Excel97とVBAを用いて、ツールを作成しています。 VBAでシートに貼り付けたボタンをEnabled=TrueにしているのをEnabled=Falseにしたいと思い、ヘルプを元に作成しました。しかし、「変数が定義されていません。」と表示されてしまいます。 Sheet オブジェクト名:CommandButton1 VBA sub 表示操作() CommandButton1.Enabled = True ← エラー箇所 end sub オブジェクトのプロパティーをVBAから操作する方法を教えて下さい。

  • VBAのプロパティウィンドウについて

    VBAでプロパティウィンドウには ・Microsoft Excel Object ・フォーム ・標準モジュール があります。 ところで、下のプログラムですが、(1)の部分を標準モジュールに書き込み、フォームにあるコマンドボタンをクリックしたら、"test.xls"が表示されます。 しかし、(1)の部分をMicrosoft Excel Object のsheet1(sheet1)のコードに書き込み、プログラムを実行させると、フォームのコマンドボタンをクリックしても"test.xls"は表示されません。 これはなぜですか? (1)の部分のコマンドボタン1はsheet1に存在します。 (1)----------------------------------- Private file_name as string Private Sub CommandButton1_Click()   file_name="test.xls" UserForm1.Show End Sub (1)----------------------------------- フォーム Sub CommandButton1_Click() MsgBox file_name End Sub

  • エクセルVBAのIDプロパティ?

    今日初めて知ったのですが「セルに識別用ラベルを設定する」IDプロパティというのがあるようです。ただVBEの「ヘルプ」を見ただけでは「Web ページとして保存し、HTML 行を Web ページに追加」するもののようで、Web ページ保存になど縁のないわたしにはさっぱりわかりません。でも、面白そうなので試してみると、 Sub ID_Wt() ActiveSheet.Range("V10").ID = "ABC" End Sub で、セルV10に"ABC"が設定され、 Sub ID_Rd() MsgBox ActiveSheet.Range("V10").ID End Sub で、読むことができました。 ◎ IDはセルのどこに保存されたのでしょうか?セルのどこを見ても見当たりませんし、そのセルはそれまでのUsedRange外に設定した場合でもUsedRangeは拡張されまれません。とても不思議です。 ◎ VBA以外の方法でIDを読むことは出来るのでしょうか? ◎ 一旦終了すると設定したIDは消えてしまうようですがそういうものなのでしょうか?

  • Excel VBA で処理中断(DoEvents)ができなくて困ってい

    Excel VBA で処理中断(DoEvents)ができなくて困っています。 まず、CommandButton1ボタンでSampleをコールし、Sample処理の中でループを廻し、途中でCommand1ボタンをクリックして、処理中断(DoEventsによって)をいれたいと思っています。 しかし、Command1ボタンをクリックしても処理中断がきかないのです。 グローバル変数fStopにはCommand1ボタンをクリックしたときにTrueが入っていることは、MsgBoxで確認していますが、Sample処理の方に値がつたわっていないようで、ループが最後まで止まりません。 コードが悪いのでしょうか、それとも、DoEventsの使い方が悪いのでしょうか。 もし、DoEventsが使えないのであれば、代替手段はありますでしょうか。 (長時間の印刷中の処理中断に応用したいと思っています) 環境はExcel 2002 SP3 , VB 6.0 , Windows XPです。 なお、DoEventsのコードは以下のURLを参考にして作成しました。 http://officetanaka.net/excel/vba/function/DoEvents.htm コードは以下のとおりです。 '********* Dim fStop As Boolean 'グローバル変数を宣言 '********* Sub Sample() Dim i As Long fStop = False For i = 1 To 1000000 DoEvents If fStop = True Then MsgBox "処理が中断されました" Exit For End If Next i End Sub '******** Private Sub CommandButton1_Click() Call Sample End Sub '******** Private Sub Command1_Click() fStop = True MsgBox "fStop=" & fStop End Sub

  • VBA クラスにプロパティが実装できません

    VBA初心者です。 現在、Excel2003-VBAでクラスにプロパティの実装を試みていますが、うまくいきません。 Publicで宣言する方法は問題なく出来たのですが…。 勉強用のため、敢えて簡単なサンプルを自分で作っています。 【状況】 下記プログラムで、メッセージを「20」と表示させたいのですが、 「スタック領域が不足しています」エラーにより、実行できません。 また「Atai」を「Suji」にかえると、メッセージとして「0」と出てきます。 あるいは、「Suji = Atai + 5」を消してみても「15」ではなく「0」と出ます。 【質問】 どちらでもうまくいかないのですが、これは (1)このコードがおかしいのか、それとも (2)単純なプログラムであるのに領域不足と出るところから、 VBA特有の不具合でどうしようもない物なのでしょうか? ご意見お待ちしています。 ===通常Module(呼び出し側)=== Option Explicit Sub 実行() Dim Haichi As New Class1 With Haichi .Suji = 15 .MSGクラス End With End Sub ===クラスMODULE(Class1)=== Option Explicit Sub MSGクラス() MsgBox Suji End Sub Public Property Let Suji(Atai As Double) Suji = Atai + 5 End Property Public Property Get Suji() As Double End Property

  • エクセルVBA イベントプロシージャに引数を渡せま

    お世話になります。 エクセル2003/XP 使用です。 イベントプロシージャに引数を渡せまるかどうか教えていただけますでしょうか? 下記のコード中の変数mysheetnameを ユーザーフォーム、→ CommandButton1のプロシージャに 引数として渡して行きたいのですが、 実行すると、一番最初のWorkbook_SheetBeforeRightClickの時点で、 コンパイルエラー:  プロシージャの宣言が、イベントまたはプロシージャの定義と一致していません。 とエラー表示されます。 イベントプロシージャに引数を渡すことはできますでしょうか? ---------- ThisWorkBook内 ---------- Public mysheetname As String Private Sub Workbook_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean) mysheetname = ActiveSheet.Name UserForm1.Show (mysheetname)     '←変数mysheetnameの値をユーザーフォームに渡したい。 End Sub ---------- ユーザーフォーム ---------- Private Sub UserForm_Initialize(ByVal mysheetname As String ) 処理 End Sub Private Sub CommandButton1_Click(ByVal mysheetname As String ) 処理 End Sub ’--------- ここまで 引数について少し理解し始めたばかりの者です。 よろしくお願いします。

  • EXCEL VBA これであっていますか?

    エクセルに地図を貼り付け、その中のある地点Aから半径1キロ、2キロ、3キロといった具合に円を描いています。ある地点B、Cも同様に円があります。セルに“A” と入力した際に該当する地点の円(1キロ、2キロ、3キロの3種類)を赤く表示し、終了すると円が消える(線なしに変わる)ようにするために以下のようなVBAを組みました。が、円が2つしか赤くならなかったり、 ばあいによっては「インデックスが境界を超えています」とエラーが出たりします。 どうしたら良いか教えてください。 Sub iro() Dim i As Variant i = InputBox("表示する地点を指定してください", "地点指定") If i = "A" Then ActiveSheet.Shapes(1).Select ActiveSheet.Shapes(2).Select ActiveSheet.Shapes(3).Select Replace:=False hyoji MsgBox "表示を終了してよろしいですか", vbOKOnly ActiveSheet.Shapes(1).Select ActiveSheet.Shapes(2).Select ActiveSheet.Shapes(3).Select Replace:=False modosu ElseIf i = "B" Then ActiveSheet.Shapes(4).Select ActiveSheet.Shapes(5).Select ActiveSheet.Shapes(6).Select Replace:=False hyoji MsgBox "表示を終了してよろしいですか", vbOKOnly ActiveSheet.Shapes(4).Select ActiveSheet.Shapes(5).Select ActiveSheet.Shapes(6).Select Replace:=False Else MsgBox "指定した地点がありません", vbOKOnly End If End Sub Sub hyoji() Selection.ShapeRange.Line.Visible = msoTrue '「線なし」に設定されている場合、線を表示 Selection.ShapeRange.Line.ForeColor.SchemeColor = 10 Range("A1").Select End Sub Sub modosu() Selection.ShapeRange.Line.Visible = msoFalse '「線なし」に設定 Range("A1").Select End Sub

  • エクセル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

専門家に質問してみよう