Option Explicit
Dim Main As Worksheet
Dim main1 As Worksheet
Dim Gyo As Long
Dim Retsu As String
Dim Ws As Worksheet
Dim Tenki As Long
Dim Saigo As Long
Private Sub S_Denpyo()
S_ANo 'メインのA列に連番を振る
Retsu = "B" '並べ替えのキー指定
S_Narabekae '社名で並べ替える
S_sakujyo 'シートが重複しないように既に作成されている伝票を削除する
S_sakusei '伝票作成
Retsu = "A" '並べ替えのキー指定
S_Narabekae '番号で並べ替える
Saigo = Main.Range("B" & Main.Rows.Count).End(xlUp).Row '最終行の設定
Main.Range("A1:A" & Saigo).Clear 'A列の値を消す
End Sub
Private Sub S_ANo()
Set Main = Worksheets("main")
Saigo = Main.Range("B" & Main.Rows.Count).End(xlUp).Row
Main.Range("A1").Value = "No." 'A列の項目名
For Gyo = 2 To Saigo 'A列に連番を振る
Main.Range("A" & Gyo).Value = Gyo - 1
Next
End Sub
Private Sub S_Narabekae() 'mainの並べ替え
Set Main = Worksheets("main")
Saigo = Main.Range("B" & Main.Rows.Count).End(xlUp).Row
Main.Range("A2:G" & Saigo).Sort _
Key1:=Main.Range(Retsu & 1), _
Order1:=xlAscending, _
Header:=xlNo
End Sub
Private Sub S_sakusei()
Set Main = Worksheets("main")
Set main1 = Worksheets("main1")
Tenki = 16
Saigo = Main.Range("B" & Main.Rows.Count).End(xlUp).Row
For Gyo = 2 To Saigo
If Main.Range("B" & Gyo).Value <> Main.Range("B" & Gyo - 1).Value Then
'社名の1行目だったら↓
If Left(ActiveSheet.Name, 4) <> "main" Then '罫線を引く
With Range("B16:K" & Tenki - 1)
.Select
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
.Borders(xlInsideHorizontal).LineStyle = xlContinuous
End With
With ActiveSheet.PageSetup 'ヘッダー・フッターの設定
.LeftHeader = "&A"
.RightHeader = "&D"
.RightFooter = "&P/&N"
.PrintArea = "B2:K" & Tenki '印刷範囲設定
.PrintTitleRows = "$14:$15"
.Orientation = xlPortrait
End With
ActiveSheet.Range("A1").Select
End If
Tenki = 16
main1.Copy After:=Worksheets(Worksheets.Count) 'main1をコピー
With ActiveSheet
.Name = Main.Range("B" & Gyo).Value 'シート名を変更
.Range("B" & Tenki).Value = Right(Year(Main.Range("C" & Gyo).Value), 2) '各項目転記↓
.Range("C" & Tenki).Value = Month(Year(Main.Range("C" & Gyo).Value))
.Range("D" & Tenki).Value = Day(Year(Main.Range("C" & Gyo).Value))
.Range("E" & Tenki).Value = Main.Range("D" & Gyo).Value
.Range("F" & Tenki).Value = Main.Range("E" & Gyo).Value
.Range("H" & Tenki).Value = Main.Range("F" & Gyo).Value
If Main.Range("G" & Gyo).Value > 0 Then
.Range("I" & Tenki).Value = Main.Range("G" & Gyo).Value
Else
.Range("J" & Tenki).Value = Main.Range("G" & Gyo).Value
End If
.Range("K" & Tenki).Value = Main.Range("G" & Gyo).Value '元データ1行目のみ計算なし
End With '転記ここまで
Tenki = Tenki + 1
Else '2行目以降の社名だったら↓
With ActiveSheet
.Range("B" & Tenki).Value = Right(Year(Main.Range("C" & Gyo).Value), 2) '各項目転記↓
.Range("C" & Tenki).Value = Month(Year(Main.Range("C" & Gyo).Value))
.Range("D" & Tenki).Value = Day(Year(Main.Range("C" & Gyo).Value))
.Range("E" & Tenki).Value = Main.Range("D" & Gyo).Value
.Range("F" & Tenki).Value = Main.Range("E" & Gyo).Value
.Range("H" & Tenki).Value = Main.Range("F" & Gyo).Value
If Main.Range("G" & Gyo).Value > 0 Then
.Range("I" & Tenki).Value = Main.Range("G" & Gyo).Value
Else
.Range("J" & Tenki).Value = Main.Range("G" & Gyo).Value
End If
If .Range("J" & Tenki).Value = "" Then '借方、貸方から残高計算
.Range("K" & Tenki).Value = .Range("K" & Tenki - 1).Value + .Range("I" & Tenki).Value
Else
.Range("K" & Tenki).Value = .Range("K" & Tenki - 1).Value + .Range("J" & Tenki).Value
End If
End With '転記ここまで
Tenki = Tenki + 1
End If
Next
With Range("B16:K" & Tenki - 1) '最後のシートに罫線をひく
.Select
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
.Borders(xlInsideHorizontal).LineStyle = xlContinuous
End With
ActiveSheet.Range("A1").Select
Main.Select
End Sub
Private Sub S_sakujyo()
For Each Ws In Worksheets
If Left(Ws.Name, 4) <> "main" Then
Application.DisplayAlerts = False
Ws.Delete
Application.DisplayAlerts = True
End If
Next
End Sub
最終的に動くものが出来たのですが、お手本の中でActivesheetを変数に入れていたので、下記のように変数を作成しやってみたのですが、これだけでまったく違う動作をしてしまい断念しました。 違う動作というのはコピー元の「main」シートが「愛知製本」になり、以降230枚ほどのシートが「main」のコピーとして作成されるというものです。 変数以外は変えていない事を確認しつつ、試行錯誤しましたが理解できず、諦めました。 何がいけなかったのでしょうか? Dim Acts As Worksheet Set Acts = Activesheet
Option Explicit
Dim Main As Worksheet
Dim main1 As Worksheet
Dim Gyo As Long
Dim Retsu As String
Dim Ws As Worksheet
Dim Tenki As Long
Dim Saigo As Long
Private Sub S_Denpyo()
Set Main = Worksheets("main")
Set main1 = Worksheets("main1")
Tenki = 0
Saigo = Main.Range("B" & Main.Rows.Count).End(xlUp).Row
S_ANo
Retsu = "B"
S_Narabekae
S_sakujyo
S_sakusei
Retsu = "A"
S_Narabekae
'↓clear(数式・文字・書式・コメント全て消す)をClearContents(数式・文字を消す)に直しました。使い分けるようにします。
Main.Range("A1:A" & Saigo).ClearContents
End Sub
Private Sub S_ANo()
Main.Range("A1").Value = "No."
For Gyo = 2 To Saigo
Main.Range("A" & Gyo).Value = Gyo - 1 '多すぎたインデントを修正しました。
Next
End Sub
Private Sub S_Narabekae()
'excel 2007 以降の書き方に変更しました。
With Main
.Sort.SortFields.Clear
.Sort.SortFields.Add Key:=.Range(Retsu & 1), _
Order:=xlAscending
.Sort.SetRange .Range("A2:G" & Saigo)
.Sort.Header = xlNo
.Sort.Apply
End With
' Main.Range("A2:G" & Saigo).Sort _
' Key1:=Main.Range(Retsu & 1), _
' Order1:=xlAscending, _
' Header:=xlNo
End Sub
Private Sub S_sakusei()
For Gyo = 2 To Saigo
If Main.Range("B" & Gyo).Value <> Main.Range("B" & Gyo - 1).Value Then
If Left(ActiveSheet.Name, 4) <> "main" Then
' Range なので、「アクティブシートの」という文脈になっています。
' 結果的には正常動作しているようですが、複数シート間でのデータ転記のマクロでは
' セルの指定時は常にシートから書くようにしたほうが良いでしょう ogawa
' ↑講義でも最初の方でご説明頂いていた箇所でした。気を付けていたつもりが抜けておりました。
' 最終的にRangeで検索をかけてチェックするなど漏れない工夫をしてみます。
With ActiveSheet.Range("B16:K" & Tenki - 1)
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
.Borders(xlInsideHorizontal).LineStyle = xlContinuous
End With
'コードでやるより、シート「main1」のヘッダー・フッターを編集するほうがスマート ogawa
'↑シート名と日付の記載方法を変えました。
With ActiveSheet.PageSetup
.LeftHeader = ActiveSheet.Name
.RightHeader = Format(Date, "Long Date")
.RightFooter = "&P/&N" 'ページ数
.PrintArea = "B2:K" & Tenki
.PrintTitleRows = "$14:$15"
.Orientation = xlPortrait
End With
End If
'[1-1] - [1-2], [2-1] - [2-2] は同じことを重複して書いているので1回で済ませられるように手直ししましょう ogawa
'↑上手く言葉にできませんが、最初に作った時と視点を切り替える事がなかなかできず、とても難しかったです。
Tenki = 16
main1.Copy After:=Worksheets(Worksheets.Count)
ActiveSheet.Name = Main.Range("B" & Gyo).Value
End If
If Tenki >= 16 Then
S_tenki
End If
Next
With ActiveSheet.Range("B16:K" & Tenki - 1)
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
.Borders(xlInsideHorizontal).LineStyle = xlContinuous
End With
Main.Select
End Sub
Private Sub S_sakujyo()
For Each Ws In Worksheets
If Left(Ws.Name, 4) <> "main" Then
Application.DisplayAlerts = False
Ws.Delete
Application.DisplayAlerts = True
End If
Next
End Sub
Private Sub S_tenki()
With ActiveSheet
.Range("B" & Tenki).Value = Right(Year(Main.Range("C" & Gyo).Value), 2)
.Range("C" & Tenki).Value = Month(Year(Main.Range("C" & Gyo).Value))
.Range("D" & Tenki).Value = Day(Year(Main.Range("C" & Gyo).Value))
.Range("E" & Tenki).Value = Main.Range("D" & Gyo).Value
.Range("F" & Tenki).Value = Main.Range("E" & Gyo).Value
.Range("H" & Tenki).Value = Main.Range("F" & Gyo).Value
If Main.Range("G" & Gyo).Value > 0 Then
.Range("I" & Tenki).Value = Main.Range("G" & Gyo).Value
Else
.Range("J" & Tenki).Value = Main.Range("G" & Gyo).Value
End If
If Tenki = 16 Then
.Range("K" & Tenki).Value = Main.Range("G" & Gyo).Value
Else
If .Range("J" & Tenki).Value = "" Then
.Range("K" & Tenki).Value = .Range("K" & Tenki - 1).Value + .Range("I" & Tenki).Value
Else
.Range("K" & Tenki).Value = .Range("K" & Tenki - 1).Value + .Range("J" & Tenki).Value
End If
End If
End With
Tenki = Tenki + 1
End Sub
Option Explicit
Dim Main As Worksheet
Dim main1 As Worksheet
Dim Gyo As Long
Dim Retsu As String
Dim Saigo As Long
Private Sub S_Denpyo()
Set Main = Worksheets("main")
Set main1 = Worksheets("main1")
Saigo = Main.Range("B" & Main.Rows.Count).End(xlUp).Row
S_ANo
Retsu = "B"
S_Narabekae
S_sakujyo
S_sakusei
Retsu = "A"
S_Narabekae
Main.Range("A1:A" & Saigo).ClearContents
End Sub
Private Sub S_ANo()
Main.Range("A1").Value = "No."
For Gyo = 2 To Saigo
Main.Range("A" & Gyo).Value = Gyo - 1
Next
End Sub
Private Sub S_Narabekae()
With Main
.Sort.SortFields.Clear
.Sort.SortFields.Add Key:=.Range(Retsu & 1), _
Order:=xlAscending
.Sort.SetRange .Range("A2:G" & Saigo)
.Sort.Header = xlNo
.Sort.Apply
End With
End Sub
Private Sub S_sakusei()
Dim Tenki As Long
For Gyo = 2 To Saigo
If Main.Range("B" & Gyo).Value <> Main.Range("B" & Gyo - 1).Value Then
If Left(ActiveSheet.Name, 4) <> "main" Then
With ActiveSheet.Range("B16:K" & Tenki - 1)
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
.Borders(xlInsideHorizontal).LineStyle = xlContinuous
End With
ActiveSheet.PageSetup.PrintArea = "B2:K" & Tenki
End If
Tenki = 16
main1.Copy After:=Worksheets(Worksheets.Count)
ActiveSheet.Name = Main.Range("B" & Gyo).Value
End If
With ActiveSheet
.Range("B" & Tenki).Value = Right(Year(Main.Range("C" & Gyo).Value), 2)
.Range("C" & Tenki).Value = Month(Year(Main.Range("C" & Gyo).Value))
.Range("D" & Tenki).Value = Day(Year(Main.Range("C" & Gyo).Value))
.Range("E" & Tenki).Value = Main.Range("D" & Gyo).Value
.Range("F" & Tenki).Value = Main.Range("E" & Gyo).Value
.Range("H" & Tenki).Value = Main.Range("F" & Gyo).Value
If Main.Range("G" & Gyo).Value > 0 Then
.Range("I" & Tenki).Value = Main.Range("G" & Gyo).Value
Else
.Range("J" & Tenki).Value = Main.Range("G" & Gyo).Value
End If
If Tenki = 16 Then
.Range("K" & Tenki).Value = Main.Range("G" & Gyo).Value
Else
If .Range("J" & Tenki).Value = "" Then
.Range("K" & Tenki).Value = .Range("K" & Tenki - 1).Value + .Range("I" & Tenki).Value
Else
.Range("K" & Tenki).Value = .Range("K" & Tenki - 1).Value + .Range("J" & Tenki).Value
End If
End If
End With
Tenki = Tenki + 1
Next
With ActiveSheet.Range("B16:K" & Tenki - 1)
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
.Borders(xlInsideHorizontal).LineStyle = xlContinuous
End With
ActiveSheet.PageSetup.PrintArea = "B2:K" & Tenki
Main.Select
End Sub
Private Sub S_sakujyo()
Dim Ws As Worksheet
For Each Ws In Worksheets
If Left(Ws.Name, 4) <> "main" Then
Application.DisplayAlerts = False
Ws.Delete
Application.DisplayAlerts = True
End If
Next
End Sub
凜さんの投稿
(投稿ID: 5501)
宿題の提出をさせて頂きます。
ここまでの丁寧なご説明のおかげで作成の流れやそれぞれのマクロの書き方はある程度理解できた為、今回は以前の授業で教えて頂いた「サブプロシージャの分割と呼び出し」「モジュールレベル変数」へのチャレンジもしてみました。
その中でふと疑問に思ったのですが、「モジュールレベル変数」でOption Explicitの直後に変数を宣言し、変数の中身は各プロシージャごとに記載したのですが、「一度、設定した変数の値は再設定されるまで複数のプロシージャ間で有効になる」という事は1番上のプロシージャですべての変数の値を記載しておくという書き方もいいのでしょうか。
今後、仕事で使っていく上で書き方としての良し悪しも合わせて教えていただけますでしょうか。
下記、添削をお願いします。
最終的に動くものが出来たのですが、お手本の中でActivesheetを変数に入れていたので、下記のように変数を作成しやってみたのですが、これだけでまったく違う動作をしてしまい断念しました。
違う動作というのはコピー元の「main」シートが「愛知製本」になり、以降230枚ほどのシートが「main」のコピーとして作成されるというものです。
変数以外は変えていない事を確認しつつ、試行錯誤しましたが理解できず、諦めました。
何がいけなかったのでしょうか?
Dim Acts As Worksheet
Set Acts = Activesheet
今回、自力でチャレンジする機会を頂いたおかげで今後の自分の仕事への活かし方が具体的に見えてきた気がします。構文は使えるようになったけど自分の仕事としてどこで使えるんだろうという疑問が払拭された感じです。
大変でしたが、とても楽しくできました。ありがとうございました。
これからもよろしくお願いします。
小川 慶一さんのコメント
(コメントID: 8245)
投稿ありがとうございます。
添削を返送します。
>「一度、設定した変数の値は再設定されるまで複数のプロシージャ間で有効になる」という事は1番上のプロシージャですべての変数の値を記載しておくという書き方もいいのでしょうか。
大丈夫です。
実際に試してみてください (^^
>今後、仕事で使っていく上で書き方としての良し悪しも合わせて教えていただけますでしょうか。
「一度で済み、そのあと変更の必要はない」ということであれば、「初期の初期に一度調べてその値を使いわます」というやり方がいちばんすっきりした方法と思います。
お手本の中でActivesheetを変数に入れていたので、下記のように変数を作成しやってみたのですが、これだけでまったく違う動作をしてしまい断念しました。
上記2行をどこに入れたのか分からないのでなんともいえませんが...。
Set Acts = Activesheet は、 Acts という変数(ニックネーム)を ActiveSheet (そのときアクティブなシート)に割り当てるわけですのでそのタイミングがおかしかったのではないかと。
この行が実行された直後に、変数 Acts に「愛知販売」なり「愛媛不動産」なりといったご希望されているシートが割り当てられているかを確認してみてください。
ともあれ、まずは、添削内容を意識したリライトをしましょう。
より頭が混乱しそうな改変は、その次ということで。
小川 慶一さんのコメント
(コメントID: 8246)
これらもご確認ください。よい学びになるかと思います (^^
凜さんのコメント
(コメントID: 8252)
ご指摘頂いた箇所を修正しました。
難しくて5日間も悩んでしまいましたが、パズルを解いているようで楽しかったです。
よろしくお願いします。
小川 慶一さんのコメント
(コメントID: 8253)
以下の条件式は常に True ですね。あと、1箇所からしか呼び出されないなら、変数 Tenki をモジュールレベル変数にしてまで別プロシージャにするより、 S_sakusei の中に書いてしまったほうが良いかなとも思います。
(発展編1レベルのスキルのときは、です。発展編2で引数つきプロシージャを学ぶとその限りではなくなりますが)
『コードでやるより、シート「main1」のヘッダー・フッターを編集するほうがスマート』という件は、エクセルの外側の(VBA)でない機能でテンプレートの書式を整えてしまったほうがよいという意味です。
そうすると、以下のコードで明示的に変更しているところをいくつかコメントアウトできますね。
凜さんのコメント
(コメントID: 8254)
ご指摘頂いた条件式・・動作に影響がなかったので、常にTRUEである事に気付けませんでした。見直す時に逆の結果が出るパターンを考えて、不要な式を残さないように気を付けます。
また「1箇所からしか呼び出されないなら、変数 Tenki をモジュールレベル変数にしてまで別プロシージャにするより、 S_sakusei の中に書いてしまったほうが良いかなとも思います。」とのご指摘ですが、これはその変数を使うプロシージャが一つか複数かを考えて使い分けた方がよいという事でよろしいでしょうか。
「Tenki」と「Ws」が一つのプロシージャでしか使われていなかった為、個別のプロシージャ内に移動しました。
ヘッダー・フッターの設定について、理解できました。
必死にマクロを書くことばかりに囚われていましたが、Excelの設定で対応するところとマクロでやるところを使い分けていくことを意識してみます。
修正したものを添付いたします。
よろしくお願いします。
小川 慶一さんのコメント
(コメントID: 8255)
モジュールレベル変数は、複数プロシージャ間で変数を使って値を共有したいときに使うものです [1]
ですので、その変数を使うプロシージャが1つであれば、モジュールレベル変数として宣言する必要はないですね。
というか、定義とプロシージャが分離してしまうので、モジュールレベル変数をみだりに使ってしまうと可読性・メンテナンス性が落ちてしまいます。
また、 [1] の意味では、さらに言うと、変数 Gyo はこれを使っている S_Ano, S_sakusei のそれぞれの内部で宣言したほうが良いです。
そうすることのメリットは、たとえば、なんらかの事情で「S_sakusei の中では for 文のカウンターとして使う変数の名前を Gyo ではなく hoge にしたい」等の修正を行うときに変更が最低限で済むことです。
モジュールレベル変数として宣言した Gyo を変更するとなると、モジュール内全域で影響が生じます。ですが、 S_sakusei の内部で宣言した変数であれば、変更はその内部で宣言した変数とその内部のプロシージャだけで済みます。
凜さんのコメント
(コメントID: 8256)
詳しい説明をありがとうございました!
小川 慶一さんのコメント
(コメントID: 8257)
ひきつづきよろしくお願いいたします (^^