Làm thế nào để hiển thị thông báo lỗi chi tiết trong quá trình.

Liên hệ QC

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
338
Được thích
139
Chào các bạn,em có một đoạn code như sau:
Mã:
Sub test()
    Dim db As Double, i As Integer, k As Long, rng As Range
    On Error GoTo Loi
    k = Sheet1.Range("A1")  'Co the say ra loi neu A1 khong phai la gia tri kieu long
    i = Sheet1.Range("A2")  'Co the say ra loi neu A1 khong phai la gia tri kieu text
    db = k / i              'co the say ra loi neu i=0
    Set rng = Range(Sheet1.Range("A3").Value) ' Co the xay ra loi neu A3 =""
    'v.v... cac truong hop loi co the say ra
    
Loi:
    Dim s1, s2, s3
    s1 = Err.Number
    s2 = Err.Description
    '...
    MsgBox s1 & vbNewLine & s2 & vbNewLine, vbCritical
    
End Sub
Đoạn code trên nó có thể sảy ra lỗi tại bất cứ dòng nào, em muốn làm thế nào để hiển thị chi tiết lỗi cụ thể tại dòng đó như:
Ví dụ A2 em nhập "A" trong khi code khai báo là Integer, mong muốn code thông báo đại loại:
Có lỗi do nhập liệu tại Sheet1.Range("A2") , mã lỗi là "XYZ", thông tin lỗi "ABC"
Ý em là tránh phải mở code để kiểm tra, mà có thể hiển thị thông tin lỗi luôn, còn nếu bắt lỗi cho từng dòng thì cũng có thể nhưng phải code nhiều và cũng khó thể lườn hết được vấn đề khác, không biết có cách nào khác không?
 
Mã:
Sub test()
    Dim db As Double, i As Integer, k As Long, rng As Range
    On Error GoTo Loi
1    k = Sheet1.Range("A1")  'Co the say ra loi neu A1 khong phai la gia tri kieu long
 2   i = Sheet1.Range("A2")  'Co the say ra loi neu A1 khong phai la gia tri kieu text
 3  db = k / i              'co the say ra loi neu i=0
 4  Set rng = Range(Sheet1.Range("A3").Value) ' Co the xay ra loi neu A3 =""
5    'v.v... Các Truòng Hop Loi Có Thê Say Ra  '
Loi:
    Dim s1, s2, s3
    s1 = Err.Number
    s2 = Err.Description
    '...
    MsgBox s1 & vbNewLine & s2 & vbNewLine, vbCritical  , , Erl()
End Sub
Là mình thì sẽ đánh số các dòng lệnh & hiển thị ngay dòng đang dừng do lỗi;
Tuy nhiên cũng đừng chú tâm là dòng (lệnh) đó đang lỗi, mà có thể là dòng trước nó gây lỗi cho nó.
 
Upvote 0
Để tránh lỗi xảy ra thì ta thường dùng IF ... End IF (Nếu là như thế này thì sẽ làm thế này)
On Error GoTo Loi => Chỉ sử dụng được có 1 lần duy nhất thôi, nếu muốn sử dụng nhiều lệnh như thế thì ta chia nhỏ ra thành các Sub con
 
Upvote 0
Code ủa bạn luộm thuộm lắm.
Bẫy lỗi kiểu On Error chỉ là giải pháp "Band-Aid" (chắp vá).

Có những cái bẫy bằng On Error, nhưng cũng có những cái bẫy bằng thứ khác.
{1} k = Sheet1.Range("A1") 'Co the say ra loi neu A1 khong phai la gia tri kieu long
{2} i = Sheet1.Range("A2") 'Co the say ra loi neu A1 khong phai la gia tri kieu text
{3} db = k / i 'co the say ra loi neu i=0
{4} Set rng = Range(Sheet1.Range("A3").Value) ' Co the xay ra loi neu A3 =""
{1} Người ta check bằng IF IsNumeric(...). Tuy nhiên, vẫn bị lỗi dữ liệu nếu A1 chứa một số có thập phân.
{2} Chỗ này bạn cẩu thả quá. Không hiểu bạn muốn gì.
{3} Chỗ này KHÔNG AI dùng bẫy lỗi cả. Nguyên tắc lập trình là LUÔN LUÔN xét một giá trị trước khi chia.
{4} Chỗ này chỉ bẫy lỗi không đủ. Thực sự phải xét xem nó có chiếu vào đúng đối tượng hay không. Tuy nó lấy dữ liệu từ Sheet1, nhưng sau đó nó tham chiếu qua sheet hiện hành.

Nếu thực sự muốn dùng On Error để bẫy lỗi thì phải biết lỗi có một đối tượng Err và một hàm Erl. Sau đó, cần nghiên cứu thêm về việc phải làm gì sau đó (điển hình: Xoá lỗi, Resume, ...). Hiện tại, code của bạn nhảy luôn ra khỏi hàm?
 
Upvote 0
Hiện tại, code của bạn nhảy luôn ra khỏi hàm?
Cảm ơn chú đã tư vấn, đúng là code của cháu đang để nếu lỗi thì thoát.
Ý cháu là nếu lỗi báo luôn ở đấy chi tiết cụ thể các tham chiếu liến quan đến nó để xử lý luôn không phải kiểm tra code (debug) ấy ạ
Có cách nào không chú?
 
Upvote 0
Cảm ơn chú đã tư vấn, đúng là code của cháu đang để nếu lỗi thì thoát.
Ý cháu là nếu lỗi báo luôn ở đấy chi tiết cụ thể các tham chiếu liến quan đến nó để xử lý luôn không phải kiểm tra code (debug) ấy ạ
Có cách nào không chú?
Có 2 cách
1/ Tự lường trước tất cả các tình huống có khả năng xảy ra để viết lệnh bẩy lỗi và ra thông báo
2/ Chờ ngài Bill tạo phần mềm trí tuệ nhân tạo viết code thay lập trình viên
 
Upvote 0
Đoạn code trên nó có thể sảy ra lỗi tại bất cứ dòng nào, em muốn làm thế nào để hiển thị chi tiết lỗi cụ thể tại dòng đó như:
Ví dụ A2 em nhập "A" trong khi code khai báo là Integer, mong muốn code thông báo đại loại:
Có lỗi do nhập liệu tại Sheet1.Range("A2") , mã lỗi là "XYZ", thông tin lỗi "ABC"
Ý em là tránh phải mở code để kiểm tra, mà có thể hiển thị thông tin lỗi luôn, còn nếu bắt lỗi cho từng dòng thì cũng có thể nhưng phải code nhiều và cũng khó thể lườn hết được vấn đề khác, không biết có cách nào khác không?
Tôi không hiểu ý bạn lắm.

Mục đích của bạn là gì? Nếu chỉ là để biết có lỗi thì tự VBA đã báo lỗi đấy thôi. Còn muốn nó báo là "Lỗi ở câu lệnh "i = Sheet1.Range("A2")" thì thông tin đó cho bạn cái gì khi mà bạn không muốn vào code để xem "chỗ đó" có gì? Lỗi là một lẽ nhưng "ngữ cảnh" không kém quan trọng. Không muốn vào code để xem, không muốn sửa lỗi thì thông tin về lỗi để làm gì? Bản thân VBA khi có lỗi nó đã cung cấp Err.Number và Err.Description. Khi nhấn Debug thì chỉ ra dòng có lỗi. Thế là đủ rồi còn gì. Còn muốn biết về lỗi mọi thông tin: tên là gì, ở đâu, học lớp mấy nhưng lại không muốn vào code thì biết để làm gì? Để chỉnh sửa thì chỉ có 1 con đường duy nhất là vào code.
 
Lần chỉnh sửa cuối:
Upvote 0
Theo tôi hiểu thì ý chủ thớt muốn bẫy các lỗi khi người dùng thao tác để tránh các lỗi có thể có phát sinh trong việc chạy code xử lý và ngăn không cho người dùng có thể vô được màn hình code khi bấm Debug từ thông báo lỗi. Đây là cách tôi hay làm khi khi viết ứng dụng.
Tuỳ nền tảng bạn viết ứng dụng thì việc bẫy lỗi nó đơn giản hay dài dòng hơn.
Đối với các CSDL như Access, SQL Server... thì nó đã bắt buộc khai báo kiểu dữ liệu ngay khi thiết kế Table rồi, còn trang tính Excel thì không có tính năng này. Bạn phải phân tích xem nên bẫy lỗi ở giai đoạn nào: bẫy ngay lúc nhập liệu để dữ liệu đầu vào không phải là rác và bẫy các trường hợp có thể phát sinh khi code xử lý.
Đối với Excel, nếu bạn nhập liệu thông qua Userform thì dễ bẫy lỗi hơn. Ví dụ: bẫy lỗi textbox chỉ cho nhập dạng số, không nhận Text. Đối với dạng Số (Number) thì trong Excel lại phải tốn thêm code để bẫy số nhập kiểu Byte, Integer, Long so với kiểu Single, Double...Đối với nhập liệu thẳng xuống Sheet (Sheet Form) thì cũng phải bẫy như trên. Đó là bẫy lỗi lúc nhập liệu, sẽ hiện thông báo để hướng dẫn người dùng nhập cho đúng. Vd: "Chỉ được nhập số nguyên vào ô này", "Không được để trống ô dữ liệu", "Phải nhập số >0",...
Sau khi bẫy lỗi lúc nhập liệu rồi thì việc bẫy lỗi khi code thực thi sẽ đỡ hơn nhiều. Ví dụ về bẫy lỗi trong code, thì cách đây vài hôm cũng có bài về xuất dữ liệu sang file Word bị lỗi, là tôi có dùng hàm để bẫy lỗi nếu giá trị đưa vào là Null.

Screen Shot 2022-03-06 at 07.57.45.png

Khi code xử lý, nếu không có dữ liệu đưa vào thì giá trị của đối tượng đó sẽ là "Null", mà nếu là Null thì code VBA sẽ báo lỗi ngay. Do đó tôi dùng hàm Nz() để biến giá trị Null thành số 0 -> khi đó code VBA sẽ chạy mà không báo lỗi.
Có những trường hợp bẫy lỗi dựa trên mã số lỗi (Err.Number) nếu khi code chạy, thông báo mã lỗi rõ ràng.

Screen Shot 2022-03-06 at 08.09.29.png
 
Upvote 0
Theo tôi hiểu thì ý chủ thớt muốn bẫy các lỗi khi người dùng thao tác để tránh các lỗi có thể có phát sinh trong việc chạy code xử lý và ngăn không cho người dùng có thể vô được màn hình code khi bấm Debug từ thông báo lỗi. Đây là cách tôi hay làm khi khi viết ứng dụng.
Tuỳ nền tảng bạn viết ứng dụng thì việc bẫy lỗi nó đơn giản hay dài dòng hơn.
Đối với các CSDL như Access, SQL Server... thì nó đã bắt buộc khai báo kiểu dữ liệu ngay khi thiết kế Table rồi, còn trang tính Excel thì không có tính năng này. Bạn phải phân tích xem nên bẫy lỗi ở giai đoạn nào: bẫy ngay lúc nhập liệu để dữ liệu đầu vào không phải là rác và bẫy các trường hợp có thể phát sinh khi code xử lý.
Đối với Excel, nếu bạn nhập liệu thông qua Userform thì dễ bẫy lỗi hơn. Ví dụ: bẫy lỗi textbox chỉ cho nhập dạng số, không nhận Text. Đối với dạng Số (Number) thì trong Excel lại phải tốn thêm code để bẫy số nhập kiểu Byte, Integer, Long so với kiểu Single, Double...Đối với nhập liệu thẳng xuống Sheet (Sheet Form) thì cũng phải bẫy như trên. Đó là bẫy lỗi lúc nhập liệu, sẽ hiện thông báo để hướng dẫn người dùng nhập cho đúng. Vd: "Chỉ được nhập số nguyên vào ô này", "Không được để trống ô dữ liệu", "Phải nhập số >0",...
Sau khi bẫy lỗi lúc nhập liệu rồi thì việc bẫy lỗi khi code thực thi sẽ đỡ hơn nhiều. Ví dụ về bẫy lỗi trong code, thì cách đây vài hôm cũng có bài về xuất dữ liệu sang file Word bị lỗi, là tôi có dùng hàm để bẫy lỗi nếu giá trị đưa vào là Null.

View attachment 272765

Khi code xử lý, nếu không có dữ liệu đưa vào thì giá trị của đối tượng đó sẽ là "Null", mà nếu là Null thì code VBA sẽ báo lỗi ngay. Do đó tôi dùng hàm Nz() để biến giá trị Null thành số 0 -> khi đó code VBA sẽ chạy mà không báo lỗi.
Có những trường hợp bẫy lỗi dựa trên mã số lỗi (Err.Number) nếu khi code chạy, thông báo mã lỗi rõ ràng.

View attachment 272766
Đúng rồi ý em là "muốn bẫy các lỗi khi người dùng thao tác để tránh các lỗi có thể có phát sinh trong việc chạy code xử lý và ngăn không cho người dùng có thể vô được màn hình code khi bấm Debug từ thông báo lỗi"
Nhưng đúng là vẫn phải bẫy lỗi để tạo ra các thông báo chi tiết mà không có cách nào khác.
Xin cảm ơn các Sao đã thảo luận.
 
Upvote 0
Có thể thử code này xem có đúng yêu cầu không.
Mã:
Public Sub TestErr()
On Error GoTo BugReport
Dim i%, n%
1    i = 0
2    i = i * 2
3    n = i Mod 2
4    i = n / 0
ExitHere:
    Exit Sub
BugReport:
    Call ErrorNotice("Module: Module1", Erl, Err.Number, Err.Description)
End Sub
Public Sub ErrorNotice(ByRef eModule As String, ByRef eLine As Long, ByRef eCode As Long, ByRef eDescription As String)
    Dim eMessage As String
    eMessage = "Xay ra loi nen khong the hoan thanh cong viec cua ban." & _
               vbNewLine & vbNewLine & "Loi xay ra tai " & eModule & vbNewLine & _
               "Dong loi : " & eLine & "          Ma loi : " & eCode & _
               vbNewLine & "Dien ta : " & eDescription
    MsgBox eMessage, vbCritical, "Thông báo!"
End Sub
 
Upvote 0
Theo tôi hiểu thì ý chủ thớt muốn bẫy các lỗi khi người dùng thao tác để tránh các lỗi có thể có phát sinh trong việc chạy code xử lý và ngăn không cho người dùng có thể vô được màn hình code khi bấm Debug từ thông báo lỗi.
Nếu thế thì phải nói: "Tôi muốn bẫy lỗi, tôi muốn xử lý lỗi thì làm như thế nào? Xin mọi người cho ví dụ xử lý trường hợp ..."

Còn đây là: "Có lỗi do nhập liệu tại Sheet1.Range("A2") , mã lỗi là "XYZ", thông tin lỗi "ABC"
Ý em là tránh phải mở code để kiểm tra, mà có thể hiển thị thông tin lỗi luôn".

Hiển thị thông tin lỗi và xử lý lỗi là 2 vấn đề hoàn toàn khác nhau.
 
Upvote 0
Có thể thử code này xem có đúng yêu cầu không.
Mã:
Public Sub TestErr()
On Error GoTo BugReport
Dim i%, n%
1    i = 0
2    i = i * 2
3    n = i Mod 2
4    i = n / 0
ExitHere:
    Exit Sub
BugReport:
    Call ErrorNotice("Module: Module1", Erl, Err.Number, Err.Description)
End Sub
Public Sub ErrorNotice(ByRef eModule As String, ByRef eLine As Long, ByRef eCode As Long, ByRef eDescription As String)
    Dim eMessage As String
    eMessage = "Xay ra loi nen khong the hoan thanh cong viec cua ban." & _
               vbNewLine & vbNewLine & "Loi xay ra tai " & eModule & vbNewLine & _
               "Dong loi : " & eLine & "          Ma loi : " & eCode & _
               vbNewLine & "Dien ta : " & eDescription
    MsgBox eMessage, vbCritical, "Thông báo!"
End Sub
Cái này thì em biết vì trước đó cũng có tham khảo ở đây:
Nhưng trong trường hợp code dài mà chạy gọi nhiều sub code dài thì không biết thế nào cả, lỗi là phải mở code là kiểm tra.
 
Upvote 0
Cái ý tưởng "Báo cáo lỗi" này nghe thì có vẻ lý tưởng nhưng trên thực tế thì không thể thực hiện. Chỉ dùng để làm cảnh.

Nguyên tắc: người dùng cứ thấy báo lỗi là quýnh lên, chả biết làm gì cả, và sẽ báo cáo lại sai bấy nhầy.

Chứng minh: quý vị đã thấy bao nhiêu phần trăm người hỏi bài ở GPE này đưa lên hỏi code báo lỗi một cách tường tận, đầy đủ, và chính xác?
 
Upvote 0
mấy trò thông báo lỗi chi tiết chỉ làm cảnh ... người dùng có thấy nó Show lên thì cũng ko làm được gì cả xong họ lại la lên thế thôi
 
Upvote 0
Lần đầu tiên tôi nghe trong lập trình, bẫy lỗi, thông báo lỗi chỉ để làm cảnh. Chắc mình lạc hậu quá rồi.

Screen Shot 2022-03-06 at 12.03.07.png Screen Shot 2022-03-06 at 12.03.17.png Screen Shot 2022-03-06 at 12.03.30.png


40647349143_945f1ba4bc_o.png Sh3oYnu.png
 
Lần chỉnh sửa cuối:
Upvote 0
Lần đầu tiên tôi nghe trong lập trình, bẫy lỗi, thông báo lỗi chỉ để làm cảnh. Chắc mình lạc hậu quá rồi.
...
Bạn lập trình từ hồi nào mà bảo mình "lạc hậu"?
Nếu đúng thì phải nói là "quá tân tiến" chứ.

Lạc hậu là tôi đây. Từ mấy chục năm nay, nếu lỗi chương trình thì ghi vào log, không bao giờ tin người dùng báo cáo lại đúng.
Nếu cần phản ứng của người dùng thì tôi báo:
"Dữ liệu không đúng ở Sheet X, ô A1. Dự tính kiểu số, ô chứa chuỗi text"

Thời đại mới bây giờ đem trưng mấy cái lỗi lên luôn.
 
Upvote 0
đó ... tôi cũng ko cần trình bày ... khắc có người trả lời rùi he/*-*/-0-0-0-
 
Upvote 0
Bạn lập trình từ hồi nào mà bảo mình "lạc hậu"?
Nếu đúng thì phải nói là "quá tân tiến" chứ.

Lạc hậu là tôi đây. Từ mấy chục năm nay, nếu lỗi chương trình thì ghi vào log, không bao giờ tin người dùng báo cáo lại đúng.
Nếu cần phản ứng của người dùng thì tôi báo:
"Dữ liệu không đúng ở Sheet X, ô A1. Dự tính kiểu số, ô chứa chuỗi text"

Thời đại mới bây giờ đem trưng mấy cái lỗi lên luôn.
Theo như anh nói ở trên, có vẻ anh đang nói một dạng bẫy lỗi hệ thống khác với những gì tôi đề cập ở trên: Bãy lỗi người dùng, để có dữ liệu đúng, chuẩn, bẫy lỗi để code chạy không báo lỗi.
Nếu người dùng đang thao tác ứng dụng (ví dụ: nhập liệu), phát sinh lỗi, không có thông báo để điều chỉnh lại cách thức nhâp ngay lúc đó, chẳng lẻ đóng ứng dụng, chờ người viết phần mềm xem file log sau đó mới hướng dẫn sửa.
Bài đã được tự động gộp:

Nếu cần phản ứng của người dùng thì tôi báo:
"Dữ liệu không đúng ở Sheet X, ô A1. Dự tính kiểu số, ô chứa chuỗi text"
Phần này theo anh sẽ gọi là nghiệp vụ gì trong lập trình?
 
Upvote 0
Upvote 1
Web KT
Back
Top Bottom