半角チルダ

ExcelVBA、その他。
覚え書きや、補足資料などのスクラップブック。
end-u(1037781)

■配列書き込み時のClearContents

2008-09-15 22:00:00 | 気をつけたほうがいいこと
シート上に2次元配列を書き込む時、その範囲に既に値があると書き込みの速度が遅くなるため、[ClearContents メソッド]は必須です。
こんなコードで検証できます。

Option Explicit

Private Declare Function timeGetTime Lib "winmm.dll" () As Long
'-------------------------------------------------
Sub try()
  Const x = 100 'テストデータ列数
  Const y = 1000 'テストデータ行数
  Const z = 10  'テスト回数
  Const n = z + 1
  Dim ws As Worksheet
  Dim t As Long
  Dim i As Long
  Dim v, w(n, 2)

  Application.ScreenUpdating = False
  With Workbooks.Add(xlWBATWorksheet)
    With .Worksheets(1).Cells(1).Resize(y, x)
      .Value = "abcde"
      w(0, 1) = "クリアなし"
      w(0, 2) = "クリアあり"
      For i = 1 To z
        w(i, 0) = i
        t = timeGetTime
        v = .Value
        .Value = v
        w(i, 1) = timeGetTime - t
        t = timeGetTime
        v = .Value
        .ClearContents
        .Value = v
        w(i, 2) = timeGetTime - t
        w(n, 1) = w(n, 1) + w(i, 1)
        w(n, 2) = w(n, 2) + w(i, 2)
      Next
      w(n, 0) = "平均"
      w(n, 1) = w(n, 1) / z
      w(n, 2) = w(n, 2) / z
    End With
    Set ws = .Sheets.Add
    With ws
      .Cells(1).Resize(n + 1, 3).Value = w
      '以下Chart作成.なくても良い
      With .ChartObjects.Add(200, 0, 250, 200).Chart
        .ChartType = xlColumnClustered
        .SetSourceData Source:=ws.Range("B1:C1").Resize(n), _
                PlotBy:=xlColumns
        For i = 1 To 2
          With .SeriesCollection.NewSeries
            .Values = Array(w(n, i), w(n, i))
            .ChartType = xlLine
            .Border.LineStyle = xlNone
            With .Trendlines.Add
              .Type = xlLinear
              .Forward = z - 1.5
              .Backward = 0.5
              .Border.Weight = xlMedium
              .Border.ColorIndex = 5 - i
              .Name = w(0, i) & w(n, 0)
            End With
          End With
        Next
        .HasLegend = True
        With .Legend
          .Position = xlTop
          For i = 4 To 3 Step -1
            .LegendEntries(i).Delete
          Next
        End With
      End With
      '以上Chart作成
    End With
  End With
  Application.ScreenUpdating = True
  Set ws = Nothing
End Sub

結果。


ぁ、あれ?......である。

実はこれ[winVista / xl2007 | xl2000]の混在環境で実行したもの。私のメイン環境の[win2000 / xl2000]ではちゃんと逆の結果になります。
では2007は、というと



こういう結果。フリーズしたのかと思うほど遅い。
個々に見ると、
ClearContents が遅いようです。

Option Explicit

Private Declare Function timeGetTime Lib "winmm.dll" () As Long
'-------------------------------------------------
Private Function timechk(t As Long) As Long
  Static chk As Long
  timechk = t - chk
  chk = t
End Function
'-------------------------------------------------
Sub try2()
  Const x = 100
  Const y = 1000
  Dim v, w(4, 2)

  Application.ScreenUpdating = False
  With Workbooks.Add(xlWBATWorksheet)
    With .Sheets(1).Cells(1).Resize(y, x)
      .Value = "abcde"
      w(0, 1) = "クリアなし"
      w(0, 2) = "クリアあり"
      w(1, 0) = "v = .Value"
      w(2, 0) = ".ClearContents"
      w(3, 0) = ".Value = v"
      w(4, 0) = "計"
      Call timechk(timeGetTime)
      v = .Value
      w(1, 1) = timechk(timeGetTime)
      .Value = v
      w(3, 1) = timechk(timeGetTime)
      v = .Value
      w(1, 2) = timechk(timeGetTime)
      .ClearContents
      w(2, 2) = timechk(timeGetTime)
      .Value = v
      w(3, 2) = timechk(timeGetTime)
    End With
    w(4, 1) = w(1, 1) + w(2, 1) + w(3, 1)
    w(4, 2) = w(1, 2) + w(2, 2) + w(3, 2)
    .Sheets.Add.Cells(1).Resize(5, 3).Value = w
  End With
  Application.ScreenUpdating = True
End Sub



で、唐突な結論ですが、 ■ReplaceメソッドとEvents制御 の時と同じように、
イベントプロシージャがなくても、[EnableEvents プロパティ]の制御は必須のようですね。
2007では顕著な差が出ます。

Sub try3()
  Const x = 100
  Const y = 1000
  Dim i As Long
  Dim v, w(4, 2)

  Application.ScreenUpdating = False
  With Workbooks.Add(xlWBATWorksheet)
    With .Worksheets(1).Cells(1).Resize(y, x)
      .Value = "abcde"
      w(0, 1) = "Events=True"
      w(0, 2) = "Events=False"
      w(1, 0) = "v = .Value"
      w(2, 0) = ".ClearContents"
      w(3, 0) = ".Value = v"
      w(4, 0) = "計"
      For i = 1 To 2
        Call timechk(timeGetTime)
        v = .Value
        w(1, i) = timechk(timeGetTime)
        .ClearContents
        w(2, i) = timechk(timeGetTime)
        .Value = v
        w(3, i) = timechk(timeGetTime)
        Application.EnableEvents = False
      Next
      Application.EnableEvents = True
    End With
    w(4, 1) = w(1, 1) + w(2, 1) + w(3, 1)
    w(4, 2) = w(1, 2) + w(2, 2) + w(3, 2)
    .Sheets.Add.Cells(1).Resize(5, 3).Value = w
  End With
  Application.ScreenUpdating = True
End Sub



ちなみに[Vista/2000]でも効果あり。



(2008.12.15追記)
またまた懺悔ですorz
>イベントプロシージャがなくても、[EnableEvents プロパティ]の制御は必須のようですね。
>2007では顕著な差が出ます。
今日現在、上記のような事実は確認できません。
結論として、検証誤りと言われても仕方ありません。ごめんなさい。

#検証時、イベントプロシージャがあったのではないかと思われるかもしれませんが、それは無いです。
#が、2007をインストールし直しても再現しなかったので根拠が無くなりました(泣
Comment
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする