読者です 読者をやめる 読者になる 読者になる

Select / Activateメソッドの極小ハマり

状況

ワークシート

f:id:akashi_keirin:20170315232338j:plain

こんな風にシートを準備して、

f:id:akashi_keirin:20170315232345j:plain

それぞれのシートはこんな風にカレンダーにした。

クラスモジュールのコード

「オブジェクト名」は「DaySelector」にしている。

Option Explicit
'フィールド
Private startCell_ As Range
Private endCell_ As Range
Private startTime_ As Date
Private endTime_ As Date
'アクセサ
Public Property Get startCell() As Range
  Set startCell = startCell_
End Property
Public Property Get endCell() As Range
  Set endCell = endCell_
End Property
Public Property Get startTime() As Date
  startTime = startTime_
End Property
Public Property Get endTime() As Date
  endTime = endTime_
End Property
'コンストラクタ
Private Sub Class_Initialize()
  Dim m As Integer
  Dim d As Integer
  m = Month(Now())
  d = Day(Now())
  Call setStartCell(m, d)
  Set endCell_ = startCell_.Offset(0, 1)
End Sub
Private Sub setStartCell(ByVal m As Integer, ByVal d As Integer)
  With ThisWorkbook
    If m > 3 And m < 13 Then
      With .Worksheets(m - 3)
        Set startCell_ = .Range("C" & d + 1)
      End With
    Else
      With .Worksheets(m + 9)
        Set startCell_ = .Range("C" & d + 1)
      End With
    End If
  End With
End Sub

'メソッド
Public Sub writeStartTime()
  If startCell_.Value = "" Then
    startCell_.Value = Format(Now(), "hh:mm")
    MsgBox "始業時刻を書き込みました。" & vbCrLf & _
           "修正する場合は、セルに時刻を直接入力してください。"
  End If
  startCell_.Select
End Sub
Public Sub writeEndTime()
  Dim res As Integer
  res = MsgBox(PROMPT:="終業時刻を書き込みますか?", Buttons:=vbYesNo)
  If res = vbYes Then
    endCell_.Value = Format(Now(), "hh:mm")
  End If
End Sub

標準モジュールのコード

Public ds As DaySelector

Workbookモジュールのコード

Option Explicit
Private Sub Workbook_Open()
  Set ds = New DaySelector
  ds.writeStartTime
End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)
  Set ds = New DaySelector
  ds.writeEndTime
End Sub

実行結果

f:id:akashi_keirin:20170315232350j:plain

f:id:akashi_keirin:20170315232359j:plain

ここまではうまいこと行くのだが……。

f:id:akashi_keirin:20170315232354j:plain

こんなエラーが出てしまう。

エラーの原因

エラーメッセージから、DaySelectorクラスのwriteStartTimeメソッドに問題があることはすぐに分かったが、処理があまりにも単純なので、かなりの時間、何が悪いのか分からなかった。

結局、シートがアクティブでないのに、そのシートのセルを選択/アクティベートしようとしたためにエラーになった、というだけのことだった。

コードの修正

startCell_.Select

を、

startCell_.Parent.Activate
startCell_.Select

にするだけ。たったこれだけ。

やっぱり、「Parent」プロパティは便利だ。

それはともかく、結構初歩的なところでハマることもある、というお話でした。

@akashi_keirin on Twitter