[[20150218000939]] 『グラフ要素の参照先を変更するとメモリが増えて動』(初心者です) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『グラフ要素の参照先を変更するとメモリが増えて動作しなくなる』(初心者です)

VBA初心者です。

 VBAでActiveChart.SeriesCollection().Valuesによりグラフの参照先を変更すると、使用可能メモリが減少して、最終的に動作しなくなります。例のコードを次に示します。
 対策を教えていただけると助かります。よろしくお願いします。

例ではA,B,C列に最終行まで数値データを入力した上で実行すると、使用可能メモリがどんどん減少いていきます。

Sub test()

    Range("A1:C11").Select

    ActiveSheet.Shapes.AddChart2(332, xlLineMarkers).Select

    ActiveChart.SetSourceData Source:=Range("Sheet1!$A$1:$C$11")

i = 1

Do

    ActiveChart.SeriesCollection(1).Values = "" & "='" & "Sheet1" & "'" & "!" & Cells(2 + i, 1).Address & ":" & Cells(12 + i, 1).Address

    ActiveChart.SeriesCollection(2).Values = "" & "='" & "Sheet1" & "'" & "!" & Cells(2 + i, 2).Address & ":" & Cells(12 + i, 2).Address

    ActiveChart.SeriesCollection(3).Values = "" & "='" & "Sheet1" & "'" & "!" & Cells(2 + i, 3).Address & ":" & Cells(12 + i, 3).Address

i = i + 1

Loop

End Sub

< 使用 Excel:Excel2013、使用 OS:Windows7 >


 ループし続けて、抜けるところがないからでしょ
 グラフは関係ない
 何処までやってループを抜けるか、
 Exit do
 Do until
 Do while
 Loop until
 Loop while

 を検索してみてください
 あるいは内容によって、Forのほうがよいかもしれません

 最終行は、end(xlup)を検索してみてください

 一度試していただいて、わからなければ
 どの様にやったら、どの様な現象がでたか説明してください

(稲葉) 2015/02/18(水) 06:26


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

残念ながら、最終行にたどり着く前にメモリ不足でエクセルが停止してしまいます。
ループを抜けれず停止するのではなく、ループ中に停止してしまいます。
実行したい処理は、要素数はそのままで参照範囲を1行ずつずらしていくというものです。

お手数ですがよろしくお願いいたします。

Sub test()

    Range("A1:C11").Select

    ActiveSheet.Shapes.AddChart2(332, xlLineMarkers).Select

    ActiveChart.SetSourceData Source:=Range("Sheet1!$A$1:$C$11")

i = 1

Do until i=1048576

    ActiveChart.SeriesCollection(1).Values = "" & "='" & "Sheet1" & "'" & "!" & Cells(2 + i, 1).Address & ":" & Cells(12 + i, 1).Address

    ActiveChart.SeriesCollection(2).Values = "" & "='" & "Sheet1" & "'" & "!" & Cells(2 + i, 2).Address & ":" & Cells(12 + i, 2).Address

    ActiveChart.SeriesCollection(3).Values = "" & "='" & "Sheet1" & "'" & "!" & Cells(2 + i, 3).Address & ":" & Cells(12 + i, 3).Address

i = i + 1

Loop

End Sub

(初心者です) 2015/02/18(水) 21:46


何をしたいか理解できていませんので、的はずれな発言かもしれませんが。
ループせずに最初から最終行をセットしては駄目なのですか。

(マナ) 2015/02/18(水) 22:27


なんどもすみません。
最初から最終行をセットするのではなく、例ように決まった数の要素をグラフ上に表示させ、その要素を変化させたいのです。(行番号の増える向きに要素の範囲をずらしていきたい)

よろしくお願いいたします。
(初心者です) 2015/02/18(水) 23:28


 >その要素を変化させたいのです。
 >(行番号の増える向きに要素の範囲をずらしていきたい) 

 にしても・・・

 >Do until i=1048576 

 失礼ながら、常軌を逸してないですか?
 なんで百万回もこんなことやるんですか?

(半平太) 2015/02/18(水) 23:32


説明不足で恐縮です。

例については、次に説明する処理を実現するたのに障害となっている部分を、なるべくわかりやすく理解してもらうために提示しました。

実際に実行したい処理
毎秒、数個の新しいデータが、新しい1行に追加される。
それらのデータを、グラフに表示する。
表示するデータは、新しいものから順に数百個データ分で、データが追加されるたびにグラフは新しいデータに更新される。

この処理の途中で、メモリ不足が発生します。データを追加する部分の処理で問題となるメモリ消費は発生しません。参照データの範囲変更の部分でメモリ消費が発生します。上述のコードで確認できると思います。(例のDO LOOPの部分)

どうしてもここが乗り越えられなくて困っております。
お手数ですが、よろしくお願いいたします。
(初心者です) 2015/02/19(木) 07:44


 じゃあデータが更新されるたびに、差分だけ実行するコードにすればいいんじゃない?
(稲葉) 2015/02/19(木) 08:33

参照データの範囲変更なら
変更したいシートに
Private Sub Worksheet_Change(ByVal Target As Range)
 Dim myData As Range, c As Range
    Set myData = Application.Intersect(Target, Range("A:C"))
    If myData Is Nothing Then Exit Sub
MaxRow = Cells(Rows.Count, 1).End(xlUp).Row
'最終行から表示したいデータ分引く
changeRow = MaxRow - 10

ActiveSheet.ChartObjects(1).Chart.SetSourceData
の範囲を
ActiveSheet.ChartObjects(1).Chart.SetSourceData Range("A" & changeRow & ":C" & MaxRow)
のようにして最終行から可変にしてデータが入った時に参照範囲の変更を実行するというのはどうでしょうか
(デイト) 2015/02/19(木) 08:35


 >この処理の途中で、メモリ不足が発生します
 Excel2010で検証していますが、メモリ不足というエラー内容だとは確定しませんが、
 確かにそれらしいエラー(1004)が発生しそれ以降は、グラフはまともに操作できません。

 Excelって、データ量が少ないときに可能なすばらしい機能が、その機能が扱うデータ量が多くなると
 エラーになったり、極端に処理時間がかかったりする現象をいくつか経験したことがあります。

 バージョンアップによって 治っている現象もありますけどね!!

 この現象 私がちょこっと調べたかぎりでは・・・。

 On Error Resume 又は、 On Error Goto 〜  等で エラートラップを拾います。

 1 一つは、上記でエラーを検知したら、そのとき使用しているグラフ(Chartobject)は、あきらめて削除し、新たにグラフを作成し、続きから(iの値が止まった値から)表示を始める

 2 同じようにエラーを検知したら、グラフの移動で新たなシートにグラフを移し(グラフシートにする)、このグラフシートを再度、元のワークシートのChartobjectに移動しなおします。そして、
 続きから(iの値が止まった値から)表示を始める

 どちらかの方法で継続可能にする。グラフの作り直しが簡単なら 1、 
 グラフ自体が例題ほど単純ではないなら、2の方法、 なんて方法 いかがですか?

 仕事でグラフはほとんど使わないので 案だけですが・・・。

(ichinose) 2015/02/20(金) 06:37


 未検証ですが、グラフのデータ範囲は変更せずに その設定セル範囲のデータだけを変化させてみては?

(ichinose) 2015/02/20(金) 07:16


AccessならTop10クエリで。。。かな?
Excelならテーブルとトップテンオートフィルタ―かな?
ExcelとVBAの知識にとぼしいおいらにはこんな方法しか。。。

(水上) 2015/02/20(金) 08:31


ループ中にDoEventsを1行加えて、描画する余地を作ってあげてはどうですか?

範囲は、ずれるだけで大きさは変わっていないのだから、問題が出るのはおかしいです。
無限ループのように、表示要求だけ積み重ねていっているせいではないでしょうか。

そもそも、連続的にずらして、アニメーション効果を狙うこと自体が無茶です。最後だけ表示すればいい。
(???) 2015/02/20(金) 09:02


 「毎秒、数個の新しいデータが、新しい1行に追加される。 それらのデータを、グラフに表示する。 」

 これは、外部データとして自動的に書きこまれる仕掛けでしょうか?
 それとも、人間が手作業で入力するのでしょうか?
(β) 2015/02/20(金) 11:44

私の環境(Excel2010)では21845回目のループで、たぶんichinoseさんと同じエラー。
なので、46行すつずらせば、100万行以上までいけました。

 Sub test()
    Dim ws As Worksheet
    Dim r As Range
    Dim i As Long
    Dim t As Double

    Set ws = Sheets("Sheet1")
    Set r = ws.Range("A1:C100")

    Dim n As Long: n = 21844 '私のPCの最大回数?
    Dim o As Long: o = 46   'offset値

    t = Timer

    With ws.ChartObjects.Add(200, 30, 200, 200).Chart
        .ChartType = xlLineMarkers
        .SetSourceData Source:=r

        Do
            i = i + 1
            Set r = r.Offset(o)
 '            .SetSourceData Source:=r	'エラーが出る箇所は同じでありませんでした。
 '            .SeriesCollection(1).Values = r.Columns(1)
 '            .SeriesCollection(2).Values = r.Columns(2)
 '            .SeriesCollection(3).Values = r.Columns(3)

            .SeriesCollection(1).Values = r.Columns(1).Value
            .SeriesCollection(2).Values = r.Columns(2).Value
            .SeriesCollection(3).Values = r.Columns(3).Value

            If (i Mod 200) = 0 Then
                DoEvents
                DoEvents

                If (i Mod 1000) = 0 Then Debug.Print i, Timer - t

            End If

        Loop Until i = n
    End With

    MsgBox Timer - t

 End Sub

(マナ) 2015/02/20(金) 20:21


↑ごめんなさい。
Excel2010だと15秒ほどで終わるのに、2013で試してみたら5分経過しても半分。

結局30分近くかかりました。
2013では、.Valueとったら20秒ほどで完了。

あと、SetSourceDataの場合は、
2010、2013どちらも21792回目ループでエラーでした。

(マナ) 2015/02/20(金) 20:49


 この質問、Excelの限界を知るという意味では 良い内容だったと思います。

 おさらいという意味で

 新規ブックにて 標準モジュールに

 '==========================================================================
 Option Explicit
 Sub test1() '21845
    Dim r As Range
    Dim i As Long
    Dim rng As Range
    Call mk_sample1
    MsgBox "このサンプルデータで実行します"
    With ActiveSheet
       Set r = .Range("j4:q20")
       Set rng = .Range("a1:c11")
       With .ChartObjects.Add(r.Left, r.Top, r.Width, r.Height).Chart
          .ChartType = xlLine
          .SetSourceData Source:=rng
         ' DoEvents
          i = 1
          Do Until i >= 1040000
             .SeriesCollection(1).Values = "" & "='" & ActiveSheet.Name & "'" & "!" & Cells(2 + i, 1).Address & ":" & Cells(12 + i, 1).Address
             .SeriesCollection(2).Values = "" & "='" & ActiveSheet.Name & "'" & "!" & Cells(2 + i, 2).Address & ":" & Cells(12 + i, 2).Address
             .SeriesCollection(3).Values = "" & "='" & ActiveSheet.Name & "'" & "!" & Cells(2 + i, 3).Address & ":" & Cells(12 + i, 3).Address
             i = i + 1
          '   DoEvents
          Loop
       End With
    End With
 End Sub
 Sub test2()
    Dim r As Range
    Dim i As Long
    Dim rng As Range
    Call mk_sample2
    MsgBox "このサンプルデータで実行します"
    With ActiveSheet
       Set r = .Range("j4:q20")
       Set rng = .Range("a1:c11")
       .Range("a1:c11").Value = .Range("d1:f11").Value
       With .ChartObjects.Add(r.Left, r.Top, r.Width, r.Height).Chart
          .ChartType = xlLine
          .SetSourceData Source:=rng
       End With
       i = 1
       Do Until i >= 1040000
          DoEvents
          .Range("a1:c11").Value = .Range(.Cells(2 + i, 4), .Cells(12 + i, 7)).Value
          i = i + 1
       Loop
    End With
 End Sub
 Sub mk_sample1()
    On Error Resume Next
    ActiveSheet.ChartObjects.Delete
    Cells.Clear
    With Range("a:c")
       .Formula = "=rand()"
       .Value = .Value
    End With
 End Sub
 Sub mk_sample2()
    On Error Resume Next
    ActiveSheet.ChartObjects.Delete
    Cells.Clear
    With Range("d:f")
       .Formula = "=rand()"
       .Value = .Value
    End With
 End Sub

 test1を実行してください。サンプルデータ作成後、メッセージが表示されます。

 OKボタンクリックで グラフ作成開始です。

 i=21845 でエラーになります。

 このエラー発生後に、残ったグラフを手動操作してもまともにデータ範囲や系列の追加などができません。

 コメント化してあるDoeventsを作動させても結果は同じです。

 当初、過去にループ内にDoeventsの挿入でメモリエラーなら ガベージコレクションを行ってくれる
 ことがあったのでと試しましたが、結果は同じ個所でエラーになりました。

 前回投稿のようにエラーと拾って、小細工する方法もありまたが、

 test2のように データ範囲は変えずにその範囲の値自体を変化させていく方法だと
 最後まで作動します。

 試してみてください。

(ichinose) 2015/02/20(金) 22:26


みなさんたくさんの知識をいただきありがとうございます。
デイトさんの2015/02/19(木) 08:35 に頂いたメッセージをもとに改良した結果、以前より格段に動作時間が長くなり、今のところ停止に至っておりません。本当に助かりました。ありがとうございます。

また、コード改良のため、お返事が遅れてすみませんでした。マナさん、ichinoseさんわざわざコード作成、トライまでしていただき感謝しています。また、ご意見いただいた皆様にも深く感謝しております。βさん、データはエクセルが外部データを自動取得してくる仕組みです。

どうしても完成させたいコードでしたので本当にうれしいです。(1月ほど悩みました。)

本当にありがとうございました。

(初心者です) 2015/02/20(金) 23:19


 マナさん

 こんばんは、半平太です。

 >結局30分近くかかりました。 
 >2013では、.Valueとったら20秒ほどで完了。 

 これって、30分がたった20秒に短縮したんですか?

 本当なら、ぶったまげですね。

 なんかValueプロパティをいちいち書くのが「いわしの頭」みたいになっているなぁーなんて、
 最近思い始めているんですけど、こんな話を聞くと益々止めようかって気分になります。

(半平太) 2015/02/20(金) 23:34


 半平太さん

 はい、その通りです。びっくりというか、コードを取下げようかとあせっちゃいました。

 ただ、setsourcedataもそうですが、
 セル参照にすると、マクロ実行をくりかえすごとに時間がかかるようになっていくようです。

 1回目:20.8秒
 2回目:30.1秒
 3回目:38.9秒
(マナ) 2015/02/21(土) 00:11

 マナさん

 >はい、その通りです。

 貴重なテスト情報を、ありがとうございました。 m(__)m

(半平太) 2015/02/21(土) 00:16


>このエラー発生後に、残ったグラフを手動操作してもまともにデータ範囲や系列の追加などができません

 既存グラフにエラーが発生しない回数、例えば5000回を繰り返しても同じ状況に陥るようです。
 またExcelを再起動するとリセットされるみたいです。

 ichinoseさんの言葉を借りると「小細工」案ですが、
 定期的にカット&ペーストしています。
 たぶんこれでも最終行まで行きそうです。

 Sub test1()
    Dim ws As Worksheet
    Dim r As Range
    Dim c As Chart
    Dim n As Long
    Dim t As Double

    Set ws = Sheets("Sheet1")
    Set r = ws.Range("A1:C100")

    t = Timer

    With r.Offset(, 5)(1)
        Set c = ws.ChartObjects.Add(.Left, .Top, 200, 200).Chart
        .Select
    End With

    c.ChartType = xlLineMarkers
    c.SetSourceData Source:=r
    Do
        n = n + 1
        Set r = r.Offset(1)
        c.SeriesCollection(1).Values = r.Columns(1).Value
        c.SeriesCollection(2).Values = r.Columns(2).Value
        c.SeriesCollection(3).Values = r.Columns(3).Value
        If (n Mod 200) = 0 Then
            c.Parent.Cut
            ws.Paste
            Set c = ActiveChart
            If (n Mod 1000) = 0 Then Debug.Print n, Timer - t
        End If
    Loop Until n >= 100000  '20分近くかかりそうなので10万行でしかテストしてません

    MsgBox Timer - t

 End Sub

(マナ) 2015/02/21(土) 20:21



名前定義した範囲を参照先としても最後までいけそうです。

 Sub test2()
    Dim ws As Worksheet
    Dim r As Range
    Dim ary
    Dim c As Chart
    Dim i As Long
    Dim n As Long
    Dim t As Double

    Set ws = Sheets("Sheet1")
    Set r = ws.Range("A1:C100")
    ary = Array(, "retu1", "retu2", "retu3")

    t = Timer

    With ws.ChartObjects.Add(200, 30, 200, 200).Chart
        .ChartType = xlLineMarkers
        .SetSourceData Source:=r
        For i = 1 To UBound(ary)
            r.Columns(i).Name = ary(i)
            .SeriesCollection(i).FormulaR1C1 _
                = "=SERIES(,," & ws.Name & "!" & ary(i) & "," & i & ")"
        Next
    End With

    Do
        n = n + 1
        For i = 1 To UBound(ary)
           r.Offset(n).Columns(i).Name = ary(i)
        Next
        If (n Mod 200) = 0 Then
            DoEvents
            If (n Mod 1000) = 0 Then Debug.Print n, Timer - t
        End If
    Loop Until n >= 100000  '20分近くかかりそうなので10万行でしかテストしてません。

    MsgBox Timer - t

 End Sub

(マナ) 2015/02/21(土) 20:44


 横から失礼します。
 「いわしの頭」のテストを以下の形で実行してみました。(xl2013)
 私のPCは、そこそこパフォーマンスがいいPCなんですが、わずかな差とはいえ、「イワシの頭」を省いたほうが
 処理時間が短くなっています。

 Test1 VS Test2 は、21秒前後 VS 18秒前後。

 Test1,Test2の結果のA列の値を残した状態での Test3 VS Test4 は、2秒強 VS 1.8秒前後 でした。

 Sub Test1()
    Dim i As Long
    Dim t As Double

    t = Timer

    Columns("A").Clear

    For i = 1 To Rows.Count
        Cells(i, 1).Value = "ABCD"
    Next

    MsgBox Timer - t

 End Sub

 Sub Test2()
    Dim i As Long
    Dim t As Double

    t = Timer

    Columns("A").Clear

    For i = 1 To Rows.Count
        Cells(i, 1) = "ABCD"
    Next

    MsgBox Timer - t

 End Sub

 Sub Test3()
    Dim i As Long
    Dim t As Double
    Dim v As Variant

    t = Timer

    For i = 1 To Rows.Count
        v = Cells(i, 1).Value
    Next

    MsgBox Timer - t

 End Sub

 Sub Test4()
    Dim i As Long
    Dim t As Double
    Dim v As Variant

    t = Timer

    For i = 1 To Rows.Count
        v = Cells(i, 1)
    Next

    MsgBox Timer - t

 End Sub

(β) 2015/02/21(土) 22:13


 > Test1 VS Test2 は、21秒前後 VS 18秒前後。
 > Test3 VS Test4 は、 2秒強   VS  1.8秒前後 でした。

 早速、私のノートでもやってみました。
  Test1 VS Test2 は、67秒前後 VS 63秒前後。
  Test3 VS Test4 は、 4秒強   VS  3.5秒前後 でした。

 >「イワシの頭」を省いたほうが処理時間が短くなっています。
 この結論は以前、どこかで聞いたことあります。

 上は「イワシの頭」=「.VALUE」とした場合ですが、私の真意は「まぬけな信心」の意味です。

 .VALUEを省いては絶対いけないのだ、と云う風潮が強くなり過ぎており、
 .VALUEがオンパレードになっている汚らしいコードを見かけることも珍しくない。(本人が嬉々として書いたかは定かでない)
 VBAサイトの運営・執筆者に、「.VALUEを省略するな」なんて注文を付ける身の程知らずも出てきてしまった。

 大衆って恐ろしい。。

(半平太) 2015/02/21(土) 23:41


 解決されてて、xl2013もxl2010も持っていないので、後日談検証できないわけですが、
 質問者さんの「データはエクセルが外部データを自動取得してくる仕組みです。 」で
 どうしてループ処理(ループでグラフを描写する)が必要なのか理解できていないのですが
 どなたか教えていただけませんか??

 私もValueは付けるもんだと思っていたので、今回の結果で改心(回心?)致しました。
 獅子身中の虫ってやつですね。
(稲葉) 2015/02/23(月) 09:00

 > 私もValueは付けるもんだと思っていたので、今回の結果で改心(回心?)致しました。
 > 獅子身中の虫ってやつですね。

 すみませーん。そこまでずうずうしく言うつもりはないです。

 .Valueを付けるのが正調なんですけど、
 「付けない人は悪い人」みたいな風潮を感じる、と云う意味です。

 Valueってつけなくてもいいの?
http://officetanaka.net/excel/vba/beginner/08.htm

 特に初心者はRangeオブジェクトを渡しているのか、Valueを渡しているのか
 分からずにコーディングしていることが多いので、
 チャンと.Valueプロパティを付けるように「強く」アドバイスし続けた結果
 こうなっちゃったと感じております。

 ゴルフでヘッドアップするんじゃないとか言うアドバイスが利きすぎて
 打った後、5秒もボールの行方を追わなくなっちゃったようなもんです。

 まぁ、パットならボールはカップのそばにはあるから配はないでしょうけど、
 アドバイスも行き過ぎは嫌ですねぇ。。。。

(半平太) 2015/02/23(月) 09:35


グラフの系列の .XValuesや.ValuesプロパティにはRangeオブジェクトか配列を
設定出来ますが、.Valueを付けて配列で設定するとセルとのリンクはなくなり
グラフ内に値を保持するので要素数が膨大になると時間がかかるのでしょう。
系列を選択して、数式バーを見れば良くわかります。

(きまぐれ) 2015/02/23(月) 10:16


 >「付けない人は悪い人」みたいな風潮を感じる、と云う意味です。
 なるほど。
 善悪ではなく「省略していることを理解すること」が重要なわけで、駆け出しの新人さんは
 オブジェクトの代入と値の代入を区別するためにも、付けたほうがいいでしょうみたいなもんですね。

 >ゴルフでヘッドアップするんじゃないとか言うアドバイスが利きすぎて
 >打った後、5秒もボールの行方を追わなくなっちゃったようなもんです。 
 私はその辺柔軟にできていて、打つ前からボールの行方を追って、OBに流れていく玉を良く見ています。

(稲葉) 2015/02/23(月) 10:30


 >グラフの系列の .XValuesや.ValuesプロパティにはRangeオブジェクトか配列を 
 >設定出来ますが、.Valueを付けて配列で設定するとセルとのリンクはなくなり 
 > グラフ内に値を保持するので要素数が膨大になると時間がかかるのでしょう。 

 そう言う理屈ですか。。
 私はグラフの方のテストはしていないので(やる気が起きないです)、何とも言えません。

 そういえば、少し脇道ですが、「.VALUE」が習慣病になって馬鹿な結果を招いたケースがあります。
 Matchの第2引数でそれをやってしまった。

 ※test2OKは、馬鹿なことだが、結果はOK

 Sub test1OK()
     Range("A1").Value = 1
     Debug.Print Application.Match(1, Range("A1:A60000"), 0)
 End Sub

 Sub test2OK()
     Range("A1").Value = 1
     Debug.Print Application.Match(1, Range("A1:A60000").Value, 0)
 End Sub

 Sub test3OK()
     Range("A1").Value = 1
     Debug.Print Application.Match(1, Range("A1:A600000"), 0)
 End Sub

 Sub test4ONG()
     Range("A1").Value = 1
     Debug.Print Application.Match(1, Range("A1:A600000").Value, 0)
 End Sub

(半平太) 2015/02/23(月) 10:49


実際にこんな使い方をすることはないので、どうでいいといえば、そうなのですが…
 >.Valueを付けて配列で設定するとセルとのリンクはなくなり 

 これは、その通りなのですが、

 >グラフ内に値を保持するので要素数が膨大になると時間がかかるのでしょう。

 これが、よく理解でしません。

 先にも書きましたが、
 >Excel2010だと15秒ほどで終わるのに、2013で試してみたら5分経過しても半分。 
 >結局30分近くかかりました。 
 >2013では、.Valueとったら20秒ほどで完了。 

 もう一度確認してみました。
 やっぱり、2013で異常に時間がかかりまが、2010ではむしろ .Valueが安定して速いです。

 また、

 >ただ、setsourcedataもそうですが、
 >セル参照にすると、マクロ実行をくりかえすごとに時間がかかるようになっていくようです。

 についても、再現しています。

 '--------------------
 下記の3通りで時間を比較しました。
 マクロは、(マナ) 2015/02/20(金) 20:21 を使用。ループ回数は21000回です。
 各方法で3回測定。方法を変更する際にExcelを再起動しました。

 1) Chart.SeriesCollection(1).Values = r.Columns(1).Value
 2) Chart.SeriesCollection(1).Values = r.Columns(1)
 3) Chart.SetSourceData Source:=r 

 結果は、こんな感じです。単位は秒です。

 Excel2010

 1) 14.7, 14.7, 14.7
 2) 19.4, 28.2, 34.9
 3) 21.6, 34.2, 47.0

 Excel2013

 1) 約30分(1分ほど動かして、明らかに遅いので今回は途中でやめました)
 2) 22.8, 29.9, 37.3
 3) 23.9, 37.2, 50.4

 '--------------------

(マナ) 2015/02/23(月) 19:56


 話が意外な方向に向いていますが・・・。

 稲葉さんの

 >「データはエクセルが外部データを自動取得してくる仕組みです。 」で
 >どうしてループ処理(ループでグラフを描写する)が必要なのか理解できていないのですが

 このグラフのSeriesオブジェクトのValuesプロパティを外部データを自動取得する度に
 示されたコードのように

 ActiveChart.SeriesCollection(1).Values = "" & "='" & "Sheet1" & "'" & "!" & Cells(2 + i, 1).Address & ":" & Cells(12 + i, 1).Address

 グラフ系列の値を変更していく途中で エラーが発生したのでしょう。

 ループではなく 、何度も上記ののようにSeriesオブジェクトのValuesプロパティを変更していくと
 エラーが発生します。 

 このエラーを簡単になるべく短時間に再現する方法を 質問者は考えたのではないでしょうか!!

 質問者の問題は、このエラーが発生することだったのですから・・・。

 「初心者です」等というHNですが、なかなか どうしてどうして これは単にVBAに慣れていないだけかも
 という思いでこの質問者の方をみていました。

 ループ中にDoeventsを挿入すれば、グラフが長いデータの流れを示しているように作動しますが、
 これだと問題が再現するまで時間がかかりますからね!!

 私は、質問者が問題にしていたエラーを再現することに徹底した結果だと思いますよ!!

 ですから、
 >この質問、Excelの限界を知るという意味では 良い内容だったと思います。

 と記述しました。

 オブジェクトの既定のプロパティを省略すべきか否かの件

 私は、プロパティは 省略すべきではない という意見です。

 半平太さんご紹介のTANAKAさんのサイトの

 「省略したと認識することが大事」 これは、省略しているコードを読むときは なるほどそうでしょう。

 コードを書くときに 対象オブジェクトのプロパティを扱うときは、そのプロパティは、省略すべきではない と申し上げておきます。 イワシの頭として・・・。

 既定のプロパティがあるオブジェクトでは、そのプロパティを付けたときと 付けないときとでは
 動作が異なる場合もあります。

 私は、この話をするとき、よくTextboxを引用しますが、今回は、vbsでExcelを操った場合です。

 例1

 dim rng
 with createobject("excel.application")
   .visible=true
   with .workbooks.add.activesheet
      for each rng in .range("a1:c3")
         rng.value="aaa"
      next
   end with
 end with 

 例2

 dim rng
 with createobject("excel.application")
   .visible=true
   with .workbooks.add.activesheet
      for each rng in .range("a1:c3")
         rng="aaa"
      next
   end with
 end with 

 vbsを使って 例1 例2 では結果が違います。

 このように 既定のプロパティを付けたときと省略した時とで結果が違うことは、他にもいくつかありますから、注意してください。

 が、私は 既定のプロパティを付けるべきと思う最大の理由は、

 その方がわかりやすいコードになると確信しているからです。

 稲葉さんの記述に

 >善悪ではなく「省略していることを理解すること」が重要なわけで、駆け出しの新人さんは
 >オブジェクトの代入と値の代入を区別するためにも、付けたほうがいいでしょうみたいなもんですね。

 なんてありましたが、既定のプロパティを有するオブジェクトは、ActiveXControlには、結構あります。
 あるいは、個人的に作ったクラスだってあります。VBAのオブジェクトだって既定のプロパティは
 作れます。

 dim aaa
 aaa=myclass

 なんて知らないオブジェクトのプロパティを省略されたコード見た場合、既定のプロパティは何か?
 から、調べなければなりません。プロパティが記述されていれば そのプロパティのみに焦点を当てられるのに・・・。それだけ調べるのにも時間がかかります。

 つまり、プロパティを省略しない は、初心者だけのためではありません。

 私が Rangeオブジェクトの既定のプロパティについて、まじめに調べたのは、ほんの数年前ですが、
 納得するのに結構時間がかかりましたよ。

 イワシの頭としては、既定のプロパティは 省略すべきではない と記述しておきます。

(ichinose) 2015/02/24(火) 06:55


 >ループではなく 、何度も上記ののようにSeriesオブジェクトのValuesプロパティを変更していくと
 >エラーが発生します。 
 >このエラーを簡単になるべく短時間に再現する方法を 質問者は考えたのではないでしょうか!!
 なるほど!
 例題として「ループ」を示したわけで、別の解を求めた質問ではなかったのですね。
 納得致しました。

 >イワシの頭としては、既定のプロパティは 省略すべきではない と記述しておきます。
 ところで、DictionaryオブジェクトなどのItemプロパティはよくよく省略されますが
 これは明らかに引数があるので構わないのでしょうか?
 まだまだ納得するのは時間がかかりそうです・・・

 ただ、私は人のコードに文句は付けず、自分のコードでは付けようと考えています。

(稲葉) 2015/02/24(火) 08:38


 「イワシの頭」の意味は人によって違う様に解釈されているかも知れません。
  多分、それを「教条主義と云う意味です」と言い換えてみても状況に変わりはないのでしょうね。

 私は「既定のプロパティは全オブジェクトについて省略すべきである」などと言うつもりはないです。
 今回の考慮対象は、Rangeオブジェクトの.VALUEだけです。
 また、「一切省略すべきである」と言うつもりもないです。

 コーディングにおいてコメントを有効に使うのと同じで、
  (まぁ、コメントなんか邪魔なだけだから書くなと云う人もいます。
   コード自体が既にコメントだから、とか・・凄い手練れの人ですね。それは置いておいて)

 必要ないしベターと思ったら書く、冗長と思ったら書かない。それだけです。

 ichinoseさんにすれば、「冗長」なんてことはあり得ないと云う話になるのでしょうけど、
 私としては、「.Valueを付けない人は、悪い人」・・こう迫られると参ってしまいます。

 折角、MSが標準プロパティだか既定プロパティだかを用意して呉れているのですから、
 私が考えるような運用もありと思います。

(半平太) 2015/02/24(火) 10:31


すこし話を戻して、ichinoseさんの検証したtest1の考察。

3列使ったデータの21845回目でエラー。つまり、21845*3 = 65535。Unsigned Shortに限界があるようです。
Excelのグラフ制限各種には無い値なので、内部処理の変数等、何処かにこの限界があるのでしょうね。
(範囲を変えた回数とか?)
(???) 2015/02/24(火) 11:10


 >これは明らかに引数があるので構わないのでしょうか?
 Worksheets("sheet1")  と記述しますが、 Worksheets.Item("sheet1") とは 記述しませんね

 (VB.netでも ↑これは残っているんですってね!!)

 これはむしろ この方ががわかりやすいから ですが、
 >既定のプロパティは 省略すべきではない
 という私が このように記述するなら、

 Range オブジェクトのValueは 省略した方がわかりやすいと感じるなら 
 これも是ですね!!

 ここに何年か参加して 半平太さんは いろんな分野に造詣の深い方なので、
 その方と意見を交わせる数少ない場合は、私も 一生懸命です。

 今回の半平太さん記述

 >私の真意は「まぬけな信心」の意味です
 >「.VALUEを省略するな」なんて注文を付ける身の程知らずも出てきてしまった。

 正直・・・、怖いよ!!

 これだと、反対の意見があっても委縮してしまうし、

 プロパティを付ける人は、悪い人 なんて風潮が逆に強くなりそうです。

 そんなことになったら、わかりづらいコードが増えてしまうかもしれない
 という思いから 私も投稿しました。

 その後の投稿に フォローもありましたが、最初のインパクトが何せ 強いのです。 

 かなり、影響力あると思いますよ 半平太さんの投稿は・・・。

 VBAの場合、
 dim r as variant
 Set r=range("a1")

 と

 dim r as variant
 r=range("a1")

 このように 変数代入の場合は、Range("a1")は、オブジェクトとしてか 
 省略したValueかの区別はつきやすいですが、

 今回の事例のように

 > Chart.SeriesCollection(1).Values = r.Columns(1).Value
 > Chart.SeriesCollection(1).Values = r.Columns(1)
 (マナさんの投稿から引用)

 オブジェクトでも配列でもどちらでも指定が可能な仕様になっていますが、
 既定のプロパティが省略をされたコードを読んでいると、
 Valuesプロパティにオブジェクトを渡しているのか 配列を渡しているのか 一瞬迷ってしまいます。

 Property Let Values(myarray As Variant)

 End Property

 VBAで書けば 、このValuesは こんな手続なのでしょうから、何気に記述している

 Chart.SeriesCollection(1).Values = r.Columns(1) 

 の myarrayは、r.Columns(1) ですから
 オブジェクトそのものを 送っているのですよね!!

 でも、プロパティを省略していると、つい錯覚しそうになりませんか?
 (本来は、オブジェクトなら、 Property Set ・・・・ で分けた方が分かりやすいのですけどね!!
 これは、それなりの理由もあるのでしょう・・・。)

 >悪い人」・・こう迫られると参ってしまいます。

 技術に関して 意見交換をしているので 対象は人ではなく コードですよね。

 付けるメリット 付けいないメリット 折につけ挙げていけば、違う考えも出てくるかもしれません。

 何かおもしろい例を見つけたら また投稿します。

 何回もやっていけば 、より良いコーディングのきっかけになると思います。

(ichinose) 2015/02/25(水) 06:05


プロパティの省略については、なるべく省略しない方が、読みやすさの点では好ましいですね。
(明示することで、後から読むときに何のプロパティを操作しているのか悩まなくて済みます)
省略することで処理速度があがる場合は、省略するのも良いでしょう。

ただ、所詮Excelはインタプリンタで動作するマクロ。変数名やコメントを削る事だって性能向上しますが、微々たるものです。
そもそも、インタプリンタは遅いので、Excelがそこまで速度追求するシーンは少ないでしょう。
性能向上の意味合いが弱いならば、プロパティ省略するな!、という意見も、大抵の場合は通用すると思います。
ルールとして統一する場合も、普段省略、こういう場合は明示、とすると混乱するので、全て明示とするほうが一般的でしょう。

Rangeに限った話だと、デフォルトのプロパティはValueだ、という解説が主流だった頃があり、私もですが、RangeのValueは省略、Cellsは明示、という人が多いです。
(近年は、デフォルトは_Defaultだ、というのも広まりましたが)
今でも、Cellsは引数を入力するとインテリセンスでプロパティが表示されなくなるので、Valueを明示するメリットはあるかなぁ、なんて思ったりもします。
(RangeにもValueプロパティを明示するかどうか、思案中…。明示すべきとは思うのですが…)
(???) 2015/02/25(水) 09:42


 ROMしてたら、ひとりごとが出ちゃいました m(_ _)m

  m = Application.Match(Range("A1"), Range("B2:B60000"), 0)

 って書いたとき、
 第1引数の Range("A1")のあとに、もし省略されているプロパティがあるとしたら
 それは .Valueプロパティでなくて .Value2プロパティですよね?

 > .SeriesCollection(1).Values = r.Columns(1)

 このとき、r.Columns(1)のあとに省略されているものがあるとしたら、
 何なんだろ?
 .
(kanabun) 2015/02/25(水) 11:00

 >(近年は、デフォルトは_Defaultだ、というのも広まりましたが) 
 これについては、以前ichinoseさんに教えていただいたのですが、消化不良のままです。
 ・・と言っても、消化しようと努めていた訳でもないです。

  分からない原因を「自分の頭の悪さ」以外に求めたくて
 「誰かが嘘をついているハズだ」と割り切って放ってあります。

 あれ、また「怖いよ!!」的発言をしちゃったですか?

 さしずめ、OfficeTanakaさんの
 「省略すると○○とみなすというプロパティを標準のプロパティと呼びます」って
 なにか胡散臭いです。

 「デフォルトのプロパティ」とも「既定のプロパティ」とも言ってないですからねぇ。

 でも逆に、Rangeオブジェクトの既定のプロパティが「_Default」なら、
 省略すると何故Valueプロパティ(とおぼしき値)が出てくるの?って疑問も出てきます。
 だからTanakaさんは「標準の」プロパティと呼んでいるのかも知れない。

 >デフォルトは_Defaultだ
 これについては、ここがよく参照されたと思うのですけど(※1)
 【Excel技  コラム  E13C001】
http://www2.aqua-r.tepm.jp/~kmado/ke13c001.html

 そこでは。
 「RowIndexとColumnIndexを省略した場合、Range("a1:c3").[_Default]()となります。 
 省略してRange("a1:c3").[_Default]、或いはRange("a1:c3")()となり、
 結果としてValueプロパティと同意になります。 」
  ↑
 ここがまた胡散臭い。Defalutは分かったが、何が根拠で「結果としてValueプロパティ」になるのか
 さっぱり分からないです。それまで理詰めで来ていたと思うのですが、これにはがっかりです。

 しまいには
  > r1 = r2.Value 
  >これを既定メンバを省略した書き方で 
  > r1 = r2() 
  >とする事が出来ます。ちょっとおしゃれです。 

 何がおしゃれなのか・・・・アホかいな、って気分です。

 (※1)今ちょっと検索したらインストラクターのネタ帳にも載っていました。
 【RangeオブジェクトでValueプロパティを省略するとよくない事例】
http://www.relief.jp/itnote/archives/018289.php
  ここでは「コードも読みやすくなるんだから、書きましょうよ.Valueくらい」
  と云う結論でした。私としては
      「コードも読みやすくなるんだから、書きましょうよ.Valueくらい。100個あろうとも。」
  と書いて欲しかった。

 ・・でインストラクターのネタ帳をよく読むと、
  >Rangeオブジェクトの既定のプロパティは、あくまでも_Defaultプロパティなのです。
  >RangeオブジェクトでValueプロパティを指定しないときにValueプロパティとして扱われるのは、
  >オブジェクトブラウザから明確な仕様として読み取ることはできません。
  >経験則としてValueプロパティとして扱われることがもちろん多いですが。
 と書かれていました。
 これが正しそうな気がします。
 仕様上、.Valueになる保証がないなら、書くほかないですね。

 ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
 > 第1引数の Range("A1")のあとに、もし省略されているプロパティがあるとしたら
 > それは .Valueプロパティでなくて .Value2プロパティですよね?

 なんかkanabunさんの名前がチラホラ頭に浮かんでいたのですが、
 「Itemと云うのはぁ・・」とか言いながら出てくるかもと思っていましたので、
 「Value2」を引っ提げての登場とは予想外です。

 確かに実験すると、Valueプロパティではないと云う結果がでます。

 第一引数(検索値)についても、単一のRangeオブジェクトでプロパティを付けないものにすると、
 Valueではなく、Value2で検索するようです。(日付データではさっぱりヒットしません)

 まぁ、関数の中に入れると、Rangeオブジェクトがどう扱われるかは、
 関数の仕様次第になってしまうので、その仕様に従って決めるしかないです。

 >> .SeriesCollection(1).Values = r.Columns(1)
  >このとき、r.Columns(1)のあとに省略されているものがあるとしたら、
  >何なんだろ?

 (↓)と云うことなので、省略扱いではないと思います。
 > オブジェクトでも配列でもどちらでも指定が可能な仕様になっています、

 でも、配列も受け付ける仕様なので、プロパティ付きも処理して貰える。
 でも、このケースでは、プロパティは付けるべきではない。
 屋上屋を重ねるような書き方だと思います。
 内部の処理も異なるルーティンに入っている可能性があります(誰も真相は分かりませんが)

 翻って、冒頭にあったこの(↓)ステートメントが(兎にも角にも)処理されてるって不思議じゃないですか?

 > ActiveChart.SeriesCollection(1).Values = "" & "='" & "Sheet1" & "'" & "!" & Cells(2 + i, 1).Address & ":" & Cells(12 + i, 1).Address

 Rangeオブジェクトでも、配列でもなく、文字列ですよねぇ?
 今までの議論だったら、Addressプロパティを使ったことと同じであり、
 Valueだか、Value2だか、それを省略したか、なんて議論がぶっ飛んじゃいますね。

(半平太) 2015/02/25(水) 16:53


 ActiveChart.SeriesCollection(1).Values 
 Valuesプロパティの設定が懐が広く オブジェクト 値の配列 セルアドレスを表す文字列と
 受けているのでしょうね!!
 このプロパティが返すのは、値の配列だけみたいですけど・・・。

 Formulaプロパティの方が 何を指定したかを知るには、詳しい内容かも知れません。

 但し、Rangeオブジェクトと セル範囲のアドレスの違いは わかりませんが・・・。

 前々回の投稿で VBSから
 >例2
 >dim rng
 >with createobject("excel.application")
 >  .visible=true
 >  with .workbooks.add.activesheet
 >     for each rng in .range("a1:c3")
 >        rng="aaa"
 >     next
 >  end with
 >end with

 という例にしたコードと

 半平太さんご紹介の 

http://www.relief.jp/itnote/archives/018289.php

 に示されている
 「Valueプロパティを省略したときの不具合」で例に示している内容は 同じですね

 でも、これは 既定のプロパティのバグ(不具合)ではなく 例のようなコードが招くバグです。
 原因は はっきりしています。

 For Each rng in .range("a1:c3")

 For Each 文で扱う コレクション(配列)の要素を Variant型で受けてしまっていることに起因します。

 上記のVBSコードを 以下のようにするとわかりますが
 dim rng
 with createobject("excel.application")
   .visible=true
   with .workbooks.add.activesheet
      for each rng in .range("a1:c3")
         msgbox typename(rng) 
         rng="aaa"
         msgbox typename(rng) 
      next
   end with
 end with

 Range型だった 変数rng は、 rng="aaa" コードの実行直後には  String型に変わっています。
 良く考えれば 当たり前ですよね

 Variant型の変数は どんな型にも化けるのですから、rng="aaa" これを実行すれば rngは 文字列型に
 変わってしまい もはや このコードを実行前のRange型とは 関係がなくなります。

 よって、セルには 何も表示されないのです。

 既定のプロパティを省略することの曖昧さが起こす錯覚にすぎません。

 前回投稿の
 >でも、プロパティを省略していると、つい錯覚しそうになりませんか?

 という事の延長線上にある話だと解釈してください。

 省略することのデメリットの一例として 考慮してください。

(ichinose) 2015/02/26(木) 06:33


 >Valuesプロパティの設定が懐が広く オブジェクト 値の配列 セルアドレスを表す文字列と
 >受けているのでしょうね!!

 私のXL2010とXL2013のヘルプでは、Series.Valuesは、こう記述されています。
  >このプロパティの値は、ワークシートのセル範囲、または定数値の配列になります。

 セル範囲とは、(結果から判断すると)Rangeオブジェクトに限ってのものではなさそうです。

 いずれにしても、関数の引数に入れる場合は、
 Rangeオブジェクトのプロパティを省略していいかどうか、
 などと議論するのは無意味のようです。

 インストラクターのネタ帳を引用したため、却ってミスリードされてしまった感がありますが、
 インストラクターさんの凄いところは、分からないことを「分からない」と云ったところです。

 つまり、この部分です。
 >RangeオブジェクトでValueプロパティを指定しないときにValueプロパティとして扱われるのは、
 >オブジェクトブラウザから明確な仕様として読み取ることはできません。
 >経験則としてValueプロパティとして扱われることがもちろん多いですが。

 いままで「Valueプロパティを省略しても何故Value値が出てくるの?」と云う、
 どこの掲示板でも一度は出た質問に対して、そう謙虚に答えた人はいません。

 経験則をそのまま仕様として受け入れ「でもValueプロパティは書こうね」なんてすれ違いなことを言うか、
 既定プロパティだか、標準プロパティだか、嘘の理屈で納得させた人だけです。

 インストラクターさんの情けないところは
  >コードも読みやすくなるんだから、書きましょうよ.Valueくらい
 と不徹底なことを言ったことです。

 コードが読み易くなろうが、ならなかろうが、書かなきゃダメですよ。
 喩えそれが100個あっても、1000個あっても、と言うべきだった。

(半平太) 2015/02/26(木) 12:19


 >セル範囲とは、(結果から判断すると)Rangeオブジェクトに限ってのものではなさそうです。
https://msdn.microsoft.com/ja-jp/library/office/ff196721.aspx

 なんてのがありますから、仕様を統一したのかもしれません。

 >Rangeオブジェクトのプロパティを省略していいかどうか、
 >などと議論するのは無意味のようです。
 同感です。これはValuesプロパティの特徴を調べるということでよいですよ!!

 >インストラクターのネタ帳を引用したため、却ってミスリードされてしまった感がありますが、
 リンク先にあった事例をみたら 同じ意味のコードだったので ちょっと気になっただけです。

 >インストラクターさんの凄いところは、分からないことを「分からない」と云ったところです。
 ここを仰りたかったという事は理解しているつもりです。

 以前の議論で
[[20101209011132]]

 _Defaultがオブジェクトブラウザで 既定のプロパティであることは書かれています。

 Sub test1()
    Range("a1").Value = 123
    MsgBox TypeName(Range("a1").[_Default](1))
    MsgBox TypeName(Range("a1").[_Default])
 End Sub
 Sub test2()
    Range("a1").Value = "ichinose"
    MsgBox TypeName(Range("a1").[_Default](1))
    MsgBox TypeName(Range("a1").[_Default])
 End Sub

 このような結果から 明らかに 既定のプロパティに引数を付けたときと 付けいないときでは 結果が違っています。

 この引数を省略した時の値が Valueプロパティと同じなので 隠れているのは Valueプロパティだと
 推測できる。

 が、RangeオブジェクトのValueプロパティが 既定のプロパティだとは証明(断定)できない

 既定のプロパティを 隠しメンバの _Defaultとした事は、良い案だと思っています。

 将来 また 既定のプロパティをもう一つ 増やしたい時は 引数や 引数の型によって
 作成が可能な道を残していますからね。

 ActiveXControlの Textbox等は Valueプロパティが既定のプロパティだと
 オブジェクトブラウザでは 表示されます。
 これは、Rangeオブジェクトのような発想がなかったのか Textboxには、Value以外に既定のプロパティは
 考えられないと断定し、今日に至っているのかは わかりませんが、拡張性という意味では、
 Rangeオブジェクトのそれの方が柔軟性がある と思います。

 表現の仕方をとらえるのは、あいまいなので好きではないですが、

 Item プロパティは、Range オブジェクトに対する既定のプロパティである

 とHelpには載っています。

 AciveXControlの CommandButtonのValueプロパティのそれでは、

 コマンド ボタン (CommandButton) コントロールの既定のプロパティは、Value プロパティです

 となっています。

 Rangeオブジェクトの既定のプロパティは 一つでないから このように逆の表現をしている とも取れます。

 RangeオブジェクトのValueプロパティが 既定のプロパティだとは証明(断定)できない

 では、これを疑う反例があるのか?  

 でも、Textboxの既定のプロパティValueを省略した時と 付けたときの結果が違う例は、
 私は、見たことがあります。
[[20101203205934]] ここの Textboxを例にしたコードがそれです。
 が、Valueプロパティは、 Textboxの既定のプロパティだと
 オブジェクトブラウザでは、表示されます。

 Excel開発プロジェクトは、優秀だから この反例を承知していて、敢えてRangeのValueプロパティについて 言及しないのか?

 胡散臭さは、MS社が この事について パブリッシュしないことが大きいと思います。

  

 
(ichinose) 2015/02/27(金) 08:31


 > _Defaultがオブジェクトブラウザで 既定のプロパティであることは書かれています。
 これについては、以前教えて頂きました。m(__)m

 > が、RangeオブジェクトのValueプロパティが 既定のプロパティだとは証明(断定)できない
 上で「_Default」が既定のプロパティと云うことになりましたので、
 ValueプロパティがRangeオブジェクトの既定のプロパティになることはないと思います。
 なので、呼び方を変えたいと思うのですけど。。

 OfficeTanakaさんが「標準プロパティ」と云う(意図的だか、誤記だか分かりませんが)概念を使っていますので、
 Valueプロパティの方は、取りあえず「標準プロパティ(の可能性)」と称する事にしたいと思います。

 ・・・なんか、おかしな事を言ってたらご指摘ください。

 >RangeオブジェクトのValueプロパティが 既定のプロパティだとは証明(断定)できない
 >では、これを疑う反例があるのか?  
 反証を出すのは無理なのではないか、と感じています。

 Value値が出てくれば、ほら同じだろと云われ、
 Value値と違えば、それは途中で加工されているからだと云われてしまいます。

 先の、kanabunさんが挙げてくれたMatchの例では、
 第1引数がRangeオブジェクトの場合、Value2プロパティとなるが、
 加工されたと云われてしまう例になるでしょう。

 これは、関数に留まらず、ichnoseさんがTextBoxの例で、
 既定のプロパティとは違う扱いがなされている実例とされたケースでも、
 オブジェクトで渡したりしたら、単なる既定のプロパティを使った処理とは
 違う加工がなされるのだ、と云われるかもです。

 左辺のRangeオブジェクトのValueプロパティプロシージャ(?)の処理において、
 入り口がオブジェクトの場合と値データの場合に分かれており、
 オブジェクトの場合は、TextBoxのValueプロパティのデータ型を判定してから処理される一方、
 単なる既定プロパティで入ってきた場合は、データ型への配慮がなされずに処理される可能性があります。

 Sub objectBaseTest()
     Range("D1:E2").Clear

     Range("E1").Value = "'123"
     Range("D1").Value = Range("E1").Value
     MsgBox TypeName(Range("D1").Value)

     Range("D2").Value = Range("E1")
     MsgBox TypeName(Range("D2").Value)
 End Sub

 結局、私は、標準プロパティになるとハッキリ云えるようなケースは、
 左辺が値変数の時くらいしか言えないのでは、と思っています。

 しかし、妙ですね。
 標準のプロパティになる保証があるなら、冗長な.Valueプロパティは書かない方針の私が
 保証がないから全部書くしかないかなぁと諦めかけているのに、

 全部書くべきだと云うichinoseさんが、事例分析においては、
 標準のプロパティになるハズではないかと考えているなんて・・・(でしょう?)

(半平太) 2015/02/27(金) 21:33


 >上で「_Default」が既定のプロパティと云うことになりましたので、
 itemプロパティは、既定のプロパティです。記述されていますよね。
 内部仕様では、_Defaultが既定のプロパティですが このプロパティ隠しているので 

 外部仕様的には itemが既定のプロパティ、で引数がない時の既定のプロパティがValue 

 もっともValueについては、MS社からの記述は見つかりませんが・・・。

 まあ、名称は区別するために 標準プロパティでよいです。

 ところで 大変な間違いでした。

 Textboxの例は、取り下げます。私が勘違いしていました。

 range("a1").value=textbox1は、 Textboxというオブジェクトが引数として送られると
 中で規定のプロパティを取り出していると思っていてそれでも何らかの理由で結果が違う と思っていましたが、

 半平太さんのご指摘が正しいです。

 さんざん、Letで送られるのは プロパティがなければオブジェクトですと自分で言っておきながら 
 勘違いです。

 そうなると、やっぱり
 >胡散臭さは、MS社が この事について パブリッシュしないことが大きいと思います。

 となります。

 >しかし、妙ですね。

 これは、私も感じていました。鶏が先か 卵が先か という話で

 A君 「鶏」
 B君 「卵」
 A君 「鶏」
 B君 「卵」
 ・
 ・
 A君 「卵」
 B君 「鶏・・・、あれ?」

 というのを 思い出しました。

 Range("a1").value=range("a2")    
 これは、Valueプロパティに オブジェクトRange("a2")を引数にしているのですから
 オブジェクトを送ることを許しているのであれば、その処理や機能を理解して指定するならOK

 Range("a1").value=range("a2").value これは、Valueプロパティに 値を引数にしているのですから Valueプロパティは値(配列)を指定することを許しているのであれば その処理や機能を理解して指定するならOK

 でも

 range("a1")=range("a2")  これは、 NG

 私からすれば、 Valueプロパティは 既定のプロパティでも 記述した方がわかりやすいから きちんと記述する という理由で 

 range("a1").value=range("a2")   又は
 range("a1").value=range("a2").value

 となりますし、

 半平太さんからすると、Valueは、既定のプロパティとは言えないから、Valueプロパティに代入するなら

 range("a1").value=range("a2")   又は
 range("a1").value=range("a2").value

 と記述しなければならない

 今回は これで良いではないですか?

   

(ichinose) 2015/02/27(金) 23:28


 書かなくちゃいけない理由が二つになった??
 ディスカッションの講義では、自分の主張と反対の主張を
 証明することでしょうから
 大学の講義受けてる気分で眺めてました!

(稲葉) 2015/02/28(土) 06:20


 >今回は これで良いではないですか?
 と、言いましたが・・。

 >Range("a1").value=range("a2")    
 >これは、Valueプロパティに オブジェクトRange("a2")を引数にしているのですから
 >オブジェクトを送ることを許しているのであれば、その処理や機能を理解して指定するならOK

 記述すれば、確かにこの通りなのです。Valueプロパティにオブジェクトを送る結果を
 十分に精査して使うなら OKなのですが・・・。

 前回の半平太さんが立てたスレッドの

[[20101203205934]]

 この辺りを考慮すると、

 Sub test3()
    Range("a2:c2").Value = Array(1, 2, 3)
    Range("a1:c1").Value = Range("a2:c2")
 End Sub

 このA1:C1が Emptyになる という結果。

 この結果を考慮すると、個々のプロパティでオブジェクトを送ったときと
 それ以外を送ったときの違いを認識するのは 大変ですねえ。

 Sub test4()
    Range("a2:c2").Value = Array(1, 2, 3)
    Range("a1:c1").Value = Range("a2:c2").Value
 End Sub

 仕様によっては、付けないことの機能をつかいたいという事象もあるでしょうが。

 RangeオブジェクトのValueプロパティに限って言えば、オブジェクトを指定すれば、
 左辺Valueプロティ内(Let Value)で オブジェクトの既定のプロパティを調べていることは、
 間違いなさそうです。
 オブジェクトを送ると 処理が速いのも 少しチェックが少ないことを考えると
 合点がいきます。

 これらを考慮すると、

  RangeのValueプロパティは、右辺の場合も付けておいた方が無難にも見えます。

 

 他のオブジェクトに至ってもこのような違いを全部調べていくのは大変なことですねえ!!

(ichinose) 2015/02/28(土) 09:10


 横から失礼します。
 本来のテーマから、どんどん、興味深いものにかわっていき、特に、両御大のご意見を拝読するたびに
 ミーハーのβとしては、そうだよ、そうだよ! そしてまた、あぁ、そうか、じゃぁ、そうなんだ!
 勉強になります。

 とりあえずの現在のβとしては、何を処理しているのか、明示的に記述されていたほうが安心なので
 右辺、左辺ともに Value をつけていますし、今後もそうでしょう。1年後はわかりませんけど。

 深いところではいろいろあるんだと思いますが、どちらかというと、処理効率より、生産性(開発生産、可読性、保守性 等々)を
 高めることがTCOとして見ると、現在のβの感性にあっています。

 要は、自分、あるいは他人が(その多くが)、どの書き方がわかりやすいか、安心するか、そういった尺度で
 対処していこうと思ってますし、そうしていくと思います。

(β) 2015/02/28(土) 16:06


 ちょっと戻りますが...
  SeriesCollection(n).Values プロパティについて(昔と今)
 説明のため、マナさんの検証コードをお借りします。
 (1)
 >            .SeriesCollection(1).Values = r.Columns(1)
 系列1の.Valuesプロパティに シートのセル範囲を(オブジェクトを)設定しています。
 これを 手動で、グラフの系列1を選択して数式バーを見ますと、そこには
  =SERIES(,,Sheet1!$A$460047:$A$460146,1)
 のような式が表示されています。

 (2)いっぽう、
 >            .SeriesCollection(1).Values = r.Columns(1).Value
 と書いたとき、グラフの系列1を選択して数式バーを見ますと、そこには

 =SERIES(,,{0.558912864186267,0.765971379914785,0.0488925876211795,0.504350717413772,
 0.877398660668191,0.852676920789457,0.775678141333508,0.0762620656802114,0.0780109566437234,
 0.249441273022383,0.288563427219643,0.441816314967491,0.984248528858991,0.270421797045104,
 0.800408131261148,0.0265269641894303,0.0959446200492785,0.940834291954096,0.787602729515132,
 0.916721706581497,0.984795447997316,0.202578940841009,0.38190511108482,0.442448944733956,
 0.869593937197703,0.313950357593246,0.928254901018759,0.225525966643889,0.00200250198268581,
 0.315274746519614,0.190205108776218,0.947851630743312,0.10989028502203,0.290830807327616,
 0.384920910762852,0.31158630274546,0.878561758669971,0.0482199728761893,0.0948474595368647,
 0.303133246563367,0.0264456069670616,0.0144832230614225,0.97969993656791,0.560214161520514,
 0.0657454601617695,0.473756914579057,0.286673240184987,0.76274426000676,0.429793999325543,
 0.277994934328209,0.588706092877205,0.509770263671844,0.516801385249331,0.354853011282605,
 0.665077873264611,0.243550178416388,0.314847946494981,0.973376243373438,0.523893656423545,
 0.700623942032941,0.56958806152722,0.0391725755262355,0.935408443964379,0.688419035446996,
 0.306706649927221,0.493242583758453,0.844887688188793,0.775362512841611,0.596024668828367,
 0.348310260219679,0.498278020647821,0.911654936161275,0.446660210688471,0.474947054662357,
 0.641583081760762,0.200692965845767,0.27735352324038,0.466226698725621,0.538860598587658,
 0.566955988936891,0.798914200451075,0.346233859621671,0.498893748712469,0.967102114496701,
 0.708525980345591,0.784751345751477,0.767570363682042,0.644514277924051,0.482319233238645,
 0.376322136925447,0.14748185059024,0.420891953420768,0.482368857508984,0.0362662805171338,
 0.202556731502484,0.893157309328959,0.474651510623307,0.407300327279482,0.565121658716956,
 0.621532367936842},3)

 のような、配列データが表示されます。データの要素数は【100】あります。

 「昔」は.Values プロパティで このような(大規模な?)要素数データをセットすることは不可能でした。
 「昔」というのは Excel2000の時代です。
 「そのころ」シートにデータを書き出さずに、計算した配列データを.Valuesプロパティに
 直接セットしようとすると、上のような実数値データではせいぜい20要素とか30要素とかが限界で、
 上の Excel2010 のように 100要素も 格納することなぞ、夢のまた夢、でした。

 なぜかというと、そのころの .Values (.XValues)プロパティというのは データを「カンマ区切り
 文字列」として保持していたからです。2002年にぼくが今はないさる掲示板に質問して得た回答です:

 -----(引用) 2002/03/12 質問者kanabun
 質問「(略)マクロの中で x,yデータ1系列あたり40個のデータを計算作成し,直接,散布図チャートの
     データを .xValues=Array(,,,,,,,,,,,,40個), .Values=Array(,,,,40個) と変数に格納した値を
     ()のなかに書いてデータセット使用としましたが、失敗します。
     書き方は間違ってはいないようで、個数を10個くらいに下げると成功します。
     どうして40個入らないのでしょうか? 」
 回答 「私も同じ現象で悩まされました。
     この現象はデータの個数(40個とか10個とか)ではなく、配列データを文字列(={1,2,3,4,....})で
    表したときの長さが256を超えるとエラーとなります。
    試しにVBAではなく、Excelのグラフの元データの系列の値をセル範囲ではなく、 ={1,2,3,4.....}
    と入力すると、256文字以上は入力できません。
    (中略)たぶんExcelの(どんくさい)仕様なのでしょう。
    ちなみに私は、.Values に配列をセットするのをあきらめて、セルに値を代入しその範囲をセットする     ようにしました。」
 ----(/引用)

 いつのバージョンから Excel2000までの「カンマ区切り文字列」でのデータ格納仕様が改められ、
 .Valuesプロパティを使って、要素数無制限に描画データがセット出来るようになったのか、
 詳細は知らないのですが、.Valuesプロパティといってもバージョンによって丸で別物のスペックを
 もつものがExcelのプロパティにはけっこうあります。
 .
(kanabun) 2015/02/28(土) 21:18

 私の話は、ちょっと前までは、かすかながらグラフの話に繋がっていたので、
 ヒヤヒヤしながらも続けていたのですが、今や完全に離脱してしまい、
 誰かに怒られそうなので私のレスはこれが最終です。

 稲葉さんには申し訳ないことを言ってしまいました。

 >ただ、私は人のコードに文句は付けず、自分のコードでは付けようと考えています。

 それを続けていただければ安心、かつ、敵を作らないで済みます。^^

 > 省略したと認識することが大事
 省略をしたのではなく、一般的には書き損じた思うことが大事。

 敢えてRangeオブジェクトにしたのであれば、
 その後、何が起きるか分かっていることが大事。
 (一般ユーザーには、まず分からないことである)
 
 ichinoseさんには、機会がありましたらまた教えを乞いたいと思います。 
 ありがとうございました。 m(__)m

 kanabunさんの独り言(2015/02/25 11:00)すごく助かりました。m(__)m

(半平太) 2015/02/28(土) 23:33


 > 表示するデータは、新しいものから順に数百個データ分で、
 > データが追加されるたびにグラフは新しいデータに更新される。

 グラフの自動更新を追体験してみました。

(方法1)Worksheet_Changeイベント利用自動更新

  グラフに表示するデータをA,B,C列に 100行分作成(*) しておき、
  (*) ichinose さんの Sub mk_sample1() のほうをお借りして、
   '----------------------------------------------------------- 
   Sub mk_sample10()  '新規シートに100行のダミーデータ
      On Error Resume Next
      With Range("a1:c100")
         .Formula = "=rand()"
         .Value = .Value
      End With
   End Sub

  このデータを E,F,G列にコピーして、コピーした範囲をグラフの元データ範囲
  としてあらかじめグラフを作っておく。

 当該シートのシートモジュールに以下を記述
 '-----------------------------------------------------------
 Option Explicit

 Private Sub Worksheet_Change(ByVal Target As Range)
  Const Y = 100, X = 3  'グラフの元データは 3列 ×100行範囲

  If Target.Count = X Then '新規データがA,B,Cの3列同時更新のとき
      If Target(1).Column <> 1 Then Exit Sub

      Dim r As Range
      Set r = Target(1).Offset(-Y + 1).Resize(Y, X)
      Application.EnableEvents = False
      'グラフ用SourceDataRange に最新データ(100行分)をコピー
      Range("E1").Resize(Y, X).Value = r.Value
      Range("I1").Value = Target.Row      '最終行は何行目?
      Application.EnableEvents = True
  End If
 End Sub
 '-----------------------------------------------------------
 すると、データがA,B,Cの3列に同時に更新されるたびに、上のChangeイベント
 プロシージャが動作し、グラフの元データが更新され、グラフが更新される。

(方法2)名前定義をつかって、マクロレスで自動更新

  (方法1)とは別シートで実験 →仮に「Sheet3」とする
  グラフに表示するデータをA,B,C列に 100行分作成しておき、
  コピーした範囲をグラフの元データ範囲としてグラフを作っておく。
  Ctrl+[F3]名前定義 で 系列ごとにY軸データ範囲を名前定義する。
     名前「系列A」 定義 「=OFFSET(Sheet3!$A$1,COUNTA(Sheet3!$A:$A)-100,0,100,1)」
     名前「系列B」 定義 「=OFFSET(Sheet3!$B$1,COUNTA(Sheet3!$B:$B)-100,0,100,1)」
     名前「系列C」 定義 「=OFFSET(Sheet3!$C$1,COUNTA(Sheet3!$C:$C)-100,0,100,1)」
  つぎに、グラフの「元データ」ダイアログ 「系列」タブで
     系列1を選択  Yの値[=系列A    ]と名前定義を入力
     系列2を選択  Yの値[=系列B    ]と名前定義を入力
     系列3を選択  Yの値[=系列C    ]と名前定義を入力

 データの自動更新をシミュレーションするために、 標準モジュールに 
 以下のようなデータ送信プログラムを書いて 動作チェックしてみる。
 (初めはステップ実行してイベントの連鎖など 確かめるとよい)。
 '----------------------------------------------------------標準モジュール
 Option Explicit

 Sub SendData() '0.2秒ごとに ActiveSheet のA,B,C列にデータを送る
    Dim k&
    With ActiveSheet
      For k = 1 To 100  '100回送る
          .Cells(.Rows.Count, 1).End(xlUp).Offset(1).Resize(, 3).Value _
              = Array(Rnd(), Rnd(), Rnd())
          DoEvents
          Application.Wait [Now()+"0:00:00.2"]
      Next
    End With
 End Sub
 .
(kanabun) 2015/03/01(日) 11:37

 動的「名前」定義を使って動的にデータ元範囲の「実体」を更新していく方法は
 マクロでChangeイベント時に更新範囲を グラフ用元データ範囲にコピーする方法に比べ、
 マクロなしで済むので 簡単で、たぶん動作も軽いのではと思うのですが、
 OFFSET関数を使った範囲名は グラフの系列ごとに セットする必要があります。
 今回のような 連続するセル範囲が3系列の元データ範囲であれば、
 この3系列全体を動的名前定義した範囲 

   名前「元データ範囲」 定義 「=OFFSET(Sheet3!$A$1,COUNTA(Sheet3!$A:$A)-100,0,100,3)」

 をグラフに与えるだけで、やはりマクロレスで自動更新できそうなのに... と、
 しばらくあがいてみましたが、現行バージョンでは やっぱり無理なようですね
http://okwave.jp/qa/q4939609.html
.
(kanabun) 2015/03/01(日) 14:24

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.