Hàm GetWindowRect cho kết quả khác nhau ở các Version Excel (3 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Tôi tuân thủ nội quy khi đăng bài

Mr.hieudoanxd

Thành viên thường trực
Tham gia
25/10/19
Bài viết
346
Được thích
159
Em chào cả nhà!
Lâu rồi không hỏi đáp gì đó trên diễn đàn. Em có một băn khoăn nhỏ về hàm trong quá trình sử dụng API tìm kiếm các cửa sổ của Excel, phát hiện ra lỗi và chưa sửa được. Loay hoay mãi không ra kết quả hỏi các bác trên diễn đàn tìm lời khuyên phù hợp!
Cụ thể với hàm GetWindowRect cho kết quả RECT khác nhau ở các version Excel làm các thông số em lấy được từ hàm trên để sử dụng đưa ra kết quả sai lệch (như file em đính kèm). Các version Excel em có và đã test thử ra kết quả như em thống kê.
Vậy, em muốn biết liệu có cách nào khắc phục sai sót trên không? có hàm API khác hay hơn thay thế không?.

P/s Em đã thử vài hàm khác như GetClientRect (hàm này luôn có left và top = 0) không phù hợp với nhu cầu của em
 

File đính kèm

Em chào cả nhà!
Lâu rồi không hỏi đáp gì đó trên diễn đàn. Em có một băn khoăn nhỏ về hàm trong quá trình sử dụng API tìm kiếm các cửa sổ của Excel, phát hiện ra lỗi và chưa sửa được. Loay hoay mãi không ra kết quả hỏi các bác trên diễn đàn tìm lời khuyên phù hợp!
Cụ thể với hàm GetWindowRect cho kết quả RECT khác nhau ở các version Excel làm các thông số em lấy được từ hàm trên để sử dụng đưa ra kết quả sai lệch (như file em đính kèm). Các version Excel em có và đã test thử ra kết quả như em thống kê.
Vậy, em muốn biết liệu có cách nào khắc phục sai sót trên không? có hàm API khác hay hơn thay thế không?.

P/s Em đã thử vài hàm khác như GetClientRect (hàm này luôn có left và top = 0) không phù hợp với nhu cầu của em

Hàm API này của Windows không sai đâu. Thông số trong RECT khác nhau là do giao diện của mỗi phiên bản Excel khác nhau. Mỗi phiên bản Excel có thể cài chế độ DPI riêng vì thế nó mới có kích thước khác nhau. Chế độ DPI của Excel 2013 trở lên nó khác với Excel 2010 trở về trước khi chạy trên HĐH Windows 10 trở lên.
 
Upvote 0
Hàm API này của Windows không sai đâu. Thông số trong RECT khác nhau là do giao diện của mỗi phiên bản Excel khác nhau. Mỗi phiên bản Excel có thể cài chế độ DPI riêng vì thế nó mới có kích thước khác nhau. Chế độ DPI của Excel 2013 trở lên nó khác với Excel 2010 trở về trước khi chạy trên HĐH Windows 10 trở lên.
Vâng thầy, em cũng đoán là nó ra kết quả khác nhau thôi chứ không dám bảo sai. Thầy ơi, thế có phương án nào hiệu chỉnh không ạ? Hàm API khác hoặc phương án nào khác ấy ạ?
 
Upvote 0
Upvote 0

File đính kèm

  • Office 365.png
    Office 365.png
    25.9 KB · Đọc: 41
  • Office 2010.png
    Office 2010.png
    28.1 KB · Đọc: 36
Upvote 0
Bạn thử xem đúng ý chưa.
Mình cũng nhờ trợ giúp thôi, chứ không rành API.
Kết quả ở Office 2010 máy em hiển thị là left = -2.5 top = 211.25 có "lệch hướng suy nghĩ" một chút. Cảm ơn bác, Em sẽ nghiên cứu thêm hàm GetWindowInfo Khá nhiều thông tin hay ho
 
Upvote 0
Em đưa useform về 1 góc bên màn hình có thể bên phải, bên trên, phía dưới, bên trái. ở Ảnh Office 2010 bị lệch khung, ở các version sau ví dụ Office 365 thì đúng vị trí em cần ạ

Muốn đặt một cửa sổ nằm trong một cửa sổ khác thì phải thiết lập quan hệ cha-con. Dùng hàm SetParent để thiết lập. Tọa độ của cửa sổ con (Rect của Userform) là quan hệ theo Rect của cửa sổ cha, tức phải điều chỉnh tọa độ LEFT, TOP của cửa sổ Userform theo quan hệ/nằm trong cửa sổ cha.
 
Upvote 0
Muốn đặt một cửa sổ nằm trong một cửa sổ khác thì phải thiết lập quan hệ cha-con. Dùng hàm SetParent để thiết lập. Tọa độ của cửa sổ con (Rect của Userform) là quan hệ theo Rect của cửa sổ cha, tức phải điều chỉnh tọa độ LEFT, TOP của cửa sổ Userform theo quan hệ/nằm trong cửa sổ cha.
Thầy ơi, Em đã thử đặt Setparent tuy nhiên theo em hiểu để lấy rect sử dụng hàm GetWindowRect lại bị sai khác giữa các phiên bản office, nó lại quay lại việc lúc đầu ấy ạ. Hay em hiểu sai gì ạ?
 
Upvote 0
Thầy ơi, Em đã thử đặt Setparent tuy nhiên theo em hiểu để lấy rect sử dụng hàm GetWindowRect lại bị sai khác giữa các phiên bản office, nó lại quay lại việc lúc đầu ấy ạ. Hay em hiểu sai gì ạ?

Không thể nói hàm đó sai được, nó đúng theo DPI thiết lập của ứng dụng đấy. Nó mà giống nhau thì mới sai nếu DPI của các ứng dugngj giống nhau. Sau khi dùng RetWindowRect bạn phải sửa thông số LEFT, RIGHT cho phù hợ với cửa sổ cha. Sau khi sửa xong gửi ảnh kết quả chạy hai phiên bản Excel lên nhé.
 
Upvote 0
Tôi thấy chủ đề này giống với cái này, có thể tham khảo thêm code ở đây.

Bạn đặt câu hỏi ở topic này cũng là sâu mọt GPE rồi,. Nếu một phiên bản Excel đã làm tốt rồi nhưng khác phiên bản là phải biến hóa theo căn nguyên mới đạt. Windows 10 ra đời cùng với phát triển của phần cứng nên chúng ta sẽ phải học và vất vả hơn để thích nghi.
Chú topic:: này là thức thời nhưng không phải dế. Chìa khóa là tìm những hàm API và công thức để chuyển đổi độ phân giải màn hình, màn hình lớn sẽ có màn chính và màn phụ, bạn phải xác định khi nào là chính khi nào là phụ. Màn hình chính có pixel width, height bao nhiêu, đê hiển thị một màn hình là bao nhiều? Khi lập trình nhúng , DPI môi ứng dụng cài đặt diện khác nhau thì phải tính toán phân chia phù hợp. Càn đi sâu sẽ càng ngiều câu hỏi.
 
Upvote 0
Bạn đặt câu hỏi ở topic này cũng là sâu mọt GPE rồi,. Nếu một phiên bản Excel đã làm tốt rồi nhưng khác phiên bản là phải biến hóa theo căn nguyên mới đạt. Windows 10 ra đời cùng với phát triển của phần cứng nên chúng ta sẽ phải học và vất vả hơn để thích nghi.
Chú topic:: này là thức thời nhưng không phải dế. Chìa khóa là tìm những hàm API và công thức để chuyển đổi độ phân giải màn hình, màn hình lớn sẽ có màn chính và màn phụ, bạn phải xác định khi nào là chính khi nào là phụ. Màn hình chính có pixel width, height bao nhiêu, đê hiển thị một màn hình là bao nhiều? Khi lập trình nhúng , DPI môi ứng dụng cài đặt diện khác nhau thì phải tính toán phân chia phù hợp. Càn đi sâu sẽ càng ngiều câu hỏi.
Sau khi thử nghiệm và lấy các rect của các khung XLMAIN, XLDESK và EXCEL7 Em thấy chỉ lấy đến handle của XLDESK là khớp được khung thầy ạ.
P/s: Học viên lớp LV2 của thầy mà học dốt quá mãi chưa hiểu hết :p
Bài đã được tự động gộp:

Bài của bác @thaipv và cả phiên bản chỉnh sửa của @Nguyễn Duy Tuân nữa có điều các bác ấy sử dụng các hàm như CallWindowProc.... phương pháp trên em chưa đủ tầm để kiểm soát rất dễ đơ, treo máy, do đó em không dám theo bác ạ
Tôi thấy chủ đề này giống với cái này, có thể tham khảo thêm code ở đây.
 

File đính kèm

  • test.png
    test.png
    90.7 KB · Đọc: 19
Lần chỉnh sửa cuối:
Upvote 0
Thiết lập DPI thì chỉ liên quan đến những gì sẽ hiện thị bên trong cửa sổ.
Học về API cửa sổ nó dễ như ăn miến bánh, chỉ cần chịu khó bỏ ít thời gian, xem qua các hàm API liên quan đến cửa sổ.
Cái khó là đi chuyên sâu về các sự kiện, xử lý sự kiện, màn hình, về các thiết lập tương thích, hiển thị.

Mục tiêu hiểu về cái gọi chung là "thị giác máy tính":
Bắt đầu từ desktop, desktop Window cũng là một cửa sổ. Có thể có nhiều Desktop. Desktop hiển thị trong một màn hình nhất định. Màn hình lại có thể có nhiều màn hình. Và có thể có cặp màn hình hiển thị chung các Desktop. Mỗi màn hình có thể có nhiều Desktop. Màn hình khác nhau lại có độ phân giải khác nhau và có thiết lập DPI khác nhau. Desktop hiển thị tương thích theo từng màn hình. Điểm này là khó hiểu nhất. Cửa sổ thì hiển thị trong một Desktop, hiển thị tương thích theo Desktop. Cửa sổ thì có cửa sổ con bên trong. Cửa sổ lại có vị trí, kích thước, DPI, thuộc tính quan hệ cha con, hiển thị/ẩn, các sự kiện cửa sổ, ...

Hãy xem mô hình cây:

Markdown (GitHub flavored):
- Màn hình
-------- Desktop
--------------- Cửa sổ ứng dụng (có nhiều dạng cửa sổ)
----------------------------- Cửa sổ con bên trong cửa sổ ứng dụng

GetWindowRect - là lấy thông số cửa sổ vị trí + kích thước trên độ phân giải chung của cả hệ thống PC.
GetClientRect - là lấy thông số cửa sổ vị trí + kích thước phụ thuộc cửa sổ cha mẹ của chúng.
ScreenToClient - Chuyển vị trí chung theo hệ thống, đồng bộ theo cửa sổ
ClientToScreen - Chuyển vị trí cửa sổ đồng bộ theo vị trí chung hệ thống
MoveWindow - Di chuyển cửa sổ, có/không thông báo tin nhắn
SetWindowPos - Dùng để thiết lập đa dạng nhiều thông số khác nhau cho cửa sổ.
Và các hàm cửa sổ khác, các hàm cửa sổ nâng cao, các hàm sự kiện.

Thiết lập cửa sổ lại các thiết lập High-DPI dành cho các hệ điều hành Windows hiện đại, vì có nhiều màn hình trong một hệ thống. Vì cần độ chính xác thị giác máy trính trong kỹ thuật.

Học về API cửa sổ, bạn đã biết về các phép toán Bitwise chưa. Nếu chưa biết thì học ngay. Không biết thì đừng động đến các API này.
Tôi có chia sẻ bài học về Bitwise. Mà tôi có gán câu "tối quan trọng cho tư duy lập trình". Các phép toán Bitwise là quan trọng trong lập trình. Mọi thuật toán, giải thuật, định nghĩa, khởi đầu từ chúng mà ra.

Bài viết phép toán bitwise
 
Lần chỉnh sửa cuối:
Upvote 0
Muốn đặt một cửa sổ nằm trong một cửa sổ khác thì phải thiết lập quan hệ cha-con. Dùng hàm SetParent để thiết lập. Tọa độ của cửa sổ con (Rect của Userform) là quan hệ theo Rect của cửa sổ cha, tức phải điều chỉnh tọa độ LEFT, TOP của cửa sổ Userform theo quan hệ/nằm trong cửa sổ cha.
Người ta muốn đặt UserForm vào vị trí cell A1 (trích: "Em đưa useform về 1 góc bên màn hình có thể bên phải, bên trên, phía dưới, bên trái"), tức góc trên bên trái của UserForm vào góc trên bên trái của A1 (gọi là điểm P). Vì thế người ta muốn dùng GetWindowRect cho cửa sổ EXCEL7 (2 đường kẻ đỏ) để đọc ra rc.Left, rc.Top của của EXCEL7 - vị trí của điểm Q, rồi từ đó thử "dịch một tí sang phải và một tí xuống dưới" để có Left và Top của P.

Vậy thì tại sao lại dùng SetParent để làm gì? Người ta muốn đặt UserForm trên màn hình ở vị trí trùng với P của cell A1 thôi chứ không phải đặt UserForm trong cửa sổ EXCEL7. Bạn hiểu sai ý người ta rồi.

Vấn để nằm ở chỗ sau khi có rc.Left, rc.Top, tức điểm Q rồi thì phải tính "dịch một tí sang phải và một tí xuống dưới". "Tí" ở đây cụ thể tính thế nào, đó là cái người ta cần phải tìm.
 

File đính kèm

  • dinhvi.png
    dinhvi.png
    10.1 KB · Đọc: 10
Upvote 0
Người ta muốn đặt UserForm vào vị trí cell A1 (trích: "Em đưa useform về 1 góc bên màn hình có thể bên phải, bên trên, phía dưới, bên trái"), tức góc trên bên trái của UserForm vào góc trên bên trái của A1 (gọi là điểm P). Vì thế người ta muốn dùng GetWindowRect cho cửa sổ EXCEL7 (2 đường kẻ đỏ) để đọc ra rc.Left, rc.Top của của EXCEL7 - vị trí của điểm Q, rồi từ đó thử "dịch một tí sang phải và một tí xuống dưới" để có Left và Top của P.

Vậy thì tại sao lại dùng SetParent để làm gì? Người ta muốn đặt UserForm trên màn hình ở vị trí trùng với P của cell A1 thôi chứ không phải đặt UserForm trong cửa sổ EXCEL7. Bạn hiểu sai ý người ta rồi.

Vấn để nằm ở chỗ sau khi có rc.Left, rc.Top, tức điểm Q rồi thì phải tính "dịch một tí sang phải và một tí xuống dưới". "Tí" ở đây cụ thể tính thế nào, đó là cái người ta cần phải tìm.

Bạn xem/đọc ở chỗ nào biết người ta "Người ta muốn đặt UserForm vào vị trí cell A1"? Tôi đọc kỹ câu hỏi và xem hình ảnh mô tả của @Mr.hieudoanxd không thấy thể hiện ý đó. Vậy chủ topic vào xác nhận xem.
 
Upvote 0
Em đưa useform về 1 góc bên màn hình có thể bên phải, bên trên, phía dưới, bên trái. ở Ảnh Office 2010 bị lệch khung, ở các version sau ví dụ Office 365 thì đúng vị trí em cần ạ
Nhiều khi mình đặt nặng quá.
Nếu mình góc trái phải, gì đó giữa màn hình là oki mà.
 
Upvote 0
Bạn xem/đọc ở chỗ nào biết người ta "Người ta muốn đặt UserForm vào vị trí cell A1"? Tôi đọc kỹ câu hỏi và xem hình ảnh mô tả của @Mr.hieudoanxd không thấy thể hiện ý đó. Vậy chủ topic vào xác nhận xem.
Bạn đọc đoạn trích: "Em đưa useform về 1 góc bên màn hình có thể bên phải, bên trên, phía dưới, bên trái. ở Ảnh Office 2010 bị lệch khung, ở các version sau ví dụ Office 365 thì đúng vị trí em cần ạ", và xem ảnh office 365.png thì bạn sẽ hiểu. Đó chính là trường hợp "bên phải", còn bài của tôi nói về trường hợp "bên trái". Nếu xem tiếp ảnh office 2010.png thì thấy khác với office 365.png: 365.png "KHÍT" hơn 2010.png. Ý người ta là trường hợp 2010.png đã có sai số.
Hồi xưa trên XP nhiều người dùng tò mò kéo thanh tác vụ từ cạnh dưới của màn hình tới "bên phải", "bên trái", "bên trên" của màn hình. Có thể bạn này muốn làm một "thanh tác vụ" (Task Panel?) của riêng mình và tùy từng trường hợp mà đặt nó KHÍT "bên phải, bên trên, phía dưới, bên trái" của ActiveWindow.VisibleRange
Bài đã được tự động gộp:

Nhiều khi mình đặt nặng quá.
Nếu mình góc trái phải, gì đó giữa màn hình là oki mà.
Bạn ấy không muốn đặt ở "bên phải, bên trên, phía dưới, bên trái" của màn hình mà là của ActiveWindow.VisibleRange. Vì cái UserForm này là Form dùng làm cái gì đấy chứ không phải Form bình thường mọi người hay làm
 
Lần chỉnh sửa cuối:
Upvote 0
Người ta muốn đặt UserForm vào vị trí cell A1 (trích: "Em đưa useform về 1 góc bên màn hình có thể bên phải, bên trên, phía dưới, bên trái"), tức góc trên bên trái của UserForm vào góc trên bên trái của A1 (gọi là điểm P). Vì thế người ta muốn dùng GetWindowRect cho cửa sổ EXCEL7 (2 đường kẻ đỏ) để đọc ra rc.Left, rc.Top của của EXCEL7 - vị trí của điểm Q, rồi từ đó thử "dịch một tí sang phải và một tí xuống dưới" để có Left và Top của P.

Vậy thì tại sao lại dùng SetParent để làm gì? Người ta muốn đặt UserForm trên màn hình ở vị trí trùng với P của cell A1 thôi chứ không phải đặt UserForm trong cửa sổ EXCEL7. Bạn hiểu sai ý người ta rồi.

Vấn để nằm ở chỗ sau khi có rc.Left, rc.Top, tức điểm Q rồi thì phải tính "dịch một tí sang phải và một tí xuống dưới". "Tí" ở đây cụ thể tính thế nào, đó là cái người ta cần phải tìm.
Ý tưởng của bác xác định theo ô "A1" em hiểu và đã từng làm theo phương pháp ấy. Tuy nhiên để thực hiện thì lại phát sinh nhiều lỗi. Ví dụ để show form đúng vị trí ô A1 thì ô A1 luôn phải nằm đúng vị trí trên cùng bên trái. Nếu trường hợp thanh scroll bar kéo qua kéo lại kéo lên kéo xuống thì useform đi ra xa bờ ngay lập tức. Bác thử mà xem
P/s: Tổng hợp các ý của bác @HeSanbi và thầy @Nguyễn Duy Tuân sử dụng setparent xong tiếp tục sử dụng GetClientRect, GetWindowRect có lẽ sẽ được. Tiếc là thời gian này đang bù đầu quá nên chưa test sâu được.
Bài đã được tự động gộp:

Em thấy chỉ lấy đến handle của XLDESK là khớp được khung thầy ạ.
Cái này vẫn lỗi trong trường hợp excel có nhiều cửa sổ. Em sẽ test lại với phương án thầy hướng dẫn xem như nào
Nhiều khi mình đặt nặng quá.
Nếu mình góc trái phải, gì đó giữa màn hình là oki mà.
Em đẩy ra góc ngoài bên phải để không vướng vào màn hình thao thác thôi. Được như taskpane thì ngon nhất, tiếc là VBA không hỗ trợ. OCX ngoài thì cũng chỉ trên máy mình thôi...
Bài đã được tự động gộp:

Có thể bạn này muốn làm một "thanh tác vụ" (Task Panel?) của riêng mình và tùy từng trường hợp mà đặt nó KHÍT "bên phải, bên trên, phía dưới, bên trái" của ActiveWindow.VisibleRange
Cái này bác đoán trúng phóc!
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

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

Back
Top Bottom