- ベストアンサー
選択したセルに罫線を引くマクロ
お世話になっております。 業務上必要になり(効率化が図れるので)選択したセルにバツの罫線を引くマクロを作成しています。 まだまだ自分のレベルが低いので、マクロ記録を参考に、下記のようなマクロを作りました。 Sub バツ罫線マクロ() ActiveCell.Select With Selection.Borders(xlDiagonalDown) .LineStyle = xlContinuous .Weight = xlHairline .ColorIndex = xlAutomatic End With With Selection.Borders(xlDiagonalUp) .LineStyle = xlContinuous .Weight = xlHairline .ColorIndex = xlAutomatic End With End Sub 試してみると、選択したセルに対してバツの罫線が引かれました。 やった!と思ったのもつかの間、Ctrlキーでセルを複数選択してマクロを実行すると最後にアクティブにしたセルしか罫線が引かれないではありませんか・・・。 ネットなどで調べてみると、Ctrlキーで複数選択してもアクティブセルというのはそのうちの一つだけというような記述がありました・・・。 そして、ここで行き詰ってしまいました。 お伺いしたいのは2つあります。 ・どうすればCtrlキーで選択した全てのセルにこの罫線を引くマクロを適用させる事が出来ますか? ・変数などを用いたもっとレベルの高いコードの書き方だと、どのように記述されますか?後学のためにレベルの高い人の記述方法と比較させてもらって勉強させてもらいたいと思っています。 よろしくお願いします。
- みんなの回答 (15)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
baritsuさんのコードをいくつか修正してみました。For Each ステートメントを使うのが、VBらしいソースかと思います。 複数のセルを選択した後にマクロを実行することが前提のソースです。特に細かいエラーチェックはしていませんので、ご了承ください。 ----------------------------------------------- Sub バツ罫線マクロ() For Each OneCell In Selection With OneCell.Borders(xlDiagonalDown) .LineStyle = xlContinuous .Weight = xlHairline .ColorIndex = xlAutomatic End With With OneCell.Borders(xlDiagonalUp) .LineStyle = xlContinuous .Weight = xlHairline .ColorIndex = xlAutomatic End With Next End Sub
その他の回答 (14)
- Wendy02
- ベストアンサー率57% (3570/6232)
naktak様、Wendy02です。どうも、私のつまらない質問に早速返事していただいて、ありがとうございました。 >> 「いや、そうではない。標準モジュールはあまり使うな」という話も聞いています。>では、一体、何の目的だろうかっていうのが、私の疑問の核心です。 > >これは、多分VBが出た当初に問題になっていた事を >完全鵜呑みにしている方がおっしゃっているのでしょう。 この言った人物の名前は出したくはないのですが、ネットでも頻繁に書いている方でして、VBAのまさしく頂点にいる人の発言で、ちょっと、なかなか、見過ごすわけにはいかないわけです。その人が言うのは、「あなたの感覚で、その意味を探れ」だそうです。(^^; 結局、私としては、いくら、今のことを続けても分らないから、C言語でも勉強するしかないのかなっていう所に落ち着くわけなんです。その前に、勉強することは山ほどあるけれども、Officeは、上に行けば行くほど、対ビジネス用になって、IISだのODBCだの、会社で、その手の仕事をExcelでしている人たちのものなのですね。 これは、クラスとかは、もっと根本的なことなんですね。スクリプト型のVBAで、そこまでしていくのかなっていうチュウチョもないわけではありません。 >省略すると自動的にPublicと判断されるだけです。 >変数宣言だと勝手にVariantと判断されるのと一緒では? >私は、PublicなのかPrivateなのかFriendなのか、 >全て明示的に記述します。 Friend とかPrivate とか、Public というのは、クラスの中の宣言ですよね。それは、私も省略などしませんね。それは、一見、働きは同じでも、含む意味がかなり違いますからね。でも、変数のほうはスコープの違いになりますね。私は、あくまで「VBA」の中だけの話で、「VB」では、話が違います。「VB」では、標準モジュールのPublicステートメントをつけたプロシージャと、そうでないスコープは、変わりますからね。 baritsu様へ、スレッドを汚してすみませんです。
お礼
皆様回答ありがとうございました。 お礼を書いた後にポイントをつける段になって本当に誰につけたらよいのか判断がつかなくなってしまいました。自分の未熟さと、皆様からそれぞれ教えていただいたことがあるという点とを考えますと、優劣がつけられなくなったのです。 やむを得ず、大変失礼かもしれませんがご回答くださった方のHNであみだクジを作りましてお2人にポイントをつけさせて頂きました。 ありがとうございました。 >baritsu様へ、スレッドを汚してすみませんです。 汚したなどとは思っていないです。私自身も「何となくこういう事かな?」なんて、出てくる用語を検索しながら見させて頂きました。
- KenKen_SP
- ベストアンサー率62% (785/1258)
すみません。#13 の If C1 Is Nothing Then は、 If C2 Is Nothing Then の間違いです。コード全体を再アップしておきます。 Sub Sample2() Dim C1 As Range Dim C2 As Range For Each C1 In Selection.Areas If C2 Is Nothing Then Set C2 = C1 Else Set C2 = Union(C2, C1) End If Next C1 Application.ScreenUpdating = False For i = 5 To 6 With C2.Borders(i) .LineStyle = xlContinuous .Weight = xlHairline .ColorIndex = 1 End With Next i Set C2 = Nothing End Sub
- KenKen_SP
- ベストアンサー率62% (785/1258)
#5 です。 > 速度の違いとか明確になるかもしれませんね。 ただ、、、最近の PC は非常に高速ですから、今回の内容ではどの ような書き方をしても体感できるほどの差はでないと思いますが、 「勉強のため..」とありましたので、、、 今回の内容で、速度速度に差がでるとしたら次の点です。 1. For Each オブジェクト変数 in Selection ループの度に選択範囲内のセルがひとつオブジェクト変数に セットされます。つまり、1,000個のセルが選択されていれば、 1,000回ループします。セル毎に異なる処理が必要な場合、有効 な方法です。 2. For Each オブジェクト変数 in Selection.Areas ループの度にひとつの選択範囲ブロックがオブジェクト変数に セットされます。例えば、A1:A10 B10:C20 E1:K50 の3つの範囲 が選択されているなら、ループは3回です。 つまり、Excel の罫線描写速度は非常に低速ですから、その実行数 が少なければ少ないほど速いことになります。罫線描写の繰り返し 処理数が 1,000回 か 3回 というところの差ですね。 まとめて処理できる内容であれば、命令の実行回数が少ない方が 高速なのです。 したがって、#4 yambejp さんの Union を使う方法は、複数の選択 範囲を Union でひとつの「かたまり」として、罫線描写の命令を 1回実行するだけですから、高速だと思います。 しかし、ループ処理の中で Union を使った場合には Union が実行 される度にオブジェクト変数の内容がメモリの別の場所にコピーさ れるので、処理効率は悪いと思います。 それならば、Union の部分を下記のようにすれば、Union の実行 回数を最少限に抑えることができると思います。 Dim C1 as Range Dim C2 as Range For Each C1 In Selection.Areas If C1 Is Nothing Then Set C2 = C1 Else Set C2 = Union(C2, C1) End If Next C1 こうして、ひとかたまりとなった範囲 C2 に対して罫線描写の 命令を1回だけ実行する、、というのが最速かもしれません。 VBA に限らずプログラムの処理速度を考える場合、できるだけ最少 限の命令回数となるようにロジックを考えると良いと思います。 ご参考までに。
お礼
度々すいません。 私の独白のようなものにまで丁寧に答えていただいてありがとうございます。 >VBA に限らずプログラムの処理速度を考える場合、できるだけ最少 >限の命令回数となるようにロジックを考えると良いと思います。 肝に銘じます。
- めとろいと(@naktak)
- ベストアンサー率36% (785/2139)
度々すみません。返答、少なかったのですね^^; > 私は、概ね、Office VBAでは、クラスは、イベントやカプセル化程度だと思っています。私は、それ以上の使い道 は、あまり一般的にはないように感じています。 処理の共通化という点でもクラスは利用しますよ。 今回は全て引数で渡していましたが、 あれ(他の情報も)をプロパティにして、セルプロパティ関係のクラス、というのを 作成しても良いかと思います。 (フォント関係、書式関係、罫線関係など) 今回のコーディングだけですと、本当に無意味なクラスです。 > 「いや、そうではない。標準モジュールはあまり使うな」という話も聞いています。では、一体、何の目的だろうかっていうのが、私の疑問の核心です。 これは、多分VBが出た当初に問題になっていた事を 完全鵜呑みにしている方がおっしゃっているのでしょう。 標準モジュールは、(変数も含め)どこからでも呼び出し可能なので、 処理の流れが掴みづらくなるという事からそう言ったのだと思います。 でもそれがVBの特性ですので、それを全否定する方は VC++やJavaなどだけで開発されればと思います。 「あまり使うな」であり、「絶対使うな」とは言ってませんので、 変数や関数の利用目的に合わせれば良いのではないでしょうか。 > それから、VBAでは標準モジュールでは、すでに、共有化されていますから、Public ステートメントはつけない、ということになっていますが、必要なのでしょうか?VBAが不便なのは、プロシージャに、Public ステートメントをつけても、グローバル化しないのです。 省略すると自動的にPublicと判断されるだけです。 変数宣言だと勝手にVariantと判断されるのと一緒では? 私は、PublicなのかPrivateなのかFriendなのか、 全て明示的に記述します。 Publicの時だけ記述しないというのはちょっとバランス悪いです。 変数も、Option Explicitを記述しなければ変数宣言が不要です。 それらを明示的に宣言する事で、第三者がプログラムを 見た際により分かり易く理解出来ると考えているからです。 まぁ、変数宣言ナシや変数型宣言ナシは問題外でしょうけど(スピード落ちるの間違いナシ)。
お礼
紳士的に回答いただき、ありがとうございます。
- めとろいと(@naktak)
- ベストアンサー率36% (785/2139)
> Public Sub gSubPrintLine() > Dim pObjLine As clsLine > ↑としてしまうと、いくらクラス・オブジェクトを変数にしても、ローカルで宣言したら、そのプロシージャだけのものになっているはずですね 確かにこの書き方はあんまり意味ありません(笑) というより必要性がありません。 プロシージャ内で宣言しているのは、 コーディングが少ない為、プロシージャ内でしか利用しない為です。 ただ、今回は罫線のみ(しかも全て同じ罫線)を引くコーディングが知りたかったようですが、 今後、膨大なコーディングを行っていく上で、 クラスを使う方法もありますよ、という事を伝えたかったのです。 質問にそぐわない回答でしたね・・・。 失礼しました。
- Wendy02
- ベストアンサー率57% (3570/6232)
こんにちは。 ちょっと、ご質問主さんのスレッドをお借りして、お聞きしたいことがあります。 ご質問主のbaritsu様には、ちょっと、話がシンドイかもしれませんが、こういう話もあるということで、お許しください。 naktak 様 #8のコードを見ていて、私には少しわからない点がありますね。 Public Sub gSubPrintLine() Dim pObjLine As clsLine ↑としてしまうと、いくらクラス・オブジェクトを変数にしても、ローカルで宣言したら、そのプロシージャだけのものになっているはずですね。Rangeオブジェクトとして、すでにあるものに対して、新たに、クラス・オブジェクトを作っても、一回きりだとすると、その間の生成によるロスタイムが、生きてこないのではないかなって思うのです。また、せめて、Excel.Application が存在している間は、インスタンスは生かしておいてあげないと、せっかく作っても、もったいないような気がするのですが。 現状のコードでは、サブルーチン・プロシージャかユーザー定義関数程度(Excelのサブルーチンでは、そういう使い方は、あまりしませんが。)でよいかと思います。 私は、概ね、Office VBAでは、クラスは、イベントやカプセル化程度だと思っています。私は、それ以上の使い道は、あまり一般的にはないように感じています。「いや、そうではない。標準モジュールはあまり使うな」という話も聞いています。では、一体、何の目的だろうかっていうのが、私の疑問の核心です。 それから、VBAでは標準モジュールでは、すでに、共有化されていますから、Public ステートメントはつけない、ということになっていますが、必要なのでしょうか?VBAが不便なのは、プロシージャに、Public ステートメントをつけても、グローバル化しないのです。 私は、VBAは、まだまだ勉強中なので、分らないことが一杯あります。よかったらご指摘ください。 余計な書き込みでしたら、すみません。
補足
確かに今のレベルでは内容的にはきついですが、後学のためと思って横から見守らせていただきます(naktak様は返答くださるでしょうか?)。
- taocat
- ベストアンサー率61% (191/310)
こんばんは。 回答は出尽くした感がありますが、勉強のためということなので・・・・。 --------------------------------------------- Sub Test() Dim R As Long For R = 1 To Selection.Areas.Count With Selection.Areas(R) With .Borders(xlDiagonalDown) .LineStyle = xlContinuous .Weight = xlHairline .ColorIndex = xlAutomatic End With With .Borders(xlDiagonalUp) .LineStyle = xlContinuous .Weight = xlHairline .ColorIndex = xlAutomatic End With End With Next R End Sub ---------------------------------------------- 以上です。
お礼
これは・・・。For~Nextステートメントという奴でしょうか。 今いただいたコードを実際に使用してみているところです。 それが終わったら順番にどういう意味があるのか比べていこうと考えています。 回答ありがとうございました。
- めとろいと(@naktak)
- ベストアンサー率36% (785/2139)
クラスを利用すればもっと汎用的に対応も出来そうですね。 【標準モジュール basLine】 Public Sub gSubPrintLine() Dim pObjLine As clsLine Dim pObjRange As Range 'Excel画面の再描画を停止(速度向上) Application.ScreenUpdating = False 'clsLineインスタンスの生成 Set pObjLine = New clsLine '選択されているセル全体に対して線を引く For Each pObjRange In Selection.Areas Call pObjLine.gSubPrintLine(pObjRange.Borders(XlBordersIndex.xlDiagonalDown), _ XlLineStyle.xlContinuous, XlBorderWeight.xlHairline, _ Excel.Constants.xlAutomatic) Call pObjLine.gSubPrintLine(pObjRange.Borders(XlBordersIndex.xlDiagonalUp), _ XlLineStyle.xlContinuous, XlBorderWeight.xlHairline, _ Excel.Constants.xlAutomatic) Next 'pObjLineにセットされているインスタンスを開放 Set pObjLine = Nothing 'Excel画面再描画を開始 Application.ScreenUpdating = True End Sub 【クラスモジュール clsLine】 '線を引く Public Sub gSubPrintLine(ByRef vObjCell As Border, ByVal vLngLineStyle As Long, _ ByVal vLngWeight As Long, ByVal vLngColorIndex As Long) With vObjCell .LineStyle = vLngLineStyle .Weight = vLngWeight .ColorIndex = vLngColorIndex End With End Sub メンバを分かり易く記述したせいで、 逆に物凄く仰々しいコーディングになってしまっています(笑)
お礼
回答ありがとうございます。 クラスモジュール?と思いながら、標準モジュールとクラスモジュールにコードをコピーして実行してみたら 「コンパイルエラー ユーザー定義型は定義されていません」と出まして、OKを押すと Public Sub gSubPrintLine() の行が黄色くなります。 これはどうすればいいのでしょうか?
- Wendy02
- ベストアンサー率57% (3570/6232)
baritsu 様 こんばんは。Wendy02です。 私は、本当に人に教える段階ではないのですが、自分の勉強の進度を計る材料として、 日本VBA協会 http://www.vbaa.jp/vbae/level.htm に書いてあるレベルは、何を勉強していくのか目安になります。 多少、そのサイトにも出てきますが、オートメーションというのは、オートメーション・オブジェクトを作ることで、私が書いたのは、Visual Basic から、Excelを動かすときに、結構、見たことのないエラーが出てきます。VRam とは、Excelは、ワークシート上のオブジェクトと数値や文字列を現す一種のレイアーになっているでしょう?その時、どうしても、VRam あたりで、問題が発生することがあるのです。(確信しているわけではありませんが) >どの記述がベスト、というものはあるものなんでしょうか。まずは美しいコードでなくてもやってみる事だと思っているのですが・・・。 最初は、失敗して覚えるのだと思います。語学と同じです。ここはへんだなって思ったら、ちゃんと確認して自己修正すればよいと思います。VBAは、この先を考えると、どうしても悲観的に考えてしまいますけれども。最終的には、VBAでも、C言語の知識が必要になってくるのですね。 それから、私の持論なのですが、マクロを使う目的意識を持たないほうが上達するようですね。どうしても、目的を達成すると学習意欲が下がってしまいます。
お礼
度々ありがとうございます。 また、サイトの紹介ありがとうございます。 元々は業務を少人数で進めるためにやむを得ずというか前向きにこういったものを覚えていくべきだろうと考えていましたが、紹介いただいた先のページのように資格取得というものを目標に入れるのもいいかもしれません。相当奥が深そうなので、達成による意欲の低下は考えなくても当分良さそうです。
- banker_U
- ベストアンサー率21% (17/78)
こんばんは 天邪鬼なんでひねくれた答えですいませんが、こういう方法もあります。 要するにこの目的を達成するのにいちいちマクロ使いますか?ということです。 Excelのバージョンにもよりますが、ツールバーに斜め罫線を左上がり、右上がりとも追加しておいて、セルを選択してからそれを順次2つとも押す。 ちなみにご存知かと思いますが、ツールバーにボタンを追加するには、 ・ツールバーの開いているところを右クリック-「ユーザー選択」 ・ダイアログが出てきますので、「コマンド」タブを選択し、分類は「書式」を選ぶと下のほうにいろいろな罫線のボタンが出てくるので、斜め罫線をツールバーの任意の場所にドロップ です。
お礼
回答ありがとうございます。 ご指摘の通りとは思いますが、2つの点でマクロを作った方が良いと判断しました。 1つ目は、VBAとかマクロの勉強になるからという理由です。もちろん何でもかんでもマクロにすればいいってものではないという事も学習せねばなりませんが・・・。 その意味では回答者様に指摘いただいたことは今後気をつけていこうと思います。 2つ目は実際に行う場合の業務効率の問題です。 Excelのシートを上から下にどんどんスクロールさせて該当箇所を指定してバツ罫線を入れていく作業を考えると、 ・ボタンのある所までマウスを動かし ・2つもボタンを押す というのは、マクロをショートカットキー登録して作業する事に比較するといかにも業務効率が落ちると考えます。 以上の2点から、マクロを使った方法を模索し、(えらく初歩的な段階で)行き詰まり、こうして質問した次第です。説明不足でした。
- 1
- 2
お礼
素早い回答ありがとうございます。 やってみたら「変数の定義が・・・」とエラーがと出ましたので他の人の作ったコードを見よう見まねでOneCellを定義しましたら、何度かの失敗の後、うまく動きました。 マクロとかVBAとか使い慣れない人間からするとちょっとした感動を覚えますね。 自分のものと、教えてもらったコードの違いはこれから調べてみます。 ありがとうございました。