Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10全般 : Microsoft 365)
コードの内容
投稿日時: 22/10/04 11:05:24
投稿者: chokobanana

始めまして失礼します
前任者のユーザーを引き継いでおります
前任者が使用していたマクロを少し変更したいのですがまったくの素人なので
お力を貸していただけないでしょうか?
 
フォルダの中にあるファイルにデータがある場合は抽出してコピペする処理を
複数のマクロをつなげて使用しています
 
その中の2つのマクロで条件に従ってメッセージBOXを表示させています
それぞれのマクロを下記@、Aの使用に変更したいのです
 
@条件に合わない場合はメッセージBOXを表示させない
A条件に合う場合は次のマクロは実行しない
 
素人の為、マクロの解釈が間違っていたり、おかしなことを書いているかもしれません
気を付けていますがご了承いただけると嬉しいです
よろしくお願いいたします。
 
◆一つ目のマクロです
 ファイルが開かれている時、そのファイル名をメッセージBOXで表示していると
 思います、ファイルが開かれていない時は@に変更したいです
 
 Sub 抽出@()
     
        Dim Fname As String
        Dim dStart As Double, dEnd As Double
     
        Dim srcSH As Worksheet
        Dim dstRNG As Range
        Dim cel As Range
             
        Set dstRNG = ThisWorkbook.ActiveSheet.Cells(Rows.Count, "D").End(xlUp).Offset(1, -3)
     
        dEnd = DateValue(uf2.tx1) + TimeValue(uf2.tx2)
     
        Fname = Dir(ThisWorkbook.Path & "\*.xls*")
        FnameMsg = ""
        Do While Fname <> ""
     
            If Fname <> ThisWorkbook.Name Then
     
               On Error Resume Next
                Open ThisWorkbook.Path & "\" & Fname For Append As #1
                Close #1
                 
                   If Err.Number > 0 Then
                      
                     FnameMsg = FnameMsg & Fname & vbCrLf
                   Else
     
     
                Set srcSH = Workbooks.Open(ThisWorkbook.Path & "\" & Fname).Worksheets(1)
     
                srcSH.AutoFilterMode = False
                     
               Dim i As Long
     
                 For i = 11 To Cells(Rows.Count, 4).End(xlUp).Row
     
                   If Cells(i, 3) = "" Then
     
                     Cells(i, 4).Copy Cells(i, 4)
         
                   End If
         
                Next i
                     
                Range("A10").AutoFilter Field:=2, Criteria1:="<=" & CStr(dEnd)
                Range("A10").AutoFilter Field:=8, Criteria1:="="
                     
                If srcSH.AutoFilter.Range.Cells(1).Row <> srcSH.Cells(srcSH.Rows.Count, "D").End(xlUp).Row Then
                    With srcSH.AutoFilter.Range
     
                        Intersect(.Cells, .Offset(1), srcSH.Range("H:H"), .SpecialCells(xlCellTypeVisible)).Value = "済"
     
                         Intersect(.Cells, .Offset(1)).Copy dstRNG
                             
                           With dstRNG.Parent
                             Set dstRNG = .Cells(.Rows.Count, "D").End(xlUp).Offset(1, -3)
                          End With
     
                    End With
                End If
     
                srcSH.AutoFilterMode = False
                     
                srcSH.Parent.Save
                srcSH.Parent.Close
                     
            End If
         End If
     
            Fname = Dir()
        Loop
     
        Application.ScreenUpdating = True
        MsgBox FnameMsg
        Unload uf2
             
    End Sub

 
◆二つ目のマクロです
 ファイルのD列のセルに何か入力されていなかったらメッセージBOXで表示していると
 思います、メッセージBOX「抽出はありません」の時Aに変更したいです
 
 Sub 抽出A()
 
     Dim cel As Range
 
     Application.ScreenUpdating = False
 
     For Each cel In Range("D5", Cells(Rows.Count, "D").End(xlUp))
      
         If cel.Value <> Empty Then
          
         Unload uf2
          
         Else
          
        Application.DisplayAlerts = False
        ActiveSheet.Delete
        Application.DisplayAlerts = True
 
          
        MsgBox "抽出はありません"
              
         End If
     Next
 
     Application.ScreenUpdating = True
      
 End Sub
 
 

回答
投稿日時: 22/10/04 12:24:25
投稿者: simple

ご質問の趣旨が余りわかっていませんが、少しコメントします。
 
メッセージが不要なら、その命令をコメントにしてしまえばよいかと。
また二つ目の話は、「次のマクロを実行しない」の意味がわかりません。
次のマクロとは?
また、あなたはどのようなトライをされて、具体的にどこに詰まっているのでしょうか。
希望だけではなくて、そのあたりも書いてくださいね。

投稿日時: 22/10/04 13:16:28
投稿者: chokobanana

メッセージありがとうございます
 
追記です
説明が下手でご迷惑をおかけします
マクロは始めてなので自分で触ったら動かなくなってしまいました
こちらにアップしてますのは当初のものです
 
≪一つ目のやりたい事≫
 
If Err.Number ><>0 Then ←(コードの書き方が間違っていたらすいません、<>0です)
の時に空のメッセージBOXが出ます
このメッセージが出ないようにしたいです
 
(メモ)
命令をコメントするとはどのようなことなのでしょうか?
https://gakushikiweblog.com/comment
こちらにコメントアウトというのがありました
これであっていますか?
もし違ってましたら、教えて頂けると幸いです。
 
↓この辺りがメッセージを出しているコードではないかと思っています
 
 
 If Fname <> ThisWorkbook.Name Then
      
               On Error Resume Next
                Open ThisWorkbook.Path & "\" & Fname For Append As #1
                Close #1
                  
                   If Err.Number > 0 Then
                       
                     FnameMsg = FnameMsg & Fname & vbCrLf
                   Else
          'マクロ実行中にファイルを第三者に開いていない時はメッセージを表示しない
 
≪二つ目のやりたい事≫
 
複数のマクロをCallで繋げています
 
Call 抽出A
Call あいう
 
みたいなかんじです
 
Call 抽出AもCall あいうも同じことに対してメッセージが出ます(ただコードは全然違います)
こちらをいじるのは高度なので、できれば
 
MsgBox "抽出はありません"となる時は
Call あいうを実行しないとしたいです
 
もし可能でしたらお力を貸していただけないでしょうか?
 
 

回答
投稿日時: 22/10/04 15:58:06
投稿者: QooApp

言わんとすることはなんとなく理解できたのでいったん状況を整理しましょう。
 
1.「空のメッセージボックスが表示される->非表示にしたい」
何かしら意図しない操作でプログラムのソースコードが破損しているかもしれないのでいったん元の状態のソースコードをコピーしてきて今のファイル内のソースコードを上書きして元に戻してから以下の修正を行う事を推奨します。
 
メッセージを非表示にするだけであれば、コメントアウト処理を行うだけでいいと思います。
コメントアウトの操作に関してはその行の最初にシングルコーテーションを1文字挿入するとその行のプログラムは強制スキップします。
 
本来の用途はその部分のソースコードが何のデータ処理を行っているのか、コメントを残すことで可読性を上げる事に使用したりしますが、既存のソースコードとして機能している部分をコメントアウトすることで一時的にその処理をスキップすることができるようになります。
 
エラーが発生した際にエラーの内容を表示する用の変数「FnameMsg」に逐一エラー内容を書き込んで、最後の三行部分↓

Application.ScreenUpdating = True
MsgBox FnameMsg
Unload uf2

 
のMsgBoxでその変数の内容を表示する処理になっているので、3行部分を以下のような修正を行います。
Application.ScreenUpdating = True
If(FnameMsg<>"")Then
    MsgBox FnameMsg
endif
Unload uf2

FnameMsg変数は最初に「=""」で空化する処理を行っているので何もトラブルが無ければそのまま中身は空のままです。If文内の「<>""」は「空じゃない」という条件式の書き方の一例です。
 
2.「抽出がない場合に次の関数の実行をスキップする」
引用:
MsgBox "抽出はありません"となる時は
Call あいうを実行しないとしたいです

 
ここ、もう少し情報が欲しいです。
 
引用して記述
Sub 抽出A()
 
     Dim cel As Range
 
     Application.ScreenUpdating = False
 
     For Each cel In Range("D5", Cells(Rows.Count, "D").End(xlUp))
      
         If cel.Value <> Empty Then
          
         Unload uf2
          
         Else
          
        Application.DisplayAlerts = False
        ActiveSheet.Delete ←ここがわからない
        Application.DisplayAlerts = True
 
          
        MsgBox "抽出はありません" ←この条件を達成するときに「Call あいう」スキップというのは理解
              
         End If
     Next
 
     Application.ScreenUpdating = True
      
 End Sub

 
「ここがわからない」と書かせてもらった部分について実際に挙動している場合の動作例を教えてください。
これ、RangeD5〜D列の最終入力行まで下方向にセルを参照しておりますが、
 
D5から下へ1セルずつ、
「このセルに値が入ってなければこのシート(現在アクティブなシート)を削除する」
が繰り返し実行されているように見えます。
 
大丈夫な動作でしょうか???
 
これって、D5〜nセル目まで、
「全ての範囲でデータが入力されていなければアクティブなシートを削除」
なのか、
「事実上D5セルが記入されているかしかチェックしていないからこのソースコードで別に動作に問題なし」
なのか、
「別の解釈である」
なのかわからないです。
 
For Each cel In Range("D5", Cells(Rows.Count, "D").End(xlUp))の部分が上位の所属を指定していないので
「現在アクティブなワークシートに対して参照する仕組み」
 
ここのサイトに記載されていない何らかのぼかしが入っているなら別にいいのですが、「どのワークシートをターゲットにしているのか」が指定されていないので、思わぬタイミングで実行した時に消してはいけないワークシートを削除する動作が実行される可能性があります。
 
また、抽出A()が実行された後に別の関数を実行するか否かの制御になるので抽出A()の中身の変更だけでは対応できません。
 
Sub 抽出A()
〜〜〜〜〜
End Sub


Function 抽出A() as Boolean
〜〜〜〜
    If(希望の条件をここにかく)Then
        抽出A = True
    Else
        抽出A = False
    Endif
End Function

 
とSub関数モジュールからFunction関数モジュールに変更する処理と、
Call 抽出A
Call あいう


If(抽出A = True)Then
    Call あいう
Endif

に直す(関数の戻り値で調べてみてください)2段構えの修正をすれば一応原理的には修正できる。
 
けれど、「希望の条件を〜」の部分の記述に影響するレベルで前述の実行内容の不備疑惑があるのでいったんこれをやる前にどのようなイメージ・実際の挙動を整理してください。

投稿日時: 22/10/04 16:57:19
投稿者: chokobanana

メッセージありがとうございます
 
的確に説明できず、ご迷惑をおかけしております
 
1.「空のメッセージボックスが表示される->非表示にしたい」
 
 ▼FnameMsg空じゃない時はメッセージFnameMsgを表示
 If(FnameMsg<>"")Then
    MsgBox FnameMsg
 endif
 
空じゃない時の条件式「<>””」勉強になります
メッセージ表示されなくなりました
他の書き方も調べてみようと思います
 
2.「抽出がない場合に次の関数の実行をスキップする」
 
D5〜nセル目まで、
「全ての範囲でデータが入力されていなければアクティブなシートを削除」です
 
Callで接続されたマクロは、
@ 「ファイルかきく」と同じフォルダ内のファイルにデータが有る場合、今日の日付のみ抽出
A 「ファイルかきく」に新規sheetを作成
B Aで作成したsheetへ@をコピペ
C Bの結果が「空」ならsheetを削除
D Bの結果が「空じゃない」ならデスクトップへファイルをコピペ
となっております。
 
ActiveSheetはAで作成した新規sheetです。
「Sub 抽出@」の後にCallでActiveSheetの保存が実行されています
 
sheet名を特定して動作したほうが良いということですよね?
挑戦してみます
 
それと、Call あいうの実際の挙動を整理して試してみます
できれば、もう少しお時間頂けないでしょうか?
 
よろしくお願いします
 
 

回答
投稿日時: 22/10/04 17:32:13
投稿者: QooApp

私が見落としてるだけなら問題ないですが、
新規のワークシートを作成する処理のあと、新規作成したワークシートがアクティブなシートになります。
絶対にワークシートが生成される手順なので生成した以上消さねばならない。
 
というプログラムの流れで、かつ現状エラーが出ていなかったらとりあえず大丈夫だと思います。
いったんそこの話は省かせてもらいます。
 

引用:
D5〜nセル目まで、
「全ての範囲でデータが入力されていなければアクティブなシートを削除」です
  
Callで接続されたマクロは、
@ 「ファイルかきく」と同じフォルダ内のファイルにデータが有る場合、今日の日付のみ抽出
A 「ファイルかきく」に新規sheetを作成
B Aで作成したsheetへ@をコピペ
C Bの結果が「空」ならsheetを削除
D Bの結果が「空じゃない」ならデスクトップへファイルをコピペ
となっております。

 
であれば、以下の記述を追記してもらって前述のFunction関数化の処理と合体してもらってもいいですか?
■1.「Dim cel As Range」の下に2行追加
Dim SkipFlag As Boolean
SkipFlag = True

■2.「MsgBox "抽出はありません"」の下に1行追加
SkipFlag = False

■3.さっきの末尾処理を修正
If(SkipFlag = True)Then
        抽出A = True
    Else
        抽出A = False
    Endif
End Function

 
これで多分抽出A()の結果が抽出ない場合、外部から呼び出した時に戻り値としてFalseが返却されます。
逆に、抽出がある場合はTrueが戻り値として返却されます。
 
If(抽出A = True)Then
    Call あいう
Endif

戻り値として受け止めることで次の実行の可否を自動で決定します
 
戻り値として戻す方法が基本的に一番楽で、かつ間違いがないと思います。
戻り値に設定したい値の種類を決定するのはFunction ●●() As ▼▲▼▲
の「▼▲▼▲」部分です。
 
戻り値は変数名の定義が不要な代わりに関数名に直接値を入力することができます。
入力しなおす(上書き)もできますが、その関数が終了した時点における格納されている値が戻り値として固定されます。
 
テクニカルな方法としてターゲットしているワークシートを関数を超えて受け渡すことにも使えたりします。
(その場合、代入処理のときに「Set 関数名 = ワークシート変数」という書き方になるので詳しくは「ワークシート 変数 設定」とかで調べてみてください)

投稿日時: 22/10/11 12:52:28
投稿者: chokobanana

メッセージありがとうございます。
 
取り急ぎ、エラー無く修正できたことをご報告いたします。
 
自分で使えるようになりたいので教えて頂いたコードを勉強しております
まだ全部は理解できておりませんが、時間がかかりそうなので
こちら一度閉じさせて頂きます。
 
教えて頂いたコードが分からない時は又、こちらより質問させて頂きます。
 
どうもありがとうございました。

回答
投稿日時: 22/10/13 11:47:29
投稿者: QooApp

動いたようでなによりです。
元のソースコード、2018年頃からすでに運用されていると思われますが、せっかく制作されたものですので必要なメンテナンスを継続できるように頑張ってください。
 
調べたら18年頃に元の作者さんと思わしき人が別のサイトで質問されておりました。
導入後4年も維持できているならば少なからず悪いシステムではないでしょうから頑張ってください。
ただし、古いソースコードの形態に固執することで逆に効率が悪化することもありますのでどうにもこうにも対応しがたいと判断されるときは開発会社に投げるのも懸命な判断といえます。
 
あと、ここのサイトのシステム上、長期間未完了のスレッドも投稿件数で強制的に流される(消失する)ことになるので
追加の質問がある場合は、別スレッドを立ててもらった方がいいと思います。
スレッドを閉じることはスレッド主しかできないのでお手数ですがそちらのメッセージ入力ボックス画面の下にある解答済みチェックボックスをクリックしてもらいますようお願いします。

投稿日時: 22/10/14 08:45:17
投稿者: chokobanana

QooApp様
色々とご指導感謝します
こちらの使用も分からずご面倒おかけしました