- Tham gia
- 17/8/08
- Bài viết
- 8,662
- Được thích
- 16,725
- Giới tính
- Nam
Không biết đặt tiêu đề như vậy có sát nghĩa không, nhưng làm sao xác định được khoảng cách của 2 mũi tên (Xanh và Hồng) trong hình dưới đây:
Cám ơn rất nhiều.
Function CellPosition(Optional rCell As Range)
Dim PointsPerPixelX As Double, PointsPerPixelY As Double
Dim x As Long, y As Long
Dim rng As Range, bFound As Boolean, Arr(1 To 2)
Application.Volatile
If rCell Is Nothing Then Set rCell = ActiveCell
Set rCell = rCell(1, 1)
PointsPerPixelX = 72 / GetDeviceCaps(GetDC(0), 88)
PointsPerPixelY = 72 / GetDeviceCaps(GetDC(0), 90)
ReleaseDC 0, GetDC(0)
For x = Int(Application.Left / PointsPerPixelX) To Int(Application.Left / PointsPerPixelX + Application.Width / PointsPerPixelX)
For y = Int(Application.Top / PointsPerPixelY) To Int(Application.Top / PointsPerPixelY + Application.Height / PointsPerPixelY)
Set rng = Application.Windows(1).RangeFromPoint(x, y)
If Not (rng Is Nothing) Then
bFound = True
Exit For
End If
Next
If bFound Then Exit For
Next
Arr(1) = x * PointsPerPixelX + (rCell.Left - rng.Left)
Arr(2) = y * PointsPerPixelY + (rCell.Top - rng.Top)
CellPosition = Arr
End Function
PointsPerPixelX = 72 / GetDeviceCaps(GetDC(0), 88) <--- A
PointsPerPixelY = 72 / GetDeviceCaps(GetDC(0), 90) <--- B
ReleaseDC 0, GetDC(0) <--- C
Private Declare Function GetDC Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32.dll" (ByVal hwnd As Long, ByVal hDC As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32.dll" (ByVal hDC As Long, ByVal nIndex As Long) As Long
Function CellPosition(Optional rCell As Range)
Dim PointsPerPixelX As Double, PointsPerPixelY As Double
Dim X As Long, Y As Long
Dim rng As Range, bFound As Boolean, Arr(1 To 2), DC1 As Long, DC2 As Long, DC3 As Long
Application.Volatile
If rCell Is Nothing Then Set rCell = ActiveCell
Set rCell = rCell(1, 1)
DC1 = GetDC(0)
PointsPerPixelX = 72 / GetDeviceCaps(DC1, 88)
DC2 = GetDC(0)
PointsPerPixelY = 72 / GetDeviceCaps(DC2, 90)
DC3 = GetDC(0)
ReleaseDC 0, DC3
ReleaseDC 0, DC1
ReleaseDC 0, DC2
MsgBox "DC1 = " & DC1 & ", DC2 = " & DC2 & ", DC3 = " & DC3
End Function
DC = GetDC(0)
PointsPerPixelX = 72 / GetDeviceCaps(DC, 88)
PointsPerPixelY = 72 / GetDeviceCaps(DC, 90)
ReleaseDC 0, DC
Em hỏi ngoài lề chút: Không biết phần Help mà anh chụp hình đưa lên là anh lấy từ đâu vậy? Có thể hướng dẫn em tải về dùng được không?
À thì cài Delphi vào thì nó có đủ help thôi - Delphi.hlp và Win.hlp
Không biết tôi copy có đủ không, Tuấn thử xem
Ôi... em tìm được rồi. Em không cài Delphi (mà cũng hổng biết nó là cái gì luôn) nên phải download "nguyên con" Win32 Developer's References tới 50MB mới xài được anh à
Nó ở đây:
http://radasm.cherrytree.at/download/?did=9
(Tài liệu này nghiên cứu mấy năm chắc cũng chưa hết được! Hay!)
[/CODE]
Tóm lại ta nên thay đoạn code trên bằng
Mã:DC = GetDC(0) PointsPerPixelX = 72 / GetDeviceCaps(DC, 88) PointsPerPixelY = 72 / GetDeviceCaps(DC, 90) ReleaseDC 0, DC
Mà giá trị tính được là tính từ góc trên bên trái của MÀN HÌNH (screen) (x, y trong RangeFromPoint là tính trong hệ tọa độ screen) chứ không phải tính từ góc trên bên trái của cửa sổ Excel như bạn Nghĩa yêu cầu.
Tất nhiên tôi nói ra để cho chính xác thôi chứ chuyển sang hệ toạ độ của cửa sổ Excel không có gì khó cả.
Xin vui lòng cho em biết 3 giá trị DC1, DC2, DC3 là gì? Tại sao nó có giá trị âm, và cách để nó chuyển các giá trị đó về dạng của kích thước mà Form nó hiểu như thế nào ạ.
Cám ơn rất nhiều!
Vậy mục đích cuối cùng của Nghĩa là gì? Có phải là muốn định vị form theo vị trí cell không? Nếu đúng là vậy thì ta tiếp tục
Thì Thầy đã "đi guốc trong bụng" em rồi còn gì! Thầy hướng dẫn em đi.
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, ByVal nIndex As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDC As Long) As Long
Function CellPosition(Optional rCell As Range)
Dim PointsPerPixelX As Double, PointsPerPixelY As Double
Dim x As Long, y As Long
Dim hDC1 As Long, hDC2 As Long, hDC3 As Long
Dim rng As Range, bFound As Boolean, Arr(1 To 2)
If rCell Is Nothing Then Set rCell = ActiveCell
Set rCell = rCell(1, 1)
hDC1 = GetDC(0)
PointsPerPixelX = 72 / GetDeviceCaps(hDC1, 88)
hDC2 = GetDC(0)
PointsPerPixelY = 72 / GetDeviceCaps(hDC2, 90)
hDC3 = GetDC(0)
ReleaseDC 0, hDC3
With Application
.Volatile
For x = Int(.Left / PointsPerPixelX) To Int(.Left / PointsPerPixelX + .Width / PointsPerPixelX)
For y = Int(.Top / PointsPerPixelY) To Int(.Top / PointsPerPixelY + .Height / PointsPerPixelY)
Set rng = ActiveWindow.RangeFromPoint(x, y)
If Not (rng Is Nothing) Then
bFound = True
Exit For
End If
Next
If bFound Then Exit For
Next
End With
Arr(1) = x * PointsPerPixelX + (rCell.Left - rng.Left)
Arr(2) = y * PointsPerPixelY + (rCell.Top - rng.Top)
CellPosition = Arr
End Function
Sub ShowForm(ByRef frm As Object, rCell As Range)
Dim Arr
On Error Resume Next
Arr = CellPosition(rCell)
With frm
.Hide
.StartUpPosition = 0
.Left = Arr(1): .Top = Arr(2)
.Show False
End With
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Intersect(Target, Range("A1:A20")) Is Nothing Then
If Target.Count = 1 Then ShowForm UserForm1, Target(, 2)
Else
Unload UserForm1
End If
End Sub
![]()
Xin vui lòng cho em biết 3 giá trị DC1, DC2, DC3 là gì?
Tại sao nó có giá trị âm
và cách để nó chuyển các giá trị đó về dạng của kích thước mà Form nó hiểu như thế nào ạ
Nhân tiện sửa lại hàm theo ý kiến của anh siwtom:
Viết thêm 1 Sub để gọi UserFormPHP:Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hDC As Long, ByVal nIndex As Long) As Long Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDC As Long) As Long Function CellPosition(Optional rCell As Range) Dim PointsPerPixelX As Double, PointsPerPixelY As Double Dim x As Long, y As Long Dim hDC1 As Long, hDC2 As Long, hDC3 As Long Dim rng As Range, bFound As Boolean, Arr(1 To 2) If rCell Is Nothing Then Set rCell = ActiveCell Set rCell = rCell(1, 1) hDC1 = GetDC(0) PointsPerPixelX = 72 / GetDeviceCaps(hDC1, 88) hDC2 = GetDC(0) PointsPerPixelY = 72 / GetDeviceCaps(hDC2, 90) hDC3 = GetDC(0) ReleaseDC 0, hDC3 With Application .Volatile For x = Int(.Left / PointsPerPixelX) To Int(.Left / PointsPerPixelX + .Width / PointsPerPixelX) For y = Int(.Top / PointsPerPixelY) To Int(.Top / PointsPerPixelY + .Height / PointsPerPixelY) Set rng = ActiveWindow.RangeFromPoint(x, y) If Not (rng Is Nothing) Then bFound = True Exit For End If Next If bFound Then Exit For Next End With Arr(1) = x * PointsPerPixelX + (rCell.Left - rng.Left) Arr(2) = y * PointsPerPixelY + (rCell.Top - rng.Top) CellPosition = Arr End Function
Gọi form bằng sự kiện SelectionChange nhé:PHP:Sub ShowForm(ByRef frm As Object, rCell As Range) Dim Arr On Error Resume Next Arr = CellPosition(rCell) With frm .Hide .StartUpPosition = 0 .Left = Arr(1): .Top = Arr(2) .Show False End With End Sub
Vậy thôiPHP:Private Sub Worksheet_SelectionChange(ByVal Target As Range) If Not Intersect(Target, Range("A1:A20")) Is Nothing Then If Target.Count = 1 Then ShowForm UserForm1, Target(, 2) Else Unload UserForm1 End If End Sub
(hàm chính đã có, sao Nghĩa không tự ráp vào mà thí nghiệm nhỉ?)
hDC1 = GetDC(0)
PointsPerPixelX = 72 / GetDeviceCaps(hDC1, 88)
hDC2 = GetDC(0)
PointsPerPixelY = 72 / GetDeviceCaps(hDC2, 90)
hDC3 = GetDC(0)
ReleaseDC 0, hDC3
hDC3 = GetDC(0)
ReleaseDC 0, hDC3
ReleaseDC 0, GetDC
DC = GetDC(0)
PointsPerPixelX = 72 / GetDeviceCaps(DC, 88)
PointsPerPixelY = 72 / GetDeviceCaps(DC, 90)
ReleaseDC 0, DC
![]()
Xin vui lòng cho em biết 3 giá trị DC1, DC2, DC3 là gì? Tại sao nó có giá trị âm, và cách để nó chuyển các giá trị đó về dạng của kích thước mà Form nó hiểu như thế nào ạ.
Cám ơn rất nhiều!
Trời ơi, sao lại gọi GetDC 3 lần là sao? Gọi 1 lần thôi. Mà vẫn không chuẩn như cũ.
Mã:hDC1 = GetDC(0) PointsPerPixelX = 72 / GetDeviceCaps(hDC1, 88) hDC2 = GetDC(0) PointsPerPixelY = 72 / GetDeviceCaps(hDC2, 90) hDC3 = GetDC(0) ReleaseDC 0, hDC3
Sao không gọi ReleaseDC cho hDC1, hDC2?
Mà
Mã:hDC3 = GetDC(0) ReleaseDC 0, hDC3
Function CellPosition(Optional rCell As Range)
......................
hDC1 = GetDC(0)
PointsPerPixelX = 72 / GetDeviceCaps(hDC1, 88)
ReleaseDC 0, hDC1
hDC2 = GetDC(0)
PointsPerPixelY = 72 / GetDeviceCaps(hDC2, 90)
ReleaseDC 0, hDC2
......................
End Function
Vậy anh làm luôn đi cho em tham khảo vớiNếu là tôi thì tôi sẽ tối ưu chút code bằng việc giảm số vòng "thừa" này.
Đã nói là em không rành mà, nhất là code liên quan đến API
(Anh có nói em mới biết chứ)
Tức là sửa thành vầy:
Đúng không anh?PHP:Function CellPosition(Optional rCell As Range) ...................... hDC1 = GetDC(0) PointsPerPixelX = 72 / GetDeviceCaps(hDC1, 88) ReleaseDC 0, hDC1 hDC2 = GetDC(0) PointsPerPixelY = 72 / GetDeviceCaps(hDC2, 90) ReleaseDC 0, hDC2 ...................... End Function
Ẹc... Ẹc...
Anh có nói rằng:
Vậy anh làm luôn đi cho em tham khảo với
Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY As Long = 90
Private Const POINTS_PER_INCH As Long = 72
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function GetWindowRect Lib "user32.dll" (ByVal hwnd As Long, ByRef lpRect As RECT) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetDC Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32.dll" (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32.dll" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Function CellPosition(Optional rCell As Range)
Dim PointsPerPixelX As Double, PointsPerPixelY As Double, DC As Long
Dim x As Long, y As Long, h As Long, rc As RECT
Dim rng As Range, bFound As Boolean, Arr(1 To 2)
If rCell Is Nothing Then Set rCell = ActiveCell
Set rCell = rCell(1, 1)
DC = GetDC(0)
PointsPerPixelX = POINTS_PER_INCH / GetDeviceCaps(DC, LOGPIXELSX)
PointsPerPixelY = POINTS_PER_INCH / GetDeviceCaps(DC, LOGPIXELSY)
ReleaseDC 0, DC
h = FindWindow("XLMAIN", Application.Caption)
h = FindWindowEx(h, 0, "XLDESK", vbNullString)
h = FindWindowEx(h, 0, "EXCEL7", vbNullString)
GetWindowRect h, rc
For x = rc.Left To rc.Right
For y = rc.Top To rc.Bottom
Set rng = Application.Windows(1).RangeFromPoint(x, y)
If Not (rng Is Nothing) Then
bFound = True
Exit For
End If
Next
If bFound Then Exit For
Next
Arr(1) = x * PointsPerPixelX + (rCell.Left - rng.Left)
Arr(2) = y * PointsPerPixelY + (rCell.Top - rng.Top)
CellPosition = Arr
End Function
Xin mời.
Chỉ có điều tôi viết cho Excel 2007 thôi vì không có Excel 2010 nên tôi không biết các cửa sổ có class như thế nào. Trong Excel 2007 thì tôi dùng class: "XLMAIN", "XLDESK", "EXCEL7"
h = FindWindow("XLMAIN", Application.Caption)
[COLOR=#ff0000]h = FindWindowEx(h, 0, "XLDESK", vbNullString)
h = FindWindowEx(h, 0, "EXCEL7", vbNullString)[/COLOR]
Excel 2010 chạy được luôn anh à!
Em hỏi tí. Trong code có đoạn:
Không biết đoạn màu đỏ có thừa không? Vì em xóa luôn nó vẫn chạy chính xácMã:h = FindWindow("XLMAIN", Application.Caption) [COLOR=#ff0000]h = FindWindowEx(h, 0, "XLDESK", vbNullString) h = FindWindowEx(h, 0, "EXCEL7", vbNullString)[/COLOR]
loop = loop + 1
Nhân tiện sửa lại hàm theo ý kiến của anh siwtom:
........................................
(hàm chính đã có, sao Nghĩa không tự ráp vào mà thí nghiệm nhỉ?)
Thật sự là hàm trước mà Thầy làm em đã ứng dụng và chạy rất tốt rồi, em cám ơn Thầy nhiều
Còn việc em hỏi thì xin thưa với các Thầy là cho tới giờ em vẫn mù mờ về đơn vị tính Vị trí của cell hoặc form đấy, em chẳng biết nó tính bằng đơn vị gì nữa! Cái này em NGU nên em phải hỏi cho BỚT NGU ạ.
Chẳng hạn cột A các Thầy nhìn hình sẽ thấy cũng là Width nhưng nó có tới 3 đơn vị đo khoảng cách (8.38 - 72 pixel) trong immediate lại là 54
![]()
![]()
.
Tôi cũng NGU vậy thôi, có điều tôi không quan tâm vấn đề này, miễn biết ứng dụng là đượcVà như vậy làm em rối tung lên, chẳng hiểu nó tính bằng đơn vị gì và convert nó lại như thế nào. Hơn thế, cái hàm của Thầy Siwtom lại cho ra số hàng triệu thì lại càng không biết đó lại là đơn vị gì nữa, đã NGU càng thêm NGU.
Còn việc em hỏi thì xin thưa với các Thầy là cho tới giờ em vẫn mù mờ về đơn vị tính Vị trí của cell hoặc form đấy, em chẳng biết nó tính bằng đơn vị gì nữa! Cái này em NGU nên em phải hỏi cho BỚT NGU ạ.
Và như vậy làm em rối tung lên, chẳng hiểu nó tính bằng đơn vị gì và convert nó lại như thế nào. Hơn thế, cái hàm của Thầy Siwtom lại cho ra số hàng triệu thì lại càng không biết đó lại là đơn vị gì nữa, đã NGU càng thêm NGU.
For x = Application to Application.Left + Application.Width
For x = Int(Application.Left / PointsPerPixelX) To Int(Application.Left / PointsPerPixelX + Application.Width / PointsPerPixelX)
Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY As Long = 90
Private Const POINTS_PER_INCH As Long = 72
PointsPerPixelX = POINTS_PER_INCH / GetDeviceCaps(DC, LOGPIXELSX)
PointsPerPixelY = POINTS_PER_INCH / GetDeviceCaps(DC, LOGPIXELSY)
PointsPerPixelX = POINTS_PER_INCH / GetDeviceCaps(DC, LOGPIXELSX)
PointsPerPixelY = POINTS_PER_INCH / GetDeviceCaps(DC, LOGPIXELSY)
For x = Int(Application.Left / PointsPerPixelX) To Int(Application.Left / PointsPerPixelX + Application.Width / PointsPerPixelX)
For y = Int(Application.Top / PointsPerPixelY) To Int(Application.Top / PointsPerPixelY + Application.Height / PointsPerPixelY)
Private Const LOGPIXELSX = 88
Private Const LOGPIXELSY As Long = 90
Private Const POINTS_PER_INCH As Long = 72
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function GetWindowRect Lib "user32.dll" (ByVal hwnd As Long, ByRef lpRect As RECT) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function GetDC Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32.dll" (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32.dll" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Function CellPosition(Optional rCell As Range)
Dim PointsPerPixelX As Double, PointsPerPixelY As Double
Dim x As Long, y As Long, hDC as Long
Dim rng As Range, bFound As Boolean, Arr(1 To 2)
Application.Volatile
If rCell Is Nothing Then Set rCell = ActiveCell
Set rCell = rCell(1, 1)
[COLOR=#0000ff]' "lấy" device-context handle cần thiết cho việc gọi hàm GetDeviceCaps ở phần tiếp theo.[/COLOR]
hDC = GetDC(0)
[COLOR=#0000ff]' tính PointsPerPixelX và PointsPerPixelY dùng để convert Application.Left, Top, Width, Height
' từ points sang pixels.[/COLOR]
PointsPerPixelX = POINTS_PER_INCH / GetDeviceCaps(hDC, LOGPIXELSX)
PointsPerPixelY = POINTS_PER_INCH / GetDeviceCaps(hDC, LOGPIXELSY)
[COLOR=#0000ff]' ta đã làm xong mọi việc cần có device-context handle, vậy phải giải phóng device context[/COLOR]
ReleaseDC 0, hDC
[COLOR=#0000ff]' duyệt từng CỘT pixels từ trái sang phải, bắt đầu từ gờ trái của cửa sổ Application.[/COLOR]
For x = Int(Application.Left / PointsPerPixelX) To Int(Application.Left / PointsPerPixelX + Application.Width / PointsPerPixelX)
[COLOR=#0000ff]' trong mỗi CỘT pixels ta duyệt từng pixels, "đi" từ trên xuống dưới - từ trên xuống dưới là sao?
' Vì trong Windows thì gốc tọa độ là ở góc trên bên trái và trục y hướng xuống dưới.
[/COLOR] For y = Int(Application.Top / PointsPerPixelY) To Int(Application.Top / PointsPerPixelY + Application.Height / PointsPerPixelY)
Set rng = Application.Windows(1).RangeFromPoint(x, y)
If Not (rng Is Nothing) Then
bFound = True
Exit For
End If
Next
If bFound Then Exit For
Next
[COLOR=#0000ff]' do x, y được tính ở trên bằng đơn vị PIXELS nên trở về Excel ta đổi lại sang Points[/COLOR]
Arr(1) = x * PointsPerPixelX + (rCell.Left - rng.Left)
Arr(2) = y * PointsPerPixelY + (rCell.Top - rng.Top)
CellPosition = Arr
End Function
..............................
Nếu sau khi đọc kỹ mà bạn không hiểu tôi viết gì thì chịu.
Bạn chỉ cần nhớ là phải phân tích bài toán và xác định được là cần phải tính những gì, dùng gì để tính, Excel có phương pháp nào cho các việc tính ấy không, nếu không thì Windows có những hàm nào dùng để tính những cái đó không, trong những tính toán thì đơn vị dùng là gì, có cần thay đổi chuyển đơn vị không, nếu cần thì chuyển như thế nào. Nói chung cần tư duy lôgic, đi từng bước.
Và nhớ là phải đọc help. Không đọc help Excel và help Windows thì chả biết dùng hàm như thế nào. Mà đọc thì phải hiểu chứ không được: tôi viết như thế là "chạy". Viết như thế vì "người ta" cũng viết như thế. Không có "người ta" gì ở đây. Nếu "bắt trước" thì cũng phải hiểu để sau này tự mình biết trong th thế này thế này thì phải dùng cái này cái này. Và ý nghĩa của các tham số là thế này thế này
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
UserForm1.Show vbModeless
With ActiveWindow
UserForm1.Left = .PointsToScreenPixelsX(Target.Left + Target.Width)
UserForm1.Top = .PointsToScreenPixelsY(Target.Top - 50)
'Thay đổi thông số 50 cho phù hợp
End With
End Sub
Em thấy hàm API là quá cao cấp nếu chỉ muốn dùng để xác định vị trí của form hiện chỗ nào trong cell thì ta cũng có thể dùng thuộc tính có sẵn của window. Ví dụ chèn 1 UserForm1 vào và chép code này vào em nghĩ nó cũng đáp ứng được nhu cầu của a. Nghĩa
Mã:Private Sub Worksheet_SelectionChange(ByVal Target As Range) UserForm1.Show vbModeless With ActiveWindow UserForm1.Left = .PointsToScreenPixelsX(Target.Left + Target.Width) UserForm1.Top = .PointsToScreenPixelsY(Target.Top - 50) 'Thay đổi thông số 50 cho phù hợp End With End Sub
Trên máy em test thì nó hiện ở B2 khi cửa sổ excel dạng Normal khi ta thu nhỏ thì quả là có sự chênh lệch vị trí hiện form nhưng với code trên thì nếu cửa sổ excel dạng bình thường thì code hàm API với cái có sẵn trong Excel không khác là bao, nếu không muốn code phức tạp, quả là có sự lợi hại khi dùng hàm API, cảm ơn Anh đúng là khi kiểm tra lại nhiều trường hợp mới thấy là code mình nó dỡ nhưng nó cũng phù hợp với ai thích code đơn giản1. Nếu tôi chọn A1 thì code trên hiển thị Form ở đâu? ở B2?
Một vấn đề cũng gây khó khăn khi chạy code đó là không xác định chính xác tọa độ khi ZOOM <> 100%
Đã làm thử khi chia tỷ lệ với ActiveWindow.Zoom nhưng không thành công.
Làm ơn hướng dẫn thêm để hoàn thiện hàm này.
Xin cám ơn.
Một vấn đề cũng gây khó khăn khi chạy code đó là không xác định chính xác tọa độ khi ZOOM <> 100%
Đã làm thử khi chia tỷ lệ với ActiveWindow.Zoom nhưng không thành công.
Làm ơn hướng dẫn thêm để hoàn thiện hàm này.
Xin cám ơn.
Vậy cho hỏi, bạn làm sao để cho Form nó Show được vậy bạn?@all: bài này có lâu rồi, "khai quật" lại cho những ai chưa biết.
tui thường dùng hàm LocateForm dưới đây để đặt 1 userform vào vị trí 1 cell nào đó, hàm này gọn hơn, tốc độ cao hơn vì tránh được 2 vòng for
(declare getdc, getdevicecaps, releasedc như các bài trên)
Sub LocateForm(MyForm As Object, MyRange As Range)
Dim hDC&, deviceCaps88&, deviceCaps90&
hDC = GetDC(0)
deviceCaps88 = GetDeviceCaps(hDC, 88)
deviceCaps90 = GetDeviceCaps(hDC, 90)
MyForm.Left = ActiveWindow.PointsToScreenPixelsX(MyRange.Left * deviceCaps88 / 72) / deviceCaps88 * 72
MyForm.Top = ActiveWindow.PointsToScreenPixelsY(MyRange.Top * deviceCaps90 / 72) / deviceCaps90 * 72
ReleaseDC 0, hDC
End Sub
Vậy cho hỏi, bạn làm sao để cho Form nó Show được vậy bạn?
@all: bài này có lâu rồi, "khai quật" lại cho những ai chưa biết.
tui thường dùng hàm LocateForm dưới đây để đặt 1 userform vào vị trí 1 cell nào đó, hàm này gọn hơn, tốc độ cao hơn vì tránh được 2 vòng for
(declare getdc, getdevicecaps, releasedc như các bài trên)
Sub LocateForm(MyForm As Object, MyRange As Range)
Dim hDC&, deviceCaps88&, deviceCaps90&
hDC = GetDC(0)
deviceCaps88 = GetDeviceCaps(hDC, 88)
deviceCaps90 = GetDeviceCaps(hDC, 90)
MyForm.Left = ActiveWindow.PointsToScreenPixelsX(MyRange.Left * deviceCaps88 / 72) / deviceCaps88 * 72
MyForm.Top = ActiveWindow.PointsToScreenPixelsY(MyRange.Top * deviceCaps90 / 72) / deviceCaps90 * 72
ReleaseDC 0, hDC
End Sub
Thật ra còn có 1 cách đơn giản hơn nhiều
Nếu ta quyết định dùng 1 UserForm nào đó và nó chỉ Show trong sự kiện SelectionChange (Chọn cell, gọi Form để hổ trợ nhập liệu.. vân... vân...)... Lúc này ta có thể dùng Frame thay cho UserForm
Xem file ví dụ! Bảo đảm code ngắn gọn và chạy mượt
(Đương nhiên, không phải lúc nào chúng ta cũng dùng Frame thay cho UserForm <--- Tùy trường hợp cụ thể)
@ndu: tui thường làm với addin, các form do addin tạo ra và làm việc với workbook khác (kể cả không chứa code) và vì không muốn add bất kỳ object hay đoạn mã nào (vô workbook của người khác) nên không xài frame thay cho form được.
@all: cái nào tiện thì dùng thôi.