Làm sao đổi được màu chữ và màu nền trong control DTPicker (Date Time Picker)?

Liên hệ QC

phanminhphuong

Thành viên hoạt động
Tham gia
26/7/13
Bài viết
127
Được thích
68
Chào các bạn. Mình sử dụng DTPicker (đính kèm) để nhập ngày tháng.

Có cách nào để đổi màu nền hoặc màu chữ hiển thị của DTPicker không?
(KHÔNG phải màu của lịch xổ xuống khi nhấn mũi tên đâu nhé, tức là ko phải các property: CalendarBackColor, CalendarForeColor, CalendarTitleBackColor, CalendarTitleForeColor, CalendarTrailingForeColor)

Xin cám ơn!
 

File đính kèm

  • DTPICKER.jpg
    DTPICKER.jpg
    108.5 KB · Đọc: 34
  • HOW TO CHANGE DTPICKER TEXT COLOR - BACKGROUND COLOR.xls
    37.5 KB · Đọc: 27
  • mscomct2 - DTPicker control.zip
    320.8 KB · Đọc: 21
Lần chỉnh sửa cuối:
Lên mạng mò mẫn tìm được file này nhưng máy tính cơ quan không cài VB,
Các bạn kiểm tra giúp người ta làm thế nào?
Tks
 

File đính kèm

  • VB6 -DTPicker-change back color.zip
    2 KB · Đọc: 25
Upvote 0
Họ gắn 1 TextBox nằm đè lên DTPicker, xong họ format màu nền cho TextBox này, chẳng có gì ghê gớm cả
Như vậy không có giải pháp nào can thiệp vào màu chữ/ màu nền (của textbox của DTPicker) đúng không? Tại sao MS không cho property cơ bản đó nhỉ?

Mình rất cần thay đổi màu hiển thị của DTPicker để cảnh báo khi nhập liệu trên UserForm (Form của mình có nhiều DTPicker, rất dễ quên).
Mình không biết về API. Các bạn có thể kiểm chứng giúp mình cách người ta làm ở đây có được không? Nếu thực hiện được vui lòng cho xem file mẫu.

Xin cảm ơn!
 
Upvote 0
Như vậy không có giải pháp nào can thiệp vào màu chữ/ màu nền (của textbox của DTPicker) đúng không? Tại sao MS không cho property cơ bản đó nhỉ?

Mình rất cần thay đổi màu hiển thị của DTPicker để cảnh báo khi nhập liệu trên UserForm (Form của mình có nhiều DTPicker, rất dễ quên).
Mình không biết về API. Các bạn có thể kiểm chứng giúp mình cách người ta làm ở đây có được không? Nếu thực hiện được vui lòng cho xem file mẫu.

Xin cảm ơn!

Thì bạn cứ làm giống như cách ở bài 2 đi: Dùng TextBox để giả lập. Tôi thấy đó cũng là cách hay và đơn giản
Code nó chỉ bi nhiêu:
Mã:
Private Sub dtpDate_CloseUp()
    txtDate.Text = dtpDate.Value
    txtDate.SetFocus
End Sub

Private Sub dtpDate_GotFocus()
    txtDate.SetFocus
End Sub
Với dtpDate là DTPicker và txtDate là TextBox
 
Upvote 0
Thì bạn cứ làm giống như cách ở bài 2 đi: Dùng TextBox để giả lập. Tôi thấy đó cũng là cách hay và đơn giản
Code nó chỉ bi nhiêu:
Mã:
Private Sub dtpDate_CloseUp()
    txtDate.Text = dtpDate.Value
    txtDate.SetFocus
End Sub

Private Sub dtpDate_GotFocus()
    txtDate.SetFocus
End Sub
Với dtpDate là DTPicker và txtDate là TextBox
Xin vui lòng cho giúp 01 file ví dụ.
Vì trong VBA mình ko thấy có sự kiện dtpDate_GotFocus
& mình chưa làm được.
Nếu theo link này dùng API thì có làm được không?
 
Upvote 0
Như vậy không có giải pháp nào can thiệp vào màu chữ/ màu nền (của textbox của DTPicker) đúng không? Tại sao MS không cho property cơ bản đó nhỉ?

Bạn nghĩ là cơ bản thôi chứ mấy ai quan trọng cái này.

Mình rất cần thay đổi màu hiển thị của DTPicker để cảnh báo khi nhập liệu trên UserForm (Form của mình có nhiều DTPicker, rất dễ quên).

Thiếu gì cách thông báo mà phải đụng chạm tới mầu nền hả bạn?

Mình không biết về API. Các bạn có thể kiểm chứng giúp mình cách người ta làm ở đây có được không? Nếu thực hiện được vui lòng cho xem file mẫu.

Xin cảm ơn!

Trong code bạn đưa người ta dùng kỹ thuật subclassing để thay đổi hàm cửa sổ gốc của DateTimePicker bằng hàm cửa sổ của mình. Trong hàm cửa sổ thì phục vụ thông điệp WM_ERASEBKGND để "đổ mầu".

code UserForm1
Mã:
Private Sub UserForm_Initialize()
    SetWindowProc dtpRegDate.hwnd, True
End Sub

Private Sub UserForm_Terminate()
    SetWindowProc dtpRegDate.hwnd, False
End Sub

code Module2
Mã:
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Private Declare Function FillRect Lib "user32.dll" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Const GWL_WNDPROC = -4
Private Const WM_ERASEBKGND = &H14

Private OldWndProc As Long

Sub SetWindowProc(ByVal hwnd As Long, DoSet As Boolean)
    If DoSet Then
        If OldWndProc = 0 Then
'            thuc hien subclassing - set new address for the window procedure
            OldWndProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WindowProc)
        End If
    Else
        If OldWndProc <> 0 Then
'            tra lai ham cua so goc - address for the window procedure
            SetWindowLong hwnd, GWL_WNDPROC, OldWndProc
            OldWndProc = 0
        End If
    End If
End Sub

' ham cua so
Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, _
                            ByVal wParam As Long, ByVal lParam As Long) As Long
Dim hBrush As Long
Dim rc As RECT
    Select Case uMsg
'        phuc vu thong diep WM_ERASEBKGND
        Case WM_ERASEBKGND:
'            tao brush
            hBrush = CreateSolidBrush([B][COLOR=#ff0000]RGB(128, 255, 255)[/COLOR][/B])
'            doc toa do - vung chiem boi DTP
            GetClientRect hwnd, rc
'            "do mau" vao vung DTP
            FillRect wParam, rc, hBrush
'            giai phong tai nguyen - brush
            DeleteObject hBrush
            Exit Function
        Case Else:
'            voi cac thong diep khac thi truyen vao ham cua so goc (original address for the window procedure)
            WindowProc = CallWindowProc(OldWndProc, hwnd, uMsg, wParam, lParam)
    End Select
End Function

Muốn mầu khác thì thay đổi chỗ đỏ đỏ. RGB là hàm có 3 tham số là 3 bai - bai có giá trị từ 0 tới 255.
 
Upvote 0
Bạn nghĩ là cơ bản thôi chứ mấy ai quan trọng cái này.



Thiếu gì cách thông báo mà phải đụng chạm tới mầu nền hả bạn?



Trong code bạn đưa người ta dùng kỹ thuật subclassing để thay đổi hàm cửa sổ gốc của DateTimePicker bằng hàm cửa sổ của mình. Trong hàm cửa sổ thì phục vụ thông điệp WM_ERASEBKGND để "đổ mầu".

code UserForm1
Mã:
Private Sub UserForm_Initialize()
    SetWindowProc dtpRegDate.hwnd, True
End Sub

Private Sub UserForm_Terminate()
    SetWindowProc dtpRegDate.hwnd, False
End Sub

code Module2
Mã:
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function GetClientRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Private Declare Function FillRect Lib "user32.dll" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Const GWL_WNDPROC = -4
Private Const WM_ERASEBKGND = &H14

Private OldWndProc As Long

Sub SetWindowProc(ByVal hwnd As Long, DoSet As Boolean)
    If DoSet Then
        If OldWndProc = 0 Then
'            thuc hien subclassing - set new address for the window procedure
            OldWndProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WindowProc)
        End If
    Else
        If OldWndProc <> 0 Then
'            tra lai ham cua so goc - address for the window procedure
            SetWindowLong hwnd, GWL_WNDPROC, OldWndProc
            OldWndProc = 0
        End If
    End If
End Sub

' ham cua so
Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, _
                            ByVal wParam As Long, ByVal lParam As Long) As Long
Dim hBrush As Long
Dim rc As RECT
    Select Case uMsg
'        phuc vu thong diep WM_ERASEBKGND
        Case WM_ERASEBKGND:
'            tao brush
            hBrush = CreateSolidBrush([B][COLOR=#ff0000]RGB(128, 255, 255)[/COLOR][/B])
'            doc toa do - vung chiem boi DTP
            GetClientRect hwnd, rc
'            "do mau" vao vung DTP
            FillRect wParam, rc, hBrush
'            giai phong tai nguyen - brush
            DeleteObject hBrush
            Exit Function
        Case Else:
'            voi cac thong diep khac thi truyen vao ham cua so goc (original address for the window procedure)
            WindowProc = CallWindowProc(OldWndProc, hwnd, uMsg, wParam, lParam)
    End Select
End Function

Muốn mầu khác thì thay đổi chỗ đỏ đỏ. RGB là hàm có 3 tham số là 3 bai - bai có giá trị từ 0 tới 255.
Cảm ơn bạn Siwtom đã đóng góp ý kiến.
Code đã test. Chạy rất tốt. Nhu cầu của mình như thế là đủ.
Xin chân thành cảm ơn!
 
Upvote 0
Mình đang gặp 02 vấn đề mong mọi người xem giúp:

1) Làm theo hướng dẫn của bạn siwtom (Bài #7) nhưng không "đổ màu" được nhiều dtpicker Các bạn xem hình đính kèm
Mã:
Private Sub UserForm_Initialize()
    SetWindowProc dtpRegDate.hwnd, True
    SetWindowProc dtpIssueDate.hwnd, True
    SetWindowProc dtpExpiryDate.hwnd, True
    SetWindowProc dtpJoinDate.hwnd, True
End Sub

Private Sub UserForm_Terminate()
    SetWindowProc dtpRegDate.hwnd, False
    SetWindowProc dtpIssueDate.hwnd, False
    SetWindowProc dtpExpiryDate.hwnd, False
    SetWindowProc dtpJoinDate.hwnd, False
End Sub


2) Mình muốn tô nhiều màu khác nhau, VD:
- 04 dtpicker trên cùng tô màu nền là VÀNG
- 02 dtpicker tiếp theo tô màu nền là XANH
thì làm như thế nào???

Xin trân trọng cảm ơn
 

File đính kèm

  • dtpicker back color.jpg
    dtpicker back color.jpg
    67.5 KB · Đọc: 18
  • HOW TO CHANGE DTPICKER BACKGROUND COLOR.xls
    62 KB · Đọc: 9
Lần chỉnh sửa cuối:
Upvote 0
Mình đang gặp 02 vấn đề mong mọi người xem giúp:

1) Làm theo hướng dẫn của bạn siwtom (Bài #7) nhưng không "đổ màu" được nhiều dtpicker Các bạn xem hình đính kèm
Mã:
Private Sub UserForm_Initialize()
    SetWindowProc dtpRegDate.hwnd, True
    SetWindowProc dtpIssueDate.hwnd, True
    SetWindowProc dtpExpiryDate.hwnd, True
    SetWindowProc dtpJoinDate.hwnd, True
End Sub

Private Sub UserForm_Terminate()
    SetWindowProc dtpRegDate.hwnd, False
    SetWindowProc dtpIssueDate.hwnd, False
    SetWindowProc dtpExpiryDate.hwnd, False
    SetWindowProc dtpJoinDate.hwnd, False
End Sub


2) Mình muốn tô nhiều màu khác nhau, VD:
- 04 dtpicker trên cùng tô màu nền là VÀNG
- 02 dtpicker tiếp theo tô màu nền là XANH
thì làm như thế nào???

Xin trân trọng cảm ơn

Bạn giải quyết vấn đề theo cách sau.
Bạn lập một tương quan: tương ứng với handle (hwnd) thế này thế này, tức tương ứng với DTP thế này thế này, thì địa chỉ hàm cửa sổ gốc là thế này thế này, và mầu là thế này thế này. Có nhiều cách lập tương quan như thế. Vd. "gán" cho mỗi cửa sổ DTP (có hwnd cụ thể) một mầu cụ thể, và địa chỉ hàm cửa sổ gốc cụ thể bằng cách ghi thông tin vào cửa sổ đó dùng SetProp. Cũng có thể tạo mảng có 3 dòng - dòng 1 ghi hwnd, dòng 2 ghi địa chỉ của hàm cửa sỗ gốc, dòng 3 ghi mầu của cửa sổ đó - và có k cột - mỗi cột ghi thông tin cho 1 DTP. Tôi dùng cách lập mảng. Vì cách ghi thông tin vào cửa sổ (vd. dùng SetProp) là cách ghi thông tin ở đâu đó rồi khi cần thì "gọi điện thoại" (vd. GetProp) để hỏi thông tin. Còn cách dùng mảng là cách ghi thông tin trong sổ tay để trong tủ trong nhà khi cần thì đọc ra không phải gọi điện đi đâu cả.

Việc ghi địa chỉ hàm cửa sổ gốc cho từng DTP là không cần thiết vì thực chất địa chỉ hàm cửa sổ gốc của mọi DTP đều như nhau. Vì sao? Vì các DTP đều được tạo ra từ 1 "mẫu, khuôn" duy nhất nên địa chỉ hàm cửa sổ gốc là địa chỉ của hàm cửa sổ có trong thư viện DLL, OCX. Rõ ràng khi module DLL, OCX được load vào bộ nhớ thì code của hàm cửa sổ gốc nằm đâu đó trong RAM và chỉ có 1 - duy nhất. Nhưng tôi cứ cho tất cả các địa chỉ hàm cửa sổ gốc (như nhau) vào hàng 2 của mảng. Vì chuyện chúng như nhau thì chỉ những người hiểu về system mới biết. Còn ghi như hiện thời thì người dùng khỏi phải lăn tăn.

Trong hàm cửa sổ mà bạn tạo ra để đánh tráo với hàm cửa sổ gốc thì khi có được handle hwnd rồi thì phải phải duyệt trong mảng đã tạo để xác định đó là handle hwnd của cửa sổ DTP nào để đọc ra mầu của nó.

Thế thôi.

Bạn hãy so sánh code tôi gửi với code trong bài #7 để hiểu thêm, để biết chỗ nào đã sửa lại
------------
Trong ví dụ tôi cho DTP1 mầu vàng, DTP2, 3, 4 mầu đỏ và DTP5, 6 mầu xanh.
 

File đính kèm

  • HOW TO CHANGE DTPICKER BACKGROUND COLOR.xls
    66 KB · Đọc: 17
Upvote 0
Bạn giải quyết vấn đề theo cách sau.
Bạn lập một tương quan: tương ứng với handle (hwnd) thế này thế này, tức tương ứng với DTP thế này thế này, thì địa chỉ hàm cửa sổ gốc là thế này thế này, và mầu là thế này thế này. Có nhiều cách lập tương quan như thế. Vd. "gán" cho mỗi cửa sổ DTP (có hwnd cụ thể) một mầu cụ thể, và địa chỉ hàm cửa sổ gốc cụ thể bằng cách ghi thông tin vào cửa sổ đó dùng SetProp. Cũng có thể tạo mảng có 3 dòng - dòng 1 ghi hwnd, dòng 2 ghi địa chỉ của hàm cửa sỗ gốc, dòng 3 ghi mầu của cửa sổ đó - và có k cột - mỗi cột ghi thông tin cho 1 DTP. Tôi dùng cách lập mảng. Vì cách ghi thông tin vào cửa sổ (vd. dùng SetProp) là cách ghi thông tin ở đâu đó rồi khi cần thì "gọi điện thoại" (vd. GetProp) để hỏi thông tin. Còn cách dùng mảng là cách ghi thông tin trong sổ tay để trong tủ trong nhà khi cần thì đọc ra không phải gọi điện đi đâu cả.

Việc ghi địa chỉ hàm cửa sổ gốc cho từng DTP là không cần thiết vì thực chất địa chỉ hàm cửa sổ gốc của mọi DTP đều như nhau. Vì sao? Vì các DTP đều được tạo ra từ 1 "mẫu, khuôn" duy nhất nên địa chỉ hàm cửa sổ gốc là địa chỉ của hàm cửa sổ có trong thư viện DLL, OCX. Rõ ràng khi module DLL, OCX được load vào bộ nhớ thì code của hàm cửa sổ gốc nằm đâu đó trong RAM và chỉ có 1 - duy nhất. Nhưng tôi cứ cho tất cả các địa chỉ hàm cửa sổ gốc (như nhau) vào hàng 2 của mảng. Vì chuyện chúng như nhau thì chỉ những người hiểu về system mới biết. Còn ghi như hiện thời thì người dùng khỏi phải lăn tăn.

Trong hàm cửa sổ mà bạn tạo ra để đánh tráo với hàm cửa sổ gốc thì khi có được handle hwnd rồi thì phải phải duyệt trong mảng đã tạo để xác định đó là handle hwnd của cửa sổ DTP nào để đọc ra mầu của nó.

Thế thôi.

Bạn hãy so sánh code tôi gửi với code trong bài #7 để hiểu thêm, để biết chỗ nào đã sửa lại
------------
Trong ví dụ tôi cho DTP1 mầu vàng, DTP2, 3, 4 mầu đỏ và DTP5, 6 mầu xanh.
Cảm ơn bạn. Lập trình API quả là "xương", vẫn còn phải nghiên cứu thêm nhiều. Ít nhiều qua bài viết trên mình cũng học được cách tư duy logic khi làm việc với các đối tượng đó.
Một lần nữa xin cảm ơn bạn rất nhiều.
 
Upvote 0
Web KT
Back
Top Bottom