Ngày mai trời lại sáng
Thành viên thường trực
- Tham gia
- 4/7/21
- Bài viết
- 339
- Được thích
- 139
Hay quá code vẫn chạy êm như tiếng hát ru chú ạ.Sửa chứ, các bài đều bàn về code của Covid mà.
Trong modWindowStyle có
Mã:Private Sub SetStyleBit(style As Long, ByVal bit As Long, ByVal bSet As Boolean)
Sửa thành
Mã:#If VBA7 Then Private Sub SetStyleBit(style As LongPtr, ByVal bit As Long, ByVal bSet As Boolean) #Else Private Sub SetStyleBit(style As Long, ByVal bit As Long, ByVal bSet As Boolean) #End If
Tóm lại ngoài khai báo style có thiếu sót thì khi CLICK trên sheet có lỗi là do có "xung đột".
Giải thích thêm cho những người thích Windows API hiểu.
1. Tại sao trong tập tin dùng OnTime không có lỗi khi CLICK trên sheet? OnTime dùng để chạy sub doi_mau. OnTime của VBA nên do Excel chạy, cứ sau 1 s thì Excel sẽ gọi doi_moi. Khi Excel bận thì dù 1 s đã qua thì nó cũng không gọi doi_moi mà làm xong các việc bận mới gọi doi_moi. Excel tự gọi nên nó làm chủ được tình huống. Không có xung đột gì ở đây.
2. Tại sao dùng SetTimer của Windows API thì lỗi khi CLICK trên sheet?
Ta phân tích dòng code
Dòng code trên có nghĩa là ta đã gọi hàm SetTimer của system Windows, kiểu như: báo cáo sếp (Windows), tôi đặt nhiệm vụ là cứ 200 ms thì thực hiện code của tôi, tức TimerProc, ở địa chỉ xyz trong bộ nhớ. Lúc đó system Windows sẽ tạo 1 "đồng hồ", cứ 200 ms sẽ gọi sub TimerProc. Tất nhiên 200 ms là thời gian mặc định. Khi 200 ms trôi qua mà đúng lúc system bận (ngoài process của ta còn vô vàn process khác trong system, bản thân system có những lúc bận) thì system sẽ gọi TimerProc vào lúc sau. Nhưng đây là nói về việc system bận, còn chuyện Excel lúc đó có bận hay không thì system không quan tâm, cứ 200 ms là gọi TimerProc. Hàm SetTimer trả về một giá trị được ghi nhớ trong biến ID. Khi cần "hủy" đồng hồ thì gọi KillTimer và truyền ID vào để hủy đồng hồ. Tại sao KillTimer không đủ để hủy đồng hồ mà lại phải truyền ID vào? Đơn giản là mỗi app có thể tạo nhiều đồng hồ do có nhu cầu. Khi muốn hủy 1 đồng hồ nào đấy mà chỉ cần gọi KillTimer không có tham số thì cụ thánh của system Windpows cũng chịu không biết "người ta" cần hủy đồng hồ nào. Vì thế mỗi đồng hồ được tạo bởi SetTimer sẽ được gán cho một con số định danh, và SetTimer khi tạo đồng hồ sẽ trả về con số định danh (ID) đó của đồng hồ được tạo. Khi cần hủy đồng hồ nào thì gọi KillTimer và truyền con số định danh (ID) của nó vào.Mã:ID = SetTimer(0, 0, 200, AddressOf TimerProc)
Khi chạy chương trình thì code và dữ liệu (data) sẽ được load vào bộ nhớ. Mọi chuyện sảy ra là sảy ra trong bộ nhớ. Sub TimerProc nằm đâu đó trong bộ nhớ. Trong trường hợp này TimerProc được gọi bởi system Windows chứ không bởi Excel. Vì mình có "khai báo" gì với Excel đâu mà nó biết khi nào phải gọi cái gọi là TimerProc. Để Windows có thể gọi TimerProc thì phải cung cấp cho Windows địa chỉ của TimerProc trong bộ nhớ. Windows biết TimerProc ở đâu thì cứ "đến giở" là gọi nó thôi. Ta cung cấp cho Windows địa chỉ trong RAM của TimerProc bằng hàm: AddressOf TimerProc sẽ trả về địa chỉ của TimerProc trong RAM. Khi đến giờ là Windows gọi TimerProc để thực thi. Nếu đúng lúc đó người dùng CLICK trên sheet thì code của Excerl cũng được thực thi (nếu vd. Excel phát hiện có Worksheet_SelectionChange thì code của Worksheet_SelectionChange sẽ được thực thi). 2 vị khác nhau cùng thực hiện việc của mình thì sảy ra "xung đột".
Hàm mà khi gọi một hàm nào đó của Windows API ta phải cung cấp cho Windows địa chỉ của nó, để Windows biết nó nằm ở đâu trong RAM để sau đó gọi nó, hàm đó được gọi là call back. TimerProc là một call back.
Chú ơi cháu thấy có một vấn đề khi chỉ vào bản đồ (vùng màu xanh) vùng này có phải là Hà Nội không mà không xuất hiện thông tin tên thành phố chú nhỉ? Khi chỉ đến vùng khác thì hiển thị, hình ảnh là cháu đang chỉ vào Nam Định sau đó di chuyển về vùng xanh thông tin trên cái form hiển thị không thay đổi vẫn hiện Nam Định. Như vậy là có phải là vấn đề hay không chú nhỉ, cháu chưa hiểu cái món này: