Tặng tiện ích CALENDAR tuyệt đẹp!

Liên hệ QC

Hoàng Trọng Nghĩa

Chuyên gia GPE
Thành viên BQT
Moderator
Tham gia
17/8/08
Bài viết
8,616
Được thích
16,675
Giới tính
Nam
***************************************************************************************************************
***************************************************************************************************************

Đã có phiên bản mới tại đây:

Tặng tiện ích CALENDAR (Excel 2007 trở về sau)


***************************************************************************************************************
***************************************************************************************************************




Nhân dịp khoác trên vai “4 sao vàng”, tôi xin tặng các bạn một UserForm Calendar tuyệt đẹp, nó không những thay thế được với Control Calendar của Excel mà nó còn hiển thị ngày Âm lịch.

(Giới thiệu trước, gửi file ở bài sau)
3.jpg

Mặc dù mã nguồn tôi đã sưu tầm từ nhiều nơi (thật sự tôi không nhớ nguồn gốc của các mã này của ai sáng tác), nhưng tôi đã cải tiến cũng như thiết kế lại giao diện, kết hợp mã nguồn của dương lịch và mã nguồn chuyển Âm lịch, có đầy đủ “thiên can địa chi” cho năm.

Cũng như tại bài viết này tôi đã giới thiệu (http://www.giaiphapexcel.com/forum/showthread.php?36542-Đặt-caption-cho-nhiều-Label&p=242247#post242247) thì cải tiến lần này hoàn chỉnh nhất, Calendar này sẽ nhớ ngày hiện hành (hôm nay) bằng cách tô màu hồng đậm. Dùng phím mũi tên (lên, xuống, trái, phải) để di chuyển giữa các ô ngày; mỗi ô ngày được chọn sẽ có nền trắng, viền ngoài để phân biệt với ngày hiện hành và các ngày trong tháng.

Các bạn để ý sẽ thấy, khi ô ngày nào được chọn, thì Label ở dưới cùng thể hiện ngày Dương lịch được chọn bên trái và ngày Âm lịch được chọn bên phải, chúng có màu nền, cũng như màu font chữ của ô ngày hiện hành.

Cũng tại Label này, khi bạn đang chọn ngày khác với ngày hiện hành, thì bạn click vào đó nó sẽ chọn về ngày hôm nay.

2.jpg

Nếu bạn rê chuột ngang qua nó, nó sẽ show cho bạn một ToolTip để báo bạn biết chức năng của nó.

Đặc biệt, lần cải tiến này tôi đã thay đổi 2 Label tháng và năm thành 2 ComboBox THÁNG & NĂM để chúng ta có thể di chuyển ngay tới tháng hoặc năm cần xem.

1.jpg

– Chọn tháng –

4.jpg

– Chọn năm –

5.jpg

Các thao tác trên lịch:

  • Di chuyển giữa các ô ngày bằng các phím mũi tên để di chuyển qua lại, lên xuống.
  • Dùng phím Tab để di chuyển ngày kế tiếp, shift + tab để di chuyển ngược lại.
  • PgUp, PgDn để chọn tháng trước, tháng sau (tương đương với bấm vào 2 CommandButton mũi tên qua, lại sát ComboBox Tháng, cũng tương đương Shift + các phím mũi tên).
  • Shift+ PgUp/ PgDn để chọn năm trước, năm sau (tương đương với bấm vào 2 CommandButton mũi tên qua, lại sát ComboBox Năm).
  • Phím Home để trở về ngày hiện hành (ngày hôm nay).

Các bạn cứ bấm thử với Shift hoặc Ctrl kết hợp với các phím trên sẽ nắm rõ nguyên lý hoạt động của lịch.

Với phím Enter, Esc hoặc click vào ô ngày nào đó sẽ thoát lịch.

Nếu lịch được khởi động trên một UserForm và muốn nhận giá trị ngày từ Calendar vào một TextBox trên form này, thì sau khi thoát Lịch, giá trị lịch tại ô ngày nào được chọn sẽ nhập vào TextBox của UserForm đó.

Năm nào có tháng nhuần thì nó thể hiện chữ (N) trên Calendar.

6.jpg
Khi gọi Calendar từ một UserForm, nếu TextBox cần nhập Date có sẳn ngày tháng, lịch sẽ lấy ngày đó làm ngày hiển thị, ngược lại, lịch sẽ hiển thị ngày hiện hành.

7.jpg
 
Lần chỉnh sửa cuối:
Class ít sử dụng nên quên mất tiêu rồi. Nhưng trường hợp này không khó, đọc sơ qua code "trúc xanh trên form" của Kyo là làm được, vì nó sử dụng class cho command button tương tự bài này.

Vì mỗi cái thủ tục nó lại kèm theo 1 cái tên của label nên em không biết phải làm như thế nào nữa.

Ai rành về class xin vui lòng hướng dẫn sơ cho mình về trường hợp trên form lịch này được không ạ?

Trân trọng cám ơn.
 
Upvote 0
Có thể nói cái lịch này là một tiện ích "có thể" thay thế được với control Caledar của Excel VBA, giao diện thân thiện hơn, dễ chỉnh sửa, nói chung là dễ cá nhân hóa nó theo ý thích.

Nhập ngày tháng nhanh chóng bất cứ ở đâu, trên form hoặc trên sheet

Coi ngày tháng Âm lịch từ ngày 01/02/1900 (DL) đến 14/2/2200 (DL)

Nhập liệu nhanh chóng trên sheet thì chúng ta có thể làm một nút lệnh trên Cell Menu như sau:

Trong Module ThisWorkBook, đặt 2 thủ tục này để tạo Menu:

Mã:
Private Sub Workbook_Activate()
    With Application.CommandBars("Cell")
        .Reset
        .Controls("cut").BeginGroup = True
        .Controls.Add(1, , , 1).Caption = "Calendar"
        With .Controls("Calendar")
            .Style = 3
            .FaceId = 59
            .BeginGroup = True
            .OnAction = "CalShow"
        End With
    End With
End Sub

Private Sub Workbook_Deactivate()
    Application.CommandBars("Cell").Reset
End Sub

Khi click chuột phải sẽ như thế này:

attachment.php


Sau khi chọn vào Calendar thì lịch được show như vầy:

attachment.php


Chỉ việc bấm chọn ngày tháng cần thiết vào ô hoặc khối ô được chọn, chỉ với thủ tục như thế này thôi:

Mã:
Sub CalShow()
      Dim Ftop As Double, Fleft As Double
      With Selection
            Fleft = .Left [COLOR=#ff0000]+ 22[/COLOR] [COLOR=#008000]'Màu đỏ có thể chưa chính xác cho từng loại Window[/COLOR]
            Ftop = .Top + .Height[COLOR=#ff0000] + 110[/COLOR]
            With UsfCalendar
                  .StartUpPosition = 0
                  .Top = Ftop
                  .Left = Fleft
            End With
            .Value = DatePicked(.Value)
      End With
End Sub

=======================================================

Xa hơn nữa, sẽ định cải tiến trên cơ sở dữ liệu (nhỏ thôi) các ghi chú, sinh nhật, nhắc nhở v.v...

Mà thôi, thấy chẳng ai bận tâm, thậm chí chỉ một vài người cám ơn (mặc dù đã tải hơn 120 lần) nên chẳng muốn cải tiến tí nào!
Bạn hãy làm 1 ứng dụng hoàn chỉnh trên Excel rồi post file lên đây tôi xem thử
Đừng nói là khi muốn xài phải "vác" nguyên rừng code kia vào file nha ---> Nếu có thể được, phải tạo nó thành 1 Add-In. Để làm chi? Để mọi người, những ai không rành code cũng xài được!
 
Upvote 0
Hi em,
Em có thể tham khảo thêm tại đây.

Lê Văn Duyệt
 
Upvote 0
Hi em,
Em có thể tham khảo thêm tại đây.

Lê Văn Duyệt

Cám ơn Anh, đúng là code nó đơn giản thiệt, nhưng em thấy nó có nhiều hạn chế:

1) Không cho ta chọn được vào bất cứ ngày nào, nếu ta bỏ chọn Me.Hide trong sự kiện của Image:

[GPECODE=vb]Private Sub Image1_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal y As Single)
' updated 2012-05-12 by OPE
Dim d As Date
y = y + Me.Image1.Top
d = GetSelectedDate(x, y)
If d >= 0 Then ' 1.1.1900 or later
SelectedDate = d
UserCancelled = False
'Nếu bỏ chọn Me.Hide cái lịch trở nên "đóng băng"
'Me.Hide
End If
End Sub
[/GPECODE]

2) Không thể di chuyển để lựa chọn ngày bằng các phím mũi tên (lên, xuống, trái, phải)

3) Không có các chọn lựa cho phím tắt

...

Em sẽ kết hợp code với cái lịch này và cái lịch mà em đã cải tiến lại với nhau để đơn giản hóa việc sử dụng các sự kiện của các Label.

Cám ơn anh LeVanDuyet rất nhiều.
 
Upvote 0
Vì mỗi cái thủ tục nó lại kèm theo 1 cái tên của label nên em không biết phải làm như thế nào nữa.

Ai rành về class xin vui lòng hướng dẫn sơ cho mình về trường hợp trên form lịch này được không ạ?

Trân trọng cám ơn.

Tình cờ đọc được chủ đề cũ được nhắc lại.
Giới thiệu qua về class thì cũng được thôi nhưng phải xử lý sự kiện click và phải cung cấp một macro để thực hiện khi có click. Macro như thế tôi định gọi bằng Application.Run do vậy phải để nó trong Module. Hiện thời trong LabelClick bạn gọi 1 sub, nhưng macro trong Module không thể gọi sub trong UserForm nên phải chuyển sub kia vào Module. Sub kia lại gọi 1 loạt sub trong UserForm nên lại phải chuyển chúng vào Module. Rồi còn phải sửa nhiều chỗ trong các sub ấy, vd. những chỗ bạn dùng Me thì không thể để Me được.
Tóm lại với 1 rừng code thì sửa lại mệt lắm. Có khi viết lại thì nhanh hơn. Nó như đại tu căn nhà ấy, đập đi xây mới còn nhanh hơn.
Nếu bạn quan tâm thì tôi sẽ viết lại toàn bộ code, chỉ giữ giao diện gần giống như của bạn thôi - thiết kế các Label, 2 combo, 2 Label ở dòng cuối, chuyển 4 Button ở dòng đầu thành Label.
Viết qua thôi để bạn tham khảo.
 
Upvote 0
Tình cờ đọc được chủ đề cũ được nhắc lại.
Giới thiệu qua về class thì cũng được thôi nhưng phải xử lý sự kiện click và phải cung cấp một macro để thực hiện khi có click. Macro như thế tôi định gọi bằng Application.Run do vậy phải để nó trong Module. Hiện thời trong LabelClick bạn gọi 1 sub, nhưng macro trong Module không thể gọi sub trong UserForm nên phải chuyển sub kia vào Module. Sub kia lại gọi 1 loạt sub trong UserForm nên lại phải chuyển chúng vào Module. Rồi còn phải sửa nhiều chỗ trong các sub ấy, vd. những chỗ bạn dùng Me thì không thể để Me được.
Tóm lại với 1 rừng code thì sửa lại mệt lắm. Có khi viết lại thì nhanh hơn. Nó như đại tu căn nhà ấy, đập đi xây mới còn nhanh hơn.
Nếu bạn quan tâm thì tôi sẽ viết lại toàn bộ code, chỉ giữ giao diện gần giống như của bạn thôi - thiết kế các Label, 2 combo, 2 Label ở dòng cuối, chuyển 4 Button ở dòng đầu thành Label.
Viết qua thôi để bạn tham khảo.

Dạ, em rất ham muốn được học hỏi, xin thầy viết lại mới toàn bộ đi ạ. Em và những ai muốn học sẽ rất biết ơn Thầy!
 
Upvote 0
Dạ, em rất ham muốn được học hỏi, xin thầy viết lại mới toàn bộ đi ạ. Em và những ai muốn học sẽ rất biết ơn Thầy!

Vài lời về code của bạn:
1. Những chuỗi dùng trong control và Tip bạn nên dùng ChrW "trọn gói" hoặc không dùng "trọn gói" đừng làm nửa vời - một chuỗi có phần để nguyên có phần dùng ChrW. Tôi đính kèm hình cho bạn nhìn CanChi và Tip của bạn được hiển thị như thế nào

View attachment 94669

2. Trong code có chỗ thừa thì phải. Vd. bạn có UserForm_KeyDown. Bạn hãy chỉ ra cho tôi khi nào sẩy ra sự kiện UserForm_KeyDown? Hay tôi chưa xét kỹ? Vì thú thực là nhìn vào rừng code tôi không muốn theo dõi chi tiết.
---------------
Tôi đã cố viết thật hoàn chỉnh và tôi nghĩ có lẽ đã hoàn chỉnh. Tuy nhiên tôi viết mà không có thời gian nhiều để test nên rất có thể có những vấn đề tôi quên chưa làm.
0. Về giao diện thì giống của bạn tới 99,99%
1. Để làm mất focus cho 2 ComboBox (trông rất xấu) thì phải có chỗ chuyển focus đi. Tôi tạo Textbox dấu kín dùng cho mục đích chuyển focus về Textbox. Do chuyển focus về Textbox nên việc xử lý các phím nhấn được thực hiện trong Texbox1_KeyDown.
2. Về các phím thì toàn bộ code của tôi có chú thích đầy đủ nên bạn tự đọc. Ở đây tôi chỉ giải thích thêm.
a. Khi 2 Combobox không có focus (không hiện nút mở danh sách thả) và Shift, Ctrl không được nhấn thì các phím mũi tên dùng để đi sang ngày trước, sau, ở tuần trưỡc, sau.
3. Khi chỉ Shift được nhấn thì: múi tên down, mũi tên trái, phải dùng để mở ComboBox chọn tháng, chọn tháng trước, chọn tháng sau.
4. Khi chỉ Ctrl được nhấn thì: mũi tên down, mũi tên trái, phải dùng để mở ComboBox chọn năm, chọn năm trước, chọn năm sau.
5. Khi Combobox đang mở danh sách thì dùng mũi tên lên xuống. Ta có thể nhấn Enter để đóng danh sách thả và làm mất focus. Nếu ta đóng danh sách thả bằng cách click nút tam giác thì nếu muốn mất focus (vd. để dùng các phím mũi tên di chuyển sang các ngày khác) thì phải nhấn TAB cho tới khi 2 ComboBox mất focus, tức focus được chuyển về Textbox.
6. Khi Textbox có focus thì TAB không tác dụng để không thể chuyển focus sang Combobox. Muốn chuyển focus sang ComboBox và mở danh sách thả thì phải Shift / Ctrl + mũi tên Down. Chuyển focus bằng phím thì hơi rắc rối (vd. chuyển từ control đầu tới control cuối khi có nhiều control) chứ bằng chuột thì nhanh và đơn giản. Muốn focus ở đâu thì click ở đó.
7. Thậm chí cả khi ComboBox có focus và danh sách đang đóng (do click nút của ComboBox) thì user vẫn có thể dùng mũi tên Down, Up để di chuyển sang tháng, năm khác và Enter để chọn và làm mất focus trên ComboBox.
8. User không cần biết code như thế nào. Nếu muốn mở Lịch để chọn ngày tháng thì gọi hàm GetDate. Nếu sau đó user hủy ý định bằng cách nhấn ESC thì hàm trả về chuỗi rỗng. Nếu user nhấn Enter để chọn ngày đang được đánh dấu thì hàm trả về ngày đó.
9. Module modLichAm tôi lấy của bạn nhưng sửa hàm NgayAL và thêm hàm CanChi để phù hợp với nhu cầu code của tôi.
10. Code có ghi chú chi tiết. Có Button Test dùng để test.
11. À còn một vấn đề nữa. Tôi có một mảng 90 đối tượng của class clsLabel. Nhưng chỉ có 84 Label được tạo trong RunTime do 2 lý do. Thứ nhất tôi không đủ kiên nhẫn thả 84 Label xuống Form rồi căn, chỉnh, thiết lập các thuộc tính. Cái nữa là tôi chỉ tạo 84 Label trong RunTime còn 6 Label được tạo trong DesignTime để có cớ chỉ ra 2 cách thiết lập ctrl và macro.

code UserForm1:
[GPECODE=vb]
Private Sub cbMonth_Enter()
cbMonth.DropDown
End Sub

Private Sub cbMonth_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
' nếu user kết thúc lựa chọn bằng Enter thì làm mới Lịch và chuyển focus về TextBox1
If KeyCode = vbKeyReturn Then
Month = cbMonth.ListIndex + 1
FixDay
ShowCalendar
TextBox1.SetFocus
End If
End Sub

Private Sub cbYear_Enter()
cbYear.DropDown
End Sub

Private Sub cbYear_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
' nếu user kết thúc lựa chọn bằng Enter thì làm mới Lịch và chuyển focus về TextBox1
If KeyCode = vbKeyReturn Then
Year = cbYear.ListIndex + 1900
FixDay
ShowCalendar
TextBox1.SetFocus
End If
End Sub

Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
' nếu là TAB được nhấn thì không cho thoát khỏi TextBox1
If TextBox1.Tag Then
TextBox1.Tag = 0
Cancel = True
End If
End Sub

Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
' thiết lập flag rằng TAB được nhấn
If KeyCode = vbKeyTab Then
TextBox1.Tag = 1
Else
' xử lý các phím nhấn
HandleKeys KeyCode, Shift
End If
End Sub

Private Sub HandleKeys(ByVal KeyCode As Integer, ByVal Shift As Integer)
Select Case Shift
Case 0: ' Shift, Ctrl, Alt không được nhấn
Select Case KeyCode
' ngày chọn lùi dần - chỉ tới ngày đầu tháng
Case vbKeyLeft: If lastLabelIndex > StartDayOfWeek + 42 Then DoLabelClick Labels(lastLabelIndex - 1).Label
' ngày chọn tiến dần - chỉ tới ngày cuối tháng
Case vbKeyRight: If lastLabelIndex < StartDayOfWeek + TotalDays + 41 Then DoLabelClick Labels(lastLabelIndex + 1).Label
' ngày chọn là cùng thứ nhưng ở tuần trước
Case vbKeyUp: If lastLabelIndex > StartDayOfWeek + 48 Then DoLabelClick Labels(lastLabelIndex - 7).Label
' ngày chọn là cùng thứ nhưng ở tuần sau
Case vbKeyDown: If lastLabelIndex < StartDayOfWeek + TotalDays + 35 Then DoLabelClick Labels(lastLabelIndex + 7).Label
' nếu ESC thì trả về chuỗi rỗng, nêu Enter thì ngày chọn là DateSerial(Year, Month, Day)
' đóng Form
Case vbKeyEscape, vbKeyReturn:
If KeyCode = vbKeyEscape Then Day = 0
Unload Me
End Select
Case 1: ' chỉ có Shift nhấn
If KeyCode = vbKeyLeft Then
' chọn tháng trước
DoLabelClick Labels(87).Label
ElseIf KeyCode = vbKeyRight Then
' chọn tháng sau
DoLabelClick Labels(88).Label
ElseIf KeyCode = vbKeyDown Then
' mở danh sách thả chọn tháng
cbMonth.SetFocus
End If
Case 2: ' chỉ có Ctrl nhấn
If KeyCode = vbKeyLeft Then
' chọn năm trước - chỉ tới 1900
DoLabelClick Labels(89).Label
ElseIf KeyCode = vbKeyRight Then
' chọn năm sau - chỉ tới 2199
DoLabelClick Labels(90).Label
ElseIf KeyCode = vbKeyDown Then
' mở danh sách thả chọn năm
cbYear.SetFocus
End If
End Select
End Sub

Private Sub InitCalendar()
Dim index As Long, k As Long, t As Double, t1 As Double
On Error GoTo end_
' mảng 90 Label
ReDim Labels(1 To 90)
' tạo 84 Label và cung cấp macro cho Click - 42 Label với Caption là ngày dương, 42 Label với Caption là ngày âm
For index = 1 To 84
k = index
If k > 42 Then k = k - 42
Labels(index).Create Me, index, "DoLabelClick", 1 + ((k - 1) Mod 7) * 40, 37 + ((k - 1) \ 7) * 30, 40, 30
Next
' 6 Label cho vào mảng đã được tạo trong DesignTime
Set Labels(85).Label = lbDuong
Set Labels(86).Label = lbAm
Set Labels(87).Label = lbMonthLeft
Set Labels(88).Label = lbMonthRight
Set Labels(89).Label = lbYearLeft
Set Labels(90).Label = lbYearRight
' cung cấp macro cho Click cho các Label <, >
For index = 87 To 90
Labels(index).Label.Tag = index
Labels(index).Macro = "DoLabelClick"
Next
' tiêu đề các này trong tuần
Label1.Caption = "CN"
Label2.Caption = "Hai"
Label3.Caption = "Ba"
Label4.Caption = "T" & ChrW(432)
Label5.Caption = "N" & ChrW(259) & "m"
Label6.Caption = "S" & ChrW(225) & "u"
Label7.Caption = "B" & ChrW(7849) & "y"
' các lời nhắc, mách nước cho các Label <, > và 2 ComboBox chọn Tháng và Năm
lbMonthLeft.ControlTipText = "Ch" & ChrW(7885) & "n th" & ChrW(225) & "ng tr" & ChrW(432) & ChrW(7899) & "c"
lbMonthRight.ControlTipText = "Ch" & ChrW(7885) & "n th" & ChrW(225) & "ng sau"
lbYearLeft.ControlTipText = "Ch" & ChrW(7885) & "n n" & ChrW(259) & "m tr" & ChrW(432) & ChrW(7899) & "c"
lbYearRight.ControlTipText = "Ch" & ChrW(7885) & "n n" & ChrW(259) & "m sau"
cbMonth.ControlTipText = "Ch" & ChrW(7885) & "n th" & ChrW(225) & "ng"
cbYear.ControlTipText = "Ch" & ChrW(7885) & "n n" & ChrW(259) & "m"
' nhập tháng vào ComboBox chọn Tháng
For index = 1 To 12
cbMonth.AddItem "Th" & ChrW(225) & "ng " & Format(index, "00")
Next
' nhập năm vào ComboBox chọn Năm
For index = 1900 To 2199
cbYear.AddItem "N" & ChrW(259) & "m " & index
Next
' số ngày các tháng bình thường (không nhuận) trong năm
MonthLen = Array(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
' tên các ngày trong tuần
TenNgay = Array("Ch" & ChrW(7911) & " Nh" & ChrW(7853) & "t", "Th" & ChrW(7913) & " Hai", "Th" & ChrW(7913) & " Ba", "Th" & ChrW(7913) & " T" & ChrW(432), _
"Th" & ChrW(7913) & " N" & ChrW(259) & "m", "Th" & ChrW(7913) & " S" & ChrW(225) & "u", "Th" & ChrW(7913) & " B" & ChrW(7849) & "y")
' ngày hiện tại
YearToday = DatePart("yyyy", Date)
MonthToday = DatePart("m", Date)
DayToday = DatePart("d", Date)
todayLabelIndex = FirstDayOfMonth(MonthToday, YearToday) + DayToday - 1
' ngày đang được chọn
If Not IsDate(SelectDate) Then SelectDate = Date
Year = DatePart("yyyy", SelectDate)
Month = DatePart("m", SelectDate)
Day = DatePart("d", SelectDate)
' nhập vào ComboBox chọn Tháng và Năm ngày đang được chọn - ngày hiện tại ở lần mở đầu tiên
' hoặc ngày được chọn ở lần mở trước
cbMonth.Value = "Th" & ChrW(225) & "ng " & Format(Month, "00")
cbYear.Value = "N" & ChrW(259) & "m " & Year
end_:
End Sub

Private Sub HideTitlebar(ByVal hForm As Long)
Dim Style As Long, TitleHeight As Single
Style = GetWindowLong(hForm, GWL_STYLE)
TitleHeight = Me.height - Me.InsideHeight
Style = (Style And Not WS_CAPTION)
SetWindowLong hForm, GWL_STYLE, Style
Me.height = Me.height - TitleHeigh
DrawMenuBar hForm
End Sub

Private Sub UserForm_Initialize()
Dim hForm As Long
On Error GoTo end_
' tìm handle của cửa sổ UserForm - cửa sổ Lịch
hForm = FindWindow("ThunderDFrame", Me.Caption)
' bỏ thanh tiêu đề
HideTitlebar hForm
' khởi tạo các control và thiết lâp
InitCalendar
' hiển thị Lịch
ShowCalendar
end_:
End Sub

Private Sub UserForm_Terminate()
' hủy các Label được tạo
Erase Labels
End Sub
[/GPECODE]
 

File đính kèm

  • myCalendar.rar
    61.4 KB · Đọc: 104
Lần chỉnh sửa cuối:
Upvote 0
Tiếp bài trước. Do dài quá nên phải chia làm 2 phần.

code module modCalendar:
[GPECODE=vb]
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function DrawMenuBar Lib "user32" (ByVal hWnd As Long) As Long

Public Const WS_CAPTION = &HC00000
Public Const GWL_STYLE = (-16)

Public Labels() As New clsLabel
Public Year As Long, Month As Long, Day As Long, YearToday As Long, MonthToday As Long, DayToday As Long
Public MonthLen As Variant, TenNgay As Variant
Public SelectDate As Variant, Today As Variant, lastLabelIndex As Long, todayLabelIndex As Long
Public StartDayOfWeek As Integer, TotalDays As Integer

' hàm trả về ngày tháng năm được chọn hoặc chuỗi rỗng nếu user nhấn ESC để hủy chọn
Function GetDate()
UserForm1.Show
' nếu user hủy chon bằng cách nhấn ESC thì Day = 0
If Day Then
' ngày tháng năm được chọn
SelectDate = DateSerial(Year, Month, Day)
GetDate = SelectDate
Else
GetDate = vbNullString
End If
End Function

' hàm trả về số thứ tự trong tuần (chủ Nhật là ngày đầu tiên) của ngày mồng 1 của tháng
Function FirstDayOfMonth(ByVal m As Integer, ByVal y As Integer) As Integer
FirstDayOfMonth = DatePart("w", DateSerial(y, m, 1), vbSunday)
End Function

Public Sub ShowCalendar()
Dim index As Long, currLabelIndex As Long

StartDayOfWeek = FirstDayOfMonth(Month, Year)
' số thứ tự của Label hiện hành tưng ứng với ngày đang được chọn
currLabelIndex = StartDayOfWeek + Day + 41
' số ngày trong tháng đang được chọn
If Month <> 2 Then
TotalDays = MonthLen(Month)
Else
TotalDays = DatePart("d", DateSerial(Year, 3, 1) - 1)
End If
' ẩn những Label không cần thiết và hiện những Label cần thiết trong tuần đầu tiên
For index = 1 To 7
If index < StartDayOfWeek Then
Labels(index).Label.Visible = False
Labels(index + 42).Label.Visible = False
Else
Labels(index).Label.Visible = True
Labels(index + 42).Label.Visible = True
End If
Next
' ẩn những Label không cần thiết và hiện những Label cần thiết trong các dòng cuối
For index = 29 To 42
If index < StartDayOfWeek + TotalDays Then
Labels(index).Label.Visible = True
Labels(index + 42).Label.Visible = True
Else
Labels(index).Label.Visible = False
Labels(index + 42).Label.Visible = False
End If
Next
' "in" ngày dương và âm trên các Label
For index = 1 To TotalDays
Labels(index + StartDayOfWeek - 1).Label.Caption = index
Labels(index + StartDayOfWeek + 41).Label.Caption = NgayAL(index, Month, Year)
Next

UpdateSelectedDate currLabelIndex
End Sub

Private Sub UpdateSelectedDate(ByVal currLabelIndex As Long)
Dim form As Object
' ngày đang được chọn
Day = Labels(currLabelIndex - 42).Label.Caption
' nếu có ngày trước đó được chọn tức Label có khung viền thì bỏ khung viền và mầu
If lastLabelIndex Then
Labels(lastLabelIndex).Label.BorderColor = &H80000004
Labels(lastLabelIndex - 42).Label.BackStyle = fmBackStyleTransparent
End If
lastLabelIndex = currLabelIndex
' hiện khung viền và mầu nền cho ngày hiện được chọn
Labels(lastLabelIndex).Label.BorderColor = &H0
Labels(lastLabelIndex - 42).Label.BackStyle = fmBackStyleOpaque
' thông tin về ngày dương và ngày âm - dòng cuối
Labels(85).Label.Caption = TenNgay((currLabelIndex - 1) Mod 7) & " " & DateSerial(Year, Month, Day)
Labels(86).Label.Caption = Replace(Labels(currLabelIndex).Label.Caption, vbCrLf, " ") & " " & Canchi(Day, Month, Year)
' nếu lịch của tháng và năm hiên hành thì tômầu nền của ngày hiện hành - today
If Month = MonthToday And Year = YearToday Then
Labels(todayLabelIndex).Label.BackStyle = fmBackStyleOpaque
Labels(todayLabelIndex).Label.BackColor = &HFF
Labels(todayLabelIndex).Label.ForeColor = &HFFFFFF
Labels(todayLabelIndex + 42).Label.ForeColor = &HFFFFFF
Else
' ngược lại thì bỏ mầu
Labels(todayLabelIndex).Label.BackStyle = fmBackStyleTransparent
Labels(todayLabelIndex).Label.BackColor = &HC0FFFF
Labels(todayLabelIndex).Label.ForeColor = &H0
Labels(todayLabelIndex + 42).Label.ForeColor = &H0
End If
End Sub

' macro thực thi khi click Label
Sub DoLabelClick(ctrl As MSForms.Label)
If ctrl.Tag < 85 Then
' chỉ các Label ứng với các ngày trong tháng
UpdateSelectedDate ctrl.Tag
Else
' các Label chuyển tháng hoặc năm - các Label <, >
Select Case ctrl.Tag
' tăng 1 hoặc giảm 1 giá trị của tháng hoặc năm
Case 87: If Month > 1 Or Year > 1900 Then Month = Month - 1
Case 88: If Month < 12 Or Year < 2199 Then Month = Month + 1
Case 89: If Year > 1900 Then Year = Year - 1
Case 90: If Year < 2199 Then Year = Year + 1
End Select
' sửa lại tháng
If Month < 1 Then
Month = 12
Year = Year - 1
ElseIf Month > 12 Then
Month = 1
Year = Year + 1
End If

FixDay
' thay đổi giá trị của ComboBox chọn tháng và năm
ctrl.Parent.cbMonth.ListIndex = Month - 1
ctrl.Parent.cbYear.ListIndex = Year - 1900
' hiển thị Lịch
ShowCalendar
End If
End Sub

Sub FixDay()
' nếu chỉ số ngày hiện hành > số ngày trong tháng thì giảm chỉ số ngày hiện hành
Do While MonthLen(Month) < Day
Day = Day - 1
Loop
End Sub
[/CODE]

code clsLabel:
Mã:
Private WithEvents ctrl As MSForms.Label
Private strMacro As String, DoFree As Boolean

Private Sub Class_Terminate()
    If DoFree And Not ctrl Is Nothing Then
        Set ctrl = Nothing
    End If
End Sub

Property Get Label() As MSForms.Label
    Set Label = ctrl
End Property

Property Set Label(ctl As MSForms.Label)
    Set ctrl = ctl
End Property

Property Let Macro(ByVal cmd As String)
    strMacro = cmd
End Property

Public Sub Create(form As MSForms.UserForm, ByVal index As Long, ByVal Macro As String, _
    ByVal left As Integer, ByVal top As Integer, ByVal width As Integer, ByVal height As Integer)
On Error Resume Next
    Set ctrl = form.Controls.Add("Forms.Label.1")
    If Not ctrl Is Nothing Then
        strMacro = Macro
        DoFree = True
        With ctrl
            .BorderColor = &H80000004
            .BorderStyle = fmBorderStyleSingle
            .BackColor = &HC0FFFF
            .BackStyle = fmBackStyleTransparent
            If (index - 1) Mod 7 = 0 Then .ForeColor = &HFF
            .Font.Name = "Times New Roman"
            .Font.Size = 10
            If index > 42 Then .TextAlign = fmTextAlignRight
            .Tag = index
            If left > 0 Then .left = left
            If top > 0 Then .top = top
            If width > 0 Then .width = width
            If height > 0 Then .height = height
        End With
    End If
End Sub

Private Sub ctrl_Click()
    On Error Resume Next
    If strMacro <> vbNullString Then Application.Run strMacro, ctrl
End Sub
[/GPECODE]
 
Lần chỉnh sửa cuối:
Upvote 0
Hôm trước mình có gợi ý Nghĩa sử dụng class cho các label, nhưng khi thử làm thì không được.
Hôm nay thấy siwtom làm class, mừng quá lấy về xem, thì thấy còn lâu mình mới tự làm được như vậy. Hic, còn phải học nhiều!
 
Upvote 0
Hôm trước mình có gợi ý Nghĩa sử dụng class cho các label, nhưng khi thử làm thì không được.
Hôm nay thấy siwtom làm class, mừng quá lấy về xem, thì thấy còn lâu mình mới tự làm được như vậy. Hic, còn phải học nhiều!

Cái này nó là một phần kiến thức trong lập trình dù bạn lập trình trong ngôn ngữ nào.
Do bạn chưa có nhu cầu nên bạn chưa làm hoặc ít làm. Chứ nếu phải làm thì bạn phải học, tức phải đọc, phải tự viết, tự thử nghiệm thì đương nhiên bạn sẽ biết làm. Sau đó có chuyển sang ngôn ngữ khác thì bạn cũng nhanh chóng biết làm vì cái cơ bản bạn đã hiểu, đã biết. Cú pháp có thể khác trong mỗi ngôn ngữ nhưng "cơ cấu cơ bản", lôgíc, triết lý là như nhau.
 
Upvote 0
---------------
Tôi đã cố viết thật hoàn chỉnh và tôi nghĩ có lẽ đã hoàn chỉnh. Tuy nhiên tôi viết mà không có thời gian nhiều để test nên rất có thể có những vấn đề tôi quên chưa làm.
[/GPECODE]
Tôi muốn khi chọn (hoặc gõ) tháng và năm trên các Combobox thì lịch nhảy theo, hình như anh quên?

--------
To Nghĩa: Cần phải bố trí thêm một nút để quay trở về ngày hiện tại
 
Upvote 0
Tôi muốn khi chọn (hoặc gõ) tháng và năm trên các Combobox thì lịch nhảy theo, hình như anh quên?

--------
To Nghĩa: Cần phải bố trí thêm một nút để quay trở về ngày hiện tại

Tại 2 label cuối của form hiển thị lịch Dương và Âm, anh rê ngang chuột sẽ thấy có dòng Tip, dĩ nhiên anh click vào 2 label này nó trở về ngày hiện hành.

Anh nên tải tại bài này, nó đầy đủ hơn (file đã update):

http://www.giaiphapexcel.com/forum/...n-ích-CALENDAR-tuyệt-đẹp!&p=451406#post451406
 
Lần chỉnh sửa cuối:
Upvote 0
Cái này nó là một phần kiến thức trong lập trình dù bạn lập trình trong ngôn ngữ nào.
Do bạn chưa có nhu cầu nên bạn chưa làm hoặc ít làm. Chứ nếu phải làm thì bạn phải học, tức phải đọc, phải tự viết, tự thử nghiệm thì đương nhiên bạn sẽ biết làm. Sau đó có chuyển sang ngôn ngữ khác thì bạn cũng nhanh chóng biết làm vì cái cơ bản bạn đã hiểu, đã biết. Cú pháp có thể khác trong mỗi ngôn ngữ nhưng "cơ cấu cơ bản", lôgíc, triết lý là như nhau.
Bài này Thầy gửi lên rất quan trọng đối với em và mọi người để được học thuật và cải thiện kiến thức của mình. Em rất cám ơn sự nhiệt huyết của Thầy.

Tuy nhiên cho em nói về file của Thầy một chút, có một số cần phải nói vì Thầy cũng cần có người test những sản phẩm của mình.

1) Các combobox tháng, năm không hoạt động khi chúng thay đổi do người dùng chọn.

2) Khi bấm phím phải hoặc trái, tại ngày đầu tháng hoặc cuối tháng nó không thể di chuyển sang tháng sau hoặc tháng trước. Và cũng vậy với phím lên xuống, khi ô hiện hành sát ở đỉnh hoặc đáy thì bấm thêm nó không chuyển qua tháng trước hoặc tháng sau.

3) Nên chăng thêm thuộc tính kéo thả form cho các Label thứ trong tuần.

4) Để trở về ngày hiện hành, em vẫn chưa biết vận dụng như thế nào.

5) Không biết có ý đồ gì không, nhưng hình như qua tháng khác thì ngày 28 lại không đổi màu.

Đó là một số vấn đề em test được, xin được Thầy cải tiến thêm.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi muốn khi chọn (hoặc gõ) tháng và năm trên các Combobox thì lịch nhảy theo, hình như anh quên?

Đúng là mải mê chuột với bàn phím nên quên về chuyện user có thể tự gõ chứ không chọn bằng chuột hay bàn phím. Vd. nếu muốn chọn Năm 2155 thì phải cuộn danh sách lâu nên nhanh nhất là tự gõ.
Nhưng không phải là hiện giờ user không gõ được. Gõ được bình thường. Chỉ có điều tôi quên vụ user tự gõ nên không chuẩn bị thuốc cho bệnh "gõ nhầm", cố tình "gõ nhầm" (vd. gõ hichic). Code phải "trơ" với những tình huống như thế.
------------
Tôi thay
Mã:
Private Sub cbMonth_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    If KeyCode = vbKeyReturn Then
        Month = cbMonth.ListIndex + 1
        FixDay
        ShowCalendar
        TextBox1.SetFocus
    End If
End Sub

Private Sub cbYear_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    If KeyCode = vbKeyReturn Then
        Year = cbYear.ListIndex + 1900
        FixDay
        ShowCalendar
        TextBox1.SetFocus
    End If
End Sub

bằng

Mã:
Private Sub cbMonth_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
'    nếu user kết thúc lựa chọn bằng Enter thì làm mới Lịch và chuyển focus về TextBox1
    If KeyCode = vbKeyReturn Then
        If cbMonth.ListIndex > -1 Then
            Month = cbMonth.ListIndex + 1
            FixDay
            ShowCalendar
        Else
            cbMonth.Value = "Th" & ChrW(225) & "ng " & Format(Month, "00")
        End If
        TextBox1.SetFocus
    End If
End Sub

Private Sub cbYear_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
'    nếu user kết thúc lựa chọn bằng Enter thì làm mới Lịch và chuyển focus về TextBox1
    If KeyCode = vbKeyReturn Then
        If cbYear.ListIndex > -1 Then
            Year = cbYear.ListIndex + 1900
            FixDay
            ShowCalendar
        Else
            cbYear.Value = "N" & ChrW(259) & "m " & Year
        End If
        TextBox1.SetFocus
    End If
End Sub

Nên chú ý là không có chuyện "Tôi muốn khi chọn (hoặc gõ) tháng và năm trên các Combobox thì lịch nhảy theo". Vì nếu nói về chọn bằng chuột thì có thể chọn nhầm, ta cho user cơ hội chọn lại. Còn về gõ thì biết lúc nào user gõ xong? Vậy chọn hay gõ xong thì phải Enter. Tôi đã viết rõ rồi - điểm 7 của hướng dẫn

Còn nếu ý bạn là "chọn - gõ" có nghĩa là chọn hoặc gõ xong thì Enter thì hiện thời vẫn làm được đó thôi. Cái tôi quên là chưa "chuẩn bị thuốc" cho bệnh nhập sai.


Các bạn xem lại hộ. Tập tin đính kèm cũng đã sửa lại.
 
Lần chỉnh sửa cuối:
Upvote 0
Bài này Thầy gửi lên rất quan trọng đối với em và mọi người để được học thuật và cải thiện kiến thức của mình. Em rất cám ơn sự nhiệt huyết của Thầy.

Tuy nhiên cho em nói về file của Thầy một chút, có một số cần phải nói vì Thầy cũng cần có người test những sản phẩm của mình.

1) Các combobox tháng, năm không hoạt động khi chúng thay đổi do người dùng chọn.

Bạn không đọc kỹ bài của tôi rồi

7. Thậm chí cả khi ComboBox có focus và danh sách đang đóng (do click nút của ComboBox) thì user vẫn có thể dùng mũi tên Down, Up để di chuyển sang tháng, năm khác và Enter để chọn và làm mất focus trên ComboBox.

Tức là khi gõ hoặc chọn xong thì chả có gì thay đổi cả. Phải nhấn Enter để kết thúc, lúc đó mới có thay đổi.
Tôi đã viết ở bài cho thanhlanh: user có thể chọn sai, tôi cho user cơ hội chọn lại. Khi kiểm tra thấy đúng ý mình thì ENTER để thay đổi.
Chuyện này là dụng ý của tôi thế và tôi đã viết hướng dẫn.

2) Khi bấm phím phải hoặc trái, tại ngày đầu tháng hoặc cuối tháng nó không thể di chuyển sang tháng sau hoặc tháng trước. Và cũng vậy với phím lên xuống, khi ô hiện hành sát ở đỉnh hoặc đáy thì bấm thêm nó không chuyển qua tháng trước hoặc tháng sau.

Đây cũng là tôi cố tình cho thế

' ngày chọn lùi dần - chỉ tới ngày đầu tháng
Case vbKeyLeft: If lastLabelIndex > StartDayOfWeek + 42 Then DoLabelClick Labels(lastLabelIndex - 1).Label
' ngày chọn tiến dần - chỉ tới ngày cuối tháng
Case vbKeyRight: If lastLabelIndex < StartDayOfWeek + TotalDays + 41 Then DoLabelClick Labels(lastLabelIndex + 1).Label

Cái chữ đỏ là tôi muốn nói chỉ cho phép như thế. 2 cái IF chính là để đảm bảo "chỉ cho phép như thế". Tôi cố tình như thế vì tôi cho rằng nếu vd. user đang đứng ở ngày 25 thì để chuyển sang ngày cuối tháng trước hay ngày đầu tháng sau thì chọn luôn tháng trước hay tháng sau nhanh hơn.

Nói chung mỗi người có một quan niệm. Tôi không muốn làm y như bạn và thực tình cũng không đọc hết các bài dài để biết bạn muốn có những chi tiết gì. Tôi viết chỉ để bạn tham khảo chứ không phải viết theo đơn đặt hàng của bạn. Vì viết theo đơn đặt hàng thì phải có tất cả mọi chức năng mà người đặt hàng yêu cầu, dù cho những yêu cầu đó như thế nào chăng nữa, thậm chí phi lý. Vì "người chi tiền" là thượng đế mà. Không đúng thế thì "không thanh toán".


3) Nên chăng thêm thuộc tính kéo thả form cho các Label thứ trong tuần.
Bạn có thể miêu tả "thuộc tính kéo thả form cho các Label thứ trong tuần" mặt mũi nó thế nào không?
Tôi không đọc hết các bài bạn giới thiệu Lịch của mình nên tôi không biết nó có những chức năng gì thêm

4) Để trở về ngày hiện hành, em vẫn chưa biết vận dụng như thế nào.
À, cái này thì tôi chưa có. Bạn cần thế à? Nếu cần thì để tôi thêm

5) Không biết có ý đồ gì không, nhưng hình như qua tháng khác thì ngày 28 lại không đổi màu.

Đó là một số vấn đề em test được, xin được Thầy cải tiến thêm.

Bạn miêu tả rõ một chút tôi sẽ xem xét lại.
 
Upvote 0
Theo tôi nghĩ thì đúng như siwtom nói: Bài viết topic này cũng như tất cả các topic khác của gpe, của siwtom cũng như của người khác, là đưa ra giải thuật để người đọc chọn lọc, nếu hay thì học hỏi. Chứ không phải viết theo đơn đặt hàng, cũng như không phải viết để cho giống cái có sẵn 100%.

Người dùng có muôn ngàn nhu cầu khác nhau, và cách dùng khác nhau. Để chọn 1 mục trong combobox, có người dùng bàn phím gõ, người dùng phím mũi tên, người thì dùng chuột.

Người thì muốn có kết quả ngay dù đúng hay sai, người thì muốn sửa sang cho đúng ý rồi mới enter. Làm sao mà chiều cho hết được?

Nói thật, trong topic này tôi chỉ muốn học cái class của siwtom. Còn những code khác như mouse move, key up, key down (của Nghĩa), tôi không quan tâm. Như tôi đã nói trong bài trên, Nghĩa dồn tất cả cái biết, cái đã học, cái đã nghiên cứu, ... vào trong 1 dự án, mà về chức năng thì Excel có sẵn. Sau đó, lại muốn người khác làm cho giống hệt cái của mình. Dẫu để học chăng nữa (cũng đáng để học), nhưng vẫn là để nhồi nhét những cái tốt hơn vào dự án ban đầu, mà dự án đó, thay xong, vẫn chỉ bằng hoặc kém hơn cái có sẵn của excel.

Tát nhiên có cái hơn là có âm lịch, nhưng nếu chỉ để xem âm lịch thì có bao nhiêu loại lịch trên gpe để xem mà lại đơn giản hơn nhiều.

Nếu bây giờ bàn rằng tạo thêm tiện ích sao cho khi chọn ngày xong có thể set ngày chọn âm lịch xuống sheet hoặc xuống form khác, chắc chắn cũng sẽ làm được. Nhưng nghĩa là cái dự án cứ thế phình to ra, trong khi công dụng thực sự chả mấy tí.
 
Upvote 0
Thí dụ với yêu cầu này:
3) Nên chăng thêm thuộc tính kéo thả form cho các Label thứ trong tuần.
Theo tôi hiểu thì Nghĩa muốn kéo thả label chẳng hạn như Sunday từ cuối lên đầu và ngược lại, để cho tuần bắt đầu từ chủ nhật thay vì thứ hai.

Yêu cầu này tôi cho rằng có thể làm được. Có nghĩa là thêm ít nhất 1 trang A4 code nữa. Nhưng để làm gì? Để phục vụ người dùng chăng? Rồi nếu có người muốn tuần bắt đầu từ thứ 4 cơ, hoặc mở rộng ra thì muốn tuần bắt đầu từ thứ mấy cũng được, thì sẽ vứt 1 trang A4 vừa rồi, làm lại 1 trang rưỡi A4 khác.

Cứ thế, và cứ thế, cuối cùng thì sau khi tạo thành add-in cho người dùng, nội việc load nó vào excel cũng đủ mệt mỏi, mà không phải lúc nào cũng dùng tới.
Hoặc gắn nó vào mỗi file chuyên dùng, thì lại quá dư. Mỗi file chắc chắn chỉ dùng 1 vài chức năng trong số hàng mấy chục chức năng đã khổ công viết.
 
Upvote 0
Bạn không đọc kỹ bài của tôi rồi

7. Thậm chí cả khi ComboBox có focus và danh sách đang đóng (do click nút của ComboBox) thì user vẫn có thể dùng mũi tên Down, Up để di chuyển sang tháng, năm khác và Enter để chọn và làm mất focus trên ComboBox.

Em tải cái file đầu tiên, khi em chọn một mục ở combobox Tháng, rồi enter, ngay lập tức nó chuyển focus sang combobox Năm, xổ list của combobox này ra, nhưng hoàn toàn không có việc thay đổi ngày tháng năm theo những tháng, năm em chọn.

Và em đã tải 3 lần, cả 3 lần code đều khác nhau, có thể Thầy đã update trong mỗi phiên bản.

Như em cũng đã nói là học thuật, vì học thuật cũng có nhiều cách để học, Thầy dạy cho em nhiều thì em được biết nhiều, Thầy dạy cho em ít thì em biết ít. Có thể nói em tham lam, nhồi nhét nhiều thủ tục trong một ứng dụng, thật sự em cũng muốn người dùng cảm thấy hơn cái mà họ có sẳn và tiện ích hơn thì em đã thành công (mặc dù code em rườm rà, dài vằng vặc là vì em không có kiến thức sâu rộng như các Thầy).

Mà đã nói ứng dụng thay thế, nếu nó không bằng thằng control calendar, thì ai mà xài? Phải có điểm hơn mới thể dùng được.

Các điểm hơn mà chúng ta phải tạo:

1) Về các ngày thứ bảy, chủ nhật chúng ta phải cá nhân hóa bằng màu nền (cái này calendar không có); ngày hiện hành nó cũng không cho ta biết nằm ở đâu, chỉ có ngày mà chúng ta chọn nó khác màu so với các ngày khác. Đã ăn chắc mặc bền rồi thì cũng phải có nhu cầu cao hơn là ăn ngon mặc đẹp nữa chứ!

2) Chọn về ngày hôm nay (ngày hiện hành) mình làm được (dĩ nhiên calendar cũng làm được nếu ta cho nút lệnh calendar.value = date)

3) Giống hoặc gần giống hoàn toàn với calendar về nhiều thứ, nhất là khoản chọn lịch trên combobox: Không cho gõ trên đó, chỉ được xổ danh sách và chọn trong đó, sau khi chọn nó update liền tháng, năm được chọn, kể cả lịch trong điện thoại di động cũng làm như thế.

Các điểm hạn chế của lịch em cải tiến là:

- Khi chọn tháng, năm lịch update ngày hơi chậm hơn so với calendar

- Mỗi lần qua tháng khác, năm khác thường bị chớp màn hình.

- Code quả thật như các Thầy nhận xét, quá dài (nhưng đành chịu, không bỏ một trong các mắc xích được vì kiến thức hạn hẹp)

CHÍNH VÌ HIỂU ĐƯỢC BẢN CHẤT CỦA MÌNH MẠNH ĐIỂM NÀO, YẾU ĐIỂM NÀO ĐỂ MÌNH PHÁT HUY VÀ KHẮC PHỤC, cho nên em muốn học thêm thuật toán của các THẦY để dần dần hoàn thiện. Và luôn tự nhủ mình học vậy là hoàn toàn miễn phí từ các Thầy, nên các Thầy truyền đạt được nhiều thì em học được nhiều, dù ít hay nhiều em vẫn luôn luôn biết ơn và trân trọng, chứ em không bao giờ có ý nghĩ mình là người "đặt hàng" để đòi hỏi người "nhận hàng" phải làm thế này thế kia.

Em cám ơn Thầy rất nhiều ạ.
 
Lần chỉnh sửa cuối:
Upvote 0
Cái mà tôi quan tâm nhất trong topic này là: Liệu có thể tạo được 1 cái Calendar hoạt động gần giống như Calendar Control của Excel không?
Hoạt động gần giống nghĩa là:
- Khi click vào 1 ngày nào đó, tôi muốn giá trị ngày ấy gán vào đâu (trên cell, trên textbox hay bất kỳ đâu) thì nó sẽ gán vào đó
- Khi tôi muốn Calendar Show tại vị trí nào thì nó sẽ show đúng vị trí đó
- Code phải được Save thành 1 AddIn để dùng bất cứ khi nào tôi cần
vân vân...
Để làm chi? Để trong trường hợp tôi không thể cài được MSCAL.OCX (Office 64 không xài được) thì ít nhất tôi cũng có cái để dùng
----------------
Như vậy đấy! Nhưng xem ra thì cuối cùng cái Calendar này chỉ để... nhìn, mức độ ứng dụng chưa cao
 
Upvote 0
Web KT
Back
Top Bottom