VBA編其ノ6 罫線を引いてみる
今日のテーマは、差し当たり「罫線を引く」です。
ですがそれは、あくまでも表向きのハナシ。
本当のところ伝えたいのは、「変数の使い方」です。
変数、前回(其ノ5で)登場しましたね。
本日は、表に罫線を引く作業を通して、変数の使い方に慣れていってもらおうと思っています。
でも、その前に。
無限ループ
前回、ループ処理を扱いましたね。
その際、ひとつ気を付けてほしいのが、無限ループってヤツです。
無限ループ…、字面からなんとなく想像はつくと思います、が、とりあえず下↓のコードを見てください※1。
あ!
せっかちな人のために言っておきますが、この↓マクロはダメマクロなので、止まりません。
止めるには緊急脱出を使いますので注意(緊急脱出の仕方は下記参照)。
Dim i As Integer
i = 1
Do Until i = 3
Cells(1, i).Select
i = i + 1
Cells(1, i).Select
i = i - 1
Loop
さて、動かす前に、ちょっと立ち止まって考えてみましょう。
このマクロ、i が 3 になったら止まる仕様になっています。
で、i は 1 からスタート。
最初の「i = i + 1」で i は 2 になるのですが、次の「i = i - 1」のところで i は 1 に戻っちゃうんですよ。
と、いうことは…、i は永遠に 3 にならない…。
なので、このマクロ、止まりません。
動かした際は、Escキーで無理矢理ストップさせましょう※2 ※3。
マクロ実行中にEscキーを押すと上↑のアラートが出るので、そこで「終了」を選べばマクロから脱出できます。
…このマクロ、そもそも無意味なマクロ(A1セルとB1セルを往復するだけ)なのであまり参考にならないのですが、無限ループがどんなものかはわかったと思います。
無限ループって、Excelゲーム作成の時なんかだと使うこともあるみたいですけど、仕事でマクロ使う分には絶対避けたいところです。
なので、ループ処理を組むときには、こうならないよう気をつけましょう。
基本的には、処理の終わり(Do Until~の「Until~」のところ)をきちんと設定してあげれば、避けられるはずなので。
以上、注意喚起でした。
罫線を引く
ハイ、では。罫線を引く話に。
まず、お手数ですが、サンプルとなる表を作ってほしいんですよ。
下↓みたいな※4。
これからマクロで罫線を描くので、当然罫線はナシですよ。
で、このサンプル表の作成場所なんですけど…、いつもマクロを書いているブック(「マクロ練習.xls」)のシート1に作っても良いのですが、今回は、別で新たなブックを作ってその中に作りましょうか※5。
そうすれば、「マクロなしExcelでマクロを動かす」練習にもなりますしね。
では、マクロの中身の話に。
まず、ちょっと想像してみましょう。
「この表に罫線を引く」マクロって、どんなイメージでしょうか?
コードを見る前に少し考えてみてください。
…もちろん、「罫線を引く」という命令をまだ紹介していないので、そこはわからない。
だけど…、この表には範囲があって、そこにに罫線を引くわけだから、Rangeを使いそうだな、というような予測が立てられるような気がします。
つまり、「Range(Cells(1,1),Cells(6,4))」が目的語になるだろう、と。
だからあとは、「罫線を引く」という部分の書き方が判明すれば…、イケそうですよね※6。
なので、ためしに、1コのセルだけに罫線を引いてみましょう。
マクロを書くのは「マクロ練習.xls」の方に、ですよ。
こんな感じ↓になります※7。
With Cells(8, 3)
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
End With
たかが罫線引くだけなのに、コード長いなー。
…これね、4行あって、「Top」「Left」「Right」「Bottom」とあることからもわかるとおり、上下左右それぞれに罫線を引く、という命令を1コ1コ与えてるんですよ。
だから、こんなんなってしまうワケで…。
あ、そうそう。「.LineStyle = xlContinuous」の「xlContinuous」は、実線(破線じゃない、1本のちゃんとした直線)のことね。
「continuous」は「連続的」とか、そんな意味。
破線を入れたいときは、「xlContinuous」のところを「xlDash」「xlDot」「xlDashDot」などにしてみてください。
破線にはいくつか種類があるので、それにともなってLineStyleの値もいろいろあるんですよね。
では、動かしてみましょう。
サンプル表のExcelと、マクロの入っている「マクロ練習.xls」の2つを両方開いてください※8。
そして、サンプル表のExcelの方(これから罫線を入れたい側)をアクティブにします。
で、サンプル表Excelの方で「開発」→「マクロ」を見ると…、さっき作ったマクロがいますよね※9。
あとは、コイツを動かしてやればOK。 こうなります※10。
お。罫線が引けました。
で、あれば、「Cells(8, 3)」のところを「Range~」にしてやれば…※11 ※12。
あれ?
格子状にならないや…。
…大丈夫です。
考え方は間違っていないです。
ですが、範囲を格子状にするためには、4行じゃ足りないんですよ。
あと2行、インサイドに線を引く命令を追加してやらないといけない。
なので、下記↓のように手直ししてあげてください、お手数ですが※13。
With Range(Cells(1, 1), Cells(6, 4))
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
.Borders(xlInsideHorizontal).LineStyle = xlContinuous
End With
edgeは「端っこ」、insideは「内側」って意味ですもんね。
さっきは、insideに対する命令がなかったもんだから、内側に罫線が引かれなかったんですね。
ちなみに、verticalは「垂直方向」、horizontalは「水平方向」です。
僕の場合だと、verticalは「グラディウスⅢ」、horizontalはホライゾン(『ダッシュ!四駆郎』)のおかげで覚えられました。
では、さっき引いた罫線を消した上で、このマクロを動かしてみましょう※14。
罫線引けました。
…でもやっぱり、6行書くのはダルいですよね…。
上下左右別々に罫線を引ける、というのはそれはそれで便利な時もあると思いますが、
まとめて引きたいときにはめんどくさく感じると思います。
そういうときは、下↓の省略形、
Range(Cells(1, 1), Cells(6, 4)).Borders.LineStyle = xlContinuous
でもOKです。 この1行で、さきほどと同じ効果が現れます※15。
なので、ここから先はコイツを使います。 で、ここまでが実は話の前段。
行数が変わったときの対応
さて。ではここで、今引いた罫線を一度消して、1行レコードを追加してみましょうか※16。ためしに。
たった1行追加しただけで、さっきのマクロが役に立たないことは、もうおわかりですよね※17。
たとえレコードが増減しても、表の範囲に合わせて罫線を引いてくれると助かるんですが…、では、どうしたらよいでしょうか。
・
・
ひとつは、下↓のマクロを1行書いて、で、自分で範囲を選択するやり方※18。
Selection.Borders.LineStyle = xlContinuous
こうすると、あらかじめ選択した範囲に、線を引くことができます※19 ※20。
「Selection」は「選択範囲」ぐらいの意味で、目的語として使えます。
…でも、このやり方だと、手作業で罫線引くのとほとんど変わらないんですよね。
もちろん、「Selection」は、これはこれで便利なので、頭の片隅に置いといてください。
で、実は、今日の本命はコチラ↓。 表の最終行を判断して罫線を引いてくれます※21。
Dim i As Integer
i = Cells(Rows.Count, 1).End(xlUp).Row
Range(Cells(1, 1), Cells(i, 4)).Borders.LineStyle = xlContinuous
もう1行追加したとしても、対応してくれます※22。
ハイ、では、解説。
罫線を引くときには範囲を指定してやるんですけど、Rangeを使うには左上のセルと右下のセルを入れてやらないといけない。
で、今回のケースだと、左上は(1, 1)って決まってる…って、僕は自分で表を作るときはきっちり左上から始めることにしているんだけど、人によっては(2, 2)から始める人もいて、何でよけいなアキを作るのか僕には理由がよくわからないんだけど、まあ、とにかく今回は(1, 1)から始まる、と。
で、あとは、右下のセルがどこにあるのかがわかれば、罫線を引くことができますよね。
だけど、この一番右下、ってのが、不確定要素なワケですよ。
表の行数の増減があるので。
差し当たり、一番右の列数は「4」固定を想定しているので、右下セルの列番号は「4」。
あとわからないのは一番右下のセルの行番号ですね。
なので、そこを変数 i とします※23。
変数の宣言(其ノ5参照)も忘れずに。
あとは、変数 i の中身ですね。
まず、Cells(Rows.Count, 1)の部分から見ていきましょう。
実はここは、ふつうのセル位置指定、Cells(1, 1)とかCells(6, 4)とかと同じです。
ただ、行番号が「Rows.Count」になっているだけで。
んで、「Rows.Count」の「Count」は「数」って意味ね。
で、「Rows」っていうのは「すべての行」の意味。
「Row」は英語で「行」という意味で、
VBAだと「Rows」はふつう、Rows(3)とかRows(5)のように、数を指定してやることで「3行目」「5行目」を指すワードになるんだけど、()かっこに何も指定しない「Rows」だと、「すべての行」の意味になります。
すべての行っていうのは、「Excelが限界まで使用できるすべての行」のことで、Excel2003だと65536行、2007以降だと1048576行、だっけかな?
そこまですべて、ということになります。
()かっこを省略すると「すべて」になる、というのはCellsも(そして、Columnsも)同じで、いつもCells(4, 2)とか使っているコレの()かっこを付けずに「Cells」とすると、「すべてのセル」を指します。
なので、「Rows.Count」だと「すべての行の数」の数値をもってきてくれます。 だから、Cells(Rows.Count, 1)は、Cells(65536, 1)(ないし、Cells(1048576, 1))と同じことになります。 これはつまり、こういう↓ことね※24。
ここまではオケイ?
で、次の.End(xlUp)は、ctrl + ↑[上キー]と似たようなものだと思ってください。
つまり、情報が入っているセルにぶつかるまで上に進み、ぶつかるとそこで止まる、という感じです。
さっきのExcel最下段からctrl + ↑[上キー]を押すと、ココ、つまりテーブルの一番下に辿り着きますよね※25。
そして、最後の「Row」は行番号を返すワードです。
なので、Cells(Rows.Count, 1).End(xlUp)で辿り着いた先のセルの行番号、下画面で言うと「8」が、返されます※26。
それが、変数 i に格納されるんですね。
「Row」と「Rows」は別モノなので注意。 「Rows」の方は「行」という範囲を指すのに対して、今使った「Row」(sなし)の方は、「行番号」という数値(1とか2とか…)を返します、…と、一応は説明してみましたが、この辺りはおいおい慣れていってもらうとして。 ていうか、もうね、決まり文句として「Cells(Rows.Count, 1).End(xlUp).Row」覚えてください。
…けどね、一点注意しておくと、「Cells(Rows.Count, 1).End(xlUp).Row」は上述のような軌道で動いているので、こんなふう↓に途中にひっかかりがあると…、※27
こんなふうに↓なっちゃう※28。
このような弱点はありますが、これは表の組み方を気を付けていれば、またCells(Rows.Count, 1).End(xlUp).Rowの挙動を理解していれば防げると思います。 Cells(Rows.Count, 1).End(xlUp).Rowは使えるので、 この機会に覚えてください。
あとね、もう1点。
Cells(Rows.Count, 1).End(xlUp).Rowの列番号は、何で「1」なんだろう?
範囲の右下のセルを見に行くのだから、Cells(Rows.Count, 4).End(xlUp).Rowでもよいのでは…※29。
お答えしますと、別に「4」でも良いんですよ、4列目が空白なくみっちり埋まっている、ということがわかっていれば。
今回のサンプル表だと、4列目には「1」か「0」が必ず埋まっているみたいなので、問題はなさそうです。
しかし…。仮に、「4」でマクロを組んでみましょう※30。
それでね、もし仮に、4列目がアキのある列だったら…。
ためしに、サンプル表のデータを下↓のように変更して、今のマクロを動かしてみてください※31 ※32。
End(xlUp)法は、上述のような挙動をするため、空白セルがところどころ存在するような列に対しては使えないんですよ。
だから、確実にデータがおしりまで埋まっている列に対して使いたい。
それでね、一番左の列だったら、きっちり埋まっているだろう、と…。
…え?そんなの確実かどうかわからない、って?
たしかにそうですね。
ただ、自分の場合は(あくまで僕個人の話なんですけど)、
・表は必ず左上[セル(1, 1)]から始める
・一番左の列と一番上の行[ヘッダー行]は必ずきっちり埋める
をマイルールにしていますので…※33。
てゆーか、何で表を(2, 2)から始めたり、最左列にところどころアキがあったり、ヘッダー行がちゃんとしてないデータを作るんだ?
フィルタかけるときとか、めんどくさくないのかな…。
愚痴っちゃいました。
スミマセン。
というわけで、End(xlUp)法は、各人の表の作り方を踏まえたうえで、アキのない列に対して使用するようにしてください。
以上、行数の増減に対応する方法の解説終わり。
列数の可変にも対応する
ここまで来たら、列数の増減にも対応したいですよね。 列数の変化に対応するには、変数をもう1コ増やして、こんなふう↓にします※34。
Dim i As Integer
Dim j As Integer
i = Cells(Rows.Count, 1).End(xlUp).Row
j = Cells(1, Columns.Count).End(xlToLeft).Column
Range(Cells(1, 1), Cells(i, j)).Borders.LineStyle = xlContinuous
変数 j が増えましたが、考え方はさっきのEnd(xlUp)法と同じです。
ただ今度は、いったん一番右の列に行って、左に戻ってくる、というだけで。
これで、たとえ列数が増えても※35、対応できます※36。
いかがでしたでしょうか。
変数は、よくわからないもの、まだ情報が固まっていないもの、可変する可能性のあるものに対して使う、
ってことが、なんとなくわかっていただけましたかね。
あ、まだ「なんとなく」で良いですよ。徐々に、慣れていっていただければ。