#HookLab - Thảo luận về cách tạo Highlight bằng UserForm

  • Thread starter Thread starter thaipv
  • Ngày gửi Ngày gửi
Liên hệ QC

thaipv

XA Project
Tham gia
18/5/14
Bài viết
158
Được thích
239
Giới tính
Nam
Hiện nay tôi đang nghiên cứu cách tạo highlight (tô sáng / làm nổi bật những ô được chọn) bằng UserForm. Thuật toán vắn tắt như sau :

1. Hiện UserForm (đặt tên là frmHighlight) có kích thước và vị trí bằng cửa sổ của Sheet hiện hành (ActiveSheet / của sổ EXCEL7)
2. Cắt frmHighlight sao cho làm nổi bật vùng đang được chọn (Application.Selection).
3. Làm trong suốt frmHighlight.
4. Khi người dùng click chuột trái hay chuột phải trên frmHighlight thì ta gửi sự kiện tương ứng đến Sheet hiện hành sao cho mọi thao tác trên frmHighlight giống như người dùng đang thao tác với Sheet hiện hành.
5. Dùng kỹ thuật hook (hoặc subclassing) để bắt sự kiện Sheet hiện hành cuộn, di chuyển, thay đổi kích thước... và định lại kích thước, vị trí của frmHighlight sao cho phù hợp.
223918
Tuy nhiên, ở bước thứ 2 tôi chưa biết cách xác định Chiều cao và Chiều rộng của Outline và Heading (dòng tiêu đề của excel, các cột A, B, C, ... và các dòng 1, 2, 3...). Các bạn xem Sub Design trong frmHighlight, các biến x0 và y0. Bạn nào biết cách tính và các bạn có góp ý hay thảo luận gì thì trao đổi ở đây nhé.

Cách làm này giống với addin Kutools nha các bạn.
 

File đính kèm

Lần chỉnh sửa cuối:
Có lẽ dùng CF sẽ đơn giản hơn nhiều.
 
Upvote 0
Có lẽ dùng CF sẽ đơn giản hơn nhiều.
Dùng CF đơn giản hơn nhưng gặp 1 số nhược điểm như :
1. Bị mất format của cell nếu bẫy lỗi không khéo.
2. Chương trình sẽ chạy nặng hơn nếu dữ liệu nhiều dòng, cột.
3. Tính thẩm mỹ không cao bằng dùng UserForm...

Tất nhiên cách dùng UserForm này là cách khó.
 
Upvote 0
Hiện nay tôi đang nghiên cứu cách tạo highlight (tô sáng / làm nổi bật những ô được chọn) bằng UserForm. Thuật toán vắn tắt như sau :

1. Hiện UserForm (đặt tên là frmHighlight) có kích thước và vị trí bằng cửa sổ của Sheet hiện hành (ActiveSheet / của sổ EXCEL7)
2. Cắt frmHighlight sao cho làm nổi bật vùng đang được chọn (Application.Selection).
3. Làm trong suốt frmHighlight.
4. Khi người dùng click chuột trái hay chuột phải trên frmHighlight thì ta gửi sự kiện tương ứng đến Sheet hiện hành sao cho mọi thao tác trên frmHighlight giống như người dùng đang thao tác với Sheet hiện hành.
5. Dùng kỹ thuật hook (hoặc subclassing) để bắt sự kiện Sheet hiện hành cuộn, di chuyển, thay đổi kích thước... và định lại kích thước, vị trí của frmHighlight sao cho phù hợp.
View attachment 223918
Tuy nhiên, ở bước thứ 2 tôi chưa biết cách xác định Chiều cao và Chiều rộng của Outline và Heading (dòng tiêu đề của excel, các cột A, B, C, ... và các dòng 1, 2, 3...). Các bạn xem Sub Design trong frmHighlight, các biến x0 và y0. Bạn nào biết cách tính và các bạn có góp ý hay thảo luận gì thì trao đổi ở đây nhé.

Cách làm này giống với addin Kutools nha các bạn.
Thoạt nhìn rất chuyên nghiệp như khi thay đổi kích thước cửa sổ thì lòi ra cái không được. Chắc phải khắc phục thêm.
 
Upvote 0
Dùng CF đơn giản hơn nhưng gặp 1 số nhược điểm như :
1. Bị mất format của cell nếu bẫy lỗi không khéo.
2. Chương trình sẽ chạy nặng hơn nếu dữ liệu nhiều dòng, cột.
3. Tính thẩm mỹ không cao bằng dùng UserForm...

Tất nhiên cách dùng UserForm này là cách khó.
Tốc độ của UserForm này cũng nhanh hơn CF nữa.
 
Upvote 0
002.pngCập nhật : Tôi đã gần hoàn thiện bước 2. Tuy nhiên, vẫn còn 1 số lỗi nhỏ tôi chưa khắc phục được :
+ Bảng tính hiện hành hiện từ phải sang trái (ActiveWindow.DisplayRightToLeft = True) và có đóng băng khung (Freeze Pane) thì tọa độ bị lệch.
+ Bảng tính hiện hành có chia cửa sổ (Split Window) thì bị lệch vài pixel.
Bạn nào biết thì sửa giúp mình nhé.

Cảm ơn bạn @huynhkimtien đã chia sẻ code rất hữu ích.

Như vậy là gần hoàn thiện các bước từ 1->4, bắt đầu code bước 5 (củ chuối nhất)
 

File đính kèm

Upvote 0
Cập nhật : Tôi đã gần hoàn thiện bước 2. Tuy nhiên, vẫn còn 1 số lỗi nhỏ tôi chưa khắc phục được :
+ Bảng tính hiện hành hiện từ phải sang trái (ActiveWindow.DisplayRightToLeft = True) và có đóng băng khung (Freeze Pane) thì tọa độ bị lệch.
+ Bảng tính hiện hành có chia cửa sổ (Split Window) thì bị lệch vài pixel.
Bạn nào biết thì sửa giúp mình nhé.
Vì sao không SetParent cho Form là Excel7 vậy.
Bác viết code vô tình quên hay là cố ý không Set, hay là không nên làm như vậy.
Tôi thấy yếu tố này rất quan trọng.

Thiếu việc xét ActiveWindow.DisplayHeadings
và ActiveWindow.DisplayWorkbookTabs đang mở hay tắt.

Về phần khai báo các Hàm Api, bị sai sót 2 hàm.

Class Unit không được khai báo và set trước khiến Hàm API GetDC bị gọi lại liên tục.

Và quá trình cắt Form không thể thiếu Hàm API LockWindowUpdate
 
Lần chỉnh sửa cuối:
Upvote 0
Vì sao không SetParent cho Form là Excel7 vậy.
Bác viết code vô tình quên hay là cố ý không Set, hay là không nên làm như vậy.
Tôi thấy yếu tố này rất quan trọng.
SetParent thì không làm trong suốt form được nhé, bạn có cách nào không ?
Thiếu việc xét ActiveWindow.DisplayHeadings
và ActiveWindow.DisplayWorkbookTabs đang mở hay tắt.
ActiveWindow.DisplayHeading : không cần thiết xét thuộc tính này
ActiveWindow.DisplayWorkbookTabs : đã xét thuộc tính này

Về phần khai báo các Hàm Api, bị sai sót 2 hàm.

Class Unit không được khai báo và set trước khiến Hàm API GetDC bị gọi lại liên tục.

Và quá trình cắt Form không thể thiếu Hàm API LockWindowUpdate
Cảm ơn bạn về việc này.
 
Lần chỉnh sửa cuối:
Upvote 0
SetParent thì không làm trong suốt form được nhé, bạn có cách nào không ?
Trong Class cWindow của Bác thêm vào cho phù hợp cả 64 và 32
-------------------------------
Tôi thấy dư thừa GetWindowRect nếu SetParent
-------------------------------
Công đoạn 5 của Bác chỉ có thể làm thêm cho vui, chứ không thể, vì quá trình Hook sẽ làm ngắt tiến trình Excel
Nếu Bác dùng SetTimer và con trỏ hàm, thì sẽ dễ dàng bỏ qua nhiều công đoạn. Thay vì Hook.
PHP:
hResult = GetWindowLongPtr(hWindow, GWL_STYLE) Or WS_EX_LAYERED
Call SetWindowLongPtr(hWindow, GWL_STYLE, hResult And (Not WS_CAPTION))
hResult = GetWindowLongPtr(hWindow, GWL_EXSTYLE) Or WS_EX_LAYERED
Call SetWindowLongPtr(hWindow, GWL_EXSTYLE, hResult And Not WS_EX_DLGMODALFRAME)


Thay thế code dưới này cho code trên sẽ giải quyết 2 vấn đề:
1. Click được kể cả khi đã Double Click vào một Cell
2. Không cần đến nhận Sự kiện Gửi vị trí và click chuột ra sau Form.

PHP:
Call SetWindowLongPtr(hWindow, GWL_EXSTYLE, hResult Or WS_EX_NOINHERITLAYOUT Or WS_EX_NOACTIVATE Or WS_EX_TRANSPARENT Or WS_EX_DLGMODALFRAME)


Code sẽ gọn gàn hơn rất nhiều.


Thêm một lời khuyên, Đã tạo Hightlight bằng Form thì nên đưa tất cả các Code Nằm Duy nhất trong code của Form.
Bao gồm: Khai báo API và các Class cũng chuyển vào Form.
 
Lần chỉnh sửa cuối:
Upvote 0
Trong Class cWindow của Bác thêm vào cho phù hợp cả 64 và 32
-------------------------------
Tôi thấy dư thừa GetWindowRect nếu SetParent
-------------------------------
Công đoạn 5 của Bác chỉ có thể làm thêm cho vui, chứ không thể, vì quá trình Hook sẽ làm ngắt tiến trình Excel
Nếu Bác dùng SetTimer và con trỏ hàm, thì sẽ dễ dàng bỏ qua nhiều công đoạn. Thay vì Hook.
PHP:
hResult = GetWindowLongPtr(hWindow, GWL_STYLE) Or WS_EX_LAYERED
Call SetWindowLongPtr(hWindow, GWL_STYLE, hResult And (Not WS_CAPTION))
hResult = GetWindowLongPtr(hWindow, GWL_EXSTYLE) Or WS_EX_LAYERED
Call SetWindowLongPtr(hWindow, GWL_EXSTYLE, hResult And Not WS_EX_DLGMODALFRAME)

Thay thế code dưới này cho code trên sẽ giải quyết 2 vấn đề:
1. Click được kể cả khi đã Double Click vào một Cell
2. Không cần đến nhận Sự kiện Gửi vị trí và click chuột ra sau Form.

PHP:
Call SetWindowLongPtr(hWindow, GWL_EXSTYLE, hResult Or WS_EX_NOINHERITLAYOUT Or WS_EX_NOACTIVATE Or WS_EX_TRANSPARENT Or WS_EX_DLGMODALFRAME)

Code sẽ gọn gàn hơn rất nhiều.
Tôi đã thử nghiệm những code này theo bạn nhưng đều không thành công! Bạn rành thì viết luôn code vào file cho mọi người cùng học hỏi. Cảm ơn.

Theo tôi :
- Với kỹ thuật hook : Bắt và/hoặc chặn những sự kiện (thông điệp) cần thiết gửi đến cửa sổ mục tiêu.
+ Ưu điểm : Xử lý từ gốc. Chỉ cần làm việc cần thiết khi cần.
+ Nhược điểm : Crash ứng dụng nếu xử lý không khéo.
- Với kỹ thuật dùng Timer : Sự kiện đã xảy ra với cửa sổ mục tiêu, dùng biến/hàm... xác định xem có sự thay đổi nào không.
+ Ưu điểm : Dễ dàng code hơn.
+ Nhược điểm : Xử lý từ ngọn. Sau 1 khoảng thời gian định trước lại lặp lại việc này (nếu muốn ứng dụng chạy mượt thì định thời gian càng ngắn nhưng lại càng tiêu tốn tài nguyên hệ thống). Và nếu xử lý không khéo thì ứng dụng vẫn bị crash như thường.
 
Lần chỉnh sửa cuối:
Upvote 0
Hiện nay tôi đang nghiên cứu cách tạo highlight (tô sáng / làm nổi bật những ô được chọn) bằng UserForm. Thuật toán vắn tắt như sau :

1. Hiện UserForm (đặt tên là frmHighlight) có kích thước và vị trí bằng cửa sổ của Sheet hiện hành (ActiveSheet / của sổ EXCEL7)
2. Cắt frmHighlight sao cho làm nổi bật vùng đang được chọn (Application.Selection).
3. Làm trong suốt frmHighlight.
4. Khi người dùng click chuột trái hay chuột phải trên frmHighlight thì ta gửi sự kiện tương ứng đến Sheet hiện hành sao cho mọi thao tác trên frmHighlight giống như người dùng đang thao tác với Sheet hiện hành.
5. Dùng kỹ thuật hook (hoặc subclassing) để bắt sự kiện Sheet hiện hành cuộn, di chuyển, thay đổi kích thước... và định lại kích thước, vị trí của frmHighlight sao cho phù hợp.
View attachment 223918
Tuy nhiên, ở bước thứ 2 tôi chưa biết cách xác định Chiều cao và Chiều rộng của Outline và Heading (dòng tiêu đề của excel, các cột A, B, C, ... và các dòng 1, 2, 3...). Các bạn xem Sub Design trong frmHighlight, các biến x0 và y0. Bạn nào biết cách tính và các bạn có góp ý hay thảo luận gì thì trao đổi ở đây nhé.

Cách làm này giống với addin Kutools nha các bạn.
Anh đã hoàn thành bước 5 chưa ạ. :) . Em theo dõi mãi mà chưa thấy anh làm tiếp.
 
Upvote 0
Web KT

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

Back
Top Bottom