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

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

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

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

Q&A

解決済

2回答

10843閲覧

【VBA】デバックモードと実行時で動作が違う

Masalu_Kudou

総合スコア91

VBA

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

0グッド

3クリップ

投稿2019/07/15 09:10

お世話になっております。

Excel VBAでどうしても解決できない問題が発生しております。

VBA

1Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 2 3Sub enemy_move() 4 5 6 Dim enemy(4) As Integer 7 Dim gocnt As Integer 8 9 For gocnt = 1 To 5 10 enemy(0) = gocnt 11 enemy(1) = enemy(0) + 1 12 enemy(2) = enemy(0) + 2 13 enemy(3) = enemy(0) + 3 14 15 Cells(1, enemy(0)) = "V" 16 Cells(1, enemy(1)) = "." 17 Cells(1, enemy(2)) = "." 18 Cells(1, enemy(3)) = "V" 19 20 Sleep 500 21 22 Cells(1, enemy(0)) = "" 23 Cells(1, enemy(1)) = "" 24 Cells(1, enemy(2)) = "" 25 Cells(1, enemy(3)) = "" 26 Next 27 28End Sub 29 30

特に捻りもない「V..V」を右に移動させていくだけのマクロなのですが、
F5で実行すると「..V」の部分が表示されません。

しかし、F8で1行ずつ実行すると、期待の動作で動きます。
これはどのように解決すればよいでしょうか?
お分かりの方がいらっしゃればご教授お願いいたします。

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

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

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

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

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

guest

回答2

0

解決済みですか、おもしろそうなので、自分なりに作成してみました。
Enemyのテキストは配列にして、Enemyのセル範囲はRange変数にして、
一気に代入します。
Offsetメソッドで移動させます。

vba

1Sub enemy_move3() 2 Dim aryEnemy As Variant 3 aryEnemy = Split("V . . V") 4 5 Dim rngEnemy As Range 6 Set rngEnemy = ActiveSheet.Cells(1, 1).Resize(, 4) 7 8 rngEnemy.Value = aryEnemy 9 10 Dim gocnt As Long 11 For gocnt = 1 To 5 12 Application.ScreenUpdating = True 'Excel側に画面強制更新の依頼。 13 VBA.DoEvents 'Excelが画面更新できるように、処理を手放す。 14 Sleep 500 15 16 rngEnemy.ClearContents 17 Set rngEnemy = rngEnemy.Offset(, 1) '右へ1つ移動 18 rngEnemy.Value = aryEnemy 19 Next gocnt 20 21End Sub

Enemyを自由に動かしたいなら、クラスモジュールにするといいかも。

投稿2019/07/15 17:14

hatena19

総合スコア33742

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

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

Masalu_Kudou

2019/07/15 17:27

同じ目的でも、ソースの書き方が若干変わってきますね。 私は正直Offsetが得意でないので勉強になります。ありがとうございます。
imihito

2019/07/16 04:03

実際書くのなら、自分もこちらの方が書き方としては好みです 徐々に移動する感じを出そうとすると、1個ずつ代入するのも有りな気はしますが
guest

0

ベストアンサー

Excel内のVBAから処理を実行した場合、「enemy_moveというひとかたまりの処理を実行している」と判断され、enemy_moveの処理が優先となり、Excel側の画面の更新の頻度などが低下します。

画面の更新頻度が下がるため、セルに値を設定した結果が画面に反映されにくくなります。

対してデバッグモードでは、1行ずつ処理が止まるため、処理が止まっている間にExcelが画面を更新し、意図通りの表示が得られます。

解決策としては、DoEventsなどでVBA側から処理を一旦手放して、Excel側が画面を更新できるタイミングを作る方法がよく知られています。

私の環境(Win10 Excel Office 365 64bit)では、Sleepの前に以下の2行を入れることで、期待されている動作をしました。

vba

1Excel.Application.ScreenUpdating = True 'Excel側に画面強制更新の依頼。 2VBA.DoEvents 'Excelが画面更新できるように、処理を手放す。

以下、処理内で気になった点です。

配列の大きさ

vba

1Dim enemy(4) As Integer

上記のように配列を宣言した場合、enemyの要素数は0から4の5個となります(C言語などとは異なる)。

個人的には、以下のように下限を明示した方がわかりやすいと感じています(VBScriptでは使えませんが)。

vba

1Dim enemy(0 To 3) As Integer

Integer

VBAに限定した話ではありますが、VBAのIntegerは扱える数値の範囲が小さく、Longに比べると処理速度が遅いです。

そのため、IntegerよりLongを使った方が良い場面が多いです。


その他いくつか気になった点も統合すると以下のようになります。

vba

1Sub enemy_move2() 2 'Excel VBA 一般論としてセルを参照するときは親シートを明示しておいた方が良い。 3 Dim ws As Excel.Worksheet 4 Set ws = ActiveSheet 5 6 Dim enemy(0 To 3) As Long 7 Dim gocnt As Long 8 9 With ws.Cells 10 For gocnt = 1 To 5 11 enemy(0) = gocnt 12 enemy(1) = enemy(0) + 1 13 enemy(2) = enemy(0) + 2 14 enemy(3) = enemy(0) + 3 15 16 .Item(1, enemy(0)).Value = "V" 17 .Item(1, enemy(1)).Value = "." 18 .Item(1, enemy(2)).Value = "." 19 .Item(1, enemy(3)).Value = "V" 20 21 .Application.ScreenUpdating = True 'Excel側に画面強制更新の依頼。 22 VBA.DoEvents 'Excelが画面更新できるように、処理を手放す。 23 Sleep 500 24 25 .Item(1, enemy(0)).Value = "" 26 .Item(1, enemy(1)).Value = "" 27 .Item(1, enemy(2)).Value = "" 28 .Item(1, enemy(3)).Value = "" 29 Next gocnt 30 End With 31End Sub

投稿2019/07/15 11:18

imihito

総合スコア2166

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

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

Masalu_Kudou

2019/07/15 11:30

丁寧でわかりやすい解説を含め、ありがとうございました。 目から鱗が落ちるばかりです。大変勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問