プロが教えるわが家の防犯対策術!

VBAにて、ユーザーフォーム上のテキストボックスに初期値として今日の日付が入力されており、さらにそれを任意で変更するというマクロを作成しようとしています。

'テキストボックス2に初期値として今日の日付を入力
Private Sub UserForm_Initialize()
TextBox2.Text = Format$(Date, "yyyy/mm/dd")
End Sub

'テキストボックス2に入力された日付はdenpyoudateという変数に格納される
Private Sub TextBox2_Change()
denpyoudate = UserForm2.TextBox2.Value
End Sub

入力された日付を変数として利用したいので、上記のようなコードにしたのですが、実際に初期値である今日の日付を編集すると「型が一致しません」というエラーが出てしまいます。
このエラーを回避し、テキストボックスに入力された日付を変数として使用するにはどうすればよいでしょうか?

A 回答 (4件)

変数DenpyouDateがDate型でもVariant型でも


  DenpyouDate=TextBox2.Value
とする前に、TextBox2.ValueがDate型なのかチェックの必要があります。

どのイベントでチェックするかは場合によるでしょうが、
BeforUpDateイベントでやれば、TextBox2の値が日付でなかった場合
引数CanceをTrueにすることによりTextBox2の入力を取り消すことができます。
この取り消すと言う意味は他のイベントを使ってみれば分かります。

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

  Dim DenpyouDate As Date (or As Variant)

'------------------------------------------------
Private Sub TextBox2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)

  If IsDate(TextBox2.Value) Then
    DenpyouDate = TextBox2.Value
  Else
   TextBox2.Value = ""
   Cancel = True
  End If

End Sub
'------------------------------------------

● TextBox2.Value = ""
を省いた場合もテストしてみることをお勧めします。

以上です。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
検討の結果、以下のコードを流用させていただくことにしました。

  Dim DenpyouDate As Date (or As Variant)
'------------------------------------------------
Private Sub TextBox2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)

  If IsDate(TextBox2.Value) Then
    DenpyouDate = TextBox2.Value
  Else
   TextBox2.Value = ""
   Cancel = True
   msgbox("日付が不正です")
  End If

End Sub

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

お礼日時:2009/10/27 16:42

こんにちは。



今回のUserFormのTextBox に入力する場合に、日付を正しく入れるというのは、本当は、実務レベルでは難しいのです。VBAの1年ぐらいのレベルでは、なかなか分からないのです。概ね、失敗して覚えるものです。私が、#2で書いたように、Variant 型変数にすることで、当面のエラーは消えます。ただし、その値が正しいとは限りません。後は、入力するUserさん任せです。それ以上は、入門レベルの方や基本を覚えただけの人には、それを言っても分からないようにも思いました。

こういう、私も、日付値の自動変換(キャスティング)が、さっぱり分からなかった時代があります。もともと、VBAは、米環境で、アジア式や欧州式でもありませんから、基本的な日付リテラル値は、#m/d/yyyy# スタイルが標準でした。Office やOS もバージョンがあがり、そういう点で、フレキシブルな対応するようになりました。

しかし、コードを提供する側としては、Office のVersionやロケールの違いという見えない問題を考える必要があるのです。だから、入力した日付データを検査しないでそのまま、Date型変数に代入するのは難しいのです。うまく入ったからといって、それが正しいというのは、たまたまだと解釈してよいのではないかと思います。

仮に、文字長のチェックをさせたとしても、
 2009/09/31 など、存在しない日にち
 特に、うるう年などで、2008/02/30 は存在するのに、2009/02/30 は存在しません。したがって、ダイレクトに入れたら、実行時エラーが発生します。私は、それを、On Error Resume Next などのエラートラップで処理する方法を好みません。本来、エラートラップは回避できないものに対してのみに置くべきです。これも、コーディングスタイルの一つです。

手間を省くために、文字長チェックをしない場合は、
 9/31 と入れてしまった場合は、Date 型では、日付として認識してしまいます。
 3/1/9 と入れた場合は、2003年1月9日と認識します。それが当たり前のような気がしているけれども、それは、本来、Office のバージョン、日本語OSやロケールの設定によるものだと思います。

また、もしも、month/day と入力されたときは、その年、Year(Date) と同じでなくてはなりませんが、間違った入力すると、まったく別の年になっています。そういうチェックも必要です。
 
もちろん、年/月/日の位置をガッチリ決めさせる方法がないわけではありません。それは、DTPicker などを使うなら、確実な日付値が得られますから、

例:
Private Sub DTPicker1_KeyDown(KeyCode As Integer, ByVal Shift As Integer)
Dim myDate As Date
 If KeyCode <> 13 Then Exit Sub
 myDate = DTPicker1.Value
 TextBox1.Text = Format$(myDate, "yyyy/mm/dd")
End Sub

こういう方法も可能です。(Office XP以上だったと思いますが、標準的に、その他のコントロールに"Microsoft Date and Time Picker Control 6.0"として入っています。)

当面、こちらは、Excel 2003 +Win XP で、ロケールは日本で、日付値は日本型の標準にしてありますが、環境が違うことを想定すると、まだ足りないものがあるかもしれません。本来は、データの予測値というものを前提に置かなくてはならないのです。ただ、そこまでは、なかなか難しいのです。

今回のご質問者さんは、「denpyoudate = "伝票日"」ですから、ある程度の年の予測範囲は決まってくるのですが、たとえば、オールラウンドの年代の生年月日の入力なども、問題になってきます。だから、一概に、こういうコードだとは決められないのです。私は、単に、コーディング・スタイルとしてのTextBox の値を、直接、Date 型の変数に入れないということで、当面はよいのかと思っています。

サンプルマクロ
'-------------------------------------------
'UserForm モジュール
'UserForm
'TextBox 2個
'-------------------------------------------

Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  Dim myDate As Date
  Dim buf As Variant
  If KeyCode <> 13 Then Exit Sub
  buf = TextBox1.Text
  buf = StrConv(buf, vbNarrow)
  
'  '文字数をカウントする。
'  If Len(buf) - Len(Replace(buf, "/", "")) <> 2 Or Len(buf) <> 10 Then
'    MsgBox "yyyy/mm/dd で入力してください。", vbExclamation
'    KeyCode = 0
'    Exit Sub
'  End If
  
  '日付が正しく入っているかチェック
  If IsDate(buf) = False Then
    MsgBox "日付値ではありません。", vbCritical
    KeyCode = 0 '次のコントロールに行かない
    Exit Sub
  ElseIf Abs(Year(Date) - Year(buf)) > 10 Then '10年以上のブレ
    If DateChecker(buf) = False Then
      KeyCode = 0
      Exit Sub
    End If
  End If
  myDate = CDate(buf)
  MsgBox myDate
  TextBox2.Value = Format$(myDate, "GGGE年m月d日")
End Sub

Private Function DateChecker(ByVal buf As String) As Boolean
'正しく日付が入力されているかメッセージを出す
 If MsgBox(Format$(buf, "yyyy/mm/dd") & "日付は正しいでしょうか?", _
     vbQuestion + vbYesNo + vbDefaultButton2) = vbNo Then
   DateChecker = False
 Else
   DateChecker = True
 End If
End Function

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

なお、私の記憶では、この日付判定には、通常の入力には支障はありませんが、少なくとも、Office 2003 までにバグが存在していたようにも思います。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
検討の結果、以下のコードを流用させていただくことにしました。

  Dim DenpyouDate As Date (or As Variant)
'------------------------------------------------
Private Sub TextBox2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)

  If IsDate(TextBox2.Value) Then
    DenpyouDate = TextBox2.Value
  Else
   TextBox2.Value = ""
   Cancel = True
   msgbox("日付が不正です")
  End If

End Sub

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

お礼日時:2009/10/27 16:41

こんばんは。



>denpyoudateという変数に格納される

質問には、どこにも変数の宣言が書かれていませんが、一般的に、UserForm のTextBox では、その変数に日付を入れるにしても、変数を節約して使う場合は、Variant 型にします。また、日付として認識できる形になっていれば、String 型でも良いのです。Date 型にしたら、Date型の値しか入れられません。型が違うというエラーが出てきてしまいます。もし、念を入れるなら、出力の際に日付になっているか、IsDate でチェックをします。

最初から、入力を日付型と決め付けないことで作るのは、コーディング・スタイルです。人は、誰でも間違いをするから入れ物自体はフリーにして起きます。ここで、On Error トラップはうまくありません。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
検討の結果、以下のコードを流用させていただくことにしました。

  Dim DenpyouDate As Date (or As Variant)
'------------------------------------------------
Private Sub TextBox2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)

  If IsDate(TextBox2.Value) Then
    DenpyouDate = TextBox2.Value
  Else
   TextBox2.Value = ""
   Cancel = True
   msgbox("日付が不正です")
  End If

End Sub

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

お礼日時:2009/10/27 16:42

denpyoudate As Date で宣言してるのだと思いますが



TextBox2_Change()ではなくて

Private Sub TextBox2_AfterUpdate()
denpyoudate = UserForm2.TextBox2.Value
End Sub

にしてください。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
検討の結果、以下のコードを流用させていただくことにしました。

  Dim DenpyouDate As Date (or As Variant)
'------------------------------------------------
Private Sub TextBox2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)

  If IsDate(TextBox2.Value) Then
    DenpyouDate = TextBox2.Value
  Else
   TextBox2.Value = ""
   Cancel = True
   msgbox("日付が不正です")
  End If

End Sub

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

お礼日時:2009/10/27 16:42

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています