見積書の雛形をエクセルVBAで作ろう!(Part 3)

見積書の雛形をエクセルVBAで作ろう!.png

列の幅と行の高さを変更する(2)

前回の「見積書の雛形をエクセルVBAで作ろう!(Part 2)」では原本の見積書の列幅のポイント値を調べて別シートへその結果を記入する方法をご紹介しました。 今回は調べたポイント値を使って列幅を変更していこうと思います。

前回でも書きましたがエクセルVBAではポイント値を使って列幅を変更することが出来ません。列幅を変更するには「いま使用しているエクセルで設定されている標準フォントの半角の0の文字幅を1として何文字入るか」を数値にして指定します。 この基準文字幅はエクセルのバージョンやそれぞれの設定の違い等のため一定ではなく、私の今使っているエクセル環境での基準文字幅と他のかたの基準文字幅が違う可能性が高いのです。それでは同じ列幅の見積書を再現することは出来ません。 

そこで前回調べたポイント値を利用して列幅を変更するためにすこし変わったことをしてみます。

まずは保存しておいた「VBA練習1」のブック(エクセルファイル)を開いて、VBEを起動してください。この画面です ↓

先頭のシート名を変更1600×900.png

そして今回はいろいろ試験的に何回か動かしたいので前回のSubプロシージャの下にもうひとつのSubプロシージャを作って切り離しておいてください。名前は「列幅の変更をする」にしましょうか ↓

今日はここから1600×900

前回調べた見積書の列幅のポイント値は以下のとおりです。

A列:5pt、B列:27.5pt、C列:303.5pt、D列:57pt、E列:42.5pt、F列:80pt、G列:80pt、H列:94pt、I列:5pt

このポイント値を利用して見積書の列幅を変更していきましょう。

列幅をポイント値から設定するにはどうしたらよいか?

列幅のポイント値は判りました。でも列幅の文字数に変換しないと幅変更が出来ません。 1ポイントあたりの文字数を割り出して、「設定したいポイント値」×「1ポイントあたりの文字数」を計算すれば目標の文字数がでるはずです。

構文を短く見やすくしたいので前回にご紹介した変数の宣言からやっていきます。↓

' 変数の宣言
Dim rng As Range   'セルまたは列(データ型はオブジェクト型のRange)
Dim pt As Single   'ポイント値(データ型は単精度浮動小数点数型のSingle)
Dim mojisu As Single '変換後の文字数(データ型は単精度浮動小数点数型のSingle)

上記3つの変数(入れ物)を宣言しました。 rngptmojisu です。

次に2つの変数に中身を入れます。変数のデータ型がオブジェクト型の場合のみ先頭に「Set」を記入するきまりがあります。 rngには仮に「A1セル」、ptには「200」を代入しました ↓

Set rng = Range("A1")  'セルまたは列を設定
pt = 200         'ポイント値を設定

残りの変数1つに中身を入れます。↓

mojisu = pt * (rng.ColumnWidth / rng.Width) '設定する文字数を代入

( rng.ColumnWidth / rng.Width ) は、現在の文字数ポイント値で割って「1ポイントあたりの文字数」を割り出しています。 そして「設定したポイント値」×「1ポイントあたりの文字数」で「設定する文字数」を出しています。

「設定する文字数」が出たのでこれを変数のmojisuに代入しました。

ここで試しにA1セルを200ポイントの真四角に設定してみましょう。↓

rng.RowHeight = pt     '行高さをポイント値で設定
rng.ColumnWidth = mojisu  '列幅を変換後の文字数で設定

纏めるととこのようになります。↓

A1セルを真四角に設定1600×900
Sub 列幅の変更をする()
    ' 変数の宣言
    Dim rng As Range     'セルまたは列(データ型はオブジェクト型のRange)
    Dim pt As Single      'ポイント値(データ型は単精度浮動小数点数型のSingle)
    Dim mojisu As Single  '変換後の文字数(データ型は単精度浮動小数点数型のSingle)
    
    Set rng = Range("A1")   'セルまたは列を設定
    pt = 200                'ポイント値を設定
    mojisu = pt * (rng.ColumnWidth / rng.Width)  '設定する文字数を代入
    
    rng.RowHeight = pt         '行高さをポイント値で設定
    rng.ColumnWidth = mojisu   '列幅を変換後の文字数で設定
    
End Sub

書き間違えがないことを確認したらテストしてみましょう。いまの設定は「A1セル」を200ポイントの大きさで真四角になるように書かれています。今日書いたSub~End subまでの間にカーソルを置いてからキーボードの「F5キー」または「Sub/ユーザフォームの実行」ボタンを1回押して実行してみてください。どうなるでしょう?

A列とB列の境界線にカーソルをあわせて長押しすると幅のピクセル数が出ます。1行目と2行目の境界線上にカーソルをあわせて長押しすると高さのピクセル数が出ます。この2つを比べてみてください。 私の環境ではこうなりました。↓

真四角になっていない1600×900

高さはジャスト200ポイントで400ピクセルになっています。行高さは問題ありません。では幅はというと同じ400ピクセルになるはずが380ピクセルになっています。。。つまり真四角になっていないということです。これはコンピューター特有の小数点計算の誤差の問題などが関係しているようで1回ではうまく真四角になってくれません。

ではもう一度、今日書いたSub~End subまでの間にカーソルを置いてからキーボードの「F5キー」または「Sub/ユーザフォームの実行」ボタンを1回押して実行してみてください。どうなるでしょう? ↓

真四角になった1600×900

私の環境では今度は400ピクセルの真四角になりました!  事前にいろいろなポイント値でやってみたのですが、どうやら多くても3回目には正しい真四角になるようです。 これでポイント値で列幅を設定する目処がつきました。

列幅を設定するため、For~Next構文で3回処理するように書き直す

では今まで書いた構文を修正していきましょう。

「変数への代入」から繰り返し処理に変えていきます。 前回ご紹介した通り、For~Next構文の中に入れるのですね。 For~Next構文ではカウンターを使って繰り返し処理を行っていました。ですからまずカウンターに使う変数を宣言しましょう。今回はカウンターを2つ使いたいので「i」「n」の2つの変数を追加し、次の2行を変数の宣言に追記してください。 ↓

Dim i As Long '列指定用のカウンター(データ型は長整数型のLong) 
Dim n As Long '3回繰り返し用のカウンター(データ型は長整数型のLong)

変数の宣言2行を追記したら、まず変数nを使ってFor~Next構文の中に処理内容を入れてください。そして列幅のみ設定するため、行高さの設定行は削除してください。 ↓

この行は不要 1600×900

9列分の処理を繰り返すため、さらにFor~Next構文を追加する

つぎに変更するのはセルの指定をしている部分を列の指定に変えることです。 A1セルを指定している行を、列の指定に変更します。 列の指定はColumns(列番号)でします。 列番号は左から数えてA列は1、I列は9です。この列番号をカウンターにします。今度は変数 i を使いますのでこのようになります。 ↓

For i = 1 To 9
    For n = 1 To 3
        Set rng = Columns(i) 'セルまたは列を設定
        pt = 200
        mojisu = pt * (rng.ColumnWidth / rng.Width) '設定する文字数を代入
        rng.ColumnWidth = mojisu '列幅を変換後の文字数で設定
    Next n
Next i

For~Next構文(繰り返し処理)が2回出てきていますね。For i で始まる部分とFor n で始まる部分の2回です。For~Next構文は入れ子構造にすることが出来ます。↓

入れ子構造1600×900

赤枠で囲った部分は処理する内容を書いています。 その処理を青枠で囲ったFor nの部分で3回繰り返しにしています。 そして今度は黄枠で囲ったFor iの部分で、A列からI列のそれぞれの列で青枠内の処理をするために9回繰り返しとしています。 

ここでよく見ますと、「セルまたは列を設定」する行にも変数 i が使われています。For i でカウンターに使っている i をColumns( i )で列番号としても使っているのです。

一度ここまでの処理を動かしてみましょうか。 「列幅を配列を使って変更する」のSubプロシージャ内にカーソルを置いてからキーボードの「F5キー」または「Sub/ユーザフォームの実行」ボタンを1回押して実行してみてください。記入間違いがなければA列からI列までの列幅が200ポイントの幅になったはずです。

列ごとに違うポイント値を使うために「配列」を利用する

A列からI列までの列幅を200ポイントにする事は成功しました。今度はそれぞれの列に違うポイント値を使うための仕掛けをします。

For i = 1 To 9
    For n = 1 To 3
        Set rng = Columns(i) 'セルまたは列を設定
        pt = 200
        mojisu = pt * (rng.ColumnWidth / rng.Width) '設定する文字数を代入
        rng.ColumnWidth = mojisu '列幅を変換後の文字数で設定
    Next n
Next i

この変数ptが列ごとに変わってくれれば良いわけです。変数にはデータ型がありますが、バリアント型(Variant)を使えば「”配列”と呼ばれる複数のデータの集合体」を入れるための「複数の仕切りのある入れ物」のような変数を作れます

まず変数ptのデータ型をバリアント型に書き換えましょう。 ↓

' 変数の宣言
Dim rng As Range 'セルまたは列(データ型はオブジェクト型のRange)
Dim pt As Variant 'ポイント値(データ型はバリアント型のVariant
Dim mojisu As Single '変換後の文字数(データ型は単精度浮動小数点数型のSingle)
Dim i As Long '列番号(データ型は長整数型のLong)
Dim n As Long '3回繰り返し用のカウンター(データ型は長整数型)

そして変数ptの部分をこのように書き換えます。 ↓

For i = 1 To 9
    For n = 1 To 3
        Set rng = Columns(i) 'セルまたは列を設定
        pt = Array(5, 27.5, 303.5, 57, 42.5, 80, 80, 94, 5) 'ポイント値を配列で代入
        mojisu = pt(i - 1) * (rng.ColumnWidth / rng.Width) '設定する文字数を代入
        rng.ColumnWidth = mojisu '列幅を変換後の文字数で設定
    Next n
Next i

バリアント型の変数ptに「Array関数」を使って複数の数字を格納しています。この代入方法は便利ですので覚えておいたほうがいいと思います。

「Array関数」のカッコ内にはカンマ( , )で区切った9つの数字をいれました。この数字はA列からI列に代入したいポイント値です。A列:5pt、B列:27.5pt、C列:303.5pt、D列:57pt、E列:42.5pt、F列:80pt、G列:80pt、H列:94pt、I列:5pt となっています。

バリアント型の変数に”配列”を代入し、中の数字を1個ずつ取り出したい場合は変数の後にカッコをつけて格納された番号を指定します。 この格納番号はゼロから始まります

pt = Array(5, 27.5, 303.5, 57, 42.5, 80, 80, 94, 5)

と代入した場合は下記のように格納番号がついています。↓

pt(0) = 5
pt(1) = 27.5
pt(2) = 303.5
pt(3) = 57
pt(4) = 42.5
pt(5) = 80
pt(6) = 80
pt(7) = 94
pt(8) = 5

これを見ると この赤文字部分の意味が判りますね。↓

mojisu = pt(i - 1) * (rng.ColumnWidth / rng.Width) '設定する文字数を代入

変数 i がA列(列番号1)のときは格納番号0を取り出し、B列(列番号2)のときは格納番号1を取り出すように指定しているのです。

さあ、纏めて書くとこうなります。
変数ptに配列を代入する部分はFor~Next構文の中から外に出しておきましょう。↓

列幅を配列を使って変更する1600×900

「列幅を配列を使って変更する」のSubプロシージャ内にカーソルを置いてからキーボードの「F5キー」または「Sub/ユーザフォームの実行」ボタンを1回押して実行してみてください。記入間違いがなければA列からI列までの列幅がそれぞれ指定の幅になったはずです。 

列幅変更はこれでOKです。長くなったので休憩にしましょう。

タイトルとURLをコピーしました