前々回。
本家MSJPのサイトの[XL2002]印刷されるページの総数を調べる方法のソースではうまくいかない場合があるといぅところまでお話ししましたね。
てゅうわけで、今回はその続きです。
まず、Subのままだと実行→確認がめんどくさいので、Functionに書き換えてセル上で結果が確認できるよぅにします。
どぅせ最終的には行タイトル領域内のセルに埋め込みたいわけですから実害なし。むしろ先取り。てゅうほどのことではありませんが。
Function PrintPage() As Integer
Dim H_Break As Integer
Dim V_Break As Integer
Dim P_Page As Integer
Dim A_Cell As String
'--最後のセルのアドレスを取得--
A_Cell = Sheet1.UsedRange.Address
If A_Cell = "$A$1" Then
If IsEmpty(Sheet1.Range(A_Cell).Value) Then
MsgBox "印刷するデータはありません。"
Exit Function
End If
End If
'--↓の改ページ数取得--
H_Break = Sheet1.HPageBreaks.Count
'--→の改ページ数取得--
V_Break = Sheet1.VPageBreaks.Count
If V_Break = 0 Then
P_Page = H_Break + 1
Else
H_Break = H_Break + 1
V_Break = V_Break + 1
P_Page = H_Break * V_Break
End If
'--↓関数化--
PrintPage = P_Page
End Function
(赤字が追加/修正個所)
これをセルに埋め込む時には、こんな感じで。
=printpage()
PrintPageと書いても
printpageと変わっちゃうのがなんかあれですがまぁよし。
[F2]でセル編集モードに移行してEnter押さないと再実行されないのもなんかあれですがそれもまぁよし。としましょうとりあえず。
実行結果はこんな感じです。
ではこの1ページ目分をぴったり覆う罫線を引いてからもう一度実行してみます。
こんな感じ。「4」になっちゃいますよね。
てことは、この時点で縦横にひとつずつ改ページができている、ってことになります。でそれにおのおの+1されているよぅですね。
…なんてこったい。
んー、このやみくもな+1を避けるには、最初の方で未入力判断に使っていたSheet1.UsedRange.Addressと、一番右下の改ページ座標との関係を調べればなんとかなりそぅな。
では。
1ページ目分をぴったり覆う罫線を引いた場合にひとつだけできる改ページはどのセル位置なのかを調べてみましょう。
とりあえずFunctionの途中でプレイクかけて、その時点での改ページオブジェクトの行/列をイミディエイトウィンドウで直に表示させてみました。
A66(2ページ目になるはずの最左上セル)と出ました。なるほど。
ちょっとこのへん、いろんなパターンを試して使用領域の右下隅座標と右下隅改ページ座標との関連を考えてみましょう。
| 入力範囲 | 使用セル範囲 | ↓方向
改ページ数 | ↓方向最終
改ページ座標 | →方向
改ページ数 | →方向最終
改ページ座標 |
| 入力なし | $A$1 | 0 | (なし) | 0 | (なし) |
| A1のみ | $A$1 | 0 | (なし) | 0 | (なし) |
| A列1ページ分 | $A$1:$A$65 | 1 | A66 | 0 | (なし) |
| 1行1ページ分 | $A$1:$K$1 | 0 | (なし) | 1 | L1 |
| 1ページ分フル | $A$1:$K$65 | 1 | A66 | 1 | L1 |
| 1ページ分フル罫線 | $A$1:$K$65 | 1 | A66 | 1 | L1 |
| 1ページ分フル+右1セル | $A$1:$L$65 | 1 | A66 | 1 | L1 |
| 1ページ分フル+下1セル | $A$1:$K$66 | 1 | A66 | 1 | L1 |
ちなみにこの検証用に使用したコードはこんな感じ。
Sub PrintPageTest() As Integer
Dim strBf As String
strBf = ""
strBf = strBf & "使用セル範囲:" & Sheet1.UsedRange.Address
strBf = strBf & vbCrLf & "↓改ページ数:" & Sheet1.HPageBreaks.Count
strBf = strBf & vbCrLf & "↓改ページ座標:"
If (Sheet1.HPageBreaks.Count > 0) Then
strBf = strBf & vbCrLf _
& Sheet1.HPageBreaks(Sheet1.HPageBreaks.Count).Location.Column & "/" _
& Sheet1.HPageBreaks(Sheet1.HPageBreaks.Count).Location.Row
End If
strBf = strBf & vbCrLf & "→改ページ数:" & Sheet1.VPageBreaks.Count
strBf = strBf & vbCrLf & "→改ページ座標:"
If (Sheet1.VPageBreaks.Count > 0) Then
strBf = strBf & vbCrLf _
& Sheet1.VPageBreaks(Sheet1.VPageBreaks.Count).Location.Column & "/" _
& Sheet1.VPageBreaks(Sheet1.VPageBreaks.Count).Location.Row
End If
MsgBox strBf
End Function
ここから推測できるルールは、
改ページの発生は、縦方向・横方向に関わらず共通。
セルの使用形態がデータ・罫線に関わらず共通。
ページの途中までしかデータがない場合は、その下(右)に改ページは発生しない。
ページぎりぎりまでデータを入れた場合は、その直下(直右)に改ページが発生する。
くらいでしょうか。ならば。
使用セル範囲右下隅が最下(最右)改ページの
1つ上(左)ならばちょっきりと見なす。
よし、これでいこう。
いこう。ってのは簡単ですが。使用セル範囲の最右下隅座標をどう取得するかも割と大変です。Sheet1.UsedRange.Addressじゃぁ文字列で返ってくるのでセル座標数値に変換するのも大変ですし。
Sheet1.UsedRange.Rows.Countを使ってみましょうか。これならば使用行数が取得できます。
ただし、1行目にデータがない場合はその分勘定されません(2~3行にのみデータがある場合、このプロパティは「2」となります)ので、Sheet1.UsedRange.Rowで使用最上行が取得できますからこれと合わせます。
かといってただ足すと必ず1多くなりますので、そこから1引いてやる、と。
Row/Rowsの代わりにColumn/Columnsを使ってやると、同様に最右列も取得できます。
以上から、実装するロジックは
- 使用セル範囲の最右下隅座標がA1、かつA1にデータがなければそのシートは白紙なので0ページとする。
- 縦(横)方向の改ページ数が0であれば1ページあるとする。
- 使用セル範囲の最右下隅座標が一番下(右)の改ページの1つ上(左)であれば、その改ページ数をそのままページ数とする。
- でなければ改ページ位置より下(右)にまだデータがあると見なし、その改ページ数に1を足した数をページ数とする。
- 最終的なページ数は、上記で求めた縦ページ数×横ページ数で取得できる。
ああぁぁぁ、しんどい。
で、これを実装したコードはこぅだっ!
Function PrintPage() As Long
Dim lngRPage As Long
Dim lngCPage As Long
Dim lngRLastCell As Long
Dim lngCLastCell As Long
'--最後のセルのアドレスを取得--
If Sheet1.UsedRange.Address = "$A$1" Then
If IsEmpty(Sheet1.Range("$A$1").Value) Then
lngCPage = 0
Exit Function
End If
End If
'--縦方向のページ数を算出--
lngRLastCell = Sheet1.UsedRange.Rows.Count + Sheet1.UsedRange.Row - 1
lngRPage = Sheet1.HPageBreaks.Count
If (lngRPage = 0) Then
lngRPage = 1
ElseIf (lngRLastCell <> Sheet1.HPageBreaks(lngRPage).Location.Row - 1) Then
lngRPage = lngRPage + 1
End If
'--横方向のページ数を算出--
lngCLastCell = Sheet1.UsedRange.Columns.Count + Sheet1.UsedRange.Column - 1
lngCPage = Sheet1.VPageBreaks.Count
If (lngCPage = 0) Then
lngCPage = 1
ElseIf (lngCLastCell <> Sheet1.VPageBreaks(lngCPage).Location.Column - 1) Then
lngCPage = lngCPage + 1
End If
'--総ページ数を返す--
PrintPage = lngRPage * lngCPage
End Function
…もぅMicrosoftの元コードの影も形もなし。
とりあえずこれで総ページ数を表示させることはできるよぅになりました。
ただ、プレビューや印刷のタイミングではなく、この関数を埋め込んだセルを編集しないと再計算されないってのがちょっとやりにくいですね。そこで、
→さらに続くし。