[[20161205130110]] 『画面更新の停止タイミングで出力結果が変わる』(メンマ) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『画面更新の停止タイミングで出力結果が変わる』(メンマ)

初めまして。
会社で使う報告書作成用のマクロを作っていたのですが、行の削除に合わせて上に移動するはずのグラフが移動していないことに気づきました。
そこで、デバッグを行い発生箇所を特定し、再現を行ったところ下のコードで再現することを確認しました。

詳細はコメントアウトしているところに書いてありますが、Book1とBook2という二つのファイルがあり、どちらもSheet1というSheetを持っています。Sheet1のA3の位置には長方形の図形が張ってあるのですが、このマクロで1行目の行を削除したところBook1のほうはA2の位置に図形が移動しているのに対し、Book2のほうはA3の位置のままなのです。

既に対処は済ませ、解決はしているのですが、全てBookをOpenしたあとマクロを起動したBookのSheetをActivateして前面にしたあと
Application.ScreenUpdating = True
Application.ScreenUpdating = False
の2行を入れるという荒い方法を採用しています。そこでこの現象の原因と他のスマートなやり方はないかご教授願えないでしょうか。分かりにくくて申し訳ありませんがどうぞよろしくお願い致します。

Sub Macro1()

'Book1とBook2が存在
'それぞれSheet1というシートをもつ
'Sheet1のRange("A3")には長方形の図形(shapes_Aとする)が貼り付けられている。
'以下のコードにてRows(1)(1行目)を削除した場合、shapes_Aは
'Book1においてはRange("A2")に貼り付けられた状態(セルに合わせて移動している)が、
'Book2においてはRange("A3")の位置のままであるのはなぜか?

'※初期状態はRange("A1:A2")には"x"が入っており、Rows(1)が削除できていることは確認できている。

Workbooks.Open Filename:="C:\Users\xxx\Desktop\Book1.xlsx" 'book1を開く

Application.ScreenUpdating = False '描画停止

Workbooks.Open Filename:="C:\Users\xxx\Desktop\Book2.xlsx" 'book2を開く

'book1は行が削除できて図も移動する
Workbooks("Book1.xlsx").Sheets("Sheet1").Rows(1).Delete

'book2は行を削除できるが、図が移動しない
Workbooks("Book2.xlsx").Sheets("Sheet1").Rows(1).Delete

Application.ScreenUpdating = True '描画再開

End Sub

< 使用 Excel:Excel2010、使用 OS:Windows7 >


図形の書式設定−プロパティの中に、セルに合わせて移動やサイズ変更をするかどうかの指定があります。
これを、移動やサイズ変更をしない、としておけば、移動しない事で統一できるのですが、いかがでしょうか?
(???) 2016/12/05(月) 13:43

???様

ご回答ありがとうございます。
申し訳ありませんが、移動させる必要がありますのでその案は採用しかねます。

なお、記載しておりませんでしたが、図形はどちらもPlacement = 1です(Debug.Printで各処理のあとに吐かせましたが変動はありませんでした)。
(メンマ) 2016/12/05(月) 13:54


 対して違いはないが。

 Book1を開く前に
 Application.ScreenUpdating = False

 Book2を開いた後に
 ThisWorkbook.Activate
 Application.ScreenUpdating = True
 としてから行の削除。
(ねむねむ) 2016/12/05(月) 13:57

ねむねむ様

ご回答ありがとうございます。
記載している行の削除のみのマクロならそれで問題ないのですが、実際のマクロのほうではその後も別の処理が続き、そこで描画されてしまうのです。そのため全てのBookを開いたあと
ThisWorkbook.Activate
Application.ScreenUpdating = True
Application.ScreenUpdating = False
としております。つまりご回答いただいた方法を現在採用している形になります。

ですが、この記述は私にとってあまり気持ちのいいものではありません。そこで、このようになってしまう原因と、もっと簡便で済む他の方法をご教授頂きたいのです。
(メンマ) 2016/12/05(月) 14:28


>Application.ScreenUpdating = True
>Application.ScreenUpdating = False
>の2行を入れるという荒い方法を採用しています。

1回更新しておかないといけないのは、なんででしょうね。
荒いとは思いませんけど、更新してやればいいなら更新すればいいと思います。
(DoEventのおまじないは聞かないっぽいかな。。。^^;)

'Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Sub test()

    Dim sPath As String
    Dim wb1 As Workbook
    Dim wb2 As Workbook

    sPath = CreateObject("Wscript.Shell").SpecialFolders("Desktop") & "\"

    Application.ScreenUpdating = False
    Set wb1 = Workbooks.Open(Filename:=sPath & "Book1.xlsx")
    Set wb2 = Workbooks.Open(Filename:=sPath & "Book2.xlsx")

' DoEvents
' DoEvents
' Sleep 500
' DoEvents
' DoEvents

    Application.ScreenUpdating = True
    Application.ScreenUpdating = False

    wb1.Sheets(1).Rows(1).Delete
    wb2.Sheets(1).Rows(1).Delete

    Application.ScreenUpdating = True
End Sub
(まっつわん) 2016/12/05(月) 14:29

 >実際のマクロのほうではその後も別の処理が続き、そこで描画されてしまうのです。
 その後の処理でBOOK1、BOOK2をアクティブにする必要はあるのだろうか?
 それともマクロブックのほうを更新するのだろうか?

(ねむねむ) 2016/12/05(月) 14:46


 >>実際のマクロのほうではその後も別の処理が続き

実際には、最後は全部開いたままで終わりなら、↑でいいかもだけど、
順次、その都度処理したかったら、困りますね。。。

「行を削除したら、図もずれるはず」、という考えを止めて、
「行を削除したら、図もずらす」と明示的に書いてみるのもありですかね。。。

Sub test()

    Dim sPath As String
    Dim wb As Workbook
    Dim shp As Shape
    Dim Rng As Range
    Dim i As Long

    sPath = CreateObject("Wscript.Shell").SpecialFolders("Desktop") & "\"

    Application.ScreenUpdating = False
    For i = 1 To 2
        Set wb = Workbooks.Open(Filename:=sPath & "Book" & i & ".xlsx")
        Set shp = wb.Sheets(1).Shapes(1)
        Set Rng = shp.TopLeftCell
        wb.Sheets(1).Rows(1).Delete
        shp.Top = Rng.Top
    Next
    Application.ScreenUpdating = True
End Sub
(まっつわん) 2016/12/05(月) 15:04

 そんなことはないだろうと、コピペして実行してみましたが、確かに提示のコードでは
 Book2 の図形は移動しませんね。
 (あたりまえですが、移動しなくても 行は削除されていることは確認しました)

    Workbooks.Open Filename:="C:\Users\進一郎\Desktop\Test\Book1.xlsx"    'book1を開く
    Workbooks.Open Filename:="C:\Users\進一郎\Desktop\Test\Book2.xlsx"    'book2を開く
    Application.ScreenUpdating = False    '描画停止

 こうしてやると Bkk1,Book2 ともに 図形が移動します。

 また、

    Application.ScreenUpdating = False    '描画停止
    Workbooks.Open Filename:="C:\Users\進一郎\Desktop\Test\Book1.xlsx"    'book1を開く
    Workbooks.Open Filename:="C:\Users\進一郎\Desktop\Test\Book2.xlsx"    'book2を開く

 こうすると、Book1もBook2 も図形は移動しません。

 現象面からだけ推理すると、ブックが開かれたときに ちゃんと描画されている場合に、図形は移動。
 描画されていない状態であれば、なぜか、その図形が3行目の場所に配置されているということを
 エクセルが認識できていない そんな状況ですね。

 へぇ〜っと、初めてこういうことになることを知りました。
 MS のバグっぽい感じですが。

 なぜだといわれても、理由はわかりません。
 ブックを開く際に 描画状態にしてやる必要があるということだけは(現象面から)確かなようです。

(β) 2016/12/05(月) 16:35


ねむねむ様
アクティブにしていた箇所を指定する形にし実行してうまくいくことを確認しました。
が、これでは描画停止した場合に比べ速度が落ちてしまいます。できれば描画停止後に開いたBookの図形がセルの動きに追従しない点をどうにかしたいのですが…

まっつわん様
なるほど、意図してずらすというのは考えていませんでした、検討してみます(コードが増えるのがややネックですが…)。

β様
やはり原因不明ですか…図形やグラフのPlacement等の処理は描画処理に依存でもしてるんですかね?自分でもあれこれと考えて調べてみたのですが、期待した明確な答えは得られなかったのでご質問させていただいた次第です。
(メンマ) 2016/12/05(月) 17:04


 >>描画停止した場合に比べ速度が落ちてしまいます。
 >>できれば描画停止後に開いたBookの図形がセルの動きに追従しない点をどうにかしたいのですが… 

 皆さんからのアドバイスのように、この(バグっぽい)現象の回避策はいろいろあるわけですが
 速度が落ちる というのは、確かにそうですけど、開く瞬間ですよね。
 ブックを開いてしまえば、あとは ScreenUpdating を False にしても 問題なく実行されるわけですから
 βであれば、開く時点では True。開いた後に、すぐに False。

 既存のコードは一切変えず、ScreenUpdating の手当てだけですませますね。

 コード全体が見えないのですが、なぜ、Book1 だけは描画状態で開き、Book2 は 描画抑止して開くのでしょうか。
 とにかく最初に2つのブックを描画状態で開き、そのあとに False にすればいいだけのことではないですか?

 ブックが2つ開かれているといって、それぞれのブックに対する処理ができないわけではありませんので。

(β) 2016/12/05(月) 17:16


β様
記載しているコードは不具合の再現確認を行ったものと書いてあると思うのですが・・・
実際のコードで問題となったのは「画面描画を停止したあとに開いたbookの行削除を行ったところグラフが動いていなかった」です。
既に書いてありますがbookを開いたあと画面描画を再開・再停止すれば解決することはわかっています。ですが何度も画面描画の記述をするのは私的に気に食わないので他の方法か、この現象の原因がわかれば別のアプローチで解決できるのではないかと思い質問させて頂いたのです。
しかしどうやらこの現象の原因について言及できる方はいらっしゃらないようですね、ここまででもう結構です。お付き合いありがとうございました。
(メンマ) 2016/12/07(水) 08:08

 >「画面描画を停止したあとに開いたbookの行削除を行ったところグラフが動いていなかった」 
 >この現象原因がわかれば

 原因は「画面描画を停止したこと」だと思いますよ。

 描画させないと、期待通りに絵が描かれないと言うのは、
 (それをバグと呼ぼうと、仕様と呼ぼうと、言ってみても仕方がないです)
 以前からある現象です。

(半平太) 2016/12/07(水) 08:38


 もう、ご覧にならないとは思いますが。

 申し上げた通り、小手先で、コードを追加して、この現象を回避することはできるわけです。
 そういったコードを書くのが好きだということであれば、当方としては、何もいう立場にはありません。

 ただ、自分なら、その回避コードとして Application.ScreenUpdating の手当てで済ませる、そのほうが
 コード的にも簡単ですし、すっきりしてますし  と、単にそういうことです。

(β) 2016/12/07(水) 09:38


半平太様
やはり認識の相違ですね。それはこの現象のトリガーであって、少なくとも私は原因とは言いません。
くどいようですが私は期待通りにならないこの現象をできる限りコードを乱さず意図した通りの正規な処理でスマートに解決する方法を質問しているのです。

β様
多少言い方があれですが発生した問題が解決すればそれでよい、というスタンスは如何なものかと私は思います。それに私からすればApplication.ScreenUpdatingで済ませる手段はコードがすっきりしているとは到底思えません。

まっつわん様
ずいぶん遅れての追記となりますが、図形を移動させずとも行の削除時(削除後は未検証です)に図形をSelectしてやるだけで行削除に連動して移動するようになりました。Excelに図形を認識させている感じでしょうかね。なにか図形に対する処理を行うのであればこのタイミングにずらすことで解決するんですがねぇ…
(メンマ) 2016/12/08(木) 15:45


 考え方は人それぞれですので。

 半平太さんもコメントしておられますが、こと図形との関係でいえば、本件のテーマに限らず
 過去から、たとえ ScreenUpdating = True の状態で処理していても 図形の変更が 描画に反映しないということは
 やまほどあります。

 そういった場合には、ScreenUpDating = True の状態であっても、そこで ScreenUpDating = True を実行することで
 はじめて図形の変更が描画される。

 MS は、こういったことに関して、これは仕様です という場合もありますし、この問題を認識しています という場合もあります。
 で、後者のケース、いつか、バージョンアップの際に、本当に解消する場合もありますし、そのままほったらかしということも
 あります。

 仕様であれバグであれ、我々から見れば理屈に合わない状況です。
 その理屈に合わない状況を、理屈立ててもしょうがない というのが 私の考え方です。

 もちろん、仕様に間違いがなく、こちらのコードがまずい場合は、徹底的にデバッグしなければいけませんけど。

 本件、私からは、これが最後の書き込みです。

(β) 2016/12/08(木) 16:31


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.