• ベストアンサー

ExcelVBAの知恵をお貸しください。

一つのシートで、複数のセル範囲を選択している場合に、セル範囲を選択しているのか?列、行を選択しているのかを判別する方法として次のようなのを考えました。 それとなく動いているのですが、なんとなくスマートでなく、場当たり的な感じがしますが、どのようにすればいいのか判りません!! どなたか、アドバイス頂けないでしょうか?宜しくお願いいたします。 Sub test()  Dim myRang As Range  Dim myArry As Variant  For Each myRang In Selection.Areas myArry = Split(Replace(myRang.Address, ":", ""), "$") If UBound(myArry) <> 2 Then   MsgBox "セル範囲を選択しています。" & myRang.Address Else If IsNumeric(myArry(1)) Then MsgBox "行を選択しています。" & myRang.Address Else MsgBox "列を選択しています。" & myRang.Address End If End If  Next End Sub

質問者が選んだベストアンサー

  • ベストアンサー
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.1

こんばんは。 >なんとなくスマートでなく、場当たり的な感じがしますが、どのようにすればいいのか判りません!! Split(Replace(myRang.Address, ":", ""), "$") ここまでのレベルまで使ってしまって、なんとなくすっきりこない、その気持ちは分かるけれども、それを、自分の外に求めないほうがよいと思いますね。1年前の自分と比較して進歩しているなら、それで良いと思います。 年数やコードの数を重ねれば、それなりに、満足いくような格好にはなるけれども、「エラーなく、動きさえすれば良いのだ」と思って、先に進んでいくしかないと思います。ご質問のコードでも立派なものだと思います。ある別の掲示板の常連さんのコードを思い出しました。その方は、そういうスタイルの書き方で掲示板にいつも書いています。だから、キリがないです。 私だって、こんなことは自信があるわけではありません。 ただ、なるべく、エラー・フリー(エラーを出さない)を目指す、それだけだと思います。 Sub Test2()   Dim r As Range   Dim a As Range   Dim i As Long, j As Integer   Dim msg As String   If StrComp(TypeName(Selection), "Range", 1) <> 0 Then Exit Sub   Set r = Selection   For Each a In r.Areas     i = a.Rows.Count     j = a.Columns.Count     If a.Count = 1 Then       msg = "1つのセルを選択しています。"     ElseIf i > 1 And j > 1 Then       msg = "セル範囲を選択しています。"     ElseIf i > 1 Then       msg = "列を選択しています。"     ElseIf j > 1 Then       msg = "行を選択しています。"     End If     MsgBox msg & ": " & a.Address, 64   Next a   Set r = Nothing End Sub

その他の回答 (2)

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.3

こんにちは。"ある別の掲示板の常連"です。 遅すぎるレスですが、とりあえず、ご要望のものを...。 Sub Test_SS() Dim strM As String '' ...MsgBoxで表示する文字列 Dim strB As String '' ...一時的に格納する文字列(使いまわし) Dim strRngA() As String '' ...Addressを","区切りで(各Area毎に)文字列の配列に Dim strBA() As String '' ...各strRngAを"$"区切りで文字列の配列に(使いまわし) Dim i As Integer strB = ActiveWindow.RangeSelection.Address strRngA = Split(strB, ",")  For i = 0 To UBound(strRngA) strM = strM & CStr(i + 1) strB = strRngA(i) ' If strB = "$1:$65536" Then 'strM = strM & "_すべてのセル_" ' Else strBA = Split(strB, "$")   If UBound(strBA) And 4 Then strM = strM & "_セル範囲_"   ElseIf CBool(Val(strBA(1))) Then strM = strM & "_行範囲_"   ElseIf Not CBool(Val(strBA(2))) Then strM = strM & "_列範囲_"   Else strM = strM & "_単一セル_"   End If ' End If strM = strM & strB & vbLf ' & vbLf  Next i 'Erase strBA 'Erase strRngA strM = strM & "以上の 範囲 を選択中です。" 'strM = Replace$(strM, "$", "") 'strM = StrConv(strM, vbWide) MsgBox strM End Sub ''注:「無くても動く」部分をコメント('以下)にしておきます ''Excel2000/2002で動作確認済です Rangeオブジェクトやプロパティの参照・取得を減らして、 文字列変数でループ処理することでパフォーマンスを高める という狙い(?)ならば、"すっきり"したのではないでしょうか。 行数・字数を減らす意味なら、色々出来ると思いますが、 できるだけ「犠牲」にするもののないように書いてみました。 但し、このような目的の為だけに、 こうした記述を実践で使うかといえば、微妙です。 目的を実現する方法だけを問う質問だったなら、 Q&Aの回答として書くか、は、NOです。 (#1さん#2さんのような記述が一般的で妥当だと思います) 記述が長くなるということは、 「エラーの機会が増える」 「メンテナンスが複雑になる」 一般的でない書き方をするということは、 「他の人が管理・メンテナンスすることを難しくする」 といった「犠牲」を払うことになります。 どうしても必要な記述で、人に配布する場合には、 管理者向けの丁寧な説明文とセットで考える必要があるでしょう。 そこまでする必要があるのかないのか、実践での判断、 それ以前に、色々な方法がある中で、目的に照らして、 前提にした選択肢が十分で適当なものかどうか、 私はいつも考えさせられます。 昨年下半期の個人的な課題として掲げていたのが、 ・次の実践の機会に正しい選択ができるように幅を拡げる研究。 ・出来上がった自分のスタイルを、疑って、壊して、再構築。 本来は個人的に行う学習・探求なのですが、こうした事を 他者と共有できる場-"ある別の掲示板"のトピックス-で、 ご提示のコードに良く似た内容のものを書いたことがあります。 その時は、Range参照文字列そのものを編集・加工して 新たなRangeオブジェクトを合成する、という目的でしたので、 それなりに整合性はあったと思っているのですが、 説明不足や不備があって誤解を招いた面もあったようです。 こうした経緯がありましたので此処に出てくることにしました。 この場に書いて良いか迷う点もありました。 よかったら"ある別の掲示板"にも遊びに来ませんか? ご活躍を期待しております。頑張ってください。

  • onlyrom
  • ベストアンサー率59% (228/384)
回答No.2

オーソドックスなのをひとつ。。 '-------------------------------------------- Sub Test()  Dim myRang As Range  For Each myRang In Selection.Areas    If myRang.Columns.Count = Columns.Count Then      MsgBox "行選択: " & myRang.Address    ElseIf myRang.Rows.Count = Rows.Count Then      MsgBox "列選択: " & myRang.Address    Else      MsgBox "セル選択: " & myRang.Address    End If  Next End Sub '--------------------------------------------- 因みに質問者提示のコードでは、セルを【ひとつ選択】したとき正しいメッセージが出ないのでは?  

関連するQ&A

  • 無効なセルを参照した場合の判定について

    表内のセルを選択した場合と、表外のセルを選択した場合に処理を分けたいと考えています。アクティブセルがhaniに含まれる場合(または含まれない場合)ですが、<>と=では無理なようなのですが、何を調べても分かりません。どなたかよろしくお願いいたします。 Windows2003、XPです。 Sub shita() Dim a As Range Dim hani As Range Set hani = UsedRange b = ActiveCell.Address MsgBox UsedRange.Address & " " & ActiveCell.Address If b = hani.Address Then Range("A1").Select Else MsgBox "表内のセルを選択してください。" End If End Sub

  • Worksheet_SelectionChangeについて

    Private Sub Worksheet_SelectionChange(ByVal Target As Range) Dim GYO As Long ' 8列目のみを対象とする If Target.Column <> 8 Then Exit Sub Else GYO = Target.Row End If ' 8列目が空欄でなければ計算処理を呼び出す(引数は選択行) If Cells(GYO, 8).Value = "" Then Exit Sub Else: Call KEISAN(GYO) End If End Sub という方法で8列目のセルをクリックするとフォームが立ち上がるようにしているのですが、ドラッグによる範囲選択でも8列目が含まれているとフォームが立ち上がってしまいます。 単一セルの選択時のみにするにはどうしたらいいでしょうか。 それとすべてのシートにこのマクロを書いているのですがworkbook全体でやることはできないのでしょうか? Workbookのところにこのコードを入れてもうまくいきませんでした。

  • ExcelVBA どこが間違えていますか?

    ExcelVBA 初心者です。 下記のようなプロシージャを人様の作ったのをコピーして作ったのですが意図したとおりになりません。どこが間違っているのか教えてください。 私の意図は選択したフォルダの中の全ファイル(Book)名をアクティブシートのA列に順番に表示したい、です。今は実行すると全部セルA1に表示されてしまって、最後の1つのファイル名しか分かりません。ファイルごとに別のセルに表示したいのです。よろしくお願いします。 Sub ファイル一覧() Dim foldername As String Dim filename As String Dim i As Integer Dim dlg_folder As FileDialog Set dlg_folder = Application.FileDialog(msoFileDialogFolderPicker) Folder_Dialog: dlg_folder.Show If dlg_folder.SelectedItems.Count <> 1 Then Exit Sub Else foldername = dlg_folder.SelectedItems.Item(1) MsgBox "選択したフォルダは " & foldername & " です。" filename = Dir(foldername & "\*.xls", vbNormal) If filename = "" Then MsgBox "Excelファイルがありません。" GoTo Folder_Dialog End If End If Set dlg_folder = Nothing Do While filename <> "" For i = 1 To Workbooks.Count Cells(i, 1).Value = filename i = i + 1 Next i filename = Dir() Loop MsgBox "フォルダ " & foldername & " の中のファイルはすべて表示されました。" End Sub あれ、なぜかインデントが無効になっています。

  • 「IsText」の使い方を教えてください

    例えば Sub tset1() Dim mystr As String mystr = "aaa" If IsNumeric(mystr) = True Then MsgBox "数値です" End If If IsText(mystr) = True Then MsgBox "文字です" End If End Sub と言うコードを作ったのですが、 数値かどうかはIsNumericで判断できますが 文字列かどうかを判断したい時にIsStringはないようなのでIsTextを使うのかな? とおもったのですが、コンパイルエラーになるようです。 IsNumericはInformationクラスのようですが IsTextはWorksheetFunctionクラスのようです。 だからIsNumericとIsTextの使い方が違うのでしょうか? 文字かどうか評価するIsTextの使い方をご教授ください。

  • エクセルのマクロについて

    下記は、A列3行の7文字目~10文字と B列5行~文字のある最後の行までの範囲の左から1文字目~4文字 に相違がある場合 MsgBox i & “行目” を出す。 というマクロなのですが、『B列5行~文字のある最後の行までの範囲』の中でも『空白のセルに関してはMsgBox不要』というふうに付加えたいのですがどのようにすればよいでしょうか。 Sub Macro1() Dim i As Long Dim sOrgText As String Dim ltotal As Long With ActiveSheet sOrgText = Mid(.Cells(3, 1), 7, 4) ltotal = .Cells(65536, 2).End(xlUp).Row For i = 5 To ltotal If Not Mid(.Cells(i, 2), 1, 4) = sOrgText Then MsgBox i & "行目" End If Next i End With End Sub

  • ExcelVBAで、広範囲セルの空白チェックをしたいと思います。

    ExcelVBAで、広範囲セルの空白チェックをしたいと思います。 以下のようなExcelシートがあります。 ・10行目まではタイトル行 ・データ入力可能セル範囲はA11~AF65536 全てのデータ範囲を削除するために、以下のコードを作成しました。 動きとしては問題ないのですが、データが存在しない場合の 処理時間が長くなってしまいます。 Sub 全データ削除() Dim endrow As Long Dim mydelete As Integer Dim myrange As Range endrow = Range("A11").End(xlDown).Row For Each myrange In Range("A11:AF" & endrow) If myrange.Value <> "" Then GoTo 削除処理 End If Next myrange MsgBox "データがありません。" Exit Sub 削除処理: mydelete = MsgBox("全てのデータを削除しますか?", vbOKCancel) Select Case mydelete Case vbOK Rows("11:65536").Delete Range("D4").Formula = "=COUNTA(A11:A65536)" MsgBox "データを削除しました。" Exit Sub Case vbCancel MsgBox "キャンセルされました。" Exit Sub End Select End Sub データ範囲が65536行までになってしまうため時間がかかっているのだと思いますが、 回避方法がわかりません。 ご教授お願いいたします。

  • ExcelVBAで行と列の検索

       A  B  C  D  E 1  コード あ  い  う  え 2  10  ○    ○ 3  20     ○  ○ 4  30          ○ 上記の表が5000件あります。Textbox1に入力し検索ボタンを押すと A列のコードを検索して一致する列の○のあるところの1行目の項目 をtextbox2に表示したいのですがうまく行きません。 よろしくお願い致します。 Private Sub CommandButton1_Click() '検索フォームボタン Dim i As Long Dim 最終行 As String Dim サーチ行 As Long Sheets(1).Activate 最終行 = Range("A1").End(xlDown).Row サーチ行 = 0 For i = 2 To 最終行 If TextBox1.Value = Range("A" & i) Then If Range("B" & i, "N" & i) = "" Then TextBox2.Text = Range("B1", "N1") サーチ行 = i Exit For End If End If Next If サーチ行 = 0 Then MsgBox TextBox1.Value & "データはありません。", vbInformation, "無し" End If TextBox1.SetFocus End Sub エラーはでません。データはありませんとなります。  

  • VBAのinputboxで何もいれずに[OK]を押した時エラーになります

    よろしくお願い致します。 EXCELのVBAで「inputbox」を使ってセルを選択させたいと考えております。 下記のコードだと「キャンセル」や「×」で閉じられた時はmsgbox「キャンセル」が出てExit subするのですが、何も入力しないで「OK」を押した場合がどうしてもエラー(入力した数式は正しくありません)になります。 いろいろ調べて試したのですがどうしてもできず困っています。 どなたか教えてください。 Sub test() Dim myAns As Range On Error Resume Next Set myAns = Application.InputBox(Prompt:="セルを選択してください。", Title:="セル選択", Type:=8) On Error GoTo 0 If myAns Is Nothing Then MsgBox "キャンセル" Exit Sub ElseIf myAns = "" Then MsgBox "最低1つは選択してください" Exit Sub Else MsgBox myAns.Address(0, 0) End If End sub

  • エクセルマクロ インプットボックスの使い方

    エクセル2013です。 マクロの途中で作業者にマウスで列を選択してもらい その取得した列番号を使って、いろいろ処理を行うマクロを作りました。 Sub 実験() Dim マウス選択 As Range Dim 選択列 Dim 選択月表示 Dim 質問 Dim 最終列 Dim 最終行 最終列 = Cells(8, Columns.Count).End(xlToLeft).Column '8行目の最終列を取得 最終行 = Cells(Rows.Count, 1).End(xlUp).Row 'A列の最終行を取得 On Error GoTo myError Set マウス選択 = Application.InputBox("編集したい月の列を選択してください", Type:=8) 選択列 = マウス選択.Column 選択月表示 = Cells(8, 選択列).Value 質問 = MsgBox("選択した月は " & 選択月表示 & " です。いいですか?", vbYesNo) If 質問 = vbYes Then MsgBox "処理を行います" Else MsgBox "プログラムを中断します" Exit Sub End If ---処理内容---- myError: MsgBox "キャンセルが押されました。プログラム終了します。" End Sub 通常列を選択してくれればインプットボックス内には $V:$V などと表示されますが 行を選択されると $35:$35 などと表示され セルの一部を選択されると $D$40 などと表示されます。 行やセルを選択してもエラーなく最後まで進みますが選択した場所によっては とんでもない結果になってしまいます。 基本、列以外を選択したらメッセージボックスでアラームするか プログラムを停止させたいのですがどのような方法が有りますでしょうか? よろしくお願いします。

  • ExcelVBA リストボックスの複数選択処理がうまくいきません

    こんばんは、助けてください。 EXCEL2007です。 ユーザーフォームにリストボックス(Listbox1)を複数選択可能で作成。 リストボックス各行の4列目には「A」か「B」のいずれかが入っており、選択した行の4列目が「A」ならば「B」を、 「B」ならば「A」をCommandButton1押下でセルに反映させたいのですが、うまくいきません。 [反映先のセル] ・リストボックス1行目⇒セルC4(列番号3) ・リストボックス2行目⇒セルG4(列番号7) ・リストボックス3行目⇒セルK4(列番号11) ・リストボックス4行目⇒セルO4(列番号15) ・リストボックス5行目⇒セルS4(列番号19) ・以降同規則でつづく [コード] 01 Private Sub CommandButton1_Click() 02   Dim ListRow As Integer 03   Dim Retsu As Integer 04 05   For ListRow = 0 To Listbox1.ListCount - 1 06     If Listbox1.Selected(ListRow) Then 07       Retsu = (ListRow + 1) * 3 + ListRow 08       If Listbox1.List(ListRow, 3) = "A" Then 09         Cells(4, Retsu).Value = "B" 10       Else 11         Cells(4, Retsu).Value = "A" 12       End If 13    End If 14  Next ListRow 15 End Sub [現象] 1.単一選択時は、OK。 2.複数選択時は、選択した行のうち一番はじめの行のみOK。 3.試しに、EndSub直前でListbox1.Selected(各ListRow)を検証すると、すべてFalseになってしまっている。 4.IF文(07~12行目)を削除した上で、EndSub直前でListbox1.Selected(各ListRow)を検証すると、True/Falseは意図通りになっている。 IF文(07~12行目)が悪さをしているのでしょうか? うまいやり方をご教授いただければ、幸いです。m(_ _)m

専門家に質問してみよう