• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:EXCEL VBAのコンボボックスで日だけを表示する方法)

EXCEL VBAのコンボボックスで日だけを表示する方法

このQ&Aのポイント
  • EXCELのVBAを使って経費の打ち込みをするマクロを作っています。その中で、コンボボックスで日付を選択するようにしましたが、日だけを表示する方法がわかりません。
  • セルの日付の入力形式は「2008/10/1」で、表示形式を「ユーザー定義で d (日だけ表示)」に設定しています。しかし、コンボボックスで選択して表示する際には日だけを正しく表示できません。
  • 「ComboBox1 = Format(ComboBox1, "d")」とすると、コンボボックス内で数字がちらちらしてランダムに表示されてしまいます。一方、「ComboBox1 = Format(ComboBox1, "m月d日")」とすると、きちんと「10月1日」と表示されます。日だけを表示する方法を教えてください。

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

  • ベストアンサー
  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.5

こんにちは、#4です。 ご丁寧なレスをどうも。 えーと、、、 ComboBox から シリアル値を返す必要はないようですね。 〉別解2ですが、5行だとうまくいくのですが、知識不足で、一月分の31行にするときにどこを変更すればよいか分からず31行では試せませんでした… 〉この方法も面白いので試してみたいと思うのですが。 〉ちなみに、表示される日付は2008/9/1の形から9月1日等の表示に変えることができるのでしょうか? "一月分の31行"ということは、 日付型の値で、「日にちのみ」が表示されたセルが、 月の初め(1日)から末日まで、連続(欠落なく)して A5:A35(または、A5:A32、A5:A34)の範囲にある、 ということですよね? ◆別解2、改、 ComboBox1 のリストを2列にして、 選択するリストの表示は「m 月 d 日」、 選択後の.Value(.Text)は「日にちのみ」にする (※シリアル値が必要な場合は、合成することになります) (一応、締め日がズレても[26日から翌25日とか]対応する筈です) Private Sub UserForm_Initialize() Dim vA Dim i As Integer Dim dpm ' ' 当月の日数を求める dpm = Worksheets("Sheet1").Range("A5").Value dpm = Day(DateSerial(Year(dpm), Month(dpm) + 1, 1) - 1) ' ' A5から下へ当月の日数分の範囲の値をバリアント型の変数vAに格納(内部的にDate型)  vA = Worksheets("Sheet1").Range("A5:A" & dpm + 4).Value ' ' vAを一括で String型の「m 月 d 日」に変換(ワークシート関数のTEXTを使用)  vA = Application.Text(vA, "m"" 月 ""d"" 日""") ReDim Preserve vA(1 To dpm, 1 To 2) For i = 1 To dpm  vA(i, 2) = Day(vA(i, 1)) ' ' vA(i, 2) = i ' でいいのかも?  Next i ComboBox1.List = vA ComboBox1.TextColumn = 2 End Sub 一応、お尋ねの答えとしては、上のようになります。 (A列に誤(未)入力がある場合をケアしていません。) 1ヶ月分の日付を文字列にしたもの(「日にちのみ」と「m 月 d 日」)をリストにするのなら、 セル範囲にある日付を追いかけなくてもいいような気もしますね(^^;)。 ◆別解2、改、改、 わざわざ書くほどでもありませんけど、、、 (こちらは、1日から末日、専用) Private Sub UserForm_Initialize() Dim dpm Dim m As Long Dim vA Dim i As Integer dpm = Worksheets("Sheet1").Range("A5").Value m = Month(dpm) dpm = Day(DateSerial(Year(dpm), m + 1, 1) - 1) ReDim vA(1 To dpm, 1 To 2) For i = 1 To dpm vA(i, 1) = m & " 月 " & i & " 日 " vA(i, 2) = i Next i ComboBox1.List = vA ComboBox1.TextColumn = 2 End Sub それでは、また

参考URL:
http://www.clayhouse.jp/array/array.htm
hiro_ele
質問者

お礼

詳しく教えてくださり感謝します。 dpm = Day(DateSerial(Year(dpm), Month(dpm) + 1, 1) - 1) で、マクロを使ってその月の日数をもとめることができるんですね。 今までマクロを使っていないときは29日~31日のセルを関数で =IF(DAY(A32+1)<>29,"",A32+1) =IF(DAY(A32+2)<>30,"",A32+2) =IF(DAY(A32+3)<>31,"",A32+3) として、無い月はセルに表示しないようにしていました。 なのでコンボボックスで日を表示するときもセルの関数で表示しないというのをそのまま利用していましたが、マクロでその月の日数を数えれるのはいいですね。 VBAについてはまだまだ初心者なので回答していただいた内容で解読できていないところもあるので、理解できるようにもう少し勉強してみたいと思います。 ありがとうございました。

その他の回答 (4)

  • cj_mover
  • ベストアンサー率76% (292/381)
回答No.4

こんにちは ComboBoxの.Valueを変更すれば、 再び_Changeイベントが発生します。 原理的には無限ループ (無限ネスト?というか循環参照に近い状態) が起きています。 □現状を活かすとすれば、 ◆ ComboBox1_Change イベントの再帰的な呼び出し を(一度だけで)抜ける方法として、 Private Sub ComboBox1_Change() Static flg As Boolean  If Not flg Then   flg = True    With ComboBox1    .Value = Format(.Value, "d")    End With   flg = False  End If End Sub ただ、個人的には、こういう方法は選ばないと思います。 なんとなく、手数の割りに安心出来ないような気が、、、 蛇足ですが、本件に Application.EnableEvents は無関係です。 他、 □UserForm Load後の 参照元のセルの値変更を無視できるなら、 (或いは、ComboBox1 の .List をUpdateするプログラムを別に用意するとして) _Change イベントに依らない方法として、.RowSourceは指定せずに、 ◆別解1、 ComboBox1 のリストが最初から「日にちのみ」でも構わないなら、 Private Sub UserForm_Initialize() Dim vA vA = Worksheets("Sheet1").Range("A1:A5").Value vA = Application.Text(vA, "d") ComboBox1.List = vA End Sub ・ バリアント型の変数vAに、Sheet1!A1:A5 の値を配列として格納し、 ・ vAを一括で String型の「日にちのみ」に変換し(ワークシート関数のTEXTを使用)、 ・ ComboBox1 の .List プロパティーに、配列としての vA を代入。 ◆別解2、 ComboBox1 のリストを2列にして、選択するリストの表示は通常の日付、 .Valueの戻り値は「日にちのみ」にする方法として、 リストの1列目は年月日、2列目は「日にちのみ」にしておく。 Private Sub UserForm_Initialize() Dim vA Dim i As Integer vA = Worksheets("Sheet1").Range("A1:A5").Value ReDim Preserve vA(1 To 5, 1 To 2) For i = 1 To 5 vA(i, 2) = Day(vA(i, 1)) Next ComboBox1.List = vA ComboBox1.TextColumn = 2 End Sub ・ バリアント型の変数vAに、Sheet1!A1:A5 の値を配列として格納し、 ・ vAの(値を変えずに)サイズを2列に変更して、 ・ vAの2列めに「日にちのみ」を格納し、 ・ ComboBox1 の .List プロパティーに、配列としての vA を代入。 ・ .List の 2列めが .Valueになるように指定。 という方法もあります。 この(2列にした)場合は、_Change イベント内などで、 ret = ComboBox1.List(ComboBox1.ListIndex, 0) * 1 とすれば、シリアル値に戻すこともできます(この場合はVal関数は難あり)。 □実行時の手数を減らす意味では、 UserForm_Initialize は ご提示(.RowSource)のままで、 ◆ComboBox(または ListBox)に 「日にちのみ」のリストを表示させて、  _Changeイベントから  表示用に隣接させた TestBox(または Label)の .Value(.Caption)を  操作する手も考えられるでしょうか。(同時にListBoxを非表示にするなど) (Controlが増えることに若干抵抗はあるけれど) .RowSource を指定する場合は、参照される側のセル(日付型)の 「表示」(.Listへ) と 「値」 (,Valueへ) のそれぞれが反映されるようで、 その点の混乱を解消するには、.Listプロパティーに 「値」(配列)を直接指定する必要があるようですね。 この混乱のことを問題にされているように受けての回答でした。 一番すっきりさせる方法としては、参照される側のセルの値を 整数型にしておく方法かとも思うのですが、、、

hiro_ele
質問者

お礼

ご回答ありがとうございます! おっしゃる通りコンボボックスで無限ループにはまっているようでした。 ComboBox1_Change()のところを、「一度だけで抜ける方法」で解決することができました。 別解1でもうまくいきました。 今のところ別解1を採用させていただこうかと思います。 別解2ですが、5行だとうまくいくのですが、知識不足で、一月分の31行にするときにどこを変更すればよいか分からず31行では試せませんでした… この方法も面白いので試してみたいと思うのですが。 ちなみに、表示される日付は2008/9/1の形から9月1日等の表示に変えることができるのでしょうか? よければおしえてください。 cj_moverさんの回答でうまく解決できそうです。 ありがとうございました。 このあとさらに付け加えていこうと思っています。 選択したセルに数値が入っている場合は、その数値にテキストボックスの数値を加算するようにしたいと思っています。 また分からないときには新しい質問で質問させてください。 よろしくお願いいたします。

  • pkh4989
  • ベストアンサー率62% (162/260)
回答No.3

こんにちは。 以下のように変更してみてください。 Dim eFlg    As Boolean Private Sub UserForm_Initialize()   With ComboBox1     .RowSource = "sheet1!A1:A5"         '日付のセル   End With End Sub Private Sub ComboBox1_Change() If eFlg = False Then     eFlg = True     ComboBox1 = Format(ComboBox1, "d")     'ここでイベントが発生するので                           '1回のみ処理出来るように制御が必要     eFlg = False   End If Application.EnableEvents = True End Sub '又は Private Sub ComboBox1_Click()   ComboBox1 = Format(ComboBox1, "d") End Sub

hiro_ele
質問者

お礼

ご回答ありがとうございます! 回答してくださった内容を使用してみましたが残念ながら最初と同じ結果になってしまいました。 コンボボックスのマクロが何度も働いているようです。 私の理解不足かもしれませんが今回この方法はうまくいきませんでした…。 しかし、貴重な回答をありがとうございました。

  • imogasi
  • ベストアンサー率27% (4737/17069)
回答No.2

質問者のやり方に現状のエクセルVBAでは無理があるように思った。 (1)セルsheet1!A1:A5の書式を、エクセルのシートの機能の書式で「d」としておくと、コンボのドロップダウンのアイテムの表示も日数字にの1,2,3・・になること。 (2)しかしアイテムの1つを選択したとき、ボックスには、何もしないと日付シリアル値の数字が表示される。例39xxx (3)シートのセルに、選択したアイテムを表示するときは、コンボボックスの値を数値化して= Val(ComboBox1)、そのセルの書式を日付の表示形式にしておくと2008/9/3のように表示され、セルの値も日付シリアル値になって、後には日付としてそのまま使える。 日付シリアル値は数値であり、コンボやテキストボックスは文字列を返すのでVALはやむを得ないと思う。 ーー 問題はコンボで選択したときコンボに表示されるものを、日数字だけにする仕組みは無いのではないかな。 コンボに、エクセルシートでは出来る、日付のフォーマットを設定するプロパティが見当たらないから。(注) もしFormat関数でコンボボックスの値を、日だけ表示すると、連結するセルに値(日付)をセットするときに、何年+何月を添えて、日付に再構成しなくてはならないのではないか。 それならコンボは、日数字だけ選択させるほうがすっきりする。 良く年、月、日を独立したコンボて選択させている仕組みをWEBなどで見かける。 ーー それと_Change()イベントは注意しないと、コンボにプログラムで値をセットすると、_Change()イベントが起こり、ぐるぐる回りになって おかしくなる場合があるので使用は慎重に。 それ対しては、Application.EnableEvents = Falseが使える場合がある。 ーー 上記(注)の部分は100%は自信はないが、上記で私が言っていることは判ってもらえるでしょうか。

hiro_ele
質問者

お礼

回答してくださりありがとうございます! >日付のフォーマットを設定するプロパティが見当たらない 私も正攻法の仕方があるのではないかと調べてみたのですが見当たりませんでした。 何も設定しないとシリアル値が出るので、何とかしたいと思うのですが。 なぜ、日付にこだわるかというと月ごとに日付が増減して表示されるようにしているからです。 質問ではマクロの一部を簡略化して載せたので、まだ未完成な全文を載せておきます。 Private Sub UserForm_Initialize() Dim ws As Worksheet With ComboBox1 .ColumnCount = -1 .ColumnWidths = -1 .RowSource = "sheet1!A5:A35" '日付のセルを選択 End With Set ws = Sheets("Sheet1") With Me.ComboBox2 .Column = ws.Range("S3", ws.Cells(3, Columns.Count).End(xlToLeft)).Value '横列の項目を選択 End With Set ws = Nothing End Sub Private Sub CommandButton1_Click() Dim ctrl As Control, tst1 As String, txt2 As String Dim ws As Worksheet, r As Long, c As Long Set ws = Sheets("sheet1") For Each ctrl In Me.Controls Select Case ctrl.Name Case "ComboBox1", "ComboBox2", "TextBox1" If Me.Controls(ctrl.Name).Value = "" Then txt1 = txt1 & ctrl.Name & vbLf Else txt2 = txt2 & Me.Controls(ctrl.Name).Value & vbLf End If End Select Next If Len(txt1) > 0 Then MsgBox "以下の値を入力してください" & vbLf & txt1, vbExclamation Exit Sub Else ret = MsgBox("以下の値を入力します" & vbLf & txt2, vbOKCancel) If ret <> vbOK Then Exit Sub r = Me.ComboBox1.ListIndex + 5 c = Me.ComboBox2.ListIndex + 19 ws.Cells(r, c) = Me.TextBox1.Text 'テキストボックスの内容を選択したセルへ入れる End If Set ws = Nothing End Sub Private Sub ComboBox1_Change() ComboBox1 = Format(ComboBox1, "d") 'ココが問題の部分です End Sub 問題の部分を "m月d日" とし 日付のセルの表示形式を○月○日の形にするとテキストボックスの値を入力するセルをきちんと選択できます。 しかし、セルの表示形式を d とするとうまくいかないので、コンボボックスの表示形式も d の形にそろえてみようとしています。

  • xls88
  • ベストアンサー率56% (669/1189)
回答No.1

下記のようにすればいいようです。 ComboBox1.Value = Format(ComboBox1.Value, "d""日""")

hiro_ele
質問者

お礼

早速のご回答ありがとうございます! この場合「○○日」のように表示されますよね? 2008/10/1であれば「1日」と。 この形はうまくいきました。 今回はできれば数字だけ表示したいのですが。 「1」のようにしたいのです。 「ComboBox1.Value = Format(ComboBox1.Value, "d")」とすると、マクロが変な動きをする(選択した日+13で表示する)ので、解決策か別の方法を教えていただけないでしょうか。 よろしくお願いします。

関連するQ&A