Excel (一般機能)

Excelの一般機能に関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 7 Home Premium : Excel 2007)
「rangeメソッドが失敗しました」、について
投稿日時: 18/09/29 18:16:58
投稿者: なるみ
メールを送信

今ガントチャートをサンプルプログラムを見ながら作ってるのですが、
タイトルにも記載しているこのエラーに悩んでいます。
下記に問題ありと思われる箇所を記載します。
 
Private taskno As Long
Private ws1 As Worksheet
Private ws2 As Worksheet
Private ws3 As Worksheet
Private ws4 As Worksheet
 
-------------------中略-------------------
 
 Do While CNT1 < taskno
        If ws4.Range(Cells(CNT1, 5)) = "" Or ws4.Range(Cells(CNT1, 6)) = "" Then  ←エラー部
            Exit Sub
        End If
 
-------------------中略-------------------
 
概要を説明しますと、ws4をアクティブにしてガントチャートの表を生成したりトリガー用のボタンを作ったりしています。
ws4上のセル値の読み取りを行いたいので、上記のように記載しています。
間違ってなさそうにも見えるのですが・・・・・
調べても解決策が分からなかったので、ご教授願います。

回答
投稿日時: 18/09/29 19:13:17
投稿者: 半平太

>「rangeメソッドが失敗しました」
  
Worksheetにrangeメソッドなんてありましたっけ?
  
見た目(形?)からすると、
何故こうしないのかなぁと思うんですが、
     ↓
If ws4.Cells(CNT1, 5).Value = "" Or ws4.Cells(CNT1, 6).Value = "" Then
 
 
>間違ってなさそうにも見えるのですが・・・・・
 
元コードのここは何をしようとしていますか?
      ↓
ws4.Range(Cells(CNT1, 5)) = ""
 
Cells(CNT1, 5) は
 一つのRangeオブジェクトですよ。
 また、ws4上にあるRangeかどうかも定かでないです。
  色々と問題ありです。
 
いま気がついたですけど、この板はVBAじゃないですね。

投稿日時: 18/09/29 21:28:03
投稿者: なるみ
メールを送信

返信ありがとうございます。
 
>見た目(形?)からすると、
>何故こうしないのかなぁと思うんですが、
     ↓
>If ws4.Cells(CNT1, 5).Value = "" Or ws4.Cells(CNT1, 6).Value = "" Then
 
そうですね、よくよく考えればrangeいらないですね。
Cellsで指定してるのにも関わらず使うとか意味ないですね。
  
 
>元コードのここは何をしようとしていますか?
      ↓
>ws4.Range(Cells(CNT1, 5)) = ""
 
恥ずかしながら前コードの流用でして、読み取った内容がやりたいことだったので。
「セルが空白になるまで」以下処理を行うということだと思ったのですが、
違いますでしょうか?
 
  
>この板はVBAじゃないですね。
 
板の説明をよく読んでなかったです、すみません。
再度立て直すのもあれなのでこのままにします。
 
また「ws4上にあるRangeかどうかも定かでない」と仰ってましたが、
中略部に「Set ws4 = ActiveSheet」と書いてws4をアクティブにしていると思うのですが、
このこととは別問題ですか?
 
質問に質問を重ねて申し訳ないですが、よろしくお願いいします。
 

回答
投稿日時: 18/09/29 22:00:20
投稿者: なと

引用:
中略部に「Set ws4 = ActiveSheet」と書いてws4をアクティブにしていると思うのですが、
このこととは別問題ですか?

 
それはws4にActiveSheetのオブジェクト参照を格納しているだけで、アクティブシートの切り替えは行われていません。(アクティブシートの切り替えを行うなら、.Activateか.Selectメソッドが必要です)
 
中略されているため、実際のところは分かりませんが、
        ws3.Activate
        If ws4.Range(Cells(CNT1, 5)) = "" Or ws4.Range(Cells(CNT1, 6)) = "" Then

のような感じになっていると思われ、
        ws3.Activate
        If ws4.Range(ws3.Cells(CNT1, 5)) = "" Or ws4.Range(ws3.Cells(CNT1, 6)) = "" Then

と解釈されますから、質問のようなエラーになりますね。
 
解決策については、半平太さんの仰る通りです。

回答
投稿日時: 18/09/30 00:11:17
投稿者: 半平太

問題点は2つあります。
 
一つ目:これは回答者レベルでも分かっていない人がいます。
 
普通、Rangeオブジェクトへの参照を取得する時、どうやるかと言うと
 

    Set rng = Ws.Range("A1")               '(1) A1セルと同じ
    Set rng = Ws.Range("A1:C2")            '(2) A1:C2と同じ
    Set rng = Ws.Range("A1", "C2")         '(3) 同上
    Set rng = Ws.Range("A1", Cells(2, "C"))        '(4) 同上
    Set rng = Ws.Range(Cells(1, 1), Cells(2, "C")) '(5) 同上
くらいですかね?
 
そこから類推してこうやる初学者がいます。(5)を真似たんですかね?
         ↓
Set rng = Ws.Range(Cells(1, "A"))
 
でも大抵、なるみさんと同じエラーになりますよ。
 
何故か?
 
Rangeプロパティは、引数が一つだった場合、Rangeオブジェクトは想定していないからです。
なので、エクセルは、Cells(1,"A") オブジェクトの既定値であるValueプロパティを取得して
目的を達しようと試みます。
 
・・で、たまたまA1セルに「P2」と言う文字が入っていたら
エラーにはならず、P2セルが取得できます。
 
でも、多分、そんなことやりたい訳じゃないですから、
エラーにならないってだけでしかないです・・よね?
 
以上が理解できたら、A1セルに「P2」の文字、C2セルに「R4」の文字があるとして、
以下の4つのケースで、どんなRangeになるか考えてみてください。
 
    Set rng = Ws.Range(Cells(1, 1).Value, Cells(2, "C").Value)
    Set rng = Ws.Range(Cells(1, 1)   , Cells(2, "C"))
    Set rng = Ws.Range(Cells(1, 1)   , Cells(2, "C").Value)
    Set rng = Ws.Range(Cells(1, 1).Value, Cells(2, "C"))

答え
$P$2:$R$4
$A$1:$C$2
$A$1:$R$4
$C$2:$P$2
 
二つ目:これは回答者レベルなら分かっている・・のだが失敗する人がいます。(私)
 
ws4.Range(Cells(CNT1, 5))
~~~~~↑~~ ~~↑~~
   a      b

aは、明らかにws4のRangeである。
 
bは、状況依存のRangeである。
 そのコードが書かれているのが標準モジュールなら、その時アクティブなシートのRange
 そのコードがシートモジュールに書かれているなら、そのシートのRange、となる
 
なので、aとbが違ったシートであれば、食い違いでエラーとなります。
 
ws4.Range(ws4.Cells(CNT1, 5)・・・。
     ↑
     と書くのが正しい。これなら、シートの食い違いが絶対に生じない。

投稿日時: 18/09/30 01:13:06
投稿者: なるみ
メールを送信

なとさん、半平太さん、
返信ありがとうございます。
 
なとさんのお話を聞いて考えたところ、作業として使っているのはws4ですので、
そのほかのシートは参照程度ですのでアクティブにする必要はありませんでした・・・
よって
  Set ws1 = Worksheets("設定")
    taskno = ws1.Range("F2").Value
    Set ws4 = ActiveSheet
のように書き直しますと思った通りに動くことができました。
 
また半平太さんお話から極力rangeとcellsは混同しないようにしまして、
ループ処理を頻繁に使っていたためcellsで以下のように記載しました。
  Do While CNT1 < taskno + 9
        If ws4.Cells(CNT1, 5) = "" Or ws4.Cells(CNT1, 6) = "" Then
            Exit Do
        End If
その結果無事に動作確認ができました!ありがとうございます。
まだまだ勉強して1カ月程度ですが、引き続き頑張りたいと思います。