Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


4285 / 13644 ツリー ←次へ | 前へ→

【57486】特定の操作をすると処理速度が速くなる現象の原因の特定と対処方法を教えて... 一子 08/8/27(水) 12:49 質問[未読]
【57487】Re:特定の操作をすると処理速度が速くなる... mizunu 08/8/27(水) 14:55 回答[未読]
【57489】Re:特定の操作をすると処理速度が速くなる... 一子 08/8/27(水) 15:31 お礼[未読]
【57493】Re:特定の操作をすると処理速度が速くなる... mizunu 08/8/27(水) 19:10 回答[未読]
【57501】Re:特定の操作をすると処理速度が速くなる... 一子 08/8/28(木) 10:34 お礼[未読]

【57486】特定の操作をすると処理速度が速くなる現...
質問  一子  - 08/8/27(水) 12:49 -

引用なし
パスワード
   はじめまして。一子と申します。
下記のような現象の原因が特定できず
今回、こちらに投稿させていただきました。
よろしくお願いします。

まったく同じ処理を、下記AとBの方法で実行した場合、
 A:Excelファイルを開いてからすぐに実行したとき
 B:任意のセルをダブルクリックしてから実行したとき
Bの方が処理速度が速くなるという現象が発生しています。

どうも、下記のような、セルの一文字ずつの書式を
判定する処理が入っているために
 .Characters(i, 1).Font.Underline
AとBで処理速度が変わってしまうということまでは分かったのですが、
これ以上の原因を特定することができません。

できれば、Aの場合でも、Bと同程度の速度で処理をさせたいため、
Bが速くなる(またはAが速くなる)原因と対処方法を
お教えいただけるとありがたいです。

【環境】
 XP、Excel 2000

【再現方法】
(1)1シートだけのExcelファイルを新規で作成します。

(2)シートのA1〜A5のセル一つずつに200文字程度の
  任意の文字列を入力します。

(3)同シート内にボタンを配置し、このボタンの
  クリック時イベントに下記の処理を記載します。
  ※実際の処理から現象の再現に必要な部分だけ抽出しています。

-----------------------------------------------------
Private Sub CommandButton1_Click()

  Dim startTime As Date
  Dim endTime As Date
  Dim i As Long
  Dim max_i As Long
  Dim startNum As Long
  Dim endNum As Long
  Dim targetCells As Range
  Dim rngTarget As Range
  Dim charUnderLine As Variant
  
  '処理の開始時間の取得
  startTime = Now()
  
  'シートの設定
  Dim sh As Worksheet
  Set sh = ThisWorkbook.Worksheets(1)
  
  '開始行番号の指定
  startNum = 1
  
  '終了行番号の指定
  endNum = 5
  
  '対象セル群の指定
  Set targetCells = sh.Range(sh.Cells(startNum, 1), sh.Cells(endNum, 1))

  For Each rngTarget In targetCells
  
    'セル内の文字数の取得
    max_i = Len(rngTarget)
    
    '一文字ずつ処理を行う
    For i = 1 To max_i

      '※この処理が処理速度に影響を与えているらしい
      charUnderLine = rngTarget.Characters(i, 1).Font.Underline
      
      'ステータスバーに処理行数と文字数を表示
      Application.StatusBar = rngTarget.Row & "/" & endNum & " 行目の " _
                  & i & "/" & max_i & "文字目を処理中です"
    Next i
    
  Next

  'ステータスバーの表示を初期化する
  Application.StatusBar = False
  
  '処理終了時間の取得
  endTime = Now()
  
  MsgBox ("処理終了!" & vbCrLf _
      & "処理にかかった時間:" & Format(endTime - startTime, "nn分ss秒"))
  
End Sub
-----------------------------------------------------

(4)作成したExcelファイルを保存し、一旦閉じます。
  他に開いているExcelファイルがあれば、それらも全て閉じます。
  (Excelのウィンドウも閉じてください)

(5)作成したExcelファイルを開き、ボタンをクリックします。
  私の環境では、処理が終了するまでに平均1分かかりました。

(6)次は、シートの任意のセルをダブルクリックして入力状態にします。
  特に何も入力せずセルの入力状態を解除します。
  この後にボタンをクリックします。
  (5)のときより処理速度が速くなっているかと思います。
  私の環境では、処理が終了するまでに平均12秒かかりました。

以上、何卒よろしくお願いします。

【57487】Re:特定の操作をすると処理速度が速くな...
回答  mizunu  - 08/8/27(水) 14:55 -

引用なし
パスワード
   >どうも、下記のような、セルの一文字ずつの書式を
>判定する処理が入っているために
> .Characters(i, 1).Font.Underline

このマクロは例とは思いますが、
全文字を一文字づつ判定するのは時間がかかるので効率の良い方法にすべきでは。

>できれば、Aの場合でも、Bと同程度の速度で処理をさせたいため、
>Bが速くなる(またはAが速くなる)原因と対処方法を

状況は再現できました。
原因は分かりませんが、たぶんエクセルの仕様でしょう。
対処方法は根本的には分かりませんが、結果論として以下のようなコードを
プロシージャの最初に記述しておけばいいと思います。
任意のセルをダブルクリックしてから実行したとき を再現しているだけです...

SendKeys " {ESC}", True

【57489】Re:特定の操作をすると処理速度が速くな...
お礼  一子  - 08/8/27(水) 15:31 -

引用なし
パスワード
   早速のご回答ありがとうございます。

>原因は分かりませんが、たぶんエクセルの仕様でしょう。

なるほど。
コードの書き方が悪いというわけではないんですね。

>対処方法は根本的には分かりませんが、結果論として以下のようなコードを
>プロシージャの最初に記述しておけばいいと思います。
>任意のセルをダブルクリックしてから実行したとき を再現しているだけです...
>
>SendKeys " {ESC}", True

上記のコードを一文追加したところ、
Excelを起動してすぐに実行した場合でも処理が速くなりました。
大変助かりました。ありがとうございます。

しかし、こういうことができるんですね。
勉強になりました。

>全文字を一文字づつ判定するのは時間がかかるので効率の良い方法にすべきでは。

実際の処理では、
セル中の文字列の何文字目から何文字目まで下線が引いてあるか、
また、一つのセルの中で何箇所下線が引かれているか、
を取得する必要があるため、
一文字ずつ判定するしかないかな、と思っています。

以上、ありがとうございました。

【57493】Re:特定の操作をすると処理速度が速くな...
回答  mizunu  - 08/8/27(水) 19:10 -

引用なし
パスワード
   >実際の処理では、
>セル中の文字列の何文字目から何文字目まで下線が引いてあるか、
>また、一つのセルの中で何箇所下線が引かれているか、
>を取得する必要があるため、
>一文字ずつ判定するしかないかな、と思っています。

このような場合、セル中の文字列が、
1) 下線を含んでない、
2) 全て同じ下線、
3) それ以外(一部含む、異種の下線)
かを調べて、3)の場合のみ、一文字ずつ判定すれば済みます。

示されたコードの For Each の内部は一例として次のように処理できます。
あくまでも一般的にはです。今回の処理に当てはまらないかもしれませんがご参考まで。

 For Each rngTarget In targetCells
  charUnderLine = rngTarget.Font.Underline
  If IsNull(charUnderLine) Then '一文字ずつ判定
   Debug.Print "下線は含まれている"
   'セル内の文字数の取得
   max_i = Len(rngTarget)
   For i = 1 To max_i
    charUnderLine = rngTarget.Characters(i, 1).Font.Underline
    'ステータスバーに処理行数と文字数を表示
    Application.StatusBar = rngTarget.Row & "/" & endNum & " 行目の " _
     & i & "/" & max_i & "文字目を処理中です"
   Next i
  ElseIf charUnderLine = xlUnderlineStyleNone Then
   Debug.Print "下線は無い"
  Else
   Debug.Print "全て同じ下線である", charUnderLine
  End If
 Next

【57501】Re:特定の操作をすると処理速度が速くな...
お礼  一子  - 08/8/28(木) 10:34 -

引用なし
パスワード
   >このような場合、セル中の文字列が、
>1) 下線を含んでない、
>2) 全て同じ下線、
>3) それ以外(一部含む、異種の下線)
>かを調べて、3)の場合のみ、一文字ずつ判定すれば済みます。

なるほど。
セル単位でも判定することができるんですね。
教えていただいたサンプルコードを参考に
改良してみようと思います。

以上、ありがとうございました。

4285 / 13644 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free