[[20210919162049]] 『処理スピードがおそいのです』(正明) ページの最後に飛ぶ

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

 

『処理スピードがおそいのです』(正明)

Sub 在庫あり〇()
Dim cl As Integer

Dim cell As Range
Dim a As Integer
cl = ActiveCell.Column

    Select Case cl

    Case 9 To 14
 Union(Range("I8:N50"), Range("I60:N99"), Range("I109:N137")).Select

    Case 24 To 29
 Union(Range("X8:AC50"), Range("X60:AC99"), Range("X109:AC137")).Select
    Case 39 To 44
 Union(Range("AM8:AR50"), Range("AM60:AR99"), Range("AM109:AR137")).Select
    Case 54 To 59
 Union(Range("BB8:BG50"), Range("BB60:BG99"), Range("BB109:BG137")).Select
    Case 69 To 74
 Union(Range("BQ8:BV50"), Range("BQ60:BV99"), Range("BQ109:BV137")).Select
    End Select
For Each cell In Selection

If cell.Value = "" And cell.Interior.Color <> RGB(255, 183, 192) Then

cell.Value = "在庫あり〇"

End If
Next
ActiveCell.Select
End Sub
どのようにコードを書きかえればいいのでしょうか?

< 使用 Excel:Excel2019、使用 OS:Windows10 >


■1
VBAの世界では基本的に、セルなど(オブジェクトといいます)を明示すれば、いちいちアクティブにしたり選択したりする必要はありません、
無駄な選択(処理)は、遅くなる原因ですから、まずはそれを修正しましょう。

■2
処理に時間がかかるということですが、【ステップ実行】してどこでどのような処理をしているか検証してみてはどうでしょうか?
(尤も、今回のケースではちょっとわかりづらいかもしれませんが。。。)

■3
今回のケースで時間がかかるのは↓の部分です。

 For Each cell In Selection
    If cell.Value = "" And cell.Interior.Color <> RGB(255, 183, 192) Then
        cell.Value = "在庫あり〇"
    End If
 Next

要は、選択したセル範囲の中から1セルずつ取り出して、判定の結果、条件を満たしていたらセルに書き込みを行っているわけですが、この【セルへの書き込み】を逐一行っているために時間がかかっています。
条件を満たしたセルはいずれも"在庫あり〇"と書き込めばよいのですから、逐一書き込まずに、いっぺんに書き込むことを考えるとよいです。

したがって、たとえば↓のようにする方法で高速化が望めると思います。

 (そのほかも直しました。(ただの好みによる部分なので説明は省きます))

    Sub 在庫あり〇_改()
        Dim 行範囲 As Range
        Dim 列範囲 As Range
        Dim tmpRNG As Range, MyRNG As Range

        Stop 'ブレークポイントの代わり

        '▼行範囲は、8〜50,60〜99、109〜137に固定
        Set 行範囲 = Range("I8:N50,I60:N99,I109:N137").EntireRow

        '▼アクティブセルの【列】で列範囲を決定する
        Select Case ActiveCell.Column
            Case 9 To 14
                列範囲 = Range("I:N")
            Case 24 To 29
                列範囲 = Range("X:AC")
            Case 39 To 44
                列範囲 = Range("AM:AR")
            Case 54 To 59
                列範囲 = Range("BB:BG")
            Case 69 To 74
                列範囲 = Range("BQ:BV")
            Case Else
                MsgBox "アクティブセルの位置が想定外です" & vbLf & "処理を中止します"
                Exit Sub
        End Select

        '▼処理範囲のセルを巡回して該当するセルを【一旦覚えておく(処理はしない)】
        For Each tmpRNG In Intersect(行範囲, 列範囲)
            With tmpRNG
                If .Value = "" And .Interior.Color <> RGB(255, 183, 192) Then
                    If MyRNG Is Nothing Then
                        Set MyRNG = .Cells
                    Else
                        Set MyRNG = Union(MyRNG, .Cells)
                    End If
                End If
            End With
        Next tmpRNG

        '▼覚えていたセルがあったら【一気に】処理する
        If Not MyRNG Is Nothing Then MyRNG.Value = "在庫あり〇"

    End Sub

(もこな2 ) 2021/09/19(日) 17:24


もこな2ありがとうございました。コード一行々意味していることをよく考えて学んでいきます。
また、私の作ったコードでスピードが出ない数々のプロシージャに活用していきたいと思います。本当に親身になって考えてくださってありがとうございました。
(正明) 2021/09/19(日) 19:13

もこな2様 もう一つ教えてください。
↑'▼アクティブセルの【列】で列範囲を決定する
        Select Case ActiveCell.Column

 アクティブセル(一列)が選択された場合(9〜14、24〜28、33〜44、54〜59、69〜74列)の各々の列を処理→ 複数列(Selection)たとえば9〜11列を選択した場合、9〜11列を処理するようにするにはコードを書きかえればいいのでしょうか?

一列ActiveCell→複数列Selectionの場合はSelect Case 〜 End Selectのコードで対応は可能でしょうか?    申し訳ありません。
(正明) 2021/09/20(月) 07:27


selectionの列範囲の取得とIntersectの引数の入れかたが全く解りません。ご指導お願いします。

(正明) 2021/09/20(月) 10:31


遠慮して回答を止める方がいらっしゃるかもしれませんので、回答者の名指しは避けたほうがよいとおもいます。

■4
>一列ActiveCell〜
そもそも、勘違いがあるかもしれません。「ActiveCell」は1つしかありません。
複数の列を選択していようが、とびとびのセルを選択していようが同じです。

>selectionの列範囲の取得とIntersectの引数の入れかたが全く解りません。
Intersectメソッドについて調べてみましたか?
「selection」とそれぞれの「列全体」が一部でも重なっていれば処理対象とすればよいでしょう。

>Select Case 〜 End Selectのコードで対応は可能でしょうか?
無理・・・ではないかもしれませんが、複数の範囲が条件を満たす可能性がありますよね?
よって別のアプローチのほうが良いとおもいますよ。
たとえば、↓のように先に処理対象となる【列範囲】ピックアップしておくなどのほうが有効だとおもいます。

    Sub 在庫あり〇_改二()
        Dim 列範囲 As Range
        Dim 処理範囲 As Range
        Dim tmpRNG As Range, MyRNG As Range

        Stop 'ブレークポイントの代わり

        '▼処理対象となる列範囲を判定するループ
        For Each 列範囲 In Range("I:N, X:AC, AM:AR, BB:BG, BQ:BV").Areas
            If Not Intersect(Selection, 列範囲) Then
                If 処理範囲 Is Nothing Then
                    Set 処理範囲 = 列範囲
                Else
                    Set 処理範囲 = Union(処理範囲, 列範囲)
                End If
            End If
        Next 列範囲

        '▼↑で見つからなかったら処理中止
        If 処理範囲 Is Nothing Then
            MsgBox "処理対象なし"
            Exit Sub
        End If

        For Each tmpRNG In Intersect(Range("I8:N50,I60:N99,I109:N137").EntireRow, 処理範囲)
            With tmpRNG
                If .Value = "" And .Interior.Color <> RGB(255, 183, 192) Then
                    If MyRNG Is Nothing Then
                        Set MyRNG = .Cells
                    Else
                        Set MyRNG = Union(MyRNG, .Cells)
                    End If
                End If
            End With
        Next tmpRNG

        If Not MyRNG Is Nothing Then MyRNG.Value = "在庫あり〇"
    End Sub

(もこな2 ) 2021/09/20(月) 12:15


ご指導ありがとうございました。私のPCでは
↑ If Not Intersect(Selection, 列範囲) Thenここのところで
オブジェクト変数または With ブロック変数が設定されていませんや変数の形が一致しませんのエラーが出ます。なぜでしょうか?
(正明) 2021/09/20(月) 14:23

なぜでしょうか?
教えてください
(正明) 2021/09/20(月) 17:08

もこな2さん、不在のようなので、代理で、

下記に修正すればいいかと。

If Not Intersect(Selection, 列範囲) Is Nothing Then
(hatena) 2021/09/20(月) 17:15


フォローありがとうございます。
コンパイルエラーにならないことしかチェックしてなかったので気づいてなかったです。

(もこな2 ) 2021/09/20(月) 18:13


すいません ↑ If Not Intersect(Selection, 列範囲) Then →If Not Intersect(Selection, 列範囲) Is Nothing Thenに変更しましエラーはでなくなりましたが、選択された行以外 たとえば9行〜11行を選択しているにもかかわらず9行〜14行まで処理してしまうようになりますが、下の
For Each tmpRNG In Intersect(Range("I8:N50,I60:N99,I109:N137").EntireRow, 処理範囲)この箇所も変更しなければならないように思えます。
(正明) 2021/09/20(月) 19:27

■5
>選択された行以外 たとえば9行〜11行を選択しているにもかかわらず9行〜14行まで処理してしまうようになりますが〜

再三になりますが、ちゃんとコードの研究はされてますか?
例えば↓はどのようなセル範囲になるとおもいますか?

 Intersect(Range("I8:N50,I60:N99,I109:N137").EntireRow, Range("AM:AR"))

(もこな2 ) 2021/09/20(月) 20:56


コメント返信:

[ 一覧(最新更新順) ]


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