一回も披露したことのない豆知識

VBAでマクロを組んでいたところ、問題が出てきたので質問させてください。
1.任意の列を全選択する(たとえばA列とC列という離れた列です)
2.その列の中でも、すべての行にではなく、数行にだけセル結合解除という処理を施す
というマクロを組もうとしています。

しかし、全選択した列の一部の行(画像参照)にだけ処理を施す、というのができません。
1列だけ全選択→セル結合解除、というのはできるのですが、複数の列(しかも列同士が隣り合っていない)に対して処理を施すというのがうまくいかず…。

以下のようにマクロを作成してみたのですが、どこが問題になってるのでしょうか?
アドバイスいただけると幸いです。

Sub test1()
 Dim intX_1 As Long
 Dim intX_2 As Long
 Dim rg1 As Range
 Dim rg2 As Range

 Set rg1 = Range(CStr(ActiveWindow.RangeSelection.Address))
 For Each rg2 In rg1
'選択した列のうち、2行目~最後のデータが存在する行まで処理を行う
intIX_1 = 2
While rg2(intIX_1) <> ""
rg2(intIX_1).MergeCells = False
    intIX_1 = intIX_1 + 1
If rg2(intIX_1) = "" Then
Exit For
End If
Wend
Next

End Sub

「VBAで、離れた複数の列に対して処理を施」の質問画像

A 回答 (6件)

個別の範囲なら処理できる、しかし複数の選択範囲を個別の範囲にバラす方法が分からない、というのが質問の核のようなので…。


Excel VBAのヘルプでRangeオブジェクトのプロパティを見ていくと、Areasというのがあります。
これでインデックスを指定して個別に参照できます。


Sub aaaa()

Dim i As Integer
Dim r As Range '列を参照する

For i = 1 To Selection.Areas.Count
Set r = Selection.Areas(i)

'列ごとの処理を実施
MsgBox r.Address & " -> " & r.Rows("3:5").Address

Next
End Sub
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。Areaを使うと複数の連続してない範囲についての処理ができるんですね。これを改造した結果、無事に目的のマクロを作成することができました。とても助かりました。ありがとうございました。

お礼日時:2011/05/04 21:07

ちょっと横からおじゃまさせていただきます。


オブジェクト変数を使わずに、たとえば
Range("$A:$A,$D:$E")
から、スマートに単独の列をとりだす方法は思いつきませんので、オブジェクト変数を用います。
Sub test1()
Dim targetRange As Range, myArea As Range, myColumn As Range
'一旦、オブジェクト変数に受けると、インテリセンスが効いて
'Rangeオブジェクトの様々なメンバが表示されるので、参考になります
Set targetRange = Selection
'Range("$A:$A,$D:$E")の様な場合に対応するため、下記が常道
For Each myArea In targetRange.Areas
For Each myColumn In myArea.Columns
Debug.Print myColumn.Address
Next myColumn
Next myArea
'下記でも結果は同じでした
' For Each myColumn In targetRange.Columns
' Debug.Print myColumn.Address
' Next myColumn
'しかし
'Debug.Print targetRange.Columns.Count
'は最初の群の列数1を戻し、総列数の3は戻しません
End Sub

さて、本題に戻って、

Sub test2()
Dim myColumn As Range

For Each myColumn In Selection.Columns
'一列に対する処理を記述
Next
End Sub

とすれば良いですが、ご質問の文中のロジックでは、一列に対する処理の方も動かないと思います。
intIX_1 = intIX_1 + 1
では、次の結合セルに移りません。次の行に行くだけです。
intIX_1 = intIX_1 + 当該結合セルの行数(Range(...).MergeArea.Rows.Count)
にしなければいけませんね。
(他にOffset(1,0)で移る方法もあります)

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

ご回答ありがとうございます。For Eachを使ってもやり様があるのですね。勉強になりました。
あと質問文にあるintIX_1 = intIX_1 + 1 は行変更のために使ってたものなのは間違いないですし、これだと選択した他の列に移動できないのも分かってました(なので離れた列にも処理を行うには?と質問を投げました)。それは大丈夫です。ただ「intIX_1 = intIX_1 + 当該結合セルの行数(Range(...).MergeArea.Rows.Count)」の部分はとても勉強になりました。ありがとうございました。

お礼日時:2011/05/04 22:04

大事な事忘れていました。



よく素人の方だと、バージョンをまったく無視して作る方が多いです。それで、何でできないのかと、よくここで質問されます。

何のバージョンのエクセルを対象にしているか、記載しましょう。もっともちゃんと理解しているなら、最初からバージョンの記載はあるはずですが

また、COMからのアクセスは、そのプラットフォームに依存するので、例えばコレクションや引数の指定などは、できない場合もあります。それはマイクロソフトのMSDNのサイトにテクニカル情報として、どうすればいいいか記載があります。

と言うことは、COMで使用している場合は、呼び出し元も記載しないと、明確にできるとかできないとか言い切れるものではありません。
    • good
    • 0
この回答へのお礼

No3とNo4の回答について、まとめてこっちでお礼をします。回答ありがとうございます。
書き方が悪かったので訂正します。Range("E:E","G:G").SelectをRange("E1:E5","G1:G5").Selectにするのは無理ですよね?と聞いたのは、実際試してみて駄目だったんで書きました。考え方を変えて、最初からE1:E5とG1:G5のセルを選択するようにしてみようと思いましたが、離れた「任意の」列の範囲取得は無理でした。エディターで最初からRange("E1:E5","G1:G5").Selectと書いて処理を行う列を指定しておけば1行目~5行目にだけ処理を施すというのはできましたが、「任意選択した列の1行目~5行目に処理を施す」となると、アドレスの取得方法が無かったので無理でした。探してみたけど駄目でした。

私自身試行錯誤を繰り返しました。試してないと言われるのは心外です。
釣りでもなんでもないんです。本当に詰まってしまったから質問したんです。自分の知識だけでは解決が難しいと判断したから質問したんです。回答者様はただひたすら「調べろ。検証しろ。」とおっしゃっていますが、それはなんのためにおっしゃっているのでしょうか。調べて検証して、結局分からなくて質問をした自分にそれを言われても困ります。なんのために回答をくれているのかわかりません。ごめんなさい。

お礼日時:2011/05/04 17:11

偶然にもNO2の方と意見がいっちしてようで、びっくりしています。



言っておきますが、No2とNo1は関係ないので、そこんとこよろしく。

>それをRange("E1:E12,G1:G12,I1:I12").Selectに変換するなんて、たぶんできないですよね

それでいいんです。このような発想を、”机上の空論”というのです。実際にやってみましたか?

このようにできるのか、できないのかを実際にやってみて、試行錯誤するのが初心者です。

みんなやっています。そこで、いろんなやり方があるのだと理解が深まるのです。

開発は、まず理論武装します。その次に、それを実践するために、設計します。その設計段階で、理論と合わないところや、やり方ににつまります。それで、実際に、実験をしてみます。

その実験は、検証といって、ただやるのではなく、あらゆる場合も想定して、ケースを作るのです。例えば3つの物の組み合わせは、3X3=9通りが理論ですね。

実証するときは、例えば、トランプを用意して、実際に、組み合わせを並べます。これが実証です。

この事例は簡単な話なのでイメージできないと思いますが、このようにすると見えないものが見えてくるのが実証実験です。何も見えないのなら、才能が無いということで、あきらめてください。

あなたの場合、やりもしないで、ただ子供が口をあけてまっているみたいに、「できないですよね」。

別に質問者ができようと、できまいと、回答者には何の関係もありません。あ、そ。で終わりです。

金をもらっているわけでもないし、責任があるわけでもない。個人的に講習料をいただけるなら別ですが・・・

ちなみに、ちゃんとコードを分析していないですよね???

>たぶんできないですよね。

それはちゃんとマニュアルみましたか? エクセルに付属しているヘルプにリファレンスがあるので、そこを見れば、何が引数になるか、書式がでています。見ていないことがばればれですよね。

さらにいえば、このコードのポイントは、セレクトして、アクティブです。それでアクティブになったセレクションイオブジェクトになるわけです。

GUIソフトはGUI的にといったはずです。

ためさないということは、ただの釣りの質問ですよね。
    • good
    • 0

初心者にとって、大事なことを忘れていませんか。


それはマクロの記録を採って、それでは記録が採れない問題化、使えないか検討し、修正箇所・方法を勉強することです。
ーー
本件はマクロの記録を採ってみると
C列とF列の例で
Sub test01()
Range("C1:C12,F1:F12").Select
With Selection
.MergeCells = False
End With
End Sub
となりました。(一部行を不要として削除してます。)
まずこれ(または一部修正して)を実行して、質問者が検討をして、それではニーズに合わない場合、それを柱にして質問をするぐらいしてほしい。
ーー
範囲全域の結合セルをすべて解除するなら、全セルについて繰り回しをする必要ないのは知っているのかな。
書式はセル範囲の全体に一発で設定できるのだ。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。初心者なのでWith~End Withがあるのを知りませんでした。それからお言葉ですが、散々一人で悩んで試行錯誤して、どうしても駄目だったので質問をしました。検討しまくってこの結果でした。最初からそれをしてないと思われるのは少し残念です。
それから質問にあるように、私は選択したセル全体にではなく、全選択した列の一部のセルにだけ処理を施したいんです(たとえばC列を全選択したら、C1~C12のセルにだけ結合解除を行う等)。回答者様の回答でたとえるなら、Range("C1:C12,F1:F12").Selectの「"C1:C12,F1:F12"」の部分をどう取得したら良いのか分からないです。検索してもどこにも載ってないですし。

お礼日時:2011/05/04 12:48

Range("E:E,G:G,I:I").Select


Range("I1").Activate
With Selection
.VerticalAlignment = xlCenter
.WrapText = False
.Orientation = 0
.AddIndent = False
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With

を改良してつかってください。マクロの記録を使ってだしたものです。

私はこうして自動かしています。もっと早く解決する方法ですね。できなかったときに、何のオブジェクトなんだと考えると、理解が深まります。アクティブな物に対して行うものと、プログラム的に、セル選択、処理だと、あれれれ、というのが多いのがエクセル、ワード、オブジェクトです。

GUIソフトは、GUI的に処理するのが無難です。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。初心者であるため、With~End Withというものがあるのを知りませんでした。ただ、これだとE列・G列・I列のすべてのセルに処理を施してしまいます。私はE列・G列・I列の「一部の」セルにだけ処理を施したいので、回答者様の回答でたとえるなら1行目はRange("E1:E12,G1:G12,I1:I12").Selectとなるように書かなければいけないですよね。
任意の列を全選択した後でそれが可能なのでしょうか?列を全選択したらRange("E:E,G:G,I:I").Selectになりますけど、それをRange("E1:E12,G1:G12,I1:I12").Selectに変換するなんて、たぶんできないですよね。

お礼日時:2011/05/04 12:32

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

このQ&Aを見た人はこんなQ&Aも見ています


おすすめ情報

このQ&Aを見た人がよく見るQ&A