Quy trình của việc tạo Userform trong Excel và các bước thực hiện

  • Thread starter Thread starter ptm0412
  • Ngày gửi Ngày gửi
Liên hệ QC
Status
Không mở trả lời sau này.

ptm0412

Bad Excel Member
Thành viên BQT
Administrator
Tham gia
4/11/07
Bài viết
14,471
Được thích
37,137
Donate (Momo)
Donate
Giới tính
Nam
Nghề nghiệp
Consultant
Trên diễn đàn đã có rất nhiều chủ đề hỏi về Userform, cũng như nhiều chủ đề giới thiệu hoặc chia sẻ Userform. Tuy nhiên nói về căn bản tạo dựng userform không phải ai cũng biết, kết quả là userform tạo ra rất hoành tráng, rất đẹp đẽ, nhưng khi xảy ra lỗi thì lại không biết do đâu. Cũng có khi tạo userform không đúng trình tự khiến cho công việc trở nên khó khăn hơn, hoặc chọn control(s) không phù hợp khiến cho code phải viết phức tạp hơn.
Do đó tôi muốn giới thiệu kiến thức căn bản nhất trong việc tạo dựng form, và quy trình tuần tự cho việc tạo form. Nếu có thời gian, tôi sẽ viết nhiều hơn, tạm thời như sau:

Khái niệm về User form​

User form là một form mẫu nhập liệu hoặc hiển thị như 1 giao diện thay thế cho bảng tính với dòng cột đơn điệu. User form với những control đặc thù, nếu biết sắp xếp, trình bày một chút sẽ làm cho công việc của người dùng với Excel bớt tẻ nhạt.

Chức năng cơ bản của user form:​

  • Nhập liệu trên user form, tính toán một số trường sau đó xem kết quả hoặc lưu xuống bảng tính
  • Nạp dữ liệu từ bảng tính lên form để xem và hiệu chỉnh nếu cần, sau đó lưu xuống bảng tính lại
  • Tính toán ra kết quả ngay trên user form
  • Tạo các nút lệnh thực thi các thủ tục tác động lên bảng tính, lên workbook, worksheet, vùng dữ liệu như in worksheet, đóng mở workbook, tác động lên các controls của form, mở form khác, tạo mới sheet và chép dữ liệu xuống, …
  • Tạo và in báo cáo từ các nút lệnh

Chức năng phụ​

Các chức năng không cần thiết có thể bỏ qua hoặc hạn chế dùng:

  • Đăng nhập với user name và password: Hoàn toàn có thể bỏ qua, người dùng biết đọc code có thể tắt chức năng này.
  • Thay thế việc nhập liệu, sửa xóa trên bảng tính bằng cách ẩn hiển thị bảng tính. Hạn chế dùng hoặc hoàn toàn không dùng nếu không biết cách kiểm soát, vì không thể sử dụng song song với những file Excel khác.
  • Trang trí: Dùng logo, hình ảnh, định dạng màu sắc … để trang trí form. Chỉ nên dùng ở mức tối giản.

Yêu cầu phải có khi muốn tạo 1 userform​

Không phải ai muốn vẽ form cũng được, và không phải viết code thế nào form cũng chạy được. Và cũng không phải tạo form cho 1 mình mình xài, nhất là khi hỗ trợ tạo form cho người khác. Cần đáp ứng những yêu cầu sau nếu muốn tạo form ở mức hoàn thiện tối thiểu:

  • Biết căn bản về lập trình, biết tìm lỗi khi chạy thử
  • Biết rõ tính chất, tính năng và các phương thức cho từng loại control
  • Nắm vững và thực hiện đúng quy trình
  • Biết phương pháp test
  • Thấu hiểu rằng code đơn giản là code dễ quản lý, dễ hiệu chỉnh, dễ bổ sung.
  • Tư duy logic là cần thiết nhất, tư duy trang trí nghệ thuật là không cần thiết nhất

Quy trình chuẩn​

Xem sơ đồ sau:

1677555012406.png

Trong đó 3 bước đầu là quan trọng nhất, đặc biệt là phần vẽ ra giấy.
Trang trí form là việc ít quan trọng nhất, và làm sau cùng.
 
Lần chỉnh sửa cuối:
Cái vụ vẽ phác họa ra giấy có vẻ khíu chọ quá he?! Vẽ trên Excel luôn cũng được chứ có sao đâu.
Vẽ ra giấy có cái lợi so với vẽ trực tiếp trên form, đó là vẽ sẽ đúng thứ tự, không cần chỉnh sửa tab index. Giả sử vẽ xong thấy thiếu (ở bước 2), muốn vẽ thêm 1 cái textbox vào giữa mấy cái vẽ rồi thì phải di dời sắp xếp lại. Chưa kể tab Index nó loạn lên, sửa điên con luôn.

Vẽ phác họa bằng shape trên excel hay word đều được, nhưng để tờ giấy trước mặt vẽ form dễ hơn chạy qua chạy lại 2 cửa sổ.

Bước thứ nhất xác định mục tiêu và phạm vi:
Giả sử mục tiêu là lxử lý thêm mới, xóa sửa phiếu nhập xuất hàng trong kho. Lưu dữ liệu sửa xóa thêm mới, và in phiếu theo mẫu.
Phạm vi là chỉ 1 form vừa làm phiếu nhập vừa làm phiếu xuất thay vì 2 form.

Bước thứ 2: Xác định loại controls và số lượng mỗi loại
Bước này có thể tạo bảng trên Excel và tổng kết. Nhìn nó để vẽ ra giấy ở bước 3. Dùng nó để gắn Rowsource, định dạng canh trái canh phải, ... khi vẽ form thực

Thí dụ với mục tiêu ở bước 1, lập 1 bảng như sau:

1677595410505.png

Label thì đương nhiên phải có cho mỗi combobox, textbox.
Nếu dữ liệu không có SO/ PO liên quan thì bỏ bớt, hoặc chuyển từ combobox thành Textbox gõ tay
Nếu có thêm phiếu xuất/ nhập chuyển kho, thì thay 2 Option button bằng 1 Textbox Loại chứng từ nhập xuất 4 giá trị, hoặc combobox chọn 1 trong 4 giá trị. Đồng thời có thêm thông tin Kho đi/ kho đến (combobox chọn).

Làm được bảng trên thì thật sự đi được 1/3 đường rồi.

Tổng hợp lại:

1677595471065.png
 
Lần chỉnh sửa cuối:
Upvote 0
Chú: bạn có biết rằng một chuonwg trình khong nhất thiết phải thu gọn trong một flowchart? Mỗi cái hình chữ nhật có thể có riêng một flowchart của nó.
Đúng vậy. Trong sơ đồ ở bài 1, nếu muốn chi tiết hơn tôi sẽ thay 2 hình chữ nhật sau thành 1 quy trình con (hình chữ nhật hai đầu là gạch đôi)

1677596451878.png

Quy trình chính trở thành:

1677638194472.png

Quy ước các object của flowchart:

1677638216247.png

Và vẽ quy trình con:

1677638172318.png


Mục test tổng thể là quay về quy trình chính. Mục này cũng có thể tạo quy trình con.
 
Lần chỉnh sửa cuối:
Upvote 0

Bước 1: Xác định mục đích và phạm vi​

Xác định rõ ràng mục đích của việc tạo dựng form. Nếu mục đích lan man quá thì form trở nên rườm rà, khi cần nhiều mục đích hãy tạo nhiều form

Với cùng 1 mục đích thí dụ xử lý dữ liệu, có thể thêm chức năng in báo cáo sau khi chỉnh sửa, thêm bớt dữ liệu, nhưng không nên thêm chức năng vừa nhập xuất, vừa thu chi vì các đối tượng xử lý quá khác nhau. Tất nhiên nếu rất khéo léo cũng có thể dùng 1 form nhiều mục đích nhưng cần tư duy hết sức tốt và sử dụng các control hết sức linh hoạt.

Bước 2: Chọn các control(s) phù hợp​

Từ mục đích và phạm vi sẽ xác định cần những control loại nào, số lượng bao nhiêu.
  • Cân nhắc nên dùng combobox hay listbox. Nếu để chọn 1 giá trị trong list và chỉ xử lý với 1 giá trị đó thì dùng combobox (thường là chọn trong danh mục). Số lượng cột cũng chỉ nên vừa đủ. Nếu cần cái nhìn tổng quan nhiều dòng dữ liệu, và đặc biệt là nhiều cột thì dùng listbox.
  • Listbox mặc dù có thuộc tính ColumnHeads (chọn True sẽ có tiêu đề) nhưng khi lọc sẽ không còn hiển thị như mong muốn, nên có thể dùng control khác làm tiêu đề như Label. Cũng có thể dùng Button để trang trí, nhưng nên thiết lập TabStop các button này = False để tránh thao tác thừa trên bàn phím.
  • Các textbox dùng nhập liệu: Bao nhiêu thì vừa đủ, nếu có thể dùng 1 textbox nhiều chức năng trong những trường hợp khác nhau thì nên làm
  • Cân nhắc việc chọn sử dụng giữa option button và checkbox. Khi chỉ cần chọn 1 trong số các tùy chọn thì dùng Option button, nếu cần hoặc cho phép chọn nhiều thì dùng checkbox. Có thể phân nhóm cho các mục tùy chọn option button bằng các Frame, kể cả dùng Frame đóng khung cho các checkbox cùng loại, cùng nhóm.
  • Trường hợp tùy chọn đơn giản (ít mục chọn) và muốn thay đổi cho đỡ nhàm chán thì dùng các toggle button.
  • Trường hợp có 1 mục tùy chọn nhưng cho phép chọn 1 trong số quá nhiều, thì thay 5, 7 option button bằng 1 combobox để chọn.
  • Số lượng Command button cũng cần cân nhắc. Một button dùng được cho 2 chức năng thì nên tạo chỉ 1 nút. Thí dụ thay vì 1 nút chỉ lấy dữ liệu lên, hãy dùng nút ấy vừa lấy dữ liệu ra để sửa, vừa lưu dữ liệu sau khi sửa xuống. Trường hợp form nhập liệu, thì 1 nút có thể vừa dùng tạo mới vừa dùng để lưu, chỉ cần thay đổi caption và viết tách code cho 2 trường hợp là được.
  • Nếu có ý định dùng 1 form nhiều hơn 1 mục đích, thì càng cần cân nhắc về số lượng control, cân nhắc việc sử dụng 1 control cho 2 hoặc nhiều mục đích. Thí dụ trường hợp có 2 mục đích mua và bán thì dùng 1 combobox để chọn danh sách khách hàng khi bán, dùng luôn nó chọn danh sách nhà cung cấp khi mua. Thu, chi, nhập xuất cũng vậy. Tuy nhiên trường hợp đối tượng cần dùng trong form cho các mục đích là quá khác nhau, thì cần tách ra 2 form.
  • Cần liệt kê tất cả mục đích, tất cả form, và tất cả controls ra giấy hoặc ra file để đọc khi thực hiện bước phía sau.
Mẫu liệt kê:

1677812792714.png


Tổng hợp:

1677812815931.png
 
Upvote 0
Lần chỉnh sửa cuối:
Upvote 0

Phác họa thiết kế form​

Tại sao phải vẽ trên giấy?​

Tạo dựng form là 1 quá trình sửa, xóa, bổ sung nhiều lần. Bước 1 xác định mục đích xong, bước 2 cân nhắc các controls cần dùng và phân vùng cho chúng. Nhưng chỉ khi vẽ ra và suy nghĩ mới thấy cần phải thay đổi:
  • Thêm control chỗ này, chỗ khác
  • Chuyển đổi control từ loại này sang loại khác (checkbox, combobox, option button, …)
  • Bỏ bớt control không cần thiết, hoặc dùng 1 control nhiều chức năng thay vì nhiều controls
Những thay đổi này nếu làm trực tiếp trên form sẽ khó chỉnh sửa hơn trên giấy. Không những thế, thêm, xóa, chuyển đổi control sẽ làm cho thứ tự tabindex bị đảo lộn, không còn tương ứng với thứ tự nhập liệu mong muốn nữa. Tab Index là thứ mà chỉnh sửa rất tốn công.

Thậm chí có những thay đổi thiết kế khiến phải xóa đi làm lại phần lớn hoặc toàn bộ. Bỏ đi 1 tờ giấy vẽ lại nhẹ nhàng hơn việc vẽ lại toàn bộ form.

Thực hiện​

Dựa vào vị trí và số lượng các control trên bảng liệt kê đã thực hiện.
Chia vùng cho form. Tất cả các form nên có các phần chính:
  • Phần tiêu đề & header: Tiêu đề chính + các control chung nhất, áp dụng cho toàn bộ form (các combobox chủ yếu, các option button, checkbox tùy chọn chủ yếu
  • Phần thân: Các textbox nhập liệu, listbox chứa dữ liệu. Nếu dạng nhập liệu theo chứng từ nhiều dòng thì cũng nên chia 2 phần nhỏ:
  • Phần thông tin chung như số chứng từ, ngày chứng từ, người bán/ mua, người nhận/ nộp
  • Phần thông tin chi tiết cho từng dòng. Không cần thiết phải tạo chi tiết 50 controls cho 1 chứng từ 10 dòng và 5 cột. Chỉ tạo 5 controls và lưu xuống từng dòng. Nếu muốn xem trước 10 dòng trước khi lưu, thì dùng thêm 1 Listbox, nhập liệu 1 lần 5 controls, lưu vào listbox 1 dòng (add item); sau đó mới lưu xuống sheet.
  • Phần điều khiển form: bao gồm các nút nhấn tác vụ.
  • Nên có các frame và/ hoặc các đường kẻ phân cách các phần
  • Nếu nhiều page (tab) thì phân phối control cho các page 1 cách hợp lý như là phân theo chức năng: Một page nhập liệu, 1 page xử lý dữ liệu, 1 page xem và in báo cáo

Xem xét lại bản vẽ​

Trước khi vẽ thực tế lên form, cần xem xét lại thật kỹ:
  • Đối chiếu với mục đích và phạm vi của cả form. Nếu cần thay đổi thì thay đổi ngay ở thời điểm này và quay lại bước 2: liệt kê lại các controls
  • Vị trí, kích thước tương đối từng vùng, cần cân đối hài hòa
  • Số lượng controls mỗi vùng đủ so với bảng kê
  • Kích thước mỗi control: nên lớn hay nhỏ, dài hay ngắn, …
  • Vị trí từng control: nên ngang hàng với nhau hay phải xuống dòng.
Một số mẫu form để tham khảo:

1678202061683.png

1678202121471.png

1678202215302.png

1678202282677.png

1678264532470.png
 
Lần chỉnh sửa cuối:
Upvote 0

Lưu ý khi thiết kế form và vẽ form​

Form thiết kế hoành tráng hoàn toàn không có nghĩa là form hoạt động tốt, hoặc dễ dùng, dễ vẽ. Hãy tưởng tượng ra việc người dùng cảm nhận thế nào khi dùng ít nhất 1 tiếng đồng hồ liên tục, chứ không phải cảm nhận thế nào khi nhìn lần đầu. Không phải mở file excel lên rồi ngắm không làm gì khác suốt 8 tiếng làm việc.
  • Kích thước form: Không nên vẽ quá lớn hoặc zoom toàn màn hình. Zoom toàn màn hình rồi không làm việc khác được, hoặc phải đóng form để làm việc khác. Ngoài ra khi chuyển giao file cho người dùng sử dụng màn hình có độ phân giải thấp hơn, form bị tràn và không sử dụng được. Nên thiết kế và vẽ ở thiết lập độ phân giải trung bình, không ỷ lại vào máy mạnh mà vẽ form lớn, vẽ controls lớn.
  • Font chữ: nên chọn font Unicode thông dụng cho mọi máy. Các controls nên cùng 1 font chữ. Cỡ chữ lớn vừa phải so với độ phân giải trung bình. Màu chữ và màu nền nếu không để mặc định thì nên chọn màu tương phản dễ đọc.: BackColor tone màu sáng, ForeColor tone màu tối.
  • Trang trí nhiều hình ảnh, nhiều màu sắc sẽ gây rối mắt. Nên trình bày trang nhã hơn là trình bày màu sắc lòe loẹt.
  • Các controls nên sắp xếp cân đối, hợp lý, phân bổ đều, ngay hàng thẳng lối.
  • Tách các chức năng hoàn toàn khác nhau ra những form khác nhau, thay vì nhồi nhét hết vào 1 form.
  • Dùng combobox thay vì dùng 5, 10, 15 option buttons và dùng listbox multi-select thay cho 5, 10, 15 checkbox.
  • Phân nhóm các option button và bao mỗi nhóm bằng các frame theo mục đích của nhóm.
 
Lần chỉnh sửa cuối:
Upvote 0

Thực hiện vẽ form​

Kích thước form​

Kích thước form tương ứng với số lượng controls sẽ vẽ trên đó. Do vậy kích thước form chỉ nên vừa đủ không lớn quá, không nhỏ quá.
Nếu có rất nhiều controls, và đang sử dụng màn hình kích thước lớn, có độ phân giải lớn cũng không nên vẽ form toàn màn hình. Vì khi chuyển sang máy làm việc tại công ty, hoặc chuyển sang laptop, hoặc chuyển cho người khác sử dụng có độ phân giải màn hình thấp hơn, form sẽ bị mất 1 phần.
Kích thước tối đa nên phù hợp với độ phân giải màn hình trung bình.

Thứ tự vẽ​

Nên vẽ theo thứ tự từ trái qua phải và từ trên xuống dưới. VBA sẽ tự động gắn tên theo thứ tự vẽ và quan trọng là VBA gắn tự động trình tự nhập liệu nếu dùng bàn phím để tab hoặc enter (tab index).
Kích thước từng control nên tương ứng với độ dài ký tự sẽ chứa trên đó.
Minh họa thứ tự vẽ:

1689220690194.png

Nếu có 1 hoặc nhiều groupbox(es), thì mỗi group là 1 control theo thứ tự vẽ, các controls bên trong cũng vẽ theo thứ tự từ trái sang phải và từ trên xuống dưới:

1689221450637.png

Trường hợp đặc biệt:

Nếu biết chắc trình tự nhập không theo thứ tự ngang mà theo hàng dọc, thì vẽ theo thứ tự nhập liệu. Đặc biệt những control có thuộc tính ẩn, khi cần mới hiện ra sẽ vẽ sau.

1689221217739.png

Khi mở form:

Tùy chọn 1:

1689221249619.png

Tùy chọn đầy đủ:

1689221268559.png

Đặt tên​

Đặt tên lại từng control theo ý nghĩa mình mong muốn control đó thể hiện, với tiếp đầu ngữ cho loại control chẳng hạn như txt (textbox), cbb (combobox), Lb (listbox), Btn (button), …
Cũng có thể đặt tên bằng cách đặt số thứ tự trong trường hợp các option button chọn lựa cùng 1 ý nghĩa chẳng hạn như OptInput1, OptInput2, …
Khi đã đặt tên thì việc viết code sẽ nhanh hơn và không nhầm lẫn.
Thí dụ có 5 Textbox có tên Qty1 đến Qty5, 5 Textbox có tên Price1 đến Price5, 5 Textbox nữa có tên Amount1 đến Amount5, và 1 textbox có tên totalAmt như sau:

1689216555412.png

Thì việc viết code cho sự kiện ghi số lượng sẽ như sau:

Mã:
Private Sub Qty1_AfterUpdate()
 Price1 = 100
 Amount1 = Qty1 * Price1
 TotalAmt = Val(TotalAmt) + Val(Amount1)
End Sub
'_________

Private Sub Qty2_AfterUpdate()
 Price2 = 120
 Amount2 = Qty2 * Price
 TotalAmt = Val(TotalAmt) + Val(Amount2)
End Sub

'__________

Private Sub Qty3_AfterUpdate()
 Price3 = 125
 Amount3 = Qty3 * Price3
 TotalAmt = Val(TotalAmt) + Val(Amount3)
End Sub

'__________

Private Sub Qty4_AfterUpdate()
 Price4 = 130
 Amount4 = Qty4 * Price4
 TotalAmt = Val(TotalAmt) + Val(Amount4)
End Sub

'__________

Private Sub Qty5_AfterUpdate()
 Price5 = 140
 Amount5 = Qty5 * Price5
 TotalAmt = Val(TotalAmt) + Val(Amount5)
End Sub

Có thể chỉ cần viết code 1 sub cho 1 control đầu tiên, copy code cho 4 controls còn lại: chỉ sửa vài con số của tên.
Kết quả:

1689216691020.png

Gán thuộc tính​

Mỗi control vẽ ra sẽ có những thuộc tính mặc định. Cần phải gán các thuộc tính mong muốn cho chúng. Name cũng là 1 thuộc tính phải đặt, Font và cỡ font cũng vậy:
Cỡ font cân xứng với kích thước form và độ phân giải màn hình trung bình.
Chiều cao tương ứng với cỡ font, không quá chật, không quá dư thừa.

Ngoài ra còn các thuộc tính khác như:
  • TextLength, Alignment, … cho textbox
  • Bound column, column count, column width, listwidth, rowSource, … cho combobox, listbox
  • Caption cho label, command button, option button, checkbox.
  • Thuộc tính visible, thuộc tính enabled …

Các control đặc biệt​

Các control về ngày tháng​

Nếu không vẽ được Date Time Picker thì dùng calendar, nếu không có cả calendar thì dùng textbox và sử dụng inputmask như hình, kèm theo 1 hàm trong module và thủ tục change của textbox:

1689217114296.png

Controls combobox và Listbox​

Các cột dữ liệu muốn đưa vào rowsource nhưng không muốn hiển thị thì cho column width = 0:

1689217139779.png


Rowsource có thể có nhiều cột nhưng vẫn có thể khai báo column count 2 cột, và vẫn truy xuất được các cột còn lại bằng thuộc tính combobox.Column(n) với n bắt đầu bằng 0.

Thuộc tính Tab stop và Tab Index​

VBA mặc định gắn tabstop và tab index cho các control ngoại trừ các control loại label. Khi muốn thay đổi thứ tự khác với thứ tự ban đầu thì sửa trong property tab index. Việc sửa này rất cực nếu như phải sửa nhiều, do đó nên vẽ theo thứ tự và vẽ theo 1 bản thiết kế có sẵn ở bước 3 thì tốt hơn.

Nếu dùng control thuộc loại có tab index cho mục đích tạo tiêu đề, trang trí, thì phải thiết lập tab stop = false để khỏi ảnh hưởng nhập liệu.
 
Lần chỉnh sửa cuối:
Upvote 0

Lập trình: Các lưu ý​

Sự kiện Form_Initialize​

Là sự kiện xảy ra ngay trước khi form được load lên. Dùng sự kiện này để:
  • Nạp dữ liệu cho Listbox, Combobox
  • Ẩn hiện các control (hoặc enable/ disable)
  • Giá trị mặc định các control (nếu là các option thì có giá trị True/ False)
  • Chữ hiển thị cho label (caption), chữ hiển thị cho nút nhấn
Mã:
Private Sub UserForm_Initialize()
Me.VATRate = 0
Cong = 0
CongVAT = 0
Me.CtNo = ""
Me.CTIDx = Null
Me.Dgiai = ""
Me.TT = 0
Me.DTNX = ""
Me.TtVAT = 0
Me.MHH = Null
Me.Dg = 0
Me.Dvt = ""
Me.Sl = 0
Me.CtDate = "__/__/____"
Me.CtDate.SetFocus
End Sub

Các sự kiện change​

Tận dụng sự kiện change để:
  • Thay đổi thông tin controls khác, hoặc giá trị 1 biến
  • Tự động gán giá trị cho các controls khác
  • Lọc listbox theo điều kiện mới gõ
  • Hạn chế hoặc không dùng để tính toán các con số và gán vào các textbox khác
  • Không dùng để kiểm soát kiểu dữ liệu nhập từng ký tự một, hãy kiểm tra bằng sự kiện khác

Các sự kiện before Update & kiểm soát loại dữ liệu nhập​

Tùy theo loại dữ liệu nhập vào textbox, cần kiểm soát dữ liệu nhập vào, thí dụ textbox số tiền thì chỉ nhập số, dữ liệu ngày tháng theo inputmask cũng là số
Cũng có thể kiểm soát dữ liệu trùng, dữ liệu số trong phạm vi giới hạn trước, số âm, …
Sự kiện before update với tham số cancel = True cho phép bắt nhập lại dữ liệu không cho ra khỏi textbox đang được focus.

Các sự kiện AfterUpdate và Exit​

Dùng để dịnh dạng chính nó, cập nhật giá trị cho control khác. Không dùng Change cho việc này. Vì có thể sinh ra lỗi chạy lặp nhiều lần.

Các sự kiện click chọn option​

Nếu có nhiều option button thì mặc định chỉ chọn được 1 option trong 1 nhóm trong 1 frame. Tuy nhiên khi click chọn 1 option này hay option kia cũng có thể điều khiển giá trị của các control liên quan như ẩn hiện control này, thay caption của label kia
Tương tự sự kiện click đánh dấu hay bỏ dấu của checkbox cũng có thể dùng với mục đích tương tự.
Căn cứ vào giá trị True/ False của các option/ checkbox, cũng có thể tính toán theo các hướng khác nhau
Thí dụ dùng 2 option để chọn Danh sách nhà cung cấp hoặc Danh sách khách hàng

1689342841048.png

Khi chọn option nào thì combox hoặc Listbox sẽ có danh sách đó để chọn. Đồng thời thay đổi caption của 2 labels

1689342860147.png1689342869483.png

Code như sau:

Mã:
Private Sub OptKH_Click()
 Me.ComboBox1.RowSource = "DSKH"
 Me.ListBox1.RowSource = "DSKH"
 Me.LblMa.Caption = "Ma khách hang"
 Me.LblTen.Caption = "Ten khách hàng"
 ComboBox1 = ComboBox1.List(0)
 Me.txtNameNCC = ComboBox1.Column(1)
End Sub
‘--------
Private Sub OptNCC_Click()
 Me.ComboBox1.RowSource = "DSNCC"
 Me.ListBox1.RowSource = "DSNCC"
 Me.LblMa.Caption = "Ma Nha CC"
 Me.LblTen.Caption = "Ten nha CC"
 ComboBox1 = ComboBox1.List(0)
 Me.txtNameNCC = ComboBox1.Column(1)
End Sub

Lấy dữ liệu ra để sử dụng​

Các textbox có đặc điểm là luôn luôn chứa giá trị string, nên với mục đích lấy giá trị số phải dùng hàm Val(), lấy giá trị ngày tháng phải dùng hàm DateSerial(year, month, day)

Code

Mã:
SODate = DateSerial(Right(txtDate, 4), Mid(txtDate, 4, 2), Left(txtDate, 2))

Nếu muốn định dạng số có dấu phân cách hàng ngàn, thì dùng hàm Format(), nhưng khi muốn lấy giá trị số như cũ phải dùng hàm replace để loại các dấu phân cách hàng ngàn đó.
Code:

Tạo 1 hàm định dạng
Mã:
Function FmtNum(num As Double)
 FmtNum = Format(num, "#,##0.00")
End Function

Tạo 1 hàm bỏ định dạng

Mã:
Function NumRaw(num As Double)
 NumRaw = Replace(num, ",", "")
End Function

Khi nhập liệu xong: định dạng

Mã:
Private Sub Qty1_AfterUpdate()
 Amount1 = FmtNum(Qty1 * Price1)
End Sub

Khi lấy giá trị để tính toán: bỏ định dạng

Mã:
TotalAmt = Val(NumRaw(TotalAmt)) + Val(NumRaw(Amount1))

Control RefEdit: Mặc dù lấy thông tin về range trên bảng tính nhưng giá trị của RefEdit là là dạng string, nó chỉ chứa địa chỉ của vùng chọn chứ không phải chứa đối tượng range. Do đó phải dùng như 1 địa chỉ Range: Range(Ref1)



Các sự kiện nhấn nút​

Các nút lệnh có thể gắn các thủ tục với mục đích bất kỳ như: tính toán trên form, lấy dữ liệu lên, lưu dữ liệu xuống, tạo báo cáo tại các sheet với tham số truyền vào, in 1 sheet báo cáo được chỉ định, …

Một nút có thể vừa lấy dũ liệu lên để sửa, vừa lưu xuống khi sửa xong. Hoặc 1 nút vừa tạo mới, vừa lưu xuống khi tạo mới và kiểm tra xong.

Sự kiện đóng form​

Các biến đối tượng phải được giải phóng khỏi bộ nhớ

Các biến public phải được xóa

Các thiết lập của hệ thống, của Excel nếu có thay đổi phải được trả về giá trị cũ. Không đợi đến khi đóng file.
 
Upvote 1

Test form​

Test từng phần​

Mỗi sự kiện của mỗi control, mỗi thủ tục đều cần phải test cẩn thận cho hoạt động đúng ý mong muốn. Cần lường trước những sự tác động vô ý hoặc cố ý của người dùng, các kiểu dữ liệu khác nhau, các tình huống khác nhau.

Test sự kiện sau, thủ tục sau, phải test sự liên kết, sự đồng bộ với các sự kiện/ thủ tục đã viết trước đó.

Test tổng thể​

  • Mở form, đóng form
  • Sử dụng form theo các chức năng đã lập trình, theo cách của người dùng, không phải theo cách người viết code.
  • Kiểm tra tác động của form tới sheet, tới dữ liệu.
  • Đóng file mở file
  • Sử dụng đồng thời với file Excel khác.
  • Các tình huống khác
Nếu nhiều form:

  • Tác động qua lại giữa các form
  • Sự liên kết giữa các form
  • Cho phép hoặc không cho phép mở cùng lúc nhiều form.
  • Các tình huống khác

Trang trí form​

Nên thực hiện sau cùng:
Có thể tô màu form, Đổi màu chữ, đổi font, cỡ chữ cho phù hợp.
Có thể gắn logo hoặc hình ảnh nhưng nên giới hạn số lượng, kích thước và màu sắc.
Tạo frame hoặc controls khác làm đường kẻ khung để phân nhóm chức năng, chia khu vực theo chức năng.

HẾT
Phần tiếp theo sẽ là một số thủ thuật trong lập trình như:
- Control đa chức năng
- Tìm kiếm
- Listbox nhiều hơn 10 cột
- Người dùng tự chọn màu chữ, màu nền
- Tùy chọn hiển thị ngôn ngữ.
- ...
 
Upvote 0
PHẦN 2: CÁC THỦ THUẬT NÊN BIẾT

Các thủ thuật​

Màn hình Welcome và đăng nhập​

Mặc dù bản thân tôi không thích ẩn Application, không thích dùng password đăng nhập, nhưng nếu dùng, tôi sẽ thực hiện như sau:
  • Trong sự kiện WorkbookOpen ẩn cửa sổ (windows) và mở form welcome
  • Trong sự kiện Mouse move của form, đóng form welcome
  • Trong sự kiện đóng form welcome hiện trở lại windows của workbook hoặc mở form đăng nhập
  • Trong sự kiện đóng form đăng nhập, hoặc sự kiện nhấn nút đăng nhập, hiện trở lại windows của workbook
Code như sau:
  1. Khi mở file
Mã:
Private Sub Workbook_Open()
Windows(ThisWorkbook.Name).Visible = False
WelcomeFrm.Show
End Sub

1690191468388.png

2. Khi di chuyển chuột, đóng form welcome và mở form đăng nhập

Mã:
Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Unload Me
SigninFrm.Show
End Sub

1690191546856.png

3. Nếu đang gõ pass mà không nhớ đến đâu, nhấn giữ nút vuông nhỏ để xem

Mã:
Private Sub Showpass_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Me.txtPass.PasswordChar = ""
End Sub

1690191614422.png

4. Buông chuột, trả về các dấu * hiển thị

Mã:
Private Sub Showpass_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Me.txtPass.PasswordChar = "*"
End Sub

1690191684530.png

5. Khi điền đúng user name và password, nhấn nút SignIn: đóng form và show lại cửa sổ, nếu sai hiện thông báo bắt sửa lại

Mã:
Private Sub BtnSignIn_Click()
If txtUserName = "ptm0412" And txtPass = "123" Then
 Unload Me
 Windows(wb.Name).Visible = True
Else
 MsgBox "Wrong user name or password", vbOKOnly, "Can not sign in"
 txtPass.SetFocus
End If
End Sub

6. Nếu không muốn đăng nhập, nhấn nút cancel: thoát file và không lưu

Mã:
Private Sub BtnCancel_Click()
Unload Me
ThisWorkbook.Close False
End Sub

7. Ngăn chặn người dùng đóng bằng nút X

Mã:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode <> 1 Then
 MsgBox "Please click cancel button", , "Can not close by X"
 Cancel = True
End If
End Sub

Xem file đính kèm. Có thể dùng cùng lúc file này và những file khác, dù mở trước hay mở sau.
Lưu ý:
Nếu có 1 danh sách user và pass thì phải dùng phương thức find và so sánh, ở đây tôi không giới thiệu vì trên GPE có nhiều rồi.
Lưu ý 2:
2 Form này tôi vẽ và viết code ở mức tối thiểu mà mất 2 giờ đồng hồ, test nửa giờ. Thế nên tôi khuyến cáo là không nên thực hiện làm gì vì:
- Tốn công mấy tiếng đồng hồ mà chỉ xài có 5, 10 giây
- Password bị bẻ hoặc vô hiệu hóa cái một.
Xem để biết cách dùng sự kiện, cách bắt lỗi người dùng, v.v...
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0

Thủ thuật 2: User form đa nhiệm​

Một user form nếu khéo dùng có thể dùng cho 2 hoặc nhiều chức năng như:
  • Phiếu thu + phiếu chi
  • Phiếu nhập kho + phiếu xuất kho
  • Thêm, sửa, xóa chứng từ
  • Bổ sung danh mục khách hàng, nhà cung cấp, mặt hàng, …
Với điều kiện các chức năng gần với nhau, đối tượng cho công việc gần tương đồng nhau.
Hãy xem cách để tạo 1 form như vậy với 4 chức năng nhập liệu chứng từ kho: Nhập, xuất, chuyển kho, và khách trả hàng.

Vẽ form​

Để chọn 1 trong 4 tùy chọn, vẽ 4 Option buttons, nằm trong 1 frame. Do khi đổi tùy chọn thì tiêu đề sẽ thay đổi theo loại phiếu nên Label3 không set Caption, tùy theo chọn option nào sẽ dùng code gán tiêu đề đó.

1690296670000.png

Tiêu đề chính của phiếu sẽ là:
  • Phiếu xuất & phiếu khách trả hàng sẽ có 1 combobox chọn mã khách hàng, 1 textbox tự động lấy tên khách hàng.
  • Phiếu nhập sẽ có 1 combobox chọn ã nhà cung cấp và 1 textbox tự động lấy tên nhà cung cấp.
  • Phiếu chuyển kho không cần 2 cái trên, mà cần 2 combobox để chọn kho đi và kho đến.
Thay vì vẽ 2 combobox chọn KH và NCC, thêm 2 combobox chọn kho, ta chỉ vẽ 2 combobox trong đó 1 cái linh hoạt làm 3 chức năng: chọn KH, chọn nhà CC và chọn kho đi. Cái còn lại chọn kho đến.

Tương tự chỉ vẽ 1 textbox tên thôi.
Theo ý định ban đầu: khi là phiếu chuyển thì không có combobox kho đến mà có tên, các kho khác có tên mà không có chọn kho đến, nên 2 cái này vẽ chồng lên nhau.
Label1, Label2 cũng linh hoạt nên sẽ set caption bằng code

1690296745277.png

Phần nội dung phiếu còn có thêm 2 textbox số phiếu và ngày phiếu.
Phần thân sẽ giống nhau cho cả 4 loại phiếu nên vẽ theo thứ tự nhập liệu, không có gì đặc biệt. Có thể gồm các control:
  • 1 combobox chọn mã mặt hàng
  • 2 textbox tự lấy tên hàng và đơn vị tính
  • Các textbox điền tay: Số lượng, đơn giá, thành tiền.
  • Một listbox để lưu tạm phiếu (một phiếu nhiều mặt hàng)
Phần thực thi sẽ có các nút nhấn (command button):
  • Tạo phiếu mới
  • Thêm mặt hàng
  • Lưu xuống sheet
  • Đóng form
Mục thủ thuật đa nhiệm này chủ yếu code cho việc đa nhiệm nên không vẽ những controls không có code đặc biệt.

Lập trình​

Khi mở form, ta muốn mặc định đánh dấu phiếu nhập, nên code sẽ gán các thuộc tính và caption cho các controls liên quan. Code dùng sự kiện form Initialize
PHP:
Private Sub UserForm_Initialize()
 Me.OptPNhap = True ''Chon loai phieu nhap
 Me.ComboBox1.RowSource = "DSNCC"             ''gán row source combobox là 1 vùng du lieu có name
 Me.ComboBox1 = Me.ComboBox1.List(0)         '' Combobox nhan giá tri là dòng dau tiên
 Me.ComboBox2.Visible = False                 ''An combobox kho
 Me.Label1.Caption = "Mã NCC"                 '' gan label
 Me.Label2.Caption = "Tên"
 Me.txtTen.Text = Me.ComboBox1.Column(1)     '' lay ten NCC tuong ung
 Me.LblTieude.Caption = Sheet1.Range("PNK") '' gan tieu de chinh bang gia tri 1 name
 Me.Frame1.Caption = Sheet1.Range("LoaiP") '' gan tieu de cho frame
End Sub

1690296948164.png

Các danh mục đã được đặt name:

1690296984899.png

Khi chọn phiếu xuất, thiết lập lại, sự kiện là click.
Private Sub OptPxuat_Click()
PHP:
Me.ComboBox1.RowSource = "DSKH"
Me.ComboBox1 = Me.ComboBox1.List(0)
Me.Label1.Caption = "Mã KH"
Me.txtTen.Visible = True
Me.ComboBox2.Visible = False
Me.txtTen.Text = Me.ComboBox1.Column(1)
Me.Label2.Caption = "Tên"
Me.LblTieude.Caption = Sheet1.Range("PXK")
End Sub
1690297062746.png
Khi chọn phiếu nhập, sự kiện click như trên
PHP:
Private Sub OptPNhap_Click()
Me.ComboBox1.RowSource = "DSNCC"
Me.ComboBox1 = Me.ComboBox1.List(0)
Me.Label1.Caption = "Mã NCC"
Me.txtTen.Visible = True
Me.ComboBox2.Visible = False
Me.txtTen.Text = Me.ComboBox1.Column(1)
Me.Label2.Caption = "Tên"
Me.LblTieude.Caption = Sheet1.Range("PNK")
End Sub

1690297229501.png

Khi chọn phiếu trả hàng, giống phiếu xuất
PHP:
Private Sub OptPTra_Click()
Me.ComboBox1.RowSource = "DSKH"
Me.ComboBox1 = Me.ComboBox1.List(0)
Me.Label1.Caption = "Mã KH"
Me.txtTen.Visible = True
Me.ComboBox2.Visible = False
Me.txtTen.Text = Me.ComboBox1.Column(1)
Me.Label2.Caption = "Tên"
Me.LblTieude.Caption = Sheet1.Range("PTH")
End Sub
1690297310358.png
Khi chọn phiếu chuyển kho, thiết lập hơi khác: Ẩn textbox tên và cho hiện ra combobox kho đến
PHP:
Private Sub OptPchuyen_Click()
Me.ComboBox1.RowSource = "DSKho"
Me.ComboBox1 = Me.ComboBox1.List(0)
Me.txtTen.Visible = False
Me.ComboBox2.Visible = True
Me.Label2.Caption = "Kho " & ChrW(273) & ChrW(7871) & "n"
Me.Label1.Caption = "Kho " & ChrW(273) & "i"
Me.LblTieude.Caption = Sheet1.Range("PXK")
End Sub

1690297392945.png

Form này tôi vẽ và viết code trong 3 giờ, nhưng xứng đáng với việc đa nhiêm, thay vì phải dùng 4 form khác nhau.
 

File đính kèm

Upvote 0

Thủ thuật 3: Controls phụ thuộc​

Control(s) phụ thuộc là những control(s) có thuộc tính bị thay đổi do sự thay đổi giá trị của control(s) khác.
Thí dụ khi chọn tỉnh thành trong combobox này, thì combobox (quận huyện) kia sẽ có thuộc tính rowsource thay đổi theo, hoặc thuộc tính list được gán mới.
Hoặc khi chọn 1 kiểu tính toán, thì đối tượng được tính toán sẽ thay đổi theo.

Thay đổi đối tượng tính toán​

Giả sử ta muốn có 1 form tính toán đa dạng: vừa có thể tính diện tích, vừa có thể tính thể tích, trọng lượng, của các vật thể cơ khí, thậm chí tính toán 1 công thức bất kỳ.
Nếu tính diện tích, thì phải là các đối tượng phẳng, là các hình vuông tròn chữ nhật, …
Nếu tính thể tích (hoặc trọng lượng), thì đối tượng phải là các hình khối chữ nhật, hình trụ tròn, hoặc hình tháp, …
Nếu tính bằng công thức tự điền, thì không có đối tượng tính toán cụ thể mà là tính toán các tham số đưa vào công thức.
Như vậy, các controls hình dạng đối tượng bị phụ thuộc vào các controls kiểu tính toán.

Ta sẽ vẽ form với 2 nhóm option buttons,
  • Một nhóm là các kiểu tính, với caption là các kiểu tính cụ thể
  • Một nhóm là các hình dạng, với caption được gán sau bằng code
  • Một textbox để chứa công thức khi chọn cách tính bằng công thức.
1690389736528.png

Viết 2 thủ tục con để xác định hình dạng cho nhóm 2, 1 thủ tục cho các hình phẳng và 1 thủ tục cho các hình khối
PHP:
Sub TwoDimension()
Shape1.Caption = "Hinh chu nhat"
Shape2.Caption = "Hinh tron"
Shape3.Caption = "Hinh vuong"
End Sub
''___________
Sub ThreeDimension()
Shape1.Caption = "Hinh hop chu nhat"
Shape2.Caption = "Hinh tru tron"
Shape3.Caption = "Hinh lap phuong"
End Sub

Viết 1 thủ tục để ẩn hiện nhóm 2, và ẩn hiện ô công thức

Mã:
Sub HideUnhide()
   LblFormula.Visible = CalFormula
   Formula1.Visible = CalFormula
   Frame2.Visible = Not CalFormula
End Sub

Khi chọn tính diện tích (CalSquare), hình dạng là các hình phẳng
Mã:
Private Sub CalSquare_Click()
   TwoDimension
   HideUnhide
End Sub

1690389916140.png

Khi chọn tính thể tích hoặc trọng lượng, hình dạng là các hình khối

PHP:
Private Sub CalVolumn_Click()
  ThreeDimension
  HideUnhide
End Sub
''___________
Private Sub CalWeight_Click()
  ThreeDimension
  HideUnhide
End Sub

1690390010848.png

Khi chọn tính bằng công thức, sẽ không có hình dạng mà có 1 ô để chứa công thức
Mã:
Private Sub CalFormula_Click()
   HideUnhide
End Sub

1690390063901.png

Để hoàn thiện form tính toán này sẽ còn nhiều việc phải làm:

  • Các textbox chứa kích thước các hình (chỉ 1 kích thước, 2 hay 3 kích thước tùy theo hình)
  • Các label cho các kích thước (cũng tùy theo hình dài/rộng/cao, hay dài/rộng, hay dài/đường kính)
  • Một textbox chứa tỷ trọng, xuất hiện khi cần tính trọng lượng
  • Một textbox chứa số lượng vật thể cần tính
  • Một label chứa đơn vị tính thay đổi theo kiểu tính.
  • Các nút nhấn: tính toán, gán kết quả xuống sheet.
Tuy nhiên code cũng tương tự như các code trên: đổi caption cho label, ẩn hiện các ô kích thước, …

Điểm đặc biệt của code bên trên đó là viết những thủ tục con dùng chung để gọi ra nhiều lần thay vì lập lại code trong từng sự kiện.
 

File đính kèm

Upvote 0

Thủ thuật 3: Controls phụ thuộc (tiếp theo)​

Hai Combobox phụ thuộc​

Hai Combobox phụ thuộc là khi combobox thứ nhất thay đổi, thì combobox thứ hai thay đổi theo. Có nhiều loại thay đổi, nhưng ở đây tôi giới thiệu việc thay đổi dữ liệu nguồn combobox thứ hai.

Thí dụ khi chọn tỉnh thành ở combobox 1, thì combobox 2 sẽ tự lấy dữ liệu quận huyện của riêng tỉnh thành đã chọn. Hoặc khi chọn khu vực bán hàng, thì sẽ lấy được danh sách cửa hàng ở khu vực đó.

1690471463413.png

Để làm việc này có nhiều cách. Nếu dữ liệu không hợp lý, không sắp xếp, thì chỉ có cách là dùng vòng lặp duyệt hết cột để lấy dữ liệu thỏa điều kiện rồi dùng phương thức AddItem của Combobox.

Còn nếu sắp xếp dữ liệu hợp lý và kèm thủ thuật ăn gian: Bắt Excel làm thay việc của code, thì code sẽ đơn giản. Gì chứ các công cụ có sẵn của Excel là nó làm nhanh và hiệu quả lắm, code tự viết không thể nào bằng.

Dữ liệu như sau, và đã sort theo khu vực:

1690471631652.png

Đặt 1 name DSKV cho cột A, và 1 name động DSCH lấy ở cột D, căn cứ vào khu vực chọn ở ô E2. Khi thay đổi ô E2, Excel tự tính toán và cho name DSCH tham chiếu đến đúng chỗ.

Lúc này, code sẽ viết rất đơn giản như sau:
PHP:
Private Sub CbbArea_Click()
 Sheet1.[E2].Value = CbbArea.Value ''gán khu vuc chon xuong ô E2
 ''Excel tính toán lai name DSCH
 CbbStore.RowSource = "DSCH" ''gan lai rowsource voi du lieu moi
CbbStore = Sheet1.Range("DSCH")(1, 1) ''lay cua hang dau tien gan cho combobox 2
End Sub

Không vòng lặp, không add item, không dùng List hay mảng. Chỉ 1 câu lệnh duy nhất.

Xem file đính kèm bài trên (#13)
 
Upvote 0

Thủ thuật 4: Thủ tục con dùng chung​

Ở phần trên (thay đổi đối tượng tính toán) ta đã thấy 1 thù tục con dùng chung là Sub HideUnhide, nó thay thế cho việc lặp lại các sự kiện click của các option button khác nhau
Mã:
Sub HideUnhide()
LblFormula.Visible = CalFormula
Formula1.Visible = CalFormula
Frame2.Visible = Not CalFormula
End Sub
Mỗi sự kiện click ta chỉ cần 1 câu lệnh gọi HideUnhide thay vì lập lại nhiều lần 3 câu lệnh khác nhau.
Nếu ta có nhiều textbox và label cần ẩn hiện, thì cũng đưa hết vào thủ tục này, các sự kiện cũng chỉ 1 câu lệnh.

Ẩn hiện nhiều textboxes, labels​

Cũng với form calculator trên, hãy hoàn thiện bằng các textbox điền kích thước tương ứng. Tuy nhiên với mỗi hình dạng cần tính ta sẽ cần chỉ 1, 2, hay cả 3 kích thước. Nếu thêm 1 tùy chọn tính toán loại trừ lỗ trên vật thể cơ khí, thêm 1 kích thước cho lỗ. Nếu tính trọng lượng sẽ cần textbox tỷ trọng.

Do kích thước cho các hình dạng khác nhau sẽ cần tên gọi khác nhau, nên đặt tên textbox là tên chung: Dim1, Dim2, Dim3, không đặt tên là Dai, Rong, Cao vì khi dùng cho hình tròn chẳng hạn, nó vô nghĩa.

1690880179860.png

Tùy theo chọn tính cái gì hay hình nào mà cho xuất hiện những textbox và label tương ứng, có tới cả 15, 16 control cần ẩn hiện. Viết 1 thủ tục con như sau:
Mã:
Sub HideUnhide()
 Formula1.Visible = CalFormula
 Frame2.Visible = Not CalFormula
 Frame3.Visible = Not CalFormula
 Dim2.Visible = (CalSquare And Shape1) Or ((CalVolumn Or CalWeight) And Not Shape3) Or CalFormul
 Dim3.Visible = ((CalVolumn Or CalWeight) And (Shape1)) Or CalFormula
 Hole.Visible = HavingHole Or CalFormul
 Tytrong.Visible = CalWeight
 Qty.Visible = Not CalFormul
 Formula1.Visible = CalFormula
 Label2.Visible = (CalSquare And Shape1) Or ((CalVolumn Or CalWeight) And Not Shape3) Or CalFormula
 Label3.Visible = ((CalVolumn Or CalWeight) And (Shape1)) Or CalFormul
 Label4.Visible = HavingHole Or CalFormula
 Label5.Visible = Not CalFormula
 Label6.Visible = CalWeight
 LblFormula.Visible = CalFormul
End Sub

Gán nhãn cho label(s)​

Tương tự với việc ẩn hiện, khi chọn tính kiểu gì và hình nào, tên gọi của kích thước thay đổi. Vậy viết 1 thủ tục con cho việc gắn nhãn để dùng trong các sự kiện.
PHP:
Sub LabelCaption()
If CalFormula Then
    Label1.Caption = "Tham so a:"
    Label2.Caption = "Tham so b:"
    Label3.Caption = "Tham so c:"
    Label4.Caption = "Tham so d:"
    Label9.Caption = ""
ElseIf CalSquare Then
     If Shape1 Then
         Label1.Caption = "Dai (mm):"
         Label2.Caption = "Rong (mm):"
     Else
         Label1.Caption = IIf(Shape2, "Duong kinh (mm):", "Canh (mm):")
     End If
    Label4.Caption = "Duong kinh lo (mm):"
    Label9.Caption = "mm2"
ElseIf CalVolumn Or CalWeight Then
 If Shape1 Then
     Label1.Caption = "Dai (mm):"
     Label2.Caption = "Rong (mm):"
     Label3.Caption = "Cao (mm):"
     ElseIf Shape2 Then
     Label1.Caption = "Duong kinh (mm):"
     Label2.Caption = "Cao (mm):"
 ElseIf Shape3 Then
     Label1.Caption = "Canh (mm):"
 End If
    Label4.Caption = "Duong kinh lo (mm):"
    If CalVolumn Then Label9.Caption = "mm3" Else Label9.Caption = "kg"
End If
End Sub


Dùng chung trong sự kiện:​

Các sự kiện click của tất cả option button sẽ như nhau, chỉ cần 2 câu lệnh
Mã:
HideUnhide
LabelCaption
Option chọn kiểu tính thêm câu lệnh TwoDimension hoặc ThreeDimension nhằm gắn nhãn cho các hình dạng.

1690880571726.png

Sự kiện Initialize cũng chỉ cần 2 câu lệnh như vậy thay vì cả thước lệnh.

Mã:
Private Sub UserForm_Initialize()
CalSquare = True
Shape1 = True
NoHole = True
TwoDimension
LabelCaption
HideUnhide
Qty = 1
Ref1 = "A1"
End Sub

Áp dụng chung​

Với userform, sẽ có nhiều control khác nhau, mỗi loại gồm nhiều controls. Đa phần các controls cùng loại sẽ phải dùng đến cùng 1 sự kiện. Nếu các câu lệnh trong sự kiện giống nhau, hoặc na ná nhau, hãy tìm cách viết thành những thủ tục con dùng chung, code sẽ bớt rối rắm rất nhiều.

Xem file CommonFunction.xlsm
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0

Ràng buộc trách nhiệm người dùng​

Người dùng phải xác nhận hành động​

Viết code kỹ lưỡng, ràng buộc tất cả các lỗi là chuyện rất cần thiết, nhưng cũng là việc khó. Nếu ta đẩy phần trách nhiệm sang cho người dùng thì code sẽ viết đơn giản hơn một chút. Không nhiều, nhưng đỡ chút nào hay chút ấy.

Thí dụ tạo 1 form thêm sửa xóa chứng từ. Cả 3 hành động trên (thê, sửa, xóa), việc bảo đảm người dùng nhập liệu đúng chuẩn CSDL (dạng số, dạng ngày tháng, chọn đúng đối tượng trong danh mục, …) là việc của người lập trình. Ngoại trừ việc đó, nói về bảo vệ an toàn dữ liệu, đừng dùng code tự ý thêm sửa xóa, mà hãy bắt người dùng xác nhận:

  • Khi mở form load dữ liệu lên xem, chỉ cho xem, không cho sửa
  • Nếu chọn 1 dòng dữ liệu/ chứng từ, cũng chỉ cho xem.
  • Nếu người dùng muốn sửa, phải nhấn nút “sửa”. Bằng hành động nhấn nút, người dùng tự chịu trách nhiệm về việc sửa nội dung.
  • Khi sửa xong, đừng lanh chanh viết code lưu xuống ngay mà bắt người dùng nhấn nút “lưu”. Tương tự như trên, người dùng phải tự xem lại kết quả sửa rồi mới nhấn nút. Tuy vậy, cũng nên có 1 nút “hủy” việc sửa để trả dữ liệu về nội dung ban đầu, nếu người dùng muốn hủy bỏ. Dù lưu hay hủy, hãy tái lập tình trạng chỉ cho xem.
  • Nếu người dùng thêm mới 1 chứng từ, phải nhấn nút “thêm”. Bằng hành động nhấn nút, người dùng xác nhận việc muốn tạo mới.
  • Khi người dùng nhập mới xong từng textbox cũng như đã xong toàn bộ chứng từ, cũng đừng lanh chanh viết code lưu xuống ngay, mà bắt người dùng nhấn nút “lưu mới”. Và cũng cần 1 nút “hủy” để người dùng hủy bỏ thao tác thêm mới đó. Dù lưu hay hủy, hãy tái lập tình trạng chỉ cho xem.
  • Khi xóa chứng từ, người dùng nhấn nút “xóa”, nên có 1 message để người dùng cân nhắc lại việc xóa. Dù vậy, về vấn đề an toàn dữ liệu, ta cũng đừng xóa thật, mà chỉ nên đánh dấu xóa. Khi muốn phục hồi sẽ phải nhờ admin (trưởng nhóm, trưởng phòng) phục hồi, và để truy cứu trách nhiệm.
Để làm những việc trên, người lập trình hoặc phải tốn công thêm 1 chút, hoặc cũng có thể giảm công việc bớt tùy theo khả năng người lập trình. Điểm quan trọng là không bị đổ lỗi sau này, cũng không phải mỗi lần có lỗi người dùng lại phải sửa code.

Người dùng phải cung cấp thông tin​

Làm việc với Excel, người lập trình sợ nhất là người dùng chèn xóa dòng/ cột của dữ liệu. Phải hướng dẫn người dùng, chẳng hạn như không được xóa dòng/ cột, nếu chèn cột thì phải thêm ở phía sau cùng. Nếu có thể, hãy cho phép người dùng chèn ở giữa, nhưng phải thông báo vị trí của 1 hoặc nhiều cột quan trọng. Vị trí ban đầu có thể ghi trên 1 sheet trắng, khi thay đổi phải sửa vào đúng sheet đó. Code sẽ đọc và chạy theo, không cần sửa code.
 
Upvote 0

Ràng buộc trách nhiệm người dùng (tt)​

Thực hiện​

Thí dụ cho form nhập liệu, xóa sửa chứng từ đơn (chứng từ 1 dòng)
Vẽ form đầy đủ như sau:
1691121858102.png

  • Khi mở form, load dữ liệu đầy đủ, không cho sửa
  • Khi chọn khách hàng ở combobox trên, dữ liệu bị lọc theo khách hàng (cũng không cho sửa)
1691121896753.png

  • Khi nhấn New, xuất hiện nút Cancel, 2 nút còn lại bị vô hiệu. Nút New trở thành nút Save new, không còn nút Close. Nếu đóng form bằng nút X bị mắng
  • Có thể nhấn Cancel hoặc Save new. Nếu không nhấn Save thì không lưu được.
  • Chưa xong việc không cho đóng form.
1691121989567.png

Khi nhấn nút Edit cũng vậy

1691122062753.png

Khi nhấn nút Delete, Nút delete trở thành Confirm delete và có 2 tùy chọn xóa vĩnh viễn và chỉ đánh dấu xóa.

Nếu đánh dấu xóa, dữ liệu vẫn còn nhưng không hiển thị trên form.

1691122203356.png

Xem file đính kèm.
 

File đính kèm

Upvote 0
Bác không Việt hoá các nút luôn à.
Trong bài sau, tôi sẽ có thủ thuật tùy chọn ngôn ngữ, chọn tiếng Việt hay tiếng Anh là toàn bộ các hiển thị chạy theo. Các form trong các bài viết trên tôi chỉ làm mẫu và tiết kiệm thời gian cho chính tôi. Người đọc chỉ cần xem các thủ thuật.
Chứ chả lẽ tôi không biết làm thì cù lần quá
 
Lần chỉnh sửa cuối:
Upvote 0
Status
Không mở trả lời sau này.
Web KT

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

Back
Top Bottom