半角チルダ

ExcelVBA、その他。
覚え書きや、補足資料などのスクラップブック。
end-u(1037781)

■FindNext メソッドの使用例

2009-02-16 22:50:00 | 気をつけたほうがいいこと
既にメジャーな話なのですが、VBAヘルプの『FindNext メソッドの使用例』によろしくない例示があります。
以下はExcel2000でのヘルプ抜粋です。
FindNext メソッドの使用例

次の使用例はセル範囲 A1:A500 で、値に 2 が含まれていて灰色表示のセルを検索します。

With Worksheets(1).Range("a1:a500")
  Set c = .Find(2, LookIn:=xlValues)
  If Not c Is Nothing Then
    firstAddress = c.Address
    Do
      c.Interior.Pattern = xlPatternGray50
      Set c = .FindNext(c)
    Loop While Not c Is Nothing And c.Address <> firstAddress
  End If
End With


1)FindNextのLoop終了条件に『Not c Is Nothing』は不要。(※)

検索でヒットしたセルをRange変数 c にセットして FindNextメソッドを実行しているのだから、通常では c がNothingになる事はなく、終了条件として考慮する必要はない(はず)です。
Findメソッドで1つのセルのみがヒットした場合でも、次にFindNextメソッドを実行した時にその元のセルがヒットするわけなので、c はNothingになる事はありません。
(検索条件である『値が 2』のセルの値を書き換える処理をLoop内で処理している場合は別です)

2)仮に『c Is Nothing』が成立した場合、『c.Address <> firstAddress』は判定できない。

というか、『c Is Nothing』の場合、Nothingな c に Addressプロパティはありえないのでエラーになります。
Excel2002のヘルプから FindNext メソッドの使用例が変更されましたが、まさにこの事例通りエラーになります。
http://msdn.microsoft.com/ja-jp/library/cc329003.aspx



また、あまり知られていない事みたいですが、前述(1)(※)には例外があります。
(実はここからが本題だったりして)
Findメソッドを実行してセットしたRange変数が、FindNext メソッドを実行した時にNothingになるケースです。
Sub test()
  Dim c As Range
  Dim firstAddress As String

  With Sheets.Add
    With .Range("A10")
      .Value = "a"
      .Resize(2).Merge
    End With
    Set c = .Cells.Find(What:="a", _
              After:=.Cells(1), _
              LookIn:=xlFormulas, _
              LookAt:=xlPart, _
              SearchOrder:=xlByRows, _
              SearchDirection:=xlNext, _
              MatchCase:=False)
    If Not c Is Nothing Then
      firstAddress = c.Address
      Do
        c.Interior.Color = vbYellow
        Set c = .Cells.FindNext(c)
        Stop
        If c Is Nothing Then Exit Do
      Loop While c.Address <> firstAddress
      Set c = Nothing
    End If
  End With
End Sub

つまり、検索条件にヒットするセルが1個のみの場合で、かつ、そのセルが縦方向の結合セルの場合、
『c Is Nothing』が発生します。

念のための対策として
>If c Is Nothing Then Exit Do
などとしておいたほうが良いかもしれません。
Comment
  • Twitterでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

■AutoFilter FilterModeでのFillRightメソッド

2009-02-04 22:00:00 | 雑記
知らなかったのは私だけかもしれませんが、FillRight メソッドを使えば
AutoFilter 抽出後の可視セルデータを --> 同状態の可視セルのみへ コピーができるのですね。
FillRight メソッドなのでコピー先は限定されますが。

▼サンプルシートを作るマクロ
Sub sample()
  With Sheets.Add
    .Range("A1:C1").Value = [{"f1","f2","f3"}]
    With .Range("B2:C10")
      .Formula = "=int(rand()*10)"
      .Value = .Value
    End With
    .Range("4:4,7:7").ClearContents
    .Range("A4,A7,A11:A12").Value = 1
    .Range("B4,B7,B11").Select
    SendKeys "~"
    Application.CommandBars.FindControl(ID:=226).Execute
    .Range("B12").Value = "end"
    .Range("A1").Select
    .Range("A1").CurrentRegion.AutoFilter Field:=1, Criteria1:=1
    .Range("B2:B12").Interior.Color = vbYellow
    .ShowAllData
  End With
End Sub

▼こんなデータができます。



▼以下、手作業です。 A列 1 でフィルタ抽出し、B列を選択します。



▼右下コーナーにカーソルを合わせて右にフィルドラッグします。



▼右へコピーされます。



▼オートフィルタを解除してみると、ちゃんと可視セルにだけコピーされています。



(確認環境は[win2000/xl2000][winXP/xl2003])


ついでですが、上記動作をマクロ記録してみると
Sub Macro1()
'
' Macro1 Macro
' マクロ記録日 : 2009/2/4 ユーザー名 : no name
'

'
  Selection.AutoFilter Field:=1, Criteria1:="1"
  Range("B4:B12").Select
  Selection.FillRight
End Sub

これをそのまま実行しても何も起きません。

Range("B4:C12").Select

と、Select範囲を変えれば機能します。
つまり、手動操作と同じ結果を記録マクロで得るなら B4:C12セルを選択して[ Ctrl ]キー+[ r ]キー同時押し。
...のほうが良さそうです。

もうちょっと使えそうな感じで書いてみると以下。
Sub test()
  With ActiveSheet
    If .AutoFilterMode And .FilterMode Then
      With .AutoFilter.Range.Columns(2)
        If WorksheetFunction.Subtotal(3, .Cells) > 1 Then
          Intersect(.Cells, .Offset(1)).Resize(, 2).FillRight
        End If
      End With
    End If
  End With
End Sub




(2009.02.05追記)
...微妙に勘違いしてるような?

上記の手動操作の例が悪いですね。
最初から
>B4:C12セルを選択して[ Ctrl ]キー+[ r ]キー同時押し。
の例にしておけば良かったです。
同じフィルドラッグ操作でも、 FilterMode によって実行されるメソッドが違うのでした。
単純に、『オートフィルタ抽出状態での[右方向へのコピー]は可視セルだけが対象になる。』という話な...だけ?

#どうも充電が足りなかったようです XD
Comment
  • Twitterでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする