プロが教える店舗&オフィスのセキュリティ対策術

お世話になっております。

業務上必要になり(効率化が図れるので)選択したセルにバツの罫線を引くマクロを作成しています。
まだまだ自分のレベルが低いので、マクロ記録を参考に、下記のようなマクロを作りました。

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キーで選択した全てのセルにこの罫線を引くマクロを適用させる事が出来ますか?

・変数などを用いたもっとレベルの高いコードの書き方だと、どのように記述されますか?後学のためにレベルの高い人の記述方法と比較させてもらって勉強させてもらいたいと思っています。

よろしくお願いします。

A 回答 (15件中1~10件)

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
    • good
    • 0
この回答へのお礼

素早い回答ありがとうございます。

やってみたら「変数の定義が・・・」とエラーがと出ましたので他の人の作ったコードを見よう見まねでOneCellを定義しましたら、何度かの失敗の後、うまく動きました。
マクロとかVBAとか使い慣れない人間からするとちょっとした感動を覚えますね。

自分のものと、教えてもらったコードの違いはこれから調べてみます。
ありがとうございました。

お礼日時:2005/10/20 17:10

naktak様、Wendy02です。

どうも、私のつまらない質問に早速返事していただいて、ありがとうございました。

>> 「いや、そうではない。標準モジュールはあまり使うな」という話も聞いています。>では、一体、何の目的だろうかっていうのが、私の疑問の核心です。

>これは、多分VBが出た当初に問題になっていた事を
>完全鵜呑みにしている方がおっしゃっているのでしょう。

この言った人物の名前は出したくはないのですが、ネットでも頻繁に書いている方でして、VBAのまさしく頂点にいる人の発言で、ちょっと、なかなか、見過ごすわけにはいかないわけです。その人が言うのは、「あなたの感覚で、その意味を探れ」だそうです。(^^;

 結局、私としては、いくら、今のことを続けても分らないから、C言語でも勉強するしかないのかなっていう所に落ち着くわけなんです。その前に、勉強することは山ほどあるけれども、Officeは、上に行けば行くほど、対ビジネス用になって、IISだのODBCだの、会社で、その手の仕事をExcelでしている人たちのものなのですね。

これは、クラスとかは、もっと根本的なことなんですね。スクリプト型のVBAで、そこまでしていくのかなっていうチュウチョもないわけではありません。

>省略すると自動的にPublicと判断されるだけです。
>変数宣言だと勝手にVariantと判断されるのと一緒では?
>私は、PublicなのかPrivateなのかFriendなのか、
>全て明示的に記述します。

Friend とかPrivate とか、Public というのは、クラスの中の宣言ですよね。それは、私も省略などしませんね。それは、一見、働きは同じでも、含む意味がかなり違いますからね。でも、変数のほうはスコープの違いになりますね。私は、あくまで「VBA」の中だけの話で、「VB」では、話が違います。「VB」では、標準モジュールのPublicステートメントをつけたプロシージャと、そうでないスコープは、変わりますからね。

baritsu様へ、スレッドを汚してすみませんです。
    • good
    • 0
この回答へのお礼

皆様回答ありがとうございました。

お礼を書いた後にポイントをつける段になって本当に誰につけたらよいのか判断がつかなくなってしまいました。自分の未熟さと、皆様からそれぞれ教えていただいたことがあるという点とを考えますと、優劣がつけられなくなったのです。
やむを得ず、大変失礼かもしれませんがご回答くださった方のHNであみだクジを作りましてお2人にポイントをつけさせて頂きました。
ありがとうございました。

>baritsu様へ、スレッドを汚してすみませんです。

汚したなどとは思っていないです。私自身も「何となくこういう事かな?」なんて、出てくる用語を検索しながら見させて頂きました。

お礼日時:2005/10/25 19:36

すみません。

#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
    • good
    • 0

#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 に限らずプログラムの処理速度を考える場合、できるだけ最少
限の命令回数となるようにロジックを考えると良いと思います。

ご参考までに。
    • good
    • 1
この回答へのお礼

度々すいません。
私の独白のようなものにまで丁寧に答えていただいてありがとうございます。

>VBA に限らずプログラムの処理速度を考える場合、できるだけ最少
>限の命令回数となるようにロジックを考えると良いと思います。

肝に銘じます。

お礼日時:2005/10/25 19:30

度々すみません。

返答、少なかったのですね^^;

>  私は、概ね、Office VBAでは、クラスは、イベントやカプセル化程度だと思っています。私は、それ以上の使い道
は、あまり一般的にはないように感じています。

処理の共通化という点でもクラスは利用しますよ。
今回は全て引数で渡していましたが、
あれ(他の情報も)をプロパティにして、セルプロパティ関係のクラス、というのを
作成しても良いかと思います。
(フォント関係、書式関係、罫線関係など)
今回のコーディングだけですと、本当に無意味なクラスです。

> 「いや、そうではない。標準モジュールはあまり使うな」という話も聞いています。では、一体、何の目的だろうかっていうのが、私の疑問の核心です。

これは、多分VBが出た当初に問題になっていた事を
完全鵜呑みにしている方がおっしゃっているのでしょう。
標準モジュールは、(変数も含め)どこからでも呼び出し可能なので、
処理の流れが掴みづらくなるという事からそう言ったのだと思います。
でもそれがVBの特性ですので、それを全否定する方は
VC++やJavaなどだけで開発されればと思います。
「あまり使うな」であり、「絶対使うな」とは言ってませんので、
変数や関数の利用目的に合わせれば良いのではないでしょうか。

>  それから、VBAでは標準モジュールでは、すでに、共有化されていますから、Public ステートメントはつけない、ということになっていますが、必要なのでしょうか?VBAが不便なのは、プロシージャに、Public ステートメントをつけても、グローバル化しないのです。

省略すると自動的にPublicと判断されるだけです。
変数宣言だと勝手にVariantと判断されるのと一緒では?
私は、PublicなのかPrivateなのかFriendなのか、
全て明示的に記述します。
Publicの時だけ記述しないというのはちょっとバランス悪いです。
変数も、Option Explicitを記述しなければ変数宣言が不要です。
それらを明示的に宣言する事で、第三者がプログラムを
見た際により分かり易く理解出来ると考えているからです。
まぁ、変数宣言ナシや変数型宣言ナシは問題外でしょうけど(スピード落ちるの間違いナシ)。
    • good
    • 0
この回答へのお礼

紳士的に回答いただき、ありがとうございます。

お礼日時:2005/10/25 19:38

> Public Sub gSubPrintLine()


>   Dim pObjLine As clsLine
>   ↑としてしまうと、いくらクラス・オブジェクトを変数にしても、ローカルで宣言したら、そのプロシージャだけのものになっているはずですね

確かにこの書き方はあんまり意味ありません(笑)
というより必要性がありません。
プロシージャ内で宣言しているのは、
コーディングが少ない為、プロシージャ内でしか利用しない為です。

ただ、今回は罫線のみ(しかも全て同じ罫線)を引くコーディングが知りたかったようですが、
今後、膨大なコーディングを行っていく上で、
クラスを使う方法もありますよ、という事を伝えたかったのです。

質問にそぐわない回答でしたね・・・。
失礼しました。
    • good
    • 0

こんにちは。


ちょっと、ご質問主さんのスレッドをお借りして、お聞きしたいことがあります。

ご質問主のbaritsu様には、ちょっと、話がシンドイかもしれませんが、こういう話もあるということで、お許しください。

naktak 様
#8のコードを見ていて、私には少しわからない点がありますね。

Public Sub gSubPrintLine()
  Dim pObjLine As clsLine
  ↑としてしまうと、いくらクラス・オブジェクトを変数にしても、ローカルで宣言したら、そのプロシージャだけのものになっているはずですね。Rangeオブジェクトとして、すでにあるものに対して、新たに、クラス・オブジェクトを作っても、一回きりだとすると、その間の生成によるロスタイムが、生きてこないのではないかなって思うのです。また、せめて、Excel.Application が存在している間は、インスタンスは生かしておいてあげないと、せっかく作っても、もったいないような気がするのですが。

 現状のコードでは、サブルーチン・プロシージャかユーザー定義関数程度(Excelのサブルーチンでは、そういう使い方は、あまりしませんが。)でよいかと思います。

 私は、概ね、Office VBAでは、クラスは、イベントやカプセル化程度だと思っています。私は、それ以上の使い道は、あまり一般的にはないように感じています。「いや、そうではない。標準モジュールはあまり使うな」という話も聞いています。では、一体、何の目的だろうかっていうのが、私の疑問の核心です。

 それから、VBAでは標準モジュールでは、すでに、共有化されていますから、Public ステートメントはつけない、ということになっていますが、必要なのでしょうか?VBAが不便なのは、プロシージャに、Public ステートメントをつけても、グローバル化しないのです。

 私は、VBAは、まだまだ勉強中なので、分らないことが一杯あります。よかったらご指摘ください。

 余計な書き込みでしたら、すみません。

この回答への補足

確かに今のレベルでは内容的にはきついですが、後学のためと思って横から見守らせていただきます(naktak様は返答くださるでしょうか?)。

補足日時:2005/10/21 10:09
    • good
    • 0

こんばんは。


回答は出尽くした感がありますが、勉強のためということなので・・・・。

---------------------------------------------

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

----------------------------------------------

以上です。
    • good
    • 0
この回答へのお礼

これは・・・。For~Nextステートメントという奴でしょうか。
今いただいたコードを実際に使用してみているところです。
それが終わったら順番にどういう意味があるのか比べていこうと考えています。
回答ありがとうございました。

お礼日時:2005/10/24 16:00

クラスを利用すればもっと汎用的に対応も出来そうですね。



【標準モジュール 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

メンバを分かり易く記述したせいで、
逆に物凄く仰々しいコーディングになってしまっています(笑)
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
クラスモジュール?と思いながら、標準モジュールとクラスモジュールにコードをコピーして実行してみたら
「コンパイルエラー ユーザー定義型は定義されていません」と出まして、OKを押すと
Public Sub gSubPrintLine()
の行が黄色くなります。

これはどうすればいいのでしょうか?

お礼日時:2005/10/24 15:53

baritsu 様 こんばんは。

Wendy02です。

私は、本当に人に教える段階ではないのですが、自分の勉強の進度を計る材料として、

日本VBA協会
http://www.vbaa.jp/vbae/level.htm

に書いてあるレベルは、何を勉強していくのか目安になります。

多少、そのサイトにも出てきますが、オートメーションというのは、オートメーション・オブジェクトを作ることで、私が書いたのは、Visual Basic から、Excelを動かすときに、結構、見たことのないエラーが出てきます。VRam とは、Excelは、ワークシート上のオブジェクトと数値や文字列を現す一種のレイアーになっているでしょう?その時、どうしても、VRam あたりで、問題が発生することがあるのです。(確信しているわけではありませんが)

>どの記述がベスト、というものはあるものなんでしょうか。まずは美しいコードでなくてもやってみる事だと思っているのですが・・・。

最初は、失敗して覚えるのだと思います。語学と同じです。ここはへんだなって思ったら、ちゃんと確認して自己修正すればよいと思います。VBAは、この先を考えると、どうしても悲観的に考えてしまいますけれども。最終的には、VBAでも、C言語の知識が必要になってくるのですね。

それから、私の持論なのですが、マクロを使う目的意識を持たないほうが上達するようですね。どうしても、目的を達成すると学習意欲が下がってしまいます。
    • good
    • 0
この回答へのお礼

度々ありがとうございます。
また、サイトの紹介ありがとうございます。
元々は業務を少人数で進めるためにやむを得ずというか前向きにこういったものを覚えていくべきだろうと考えていましたが、紹介いただいた先のページのように資格取得というものを目標に入れるのもいいかもしれません。相当奥が深そうなので、達成による意欲の低下は考えなくても当分良さそうです。

お礼日時:2005/10/24 15:38

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!