[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『マクロの処理時間を早めたい』(こはのり)
お世話になります。
下記マクロを作りましたが約600行くらいあるシートを12シート完了するのに
10分以上かかってしまいます。
人間の手で操作するよりはましなのですが、構文を手直しすることで
処理が早くできるようであれば修正したいです。
ただ、どこをなおせばいいかと、そもそも処理が早くできるかどうかもわかりません。
お分かりになる方がいらっしゃればご助力お願いできないでしょうか。
↓マクロの説明
A1に「在庫表」と入力してあるシートを対象とし、
L列に「出荷」と入力してある行のM列からAT列まで色を白にする
L列に「入庫」と入力してある行のM列からAT列までを黄色にし、入っている項目を消す
L列に「在庫」と入力してある行のM列からAT列まで色を灰色にする
対象のシートを繰り返す
Sub リセット()
Dim maxrow As Long Dim r As Long, ws As Worksheet Application.ScreenUpdating = False For Each ws In Worksheets If ws.Range("A1").Value = "在庫表" Then maxrow = ws.Cells(Rows.Count, 12).End(xlUp).Row For r = 4 To maxrow If ws.Range("L" & r).Value = "出荷" Then ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).ClearContents ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).Interior.Pattern = xlNone
ElseIf Range("L" & r).Value = "入庫" Then
ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).Interior.Color = RGB(255, 255, 153) ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).ClearContents
ElseIf Range("L" & r).Value = "在庫" Then ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).Interior.Color = RGB(192, 192, 192)
ElseIf ws.Range("L" & r).Value = "その他" Then ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).ClearContents ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).Interior.Color = RGB(252, 213, 180) End If Next r End If Next Application.ScreenUpdating = True Range("A1").Select MsgBox ("リセットが終了しました") End Sub
< 使用 Excel:Office365、使用 OS:Windows10 >
(わからん) 2022/03/04(金) 15:59
(γ) 2022/03/04(金) 16:12
(γ) 2022/03/04(金) 16:18
→それぞれ約200行、合計で約600行でした。
γさん
Application.Calculation = xlCalculationManual
とし、最後で
Application.Calculation = xlCalculationAutomatic
と復旧させてみてはいかがでしょうか。
→こちらで試した所、1分位で完了しました。目からうろこ状態です!
ありがとうございます!
(こはのり) 2022/03/04(金) 18:16
そんなにあるんですね。
少なければ、全行ループして探すよりも検索して
特定したほうが速いと思ったので。
(わからん) 2022/03/04(金) 19:03
セルを処理する前に4行目のk列でフィルタをかけているものを外して
上記のマクロを実行し、それが終わったら再度K列でオートフィルタを設定し
次のシートに移るということをしたいのですが、そちらを下記の構文で
入れてもうまく実現できません。どちらに挿入するのが
正しいのでしょうか?度々恐縮ですが何卒よろしくお願いいたします。
↓マクロの説明
A1に「在庫表」と入力してあるシートを対象とし、
4行目のk列でフィルタをかけているものを外す。
L列に「出荷」と入力してある行のM列からAT列まで色を白にする
L列に「入庫」と入力してある行のM列からAT列までを黄色にし、入っている項目を消す
L列に「在庫」と入力してある行のM列からAT列まで色を灰色にする
4行目のk列で●がついているものを選択する。
対象のシートを繰り返す
Sub リセット2()
Dim maxrow As Long Dim r As Long, ws As Worksheet Application.ScreenUpdating = False Application.Calculation = xlCalculationManual For Each ws In Worksheets
→ここに追加 Range("$A$4:$BI$705").AutoFilter Field:=11
If ws.Range("A1").Value = "在庫表" Then maxrow = ws.Cells(Rows.Count, 12).End(xlUp).Row For r = 4 To maxrow
If ws.Range("L" & r).Value = "出荷" Then ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).ClearContents ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).Interior.Pattern = xlNone ElseIf Range("L" & r).Value = "入庫" Then ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).Interior.Color = RGB(255, 255, 153) ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).ClearContents ElseIf Range("L" & r).Value = "在庫" Then ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).Interior.Color = RGB(192, 192, 192) ElseIf ws.Range("L" & r).Value = "その他" Then ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).ClearContents ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)).Interior.Color = RGB(252, 213, 180) End If Next r End If
→ここに追加 Range("$A$4:$BI$705").AutoFilter Field:=11, Criteria1:="●"
Next Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True Range("A1").Select MsgBox ("リセットが終了しました") End Sub
(こはのり) 2022/03/04(金) 19:08
その観点から、もとのコード全般について見直しては?
また、
Select Case を使ったり、
With ws.Range(ws.Cells(r, 13), ws.Cells(r, 46))
などを使うことも検討されたらいかがですか?
(γ) 2022/03/04(金) 19:51
#コンパイルチェックしかしていないので、バグがあるかもしれません。
#フィルタはご自身でどうぞ。
Sub sample() Dim maxRow As Long Dim i As Long Dim ws As Worksheet Dim temp As Variant Dim val As Variant Dim targetRange As Range Dim col As XlRgbColor Dim isCear As Boolean Dim isPaint As Boolean Application.ScreenUpdating = False Application.Calculation = xlCalculationManual For Each ws In Worksheets If ws.Range("A1").Value = "在庫表" Then maxRow = ws.Cells(Rows.Count, "L").End(xlUp).Row temp = ws.Range("L1").Resize(maxRow, 1).Value For Each val In Array("出荷", "入庫", "在庫", "その他") Set targetRange = Nothing For i = 4 To maxRow If temp(i, 1) = val Then Select Case Not targetRange Is Nothing Case True: Set targetRange = ws.Cells(i, "M").Resize(1, 34) Case Else: Set targetRange = Union(targetRange, ws.Cells(i, "M").Resize(1, 34)) End Select End If Next i If Not targetRange Is Nothing Then Select Case val Case "出荷" isPaint = False isCear = True Case "入庫" isPaint = True col = rgbLightYellow isCear = True Case "在庫" isPaint = True col = rgbSilver isCear = False Case "その他" isPaint = True col = rgbMoccasin isCear = True End Select With targetRange If isPaint Then .Interior.Color = col Else .Interior.Pattern = xlNone End If If isCear Then .Value = "" End If End With End If Next val End If Next Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True Range("A1").Select MsgBox ("リセットが終了しました") End Sub
(tkit) 2022/03/05(土) 00:09
(こはのり) 2022/03/05(土) 03:58
「標準モジュール」のコードでシートを指定しないRangeオブジェクトは、 その時にアクティブなシートのRangeとみなされます。(末尾の*も参考に)
ループ処理の中でwsは、次々に変わっていきますが、 その都度 wsをSelectしているわけではないので、 アクティブなシートはどれか一つに固定されたままです。
従って、 Range("$A$4:$BI$705").AutoFilter Field:=11 だとか、 ElseIf Range("L" & r).Value = "入庫" Then といったシート指定がないものは、wsにあるセルとは別のシートのセルと解釈され、 本来の判定とは別の判定がされているはずです。 シート指定の省略は誤作動の原因となっていますので、修正する必要があります。
・Select Caseは分岐判定に使われるもので、IFで列挙していくより見やすいはずです。 ・また、ws.Range(ws.Cells(r, 13), ws.Cells(r, 46))が何度も出てきますが、 それぞれが同じものかどうか読む人が確認しなくてはならず、負荷を与えます。 見た目も良いものになりますので、活用されるとよいでしょう。
上の二つはワークシート指定の話とは違って、間違いということではありません。
こんな感じにするとよいと思います。(実際に動作確認していませんので、注意ください)
Sub test() Dim maxrow As Long Dim r As Long, ws As Worksheet
Application.ScreenUpdating = False Application.Calculation = xlCalculationManual
For Each ws In Worksheets ws.Range("$A$4:$BI$705").AutoFilter Field:=11 If ws.Range("A1").Value = "在庫表" Then maxrow = ws.Cells(Rows.Count, 12).End(xlUp).Row For r = 4 To maxrow With ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)) Select Case ws.Range("L" & r).Value Case "出荷" .ClearContents .Interior.Pattern = xlNone Case "入庫" .Interior.Color = RGB(255, 255, 153) .ClearContents Case "在庫" .Interior.Color = RGB(192, 192, 192) Case "その他" .ClearContents .Interior.Color = RGB(252, 213, 180) End Select End With Next r End If ws.Range("$A$4:$BI$705").AutoFilter Field:=11, Criteria1:="●" Next
Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True MsgBox "リセットが終了しました" End Sub
少し前のバージョンを使って、ほぼ同程度の個数のデータで動作させてみましたが、 0.8秒くらいで終了しました。(1分というのは少し想像しにくかったですね。他のデータの影響でしょうか) この程度での件数では、あえてフィルタを使わなくてもよいのかなという印象です。
(*)参考 シートモジュールのコードでシート指定を省略した場合は、 アクティブシートがなんであれ、コードを書いた対象のシートが指定されたものとみなされます。 標準モジュールの場合とは違います。 (γ) 2022/03/05(土) 08:33
(γ) 2022/03/05(土) 08:42
(通りのいちゃもん) 2022/03/05(土) 08:54
確かに、For ループが何重にもネストしていて、
一番深いところから、何回か Exit Forしないといけない、
などという場合、例外的にGotoを考えることがありますが、
今回はむしろ、一番浅いところですので、それに該当する気はしませんね。
少なくとも私は。
(構造化プログラム、GOTOは避けよ、などというフレーズが真っ先に頭に浮かんでしまいます)
ありがとうございました。
(γ) 2022/03/05(土) 09:25
Dim ws As Worksheet Dim maxrow As Long Dim r As Long Dim rng As Range Dim cond As String
Application.ScreenUpdating = False Application.Calculation = xlCalculationManual
For Each ws In Worksheets If ws.Range("A1").Value <> "在庫表" Then GoTo next_for
ws.Range("$A$4:$BI$705").AutoFilter Field:=11 maxrow = ws.Cells(Rows.Count, 12).End(xlUp).Row For r = 4 To maxrow
Set rng = ws.Range(ws.Cells(r, 13), ws.Cells(r, 46)) cond = ws.Range("L" & r).Value
If cond <> "在庫" Then rng.ClearContents
If cond = "出荷" Then rng.Interior.Pattern = xlNone ElseIf cond = "入庫" Then rng.Interior.Color = RGB(255, 255, 153) ElseIf cond = "在庫" Then rng.Interior.Color = RGB(192, 192, 192) Else rng.Interior.Color = RGB(252, 213, 180) End If
Next ws.Range("$A$4:$BI$705").AutoFilter Field:=11, Criteria1:="●"
next_for:
Next
Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True MsgBox "リセットが終了しました"
End Sub
(通りのいちゃんもん) 2022/03/05(土) 16:57
■1
内容からして↓の続きですよね。
[[20220110164859]] 『複数シートをマクロにて処理したい』(こはのり)
そちらでもおもいましたし、こちらでも同種のコメントがありますが必ずしも1行ずつ処理をする必要はないとおもいますよ。
すなわち
L列が【出荷】のものを一括して .ClearContents .Interior.Pattern = xlNone
L列が【入庫】のものを一括して .ClearContents .Interior.Color = RGB(255, 255, 153) .ClearContents
L列が【在庫】のものを一括して .Interior.Color = RGB(192, 192, 192) . L列が【その他】のものを一括して .ClearContents .Interior.Color = RGB(252, 213, 180)
のようにするという手もあるとおもいます。
のんびり書いている間にかぶってしまった感がありますが、例えばこんな感じです。
Sub 研究用1() Stop Dim maxrow As Long Dim r As Long, ws As Worksheet Dim tmpRNG As Range, buf As Variant, 色 As Long
For Each ws In Worksheets With ws If .Range("A1").Value = "在庫表" Then
Stop For Each buf In Array("出荷", "入庫", "在庫", "その他") Set tmpRNG = Nothing For r = 4 To .Cells(.Rows.Count, "L").End(xlUp).Row If .Cells(r, "L").Value = buf Then If tmpRNG Is Nothing Then Set tmpRNG = .Cells(r, "L") Else Set tmpRNG = Union(tmpRNG, .Cells(r, "L")) End If End If Next r
If Not tmpRNG Is Nothing Then Stop Select Case buf Case "出荷": 色 = xlNone Case "入庫": 色 = RGB(255, 255, 153) Case "在庫": 色 = RGB(192, 192, 192) Case "その他": 色 = RGB(252, 213, 180) End Select
Select Case buf Case "出荷", "入庫", "その他" Intersect(tmpRNG.EntireRow, .Range("M:AT")).ClearContents Intersect(tmpRNG.EntireRow, .Range("M:AT")).Interior.Color = 色 Case "在庫" Intersect(tmpRNG.EntireRow, .Range("M:AT")).Interior.Color = 色 End Select End If Next buf End If End With Next ws End Sub
■2
今回は、600行くらいとのことなので大丈夫かもしれませんが、"出荷", "入庫", "在庫", "その他"が飛び飛びに入り乱れていると「tmpRNG」に格納しきれなくなって、上記のアプローチだと上手くいかないかもしれません。
そのような場合には、既にアドバイスされているようにオートフィルタなどで抽出して処理をするというアプローチも有効であるとおもいます。
コードにするとこんな感じ。
Sub 研究用2() Dim ws As Worksheet Dim buf As Variant
For Each ws In Worksheets If ws.Range("A1").Value = "在庫表" Then Stop ws.AutoFilterMode = False ws.Range("L3:AT" & ws.Cells(ws.Rows.Count, "L").End(xlUp).Row).AutoFilter
For Each buf In Array("出荷", "入庫", "在庫", "その他") Stop ws.AutoFilter.Range.AutoFilter Field:=1, Criteria1:=buf If ws.Cells(ws.Rows.Count, "L").End(xlUp).Row >= 4 Then With Intersect(ws.AutoFilter.Range, ws.AutoFilter.Range.Offset(1)).SpecialCells(xlCellTypeVisible) Stop Select Case buf Case "出荷" .ClearContents .Interior.Color = xlNone
Case "入庫" .ClearContents .Interior.Color = RGB(255, 255, 153)
Case "在庫" .Interior.Color = RGB(192, 192, 192)
Case "その他" .ClearContents .Interior.Color = RGB(252, 213, 180) End Select End With End If Next buf ws.AutoFilterMode = False End If Next ws End Sub
■3
さらにL列の値で塗りつぶし色が変わればよいのであれば【条件付き書式】も有効だとおもいます。
(条件付き書式もマクロで設定することが可能です。)
Sub 研究用3() Dim ws As Worksheet Dim maxrow As Long, 行 As Long Dim tmpRNG As Range
For Each ws In Worksheets If ws.Range("A1").Value = "在庫表" Then maxrow = ws.Cells(ws.Rows.Count, "L").End(xlUp).Row Set tmpRNG = Nothing
ws.Cells.FormatConditions.Delete With ws.Range("L4:AT" & maxrow) .FormatConditions.Add(Type:=xlExpression, Formula1:="=$L4=""入庫""").Interior.Color = RGB(255, 255, 153) .FormatConditions.Add(Type:=xlExpression, Formula1:="=$L4=""在庫""").Interior.Color = RGB(192, 192, 192) .FormatConditions.Add(Type:=xlExpression, Formula1:="=$L4=""その他""").Interior.Color = RGB(252, 213, 180) End With
For 行 = 4 To maxrow Select Case ws.Cells(行, "L").Value Case "出荷", "入庫", "その他" If tmpRNG Is Nothing Then Set tmpRNG = ws.Cells(行, "L") Else Set tmpRNG = Union(tmpRNG, ws.Cells(行, "L")) End If End Select Next 行
If Not tmpRNG Is Nothing Then Intersect(tmpRNG.EntireRow, ws.Range("M:AT")).ClearContents End If Next ws End Sub
■4
ということを踏まえると以下を考慮してイチから考え直してみると新たな発見があるかもしれません。
・対象のオブジェクトをきちんと指定する ・極力まとめて操作することを考える
(もこな2) 2022/03/05(土) 22:02
やりたいことは、
「ブックの中のシートを巡回してシートを初期化をする」
ということだと思います。
ならば、
Sub test()
Dim ws As Worksheet
Application.ScreenUpdating = False Application.Calculation = xlCalculationManual
For Each ws In Worksheets If ws.Cells(1).Value = "在庫表" Then シート初期化 ws End If Next
Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub
これだけのコードになると思います。
で、、「シートの初期化」とはどういうことかを、
別のプロシージャで定義します。
Sub シート初期化(ByRef ws As Worksheet)
Dim rngTable As Range Dim rngTarget As Range
Set rngTable = ws.AutoFilter.Range Set rngTarget = intersert(ws.Range("M:AT"), rngTable, rngTable.Offset(1))
rngTarget.Interior.Color = rgbGray With rngTable .AutoFilter Field:=11, Criteria1:="<>在庫" .ClearContents
.AutoFilter Field:=11, Criteria1:="入庫" rngTarget.Interior.Color = vbYellow
.AutoFilter Field:=11, Criteria1:="その他" rngTarget.Interior.Color = vbBlue
.AutoFilter Field:=11, Criteria1:="出荷" rngTarget.Interior.ColorIndex = xlColorIndexNone
.AutoFilter Field:=11, Criteria1:="●" End With End Sub
※オートフィルターで非表示のセルの、セルの書式設定が無効なのか有効なのか
分かりませんが、こんな感じでいいのでは?
このままでだめならジャンプ機能でセル範囲を絞り込めばよいかと思います。
(エラー回避処理は省略)
※参考です。うまく動くかは未検証です。
考え方の助力になれば。。。。
(まっつわん) 2022/03/06(日) 09:59
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.