none
VB.NETで年月しか表示/選択させないコントロール(テキストボックスと組合わせ) RRS feed

  • 質問

  • 先輩の皆様

    大変お世話になっております。山内です。

    VB.NETでWINDOWSアプリを実装時、

    下図の仕様にあいました。

    実現方法は中々分からなくて、どなた様にご教授頂けると助かります。

    何卒よろしくお願い致します。


    xiaohu

    2020年12月5日 4:12

回答

  • こんな

    Imports System
    Imports System.ComponentModel
    Imports System.Runtime.InteropServices
    Imports System.Windows.Forms
    
    Namespace WindowsFormsApp1
    
        Public Class MonthPicker
            Inherits DateTimePicker
    
            Public Sub New()
                Me.Format = DateTimePickerFormat.Custom
                Me.CustomFormat = "yyyy/MM"
            End Sub
    
            Protected Overrides Sub OnDropDown(eventargs As EventArgs)
                MyBase.OnDropDown(eventargs)
    
                'カレンダーを開いたら月選択に表示を変える
                Dim hwndCal As IntPtr = Win32API.SendMessage(MyBase.Handle, Win32API.DTM.DTM_GETMONTHCAL, IntPtr.Zero, IntPtr.Zero)
                Win32API.SendMessage(hwndCal, Win32API.MCM.MCM_SETCURRENTVIEW, IntPtr.Zero, New IntPtr(Win32API.MCMV.MCMV_YEAR))
            End Sub
    
            Protected Overrides Sub WndProc(ByRef m As Message)
                If m.Msg = Win32API.WM.WM_NOFITY Then
                    Dim nmhdr As Win32API.NMHDR = CType(Marshal.PtrToStructure(m.LParam, GetType(Win32API.NMHDR)), Win32API.NMHDR)
    
                    Select Case (nmhdr.code)
                        Case Win32API.MCN.MCN_VIEWCHANGE
                            Dim nmvc As Win32API.NMVIEWCHANGE = CType(Marshal.PtrToStructure(m.LParam, GetType(Win32API.NMVIEWCHANGE)), Win32API.NMVIEWCHANGE)
                            Select Case (nmvc.dwNewView)
                                Case Win32API.MCMV.MCMV_MONTH
                                    '月内の日付選択になったらカレンダーを閉じる
                                    Win32API.SendMessage(MyBase.Handle, Win32API.DTM.DTM_CLOSEMONTHCAL, IntPtr.Zero, IntPtr.Zero)
                            End Select
                    End Select
                End If
                MyBase.WndProc(m)
            End Sub
        End Class
    
        Module Win32API
    
            <DllImport("user32.dll", CharSet:=CharSet.Auto)>
            Public Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
            End Function
    
            <StructLayout(LayoutKind.Sequential)>
            Public Structure NMVIEWCHANGE
                Public nmhdr As NMHDR
                Public dwOldView As UInteger
                Public dwNewView As UInteger
            End Structure
    
            <StructLayout(LayoutKind.Sequential)>
            Public Structure NMHDR
                Public hwndFrom As IntPtr
                Public idFrom As IntPtr
                Public code As Integer
            End Structure
    
            Public Enum WM
                WM_NOFITY = &H4E
            End Enum
    
            Public Enum DTM
                DTM_GETMONTHCAL = &H1008
                DTM_CLOSEMONTHCAL = &H100D
            End Enum
    
            Public Enum MCM
                MCM_FIRST = &H1000
                MCM_GETCURRENTVIEW = MCM_FIRST + 22
                MCM_SETCURRENTVIEW = MCM_FIRST + 32
            End Enum
            Public Enum MCN
                MCN_FIRST = -746
                MCN_VIEWCHANGE = MCN_FIRST - 4
            End Enum
            Public Enum MCMV
                MCMV_MONTH = 0 '日付選択
                MCMV_YEAR = 1 '月選択
                MCMV_DECADE = 2 '年選択
                MCMV_CENTURY = 3
            End Enum
        End Module
    End Namespace


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2020年12月5日 20:59

すべての返信

  • 何を作っているか(Windows Forms? WPF? ASP.NET Web Forms? その他?)と開発環境(OS, Visual Studio のバージョン、.NET なのか Core なのかとそのバージョン)は書けない事情とかがあるのですか?
    2020年12月5日 4:26
  • ご質問ありがとうございます。

    表現が分かり難くなりすみませんが、

    Windows Formsです。

    よろしくお願い致します。


    xiaohu

    2020年12月5日 11:18
  • 開発環境(OS, Visual Studio のバージョン、.NET なのか Core なのかとそのバージョン)は書けない事情とかがあるのですか?
    2020年12月5日 11:30
  • 小出ししてすみませんが、

    OS:WIN10 64bit

    Visual Studio のバージョン:2010

    .NET4.0、4.5

    Coreは2-4個ぐらいです。

    inputmanというミドルウエアを使っています。

    他には特になしです。

    よろしくお願い致します。


    xiaohu


    2020年12月5日 12:03
  • > Coreは2-4個ぐらいです。

    意味が分かりませんし、

    > inputmanというミドルウエアを使っています。

    そういう制約があるなら GrapeCity のサポートに聞くべきでは?

    自分が提案できるのは DateTimePicker を使うことぐらいです。初期表示は普通のカレンダー表示ですが、下の画像の赤枠部分のクリックにより表示を変えることができます。


    • 編集済み SurferOnWww 2020年12月5日 13:11 訂正
    2020年12月5日 13:10
  • 夜遅くまで手伝って頂き心から有難うございます。

    > Coreは2-4個ぐらいです。

    ⇒わたくしの理解はcpuのスペックが2コア~4コアのことです。

     論外だったら、ごめんなさいね。

     >inputmanは使っていますが、

     それで実現できるかどうかはどう調べても分かりません。

     GrapeCityについて、聞いたことがあります。余り使ったことがありません。

     調べておきます。

     >DateTimePickerを使ったら、クリックすると、日の表示となってしまうので、

     お客様のニーズに合わなくなります。

    よろしくお願い致します。


    xiaohu

    2020年12月5日 13:49
  • こんな

    Imports System
    Imports System.ComponentModel
    Imports System.Runtime.InteropServices
    Imports System.Windows.Forms
    
    Namespace WindowsFormsApp1
    
        Public Class MonthPicker
            Inherits DateTimePicker
    
            Public Sub New()
                Me.Format = DateTimePickerFormat.Custom
                Me.CustomFormat = "yyyy/MM"
            End Sub
    
            Protected Overrides Sub OnDropDown(eventargs As EventArgs)
                MyBase.OnDropDown(eventargs)
    
                'カレンダーを開いたら月選択に表示を変える
                Dim hwndCal As IntPtr = Win32API.SendMessage(MyBase.Handle, Win32API.DTM.DTM_GETMONTHCAL, IntPtr.Zero, IntPtr.Zero)
                Win32API.SendMessage(hwndCal, Win32API.MCM.MCM_SETCURRENTVIEW, IntPtr.Zero, New IntPtr(Win32API.MCMV.MCMV_YEAR))
            End Sub
    
            Protected Overrides Sub WndProc(ByRef m As Message)
                If m.Msg = Win32API.WM.WM_NOFITY Then
                    Dim nmhdr As Win32API.NMHDR = CType(Marshal.PtrToStructure(m.LParam, GetType(Win32API.NMHDR)), Win32API.NMHDR)
    
                    Select Case (nmhdr.code)
                        Case Win32API.MCN.MCN_VIEWCHANGE
                            Dim nmvc As Win32API.NMVIEWCHANGE = CType(Marshal.PtrToStructure(m.LParam, GetType(Win32API.NMVIEWCHANGE)), Win32API.NMVIEWCHANGE)
                            Select Case (nmvc.dwNewView)
                                Case Win32API.MCMV.MCMV_MONTH
                                    '月内の日付選択になったらカレンダーを閉じる
                                    Win32API.SendMessage(MyBase.Handle, Win32API.DTM.DTM_CLOSEMONTHCAL, IntPtr.Zero, IntPtr.Zero)
                            End Select
                    End Select
                End If
                MyBase.WndProc(m)
            End Sub
        End Class
    
        Module Win32API
    
            <DllImport("user32.dll", CharSet:=CharSet.Auto)>
            Public Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
            End Function
    
            <StructLayout(LayoutKind.Sequential)>
            Public Structure NMVIEWCHANGE
                Public nmhdr As NMHDR
                Public dwOldView As UInteger
                Public dwNewView As UInteger
            End Structure
    
            <StructLayout(LayoutKind.Sequential)>
            Public Structure NMHDR
                Public hwndFrom As IntPtr
                Public idFrom As IntPtr
                Public code As Integer
            End Structure
    
            Public Enum WM
                WM_NOFITY = &H4E
            End Enum
    
            Public Enum DTM
                DTM_GETMONTHCAL = &H1008
                DTM_CLOSEMONTHCAL = &H100D
            End Enum
    
            Public Enum MCM
                MCM_FIRST = &H1000
                MCM_GETCURRENTVIEW = MCM_FIRST + 22
                MCM_SETCURRENTVIEW = MCM_FIRST + 32
            End Enum
            Public Enum MCN
                MCN_FIRST = -746
                MCN_VIEWCHANGE = MCN_FIRST - 4
            End Enum
            Public Enum MCMV
                MCMV_MONTH = 0 '日付選択
                MCMV_YEAR = 1 '月選択
                MCMV_DECADE = 2 '年選択
                MCMV_CENTURY = 3
            End Enum
        End Module
    End Namespace


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2020年12月5日 20:59
  • gekka さんがサンプルを実装してくれているようなのでデバッグしつつ、コードの理解に努めた方が良いと思います。

    個人的には、標準のコントロールできないことを要求された際のアクションとして、上司・先輩・同僚に相談して解決ではなく、インターネット上で尋ねている…という現状に危惧を抱きます。

    • インターネット上の誰かの厚意を待つことになる(いわゆる丸投げ)ので、開発スピードの低下を招く
    • 本来の実力以上のものを納品してしまうことで今後の要求も同程度以上になって、あなたの実力と要求のギャップが広がり、あなたの立場がますます悪くなるかもしれない
    • サンプルや助言が提供されたとして、最終的にはあなたが成果物の責任を負うことになる

    スキル・経験の不足を補う手段としてサンプルを動かして理解を深めることは良いと思いますが、上記に挙げたように、あなたが責任を持てるよう、かつ今後の開発に活かせるように読み解く努力を忘れないようにしてください。

    2020年12月5日 22:14
    モデレータ
  • gekka様

    大変お世話になっております。山内です。

    丁寧にご教授頂き誠に有難うございます。

    デバッグさせて頂いておきます。

    年末年始のご多忙中、大事なお時間を割いて頂き、助けてくれたことを心から感謝申し上げます。

    本当に有難うございました。助かります。

    大変お手数をお掛けしました。

    よろしくお願い致します。


    xiaohu

    2020年12月6日 0:32
  • Azulean

    大変お世話になっております。山内です。

    方向的なご指導有難うございます。

    承知致しました。

    gekka先輩が大切な時間を使って実装されたソースコードをデバッグしながら理解させて頂きます。

    本件の責任はわたくし自分が負わせていただきます。

    これから仰った通りに頑張っていきたいと思っております。

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

    よろしくお願い致します。



    xiaohu

    2020年12月6日 0:45
  • gekka

    大変お世話になっております。山内です。

    作って頂いたnamespaceをcall致しまして、デバッグしてみました。

    overrideして頂いたDateTimePickerコントロールのMonthPickerは、

    うまく年と月しか表示/選択されないようになっております。

    素晴らしい実装でした。お見事です!

    心底から感心致します。

    完全新米としての下名にとっては、非常に良い勉強になりました。

    改めて心から感謝申し上げます。

    有難うございました。助かりました!

    よろしくお願い致します。


    xiaohu

    2020年12月6日 2:15
  • xiaohu19740509さん、こんにちは。フォーラムオペレーターのKumoです。
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    本件、gekkaさんより参考になる投稿が寄せられたようでなによりです。

    [回答としてマーク]機能は設定された投稿が後から参照しやすくなりますので、
    同じ問題でお困りの方のためにも参考になった投稿に設定いただけますと幸いです。

    お手数ですが、ご協力の程どうかよろしくお願いいたします。

    引き続きMSDNフォーラムをご利用いただけますようお願い申し上げます。

    MSDN/ TechNet Community Support Kumo ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2020年12月7日 1:23
    モデレータ
  • gekka様

    いつも大変お世話になっております。山内です。

    度々申し訳ございませんが、

    そのカスタマイズされた年月コントロールで選択された値を

    テキストボックスに付けようとすると、

    中々付けられません。

    MonthCalendar1_DateSelected()関数及び

    MonthCalendar1.SelectionStart.ToShortDateString()関数が

    無くなったからだと思います。

    何とかご指導頂けませんか?

    よろしくお願いいたします。


    xiaohu

    2020年12月7日 10:11