Làm sao có thể biết được phím chức năng (ví dụ F1, Esc, F2, Shift, v.v) được nhấn (2 người xem)

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

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

CEO76

Thành viên mới
Tham gia
2/1/09
Bài viết
33
Được thích
12
Chào các bạn.

Tôi có một tập tin excel có 2 form ở trong đó. Một form có duy nhất 1 lable form còn lại có rất nhiều controls ơ trên form.

Tôi dùng Userform_Keydown function trong form chỉ có duy nhất 1 label thì có thể bắt được việc phím F1 được click. Tuy nhiên trên form thứ 2 thì không có gì xẩy ra.

Tôi rất muốn biết được khi nào phím chức năng ví dụ như F1, F2, F11, SHIFT, v.v được click trên form mà có nhiều controls.

Các bạn có thể giúp tôi với vấn đề này.

Kèm theo là file excel tôi vừa mới đề cập ở trên.

Mong nhận được sự hồi âm của các bạn

Xin chân thành cảm ơn.

CEO76
 
Chào các bạn.

Tôi có một tập tin excel có 2 form ở trong đó. Một form có duy nhất 1 lable form còn lại có rất nhiều controls ơ trên form.

Tôi dùng Userform_Keydown function trong form chỉ có duy nhất 1 label thì có thể bắt được việc phím F1 được click. Tuy nhiên trên form thứ 2 thì không có gì xẩy ra.

Tôi rất muốn biết được khi nào phím chức năng ví dụ như F1, F2, F11, SHIFT, v.v được click trên form mà có nhiều controls.

Các bạn có thể giúp tôi với vấn đề này.

Kèm theo là file excel tôi vừa mới đề cập ở trên.

Mong nhận được sự hồi âm của các bạn

Xin chân thành cảm ơn.

CEO76
Code đầu tiên là viết cho chính UserForm
Còn code thứ 2 khi các control đã nhận Focus thì sự kiện UserForm_KeyDown đâu còn tác dụng
---------------------
Tôi làm 1 ví dụ cho tất cả các control thuộc TextBox nhé
1> Chèn 1 ClassModule (tên là clsKeyDetect) và code:
Mã:
Public WithEvents txtForm As MSForms.TextBox
Private Sub txtForm_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  If KeyCode = vbKeyF1 Then MsgBox "F1 is pressed"
End Sub
2> Code trong UserForm2:
Mã:
Dim Obj() As New clsKeyDetect
Private Sub UserForm_Initialize()
  Dim Ctrl As Control, n As Long
  For Each Ctrl In Me.Controls
    If TypeOf Ctrl Is MSForms.TextBox Then
      n = n + 1
      ReDim Preserve Obj(1 To n)
      Set Obj(n).txtForm = Ctrl
    End If
  Next
End Sub
Giờ mở UserForm2, bấm F1 thử xem
Code sẽ có tác dụng khi bạn đặt con trỏ vào bất cứ TextBox nào
Muốn nó có tác dụng trên các Control khác cũng viết tương tự
 

File đính kèm

Upvote 0
Code đầu tiên là viết cho chính UserForm
Còn code thứ 2 khi các control đã nhận Focus thì sự kiện UserForm_KeyDown đâu còn tác dụng
---------------------
Tôi làm 1 ví dụ cho tất cả các control thuộc TextBox nhé
1> Chèn 1 ClassModule (tên là clsKeyDetect) và code:
Mã:
Public WithEvents txtForm As MSForms.TextBox
Private Sub txtForm_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  If KeyCode = vbKeyF1 Then MsgBox "F1 is pressed"
End Sub
2> Code trong UserForm2:
Mã:
Dim Obj() As New clsKeyDetect
Private Sub UserForm_Initialize()
  Dim Ctrl As Control, n As Long
  For Each Ctrl In Me.Controls
    If TypeOf Ctrl Is MSForms.TextBox Then
      n = n + 1
      ReDim Preserve Obj(1 To n)
      Set Obj(n).txtForm = Ctrl
    End If
  Next
End Sub
Giờ mở UserForm2, bấm F1 thử xem
Code sẽ có tác dụng khi bạn đặt con trỏ vào bất cứ TextBox nào
Muốn nó có tác dụng trên các Control khác cũng viết tương tự

Cho em hỏi, dùng CLASS trong trường hợp này là tạo sự kiện cho các TextBox, và trong form lúc ta chạy thủ tục Initialize thì nó duyệt các textbox để gán sự kiện đúng không ạ?
 
Upvote 0
Xin chân thành cảm ơn anh đã giúp tôi với vấn đề này.


Tôi thêm một đoạn code sau để khi form unload thì bộ nhớ được giải phóng.


Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If IsEmpty(Obj) = True Then Exit Sub
Erase Obj
End Sub


Tôi sẽ tìm hiểu thêm về class để giúp những công việc lập đi lập lại được dễ dàng hơn.


Một lần nữa xin cám ơn anh


CEO76
 
Upvote 0
Cho em hỏi, dùng CLASS trong trường hợp này là tạo sự kiện cho các TextBox, và trong form lúc ta chạy thủ tục Initialize thì nó duyệt các textbox để gán sự kiện đúng không ạ?
Chính xác là vậy!
Trong trường hợp viết code thông thường, cứ có 100 cái TextBox thì ta phải viết 100 đoạn code trong khi nếu dùng Class, nó thu gom 100 thằng này vào làm một và dù có bao nhiêu TextBox thì code cũng bi nhiêu đó mà thôi
 
Upvote 0
Chính xác là vậy!
Trong trường hợp viết code thông thường, cứ có 100 cái TextBox thì ta phải viết 100 đoạn code trong khi nếu dùng Class, nó thu gom 100 thằng này vào làm một và dù có bao nhiêu TextBox thì code cũng bi nhiêu đó mà thôi

Cám ơn Thầy, cho em hỏi rằng khi mình Set Obj(n) = Ctrl thì khi mình giải phóng bộ nhớ sẽ làm như thế nào? Bởi em Set Obj() = Nothing thì nó báo lỗi, còn dùng Erase chỉ xóa trong Obj mà không xóa được chính nó?

----------------------------------------------------

Mà thôi, biến này nằm trong Form, khi Form Unload thì tự nó giải phóng biến. +-+-+-+

----------------------------------------------------
 
Lần chỉnh sửa cuối:
Upvote 0
Chính xác là vậy!
Trong trường hợp viết code thông thường, cứ có 100 cái TextBox thì ta phải viết 100 đoạn code trong khi nếu dùng Class, nó thu gom 100 thằng này vào làm một và dù có bao nhiêu TextBox thì code cũng bi nhiêu đó mà thôi

Rất vui là nhờ bài này em hiểu tí tí về Class. Nếu ta tạo sự kiện cho TextBox bằng Class, rồi ta lại tạo một sự kiện trên chính TextBox đó, thì sự kiện ở ngay nó xảy ra trước sau đó mới đến Class

Mã:
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
      If KeyCode = vbKeyF1 Then MsgBox "TextBox1_KeyDown F1 is pressed"
End Sub


Cám ơn Thầy rất nhiều!
 
Upvote 0
Cám ơn Thầy, cho em hỏi rằng khi mình Set Obj(n) = Ctrl thì khi mình giải phóng bộ nhớ sẽ làm như thế nào? Bởi em Set Obj() = Nothing thì nó báo lỗi, còn dùng Erase chỉ xóa trong Obj mà không xóa được chính nó?

----------------------------------------------------

Mà thôi, biến này nằm trong Form, khi Form Unload thì tự nó giải phóng biến. +-+-+-+

----------------------------------------------------

Tôi chỉ biết cách này thôi:
Mã:
Private Sub UserForm_Terminate()
  Dim n As Long
  For n = 1 To UBound(Obj)
    Set Obj(n) = Nothing
  Next
End Sub
Vì mỗi phần tử trong Obj là 1 object nên phải Set từng thằng thành Nothing
 
Upvote 0
Cho em hỏi, dùng CLASS trong trường hợp này là tạo sự kiện cho các TextBox, và trong form lúc ta chạy thủ tục Initialize thì nó duyệt các textbox để gán sự kiện đúng không ạ?
Code trong class module dùng để tạo class, và code cho sự kiện.
Class thuộc nhóm object nào sẽ có sự kiện của nhóm object đó, dựa vào đó để viết code cho các sự kiện.
Chạy code form_initialize là duyệt qua các controls để nạp các controls đúng loại vào class đã tạo.
Còn code chạy sự kiện đã được gán trong sự kiện duy nhất trong class module.

[note1]Cần phân biệt class và class module, sự kiện và code cho sự kiện[/note1]
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi chỉ biết cách này thôi:
Mã:
Private Sub UserForm_Terminate()
  Dim n As Long
  For n = 1 To UBound(Obj)
    Set Obj(n) = Nothing
  Next
End Sub
Vì mỗi phần tử trong Obj là 1 object nên phải Set từng thằng thành Nothing

Cái này là suy nghĩ của mình chứ chưa thấy ở đâu cả. Biến Obj là biến mảng vậy ta có thể dùng Redim hay Arase để xoá cái biến này không nhỉ.
 
Upvote 0
Cái này là suy nghĩ của mình chứ chưa thấy ở đâu cả. Biến Obj là biến mảng vậy ta có thể dùng Redim hay Arase để xoá cái biến này không nhỉ.

Em nghĩ chưa chắc.. vì mỗi phần tử của Array là 1 object riêng biệt, vậy anh xóa cái Array ấy đi thì cùng lắm là cho cái Array ấy thằng rổng, tức không còn phần tử nào. Thế vùng nhớ của Object thì sao? Ta chưa đề cập gì đến mà
Nói chung khi viết code thì em không quan tâm lắm đến Array (hay biến Variant nói chung)... Em chỉ quan tâm biến nào thuộc object thôi (có set Nothing thì set cho object)
--------------
Đương nhiên cũng là suy nghĩ của riêng em thôi
 
Upvote 0
Em nghĩ chưa chắc.. vì mỗi phần tử của Array là 1 object riêng biệt, vậy anh xóa cái Array ấy đi thì cùng lắm là cho cái Array ấy thằng rổng, tức không còn phần tử nào. Thế vùng nhớ của Object thì sao? Ta chưa đề cập gì đến mà
Nói chung khi viết code thì em không quan tâm lắm đến Array (hay biến Variant nói chung)... Em chỉ quan tâm biến nào thuộc object thôi (có set Nothing thì set cho object)
--------------
Đương nhiên cũng là suy nghĩ của riêng em thôi

1. Mảng tĩnh Arr (static array): Erase Arr có nghĩa là set mỗi phần tử của mảng bằng 0, vbNullString, Empty hoặc Nothing tùy theo kiểu của các phần tử. Tức nếu các phần tử là object (lưu giữ địa chỉ của object) thì các đối tượng đó bị hủy diệt. Nhưng bộ nhớ dành cho Arr vẫn thế. Vì vậy sau Erase Arr vẫn có thể truy cập tới các phần tử của Arr và đọc ra giá trị, vd. 0 nếu phần tử là Long. Nếu mảng là tĩnh thì bộ nhớ dành cho mảng luôn tồn tại, không có cách nào để giải phóng bộ nhớ này.

2. Mảng động (dynamic array): Erase Arr có nghĩa là hủy diệt các phần tử nếu nó là object, và bộ nhớ dành cho Arr cũng được giải phóng. Vì vậy sau Erase Arr không thể truy cập được tới các phần tử của Arr (lỗi subscript out of range). Muốn dùng được Arr thì lại phải Redim

Tóm lại có thể yên tâm là nếu các phần tử của mảng là object thì bất kể đó là mảng tĩnh hay động thì Erase cũng hủy diệt các object đó.
 
Upvote 0
Web KT

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

Back
Top Bottom