• ベストアンサー

VBA テキストボックスで日付を変更するとエラー

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

質問者が選んだベストアンサー

  • ベストアンサー
  • myRange
  • ベストアンサー率71% (339/472)
回答No.3

変数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 = "" を省いた場合もテストしてみることをお勧めします。 以上です。

kentaroror
質問者

お礼

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

その他の回答 (3)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.4

こんにちは。 今回の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 までにバグが存在していたようにも思います。

kentaroror
質問者

お礼

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

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.2

こんばんは。 >denpyoudateという変数に格納される 質問には、どこにも変数の宣言が書かれていませんが、一般的に、UserForm のTextBox では、その変数に日付を入れるにしても、変数を節約して使う場合は、Variant 型にします。また、日付として認識できる形になっていれば、String 型でも良いのです。Date 型にしたら、Date型の値しか入れられません。型が違うというエラーが出てきてしまいます。もし、念を入れるなら、出力の際に日付になっているか、IsDate でチェックをします。 最初から、入力を日付型と決め付けないことで作るのは、コーディング・スタイルです。人は、誰でも間違いをするから入れ物自体はフリーにして起きます。ここで、On Error トラップはうまくありません。

kentaroror
質問者

お礼

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

  • kmetu
  • ベストアンサー率41% (562/1346)
回答No.1

denpyoudate As Date で宣言してるのだと思いますが TextBox2_Change()ではなくて Private Sub TextBox2_AfterUpdate() denpyoudate = UserForm2.TextBox2.Value End Sub にしてください。

kentaroror
質問者

お礼

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

関連するQ&A