Tặng tiện ích CALENDAR tuyệt đẹp (phần 4 - Version 7 - Định vị trên Frame/MultiPage)

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,662
Được thích
16,717
Giới tính
Nam
Trong phiên bản 7 này, tôi đã cập nhật tính năng định vị CALENDAR sẽ hiển thị dưới các TextBox chứa trong UserForm, Frame/MultiPage.

Cal1.jpg

Các phiên bản trước chỉ xác định đúng khi TextBox chỉ chứa trong UserForm, nhưng một số chương trình lại đặt TextBox lấy ngày tháng đó trong một hay nhiều Frame hoặc/và Multipage thì Calendar không xác định chính xác Top & Left của nó so với TextBox. Và lần này cũng bổ sung, nếu cái TextBox sát màn hình Window, nó sẽ dịch chuyển lên trên hoặc qua trái.

Cal2.jpg

Cấu trúc của việc nhúng lịch cũng dễ dàng hơn và đơn giản hơn.

1) Trên Sheet:

1.1) Thủ tục:

Mã:
Public Sub CalendarOnSheet(ByVal RangeOrObject As Object)
    pubShowModal = False
    pubIsRange = (TypeName(RangeOrObject) = "Range")
    Set pubDateObject = RangeOrObject
    On Error Resume Next
    Dim myArr
    Dim myLeft As Single, myTop As Single
    myArr = CellOrControlPosition(RangeOrObject)
    If IsArray(myArr) Then
        myLeft = myArr(1)
        myTop = myArr(2)
        With Application
            If myLeft + usfCalendar.Width > .Left + .Width Then
                myLeft = myLeft - usfCalendar.Width
                If TypeName(RangeOrObject) = "Range" Then
                    myLeft = myLeft + RangeOrObject.Width * ActiveWindow.Zoom / 100
                End If
            End If
            If myTop + usfCalendar.Height > .Top + .Height Then
                myTop = myTop - usfCalendar.Height - RangeOrObject.Height * ActiveWindow.Zoom / 100
            End If
        End With
        If Not pubIsRange Then
            ActiveCell.Select
        End If
    End If
    DatePicked RangeOrObject.Value
    With usfCalendar
        .StartUpPosition = 0
        .Left = myLeft
        .Top = myTop
        .Show False
    End With
End Sub

1.2) Nhúng trên CELL:

Mã:
Run "CalendarShow_V.7.xla!CalendarOnSheet", Range("C5")

Run "CalendarShow_V.7.xla!CalendarOnSheet", Target

Run "CalendarShow_V.7.xla!CalendarOnSheet", ActiveCell

1.3) Nhúng trên ActiveX Controls:

Mã:
Run "CalendarShow_V.7.xla!CalendarOnSheet", TextBox1

Run "CalendarShow_V.7.xla!CalendarOnSheet", ComboBox1

2) Trên UserForm:

2.1) Thủ tục:

Trong thủ tục này, tôi đặc biệt cám ơn bạn doveandrose đã giúp tôi xác định InsideHeight của MultiPage và bạn jack nt đã giúp tôi xác định FullName của một Control.

PHP:
Public Sub CalendarOnForm(ByVal DateObject As Object, ByVal UserForm As Object)
    pubShowModal = True
    Set pubDateObject = DateObject
    On Error Resume Next
Dim Ctrl As Control
Dim myEdge As Single, myLeft As Single, myTop As Single
    With UserForm
        myEdge = (.Width - .InsideWidth) / 2
        myLeft = .Left + myEdge
        myTop = .Top + .Height - .InsideHeight - myEdge
    End With
    Set Ctrl = DateObject
    Do Until Ctrl.Parent.Name = UserForm.Name
        Set Ctrl = Ctrl.Parent
        If Not Ctrl.Name Like "Page*" Then
            Select Case TypeName(Ctrl)
            Case "Frame"
                With Ctrl
                    myEdge = (.Width - .InsideWidth) / 2
                    myLeft = myLeft + .Left + myEdge
                    myTop = myTop + .Top + .Height - .InsideHeight - myEdge
                End With
            Case "MultiPage"
                With Ctrl
                    myEdge = (.Width - .Pages(0).InsideWidth) / 2
                    myLeft = myLeft + .Left + myEdge
                    myTop = myTop + .Top + .Height - .Pages(0).InsideHeight - myEdge
                End With
            End Select
        End If
    Loop
    With DateObject
        myLeft = myLeft + .Left
        myTop = myTop + .Top + .Height
        DatePicked .Value
    End With
    With Application
        If myLeft + usfCalendar.Width > .Left + .Width Then
            myLeft = myLeft - usfCalendar.Width
        End If
        If myTop + usfCalendar.Height > .Top + .Height Then
            myTop = myTop - usfCalendar.Height - DateObject.Height
        End If
    End With
    With usfCalendar
        .StartUpPosition = 0
        .Left = myLeft
        .Top = myTop
        .Show
    End With
End Sub

2.2) Control trong UserForm, thủ tục như sau:

Mã:
Run "CalendarShow_V.7.xla!CalendarOnForm", TextBox1, Me

Run "CalendarShow_V.7.xla!CalendarOnForm", ComboBox1, UserForm1
 

File đính kèm

  • HuongDan.xls
    81.5 KB · Đọc: 88
  • CalendarShow_V.7.xla
    254.5 KB · Đọc: 112
Lần chỉnh sửa cuối:
Pass VBA vẫn như cũ ...Bạn Nghĩa
 
Upvote 0
Các bạn tải lại file tại #1 nhé! Xém chút dính chưởng! Page người ta có thể đổi tên được nên không cần phải loại ra trường hợp Like "Page*". Password vẫn là HoangTrongNghia

Đã sửa code thành:

Mã:
Public Sub CalendarOnForm(ByVal DateObject As Object, ByVal UserForm As Object)
    pubShowModal = True
    Set pubDateObject = DateObject
    On Error Resume Next
    Dim Ctrl As Control
    Dim myEdge As Single, myLeft As Single, myTop As Single
    With UserForm
        myEdge = (.Width - .InsideWidth) / 2
        myLeft = .Left + myEdge
        myTop = .Top + .Height - .InsideHeight - myEdge
    End With
    Set Ctrl = DateObject
    Do Until Ctrl.Parent.Name = UserForm.Name
        Set Ctrl = Ctrl.Parent
        Select Case TypeName(Ctrl)
        Case "Frame"
            With Ctrl
                myEdge = (.Width - .InsideWidth) / 2
                myLeft = myLeft + .Left + myEdge
                myTop = myTop + .Top + .Height - .InsideHeight - myEdge
            End With
        Case "MultiPage"
            With Ctrl
                myEdge = (.Width - .Pages(0).InsideWidth) / 2
                myLeft = myLeft + .Left + myEdge
                myTop = myTop + .Top + .Height - .Pages(0).InsideHeight - myEdge
            End With
        End Select
    Loop
    With DateObject
        myLeft = myLeft + .Left
        myTop = myTop + .Top + .Height
        DatePicked .Value
    End With
    With Application
        If myLeft + usfCalendar.Width > .Left + .Width Then
            myLeft = myLeft - usfCalendar.Width
        End If
        If myTop + usfCalendar.Height > .Top + .Height Then
            myTop = myTop - usfCalendar.Height - DateObject.Height
        End If
    End With
    With usfCalendar
        .StartUpPosition = 0
        .Left = myLeft
        .Top = myTop
        .Show
    End With
End Sub
 
Upvote 0
Trong phiên bản 7 này, tôi đã cập nhật tính năng định vị CALENDAR sẽ hiển thị dưới các TextBox chứa trong UserForm, Frame/MultiPage.

attachment.php


Các phiên bản trước chỉ xác định đúng khi TextBox chỉ chứa trong UserForm, nhưng một số chương trình lại đặt TextBox lấy ngày tháng đó trong một hay nhiều Frame hoặc/và Multipage thì Calendar không xác định chính xác Top & Left của nó so với TextBox. Và lần này cũng bổ sung, nếu cái TextBox sát màn hình Window, nó sẽ dịch chuyển lên trên hoặc qua trái.

attachment.php


Cấu trúc của việc nhúng lịch cũng dễ dàng hơn và đơn giản hơn.

Vẫn chưa đơn giản anh Nghĩa ạ . hàm CalendarOnForm em nghĩ chỉ cần truyền 1 tham số cho mọi trường hợp mới gọi là đơn giản =))
 
Upvote 0
Ý là sao đây? Làm sao xác định nó là UserForm mà truyền thêm hả?
chời ơi ních xanh cổ thụ mà mới làm khó tí đã quay lại hỏi rồi =)) . vậy sao gọi là Nghĩa đẹp chai được ?
cái em nêu ra ở #4 mới chỉ là 1 phần trong kế hoạch thôi
kế hoạch đầy đủ
bước 1 : làm cho thủ tục CalendarOnForm còn 1 tham số mà thôi . Vì sao ? khi đưa vào Object textbox thì nó đã mang gen của tổ tông nhà nó rồi , truyền UserForm vào chi ? vậy làm sao từ textbox mà lấy được thông tin của UserForm ? đấy là việc của ních xanh , tôi không biết
bước 2 : viết thủ tục đầu vào chung cho 2 thủ tục CalendarOnForm và CalendarOnSheet
đại khái sẽ là
sub SHOWCALENDAR (target as Object)
if NghiaDepTrai then
CalendarOnForm target
else
CalendarOnSheet target
end if
end sub

như vậy ở bất cứ đâu ta cũng chỉ cần gọi chung 1 thủ tục mà thôi . --=0--=0--=0
 
Upvote 0
chời ơi ních xanh cổ thụ mà mới làm khó tí đã quay lại hỏi rồi =)) . vậy sao gọi là Nghĩa đẹp chai được ?
cái em nêu ra ở #4 mới chỉ là 1 phần trong kế hoạch thôi
kế hoạch đầy đủ
bước 1 : làm cho thủ tục CalendarOnForm còn 1 tham số mà thôi . Vì sao ? khi đưa vào Object textbox thì nó đã mang gen của tổ tông nhà nó rồi , truyền UserForm vào chi ? vậy làm sao từ textbox mà lấy được thông tin của UserForm ? đấy là việc của ních xanh , tôi không biết
bước 2 : viết thủ tục đầu vào chung cho 2 thủ tục CalendarOnForm và CalendarOnSheet
đại khái sẽ là
sub SHOWCALENDAR (target as Object)
if NghiaDepTrai then
CalendarOnForm target
else
CalendarOnSheet target
end if
end sub

như vậy ở bất cứ đâu ta cũng chỉ cần gọi chung 1 thủ tục mà thôi . --=0--=0--=0
Ý tôi hỏi là nếu không có cái gì xác định là UserForm thì làm sao biết mà so sánh?

VD: TextBox trên Sheet và TextBox trên Form, làm sao biết nó tồn tại trên mảnh đất hoa màu nào?

Thậm chí cái "Ctrl.Parent" nó cũng không cho mình biết cái TypeName của nó chính xác là UserForm mà chỉ cho mình biết cái tên của UserForm đó thôi thì làm sao mà tính đây?
 
Lần chỉnh sửa cuối:
Upvote 0
Ý tôi hỏi là nếu không có cái gì xác định là UserForm thì làm sao biết mà so sánh?

VD: TextBox trên Sheet và TextBox trên Form, làm sao biết nó tồn tại trên mảnh đất hoa màu nào?

giờ mà em nói ra 1 từ thôi thì mọi chuyện lại quá đơn giản , không vừa sức anh Nghĩa , nên anh cứ từ từ suy nghĩ thêm đi nhé , lêu lêu =)) --=0--=0--=0
 
Upvote 0
giờ mà em nói ra 1 từ thôi thì mọi chuyện lại quá đơn giản , không vừa sức anh Nghĩa , nên anh cứ từ từ suy nghĩ thêm đi nhé , lêu lêu =)) --=0--=0--=0
Thôi, không nghĩ đâu, mệt lắm, lắm lúc cũng phải tự mãn những gì mình đã làm. Nhưng rõ ràng tôi không biết xác định controls nào là Form trong cái mớ Ctrl.Parent đó. Với Frame và MultiPage còn ra, riêng UserForm nó không có cho đúng Type thì không xác định được.
 
Upvote 0
Thôi, không nghĩ đâu, mệt lắm, lắm lúc cũng phải tự mãn những gì mình đã làm. Nhưng rõ ràng tôi không biết xác định controls nào là Form trong cái mớ Ctrl.Parent đó. Với Frame và MultiPage còn ra, riêng UserForm nó không có cho đúng Type thì không xác định được.
trước hết xin được lưu ý 2 điều
1/Các Control nằm trong Form được phép đặt tên trùng với UserForm luôn
vậy so sánh này không an toàn và có thể sai bất cứ lúc nào
Mã:
Do Until Ctrl.Parent.Name = UserForm.Name
2/UserForm được phép đặt tên là "Frame" hoặc "MultiPage" vậy khi lấy TypeName(Userform) có thể ra kết quả là "Frame"
bây giờ là code
xác định UserForm dựa vào Textbox
Mã:
Private Function getRootCtrl(Ctrl As Object) As Object
On Error GoTo endLoop
Do While True
    If getRootCtrl Is Nothing Then Set getRootCtrl = Ctrl.Parent Else Set getRootCtrl = getRootCtrl.Parent
Loop
endLoop:
End Function

Mã:
Public Sub CalendarOnForm2(ByVal DateObject As Object)
    pubShowModal = True
    Set pubDateObject = DateObject
    Dim Ctrl As Object, uForm As Object, typenameObj As String
    Dim myEdge As Single, myLeft As Single, myTop As Single
    Set uForm = getRootCtrl(DateObject)
    Set Ctrl = DateObject
    On Error GoTo endLoop
    Do While True
        Set Ctrl = Ctrl.Parent
        typenameObj = TypeName(Ctrl)
        If Ctrl Is uForm Then typenameObj = "Frame"
        Select Case typenameObj
        Case "Frame"
            With Ctrl
                myEdge = (.Width - .InsideWidth) / 2
                myLeft = myLeft + .Left + myEdge
                myTop = myTop + .Top + .Height - .InsideHeight - myEdge
            End With
        Case "MultiPage"
            With Ctrl
                myEdge = (.Width - .Pages(0).InsideWidth) / 2
                myLeft = myLeft + .Left + myEdge
                myTop = myTop + .Top + .Height - .Pages(0).InsideHeight - myEdge
            End With
        End Select
    Loop
endLoop:
    With DateObject
        myLeft = myLeft + .Left
        myTop = myTop + .Top + .Height
        DatePicked .Value
    End With
    With Application
        If myLeft + usfCalendar.Width > .Left + .Width Then
            myLeft = myLeft - usfCalendar.Width
        End If
        If myTop + usfCalendar.Height > .Top + .Height Then
            myTop = myTop - usfCalendar.Height - DateObject.Height
        End If
    End With
    With usfCalendar
        .StartUpPosition = 0
        .Left = myLeft
        .Top = myTop
        .Show
    End With
End Sub

đầu vào chung
Mã:
Public Sub testShowCalendar(target As Object)
If TypeName(target.Parent) = "Worksheet" Then
    CalendarOnSheet target
Else
    CalendarOnForm2 target
End If
End Sub
 
Upvote 0
trước hết xin được lưu ý 2 điều
1/Các Control nằm trong Form được phép đặt tên trùng với UserForm luôn
vậy so sánh này không an toàn và có thể sai bất cứ lúc nào
Mã:
Do Until Ctrl.Parent.Name = UserForm.Name
2/UserForm được phép đặt tên là "Frame" hoặc "MultiPage" vậy khi lấy TypeName(Userform) có thể ra kết quả là "Frame"
bây giờ là code
xác định UserForm dựa vào Textbox
Mã:
Private Function getRootCtrl(Ctrl As Object) As Object
On Error GoTo endLoop
Do While True
    If getRootCtrl Is Nothing Then Set getRootCtrl = Ctrl.Parent Else Set getRootCtrl = getRootCtrl.Parent
Loop
endLoop:
End Function

Mã:
Public Sub CalendarOnForm2(ByVal DateObject As Object)
    pubShowModal = True
    Set pubDateObject = DateObject
    Dim Ctrl As Object, uForm As Object, typenameObj As String
    Dim myEdge As Single, myLeft As Single, myTop As Single
    Set uForm = getRootCtrl(DateObject)
    Set Ctrl = DateObject
    On Error GoTo endLoop
    Do While True
        Set Ctrl = Ctrl.Parent
        typenameObj = TypeName(Ctrl)
        If Ctrl Is uForm Then typenameObj = "Frame"
        Select Case typenameObj
        Case "Frame"
            With Ctrl
                myEdge = (.Width - .InsideWidth) / 2
                myLeft = myLeft + .Left + myEdge
                myTop = myTop + .Top + .Height - .InsideHeight - myEdge
            End With
        Case "MultiPage"
            With Ctrl
                myEdge = (.Width - .Pages(0).InsideWidth) / 2
                myLeft = myLeft + .Left + myEdge
                myTop = myTop + .Top + .Height - .Pages(0).InsideHeight - myEdge
            End With
        End Select
    Loop
endLoop:
    With DateObject
        myLeft = myLeft + .Left
        myTop = myTop + .Top + .Height
        DatePicked .Value
    End With
    With Application
        If myLeft + usfCalendar.Width > .Left + .Width Then
            myLeft = myLeft - usfCalendar.Width
        End If
        If myTop + usfCalendar.Height > .Top + .Height Then
            myTop = myTop - usfCalendar.Height - DateObject.Height
        End If
    End With
    With usfCalendar
        .StartUpPosition = 0
        .Left = myLeft
        .Top = myTop
        .Show
    End With
End Sub

đầu vào chung
Mã:
Public Sub testShowCalendar(target As Object)
If TypeName(target.Parent) = "Worksheet" Then
    CalendarOnSheet target
Else
    CalendarOnForm2 target
End If
End Sub

Hỗm rày lo làm cái chương trình Rút thăm trúng thưởng cho WKT nên chưa bàn sâu vào vấn đề này.

https://www.facebook.com/hoangtrong.nghia.52/videos/747834515362918/

Đúng là mình chưa lường được tình huống là Frame hay MultiPage cũng có thể đặt trùng tên với UserForm!

Nhưng để viết như thế thì lại thêm 1 hàm xử lý nữa, nên tôi lại phải "tinh giảm biên chế" một hàm phụ này cho gọn luôn!

Mã:
Private Sub CalendarOnForm(ByVal Target As Object)
    pubShowModal = True
    Set pubTarget = Target
    Dim IsUserForm As Boolean
    Dim TypeNameObj As String
    Dim Ctrl As Object, UserForm As Object
    Dim meEdge As Single, meLeft As Single, meTop As Single
    Set Ctrl = Target
    On Error Resume Next
    Do
        Set Ctrl = Ctrl.Parent
        TypeNameObj = TypeName(Ctrl)
        Set UserForm = Ctrl.Parent
        If UserForm Is Nothing Then
            TypeNameObj = "Frame": IsUserForm = True
        Else
            If Err.Number Then TypeNameObj = "Frame": IsUserForm = True
        End If
        Select Case TypeNameObj
        Case "Frame"
            With Ctrl
                meEdge = (.Width - .InsideWidth) / 2
                meLeft = meLeft + .Left + meEdge
                meTop = meTop + .Top + .Height - .InsideHeight - meEdge
            End With
        Case "MultiPage"
            With Ctrl
                meEdge = (.Width - .Pages(0).InsideWidth) / 2
                meLeft = meLeft + .Left + meEdge
                meTop = meTop + .Top + .Height - .Pages(0).InsideHeight - meEdge
            End With
        End Select
    Loop Until IsUserForm
    With Target
        meLeft = meLeft + .Left
        meTop = meTop + .Top + .Height
        DatePicked .Value
    End With
    With Application
        If meLeft + usfCalendar.Width > .Left + .Width Then
            meLeft = meLeft - usfCalendar.Width
        End If
        If meTop + usfCalendar.Height > .Top + .Height Then
            meTop = meTop - usfCalendar.Height - Target.Height
        End If
    End With
    With usfCalendar
        .StartUpPosition = 0
        .Left = meLeft
        .Top = meTop
        .Show
    End With
End Sub

Lêu lêu ... (ẹc ... ẹc ...)--=0
 
Lần chỉnh sửa cuối:
Upvote 0
ôi mình bị anh í lêu lêu kìa . hu hu
anh ơi cho hỏi 1 target đưa vào sao biết nó nằm trên sheet hay Form vậy anh ?
Uh, thì có người nói là giải quyết vấn đề cho người khác thì sáng lắm, nên mình cũng thế mà! Lêu ... lêu ... --=0--=0--=0

P/s: Mới sáng hơn nữa kìa! Đã làm cho code gọn hơn rồi kìa! Không để lọt một trường hợp dù là chỉ 1 mà thôi! Kakakaka.
 
Upvote 0
Uh, thì có người nói là giải quyết vấn đề cho người khác thì sáng lắm, nên mình cũng thế mà! Lêu ... lêu ... --=0--=0--=0

P/s: Mới sáng hơn nữa kìa! Đã làm cho code gọn hơn rồi kìa! Không để lọt một trường hợp dù là chỉ 1 mà thôi! Kakakaka.
ơ anh chưa trả lời em mà , cái hàm CalendarOnForm anh vừa ghi đâu phải câu trả lời
 
Upvote 0
ơ anh chưa trả lời em mà , cái hàm CalendarOnForm anh vừa ghi đâu phải câu trả lời
Trả lời ở bài #14 kìa! Không phải trả lời gián tiếp rồi đó sao? Kakakaa+-+-+-+

cái này anh làm lộn chiều rồi anh ơi , bồ nhí ai cho đánh ghen ngược .
Addins này là của anh , nên câu giả dụ phải để tôi hỏi anh mới đúng chứ . hí hí --=0--=0

Cho nên chưa xài (cái thủ tục gộp gì gì của ai đó) thì chưa tính đó chứ! Hahahaha. Ta phải sửa lại mà!
 
Upvote 0
Trả lời ở bài #14 kìa! Không phải trả lời gián tiếp rồi đó sao? Kakakaa+-+-+-+



Cho nên chưa xài (cái thủ tục gộp gì gì của ai đó) thì chưa tính đó chứ! Hahahaha. Ta phải sửa lại mà!
uhm . Là em cố tình xài cách đó để thử tài ních xanh đó mà . Nếu im luôn thì đáng lo chứ quay lại lêu lêu em thì được rồi . không phải lo nữa . hi hi
 
Upvote 0
uhm . Là em cố tình xài cách đó để thử tài ních xanh đó mà . Nếu im luôn thì đáng lo chứ quay lại lêu lêu em thì được rồi . không phải lo nữa . hi hi
Công nhận, con người ta đang 6 sao bị hạ xuống 1 sao thành "thành viên mới" luôn nên có khác!
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom