Copyright © 2013 Janusz Bonarowski 1
VB_4.1_Podprogram_Sub_prędkość
Pewien etap rajdu samochodowego składa się z 3 odcinków specjalnych. Znana jest długość i czas przejazdu kaŜdego odcinka. Napisać program obliczający prędkości samochodu na kaŜdym odcinku specjalnym. Obliczenia wykonać za pomocą tej samej procedury, wywołując ją z róŜnymi parametrami. Zabezpieczyć program przed błędnie wprowadzonymi danymi (wartościami nie liczbowymi, wartościami mniejszymi od zera lub równymi zero) .
Rys. 1. Propozycja formularza
Kod aplikacji WERSJA 1
Private Sub btnOblicz_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnOblicz.Click Dim S1, S2, S3, T1, T2, T3, V1, V2, V3 As Single
'Odcinek 1
S1 = CSng(txtS1.Text) '(1) T1 = CSng(txtT1.Text) '(2) Call Obliczenia(S1, T1, V1) '(3) lblV1.Text = CStr(V1) '(4)
' Blok instrukcji od (1)...(4) powtarzamy ' (kopiujemy, z minimalnymi zmanami) ' dla kaŜdego odcinka specjalnego.
'Odcinek 2
S2 = CSng(txtS2.Text) T2 = CSng(txtT2.Text) Call Obliczenia(S2, T2, V2) lblV2.Text = CStr(V2)
'Odcinek 3
S3 = CSng(txtS3.Text) T3 = CSng(txtT3.Text) Call Obliczenia(S3, T3, V3) lblV3.Text = CStr(V3)
End Sub
Private Sub Obliczenia(ByVal droga As Single, ByVal czas As Single, _ ByRef predkosc As Single)
predkosc = droga / czas End Sub
Copyright © 2013 Janusz Bonarowski 2 Podczas wywoływania procedury Obliczenia przekazywane są do niej dwie wartości zmiennych liczbowych typu Single, droga i czas znajdujących się na miejscu pierwszym i drugim listy argumentów, na trzcim miejscu znaduje się wynik odbierany z procudry (przekazywany przez procedurę „na zewnatrz”).
Podczas pisania własnej procedury - środowisko automatycznie dopisuje przed nazwami argumentów słowa kluczowe ByVal określające tryb przekazywania argumentów.
Taki tryb oznacza przekazanie argumentu przez wartość. Konsekwencją trybu ByVal jest to, Ŝe Ŝadna zmiana wartości argumentów wykonana wewnątrz procedury nie jest przekazywana na zewnątrz, czyli wyliczenia wartości zmiennej predkosc, gdyby była deklarowana poprzez ByVal - nie zostanie przekazane do programu wywołującego i w efekcie w etykietach wyświetlających prędkość pojawiłaby się wartość 0.
Aby w programie nadrzędnym otrzymać (uzyskać) wartość trzeciego argumentu wyliczonego przez procedurę naleŜy określić tryb przekazywania wartości tego argumentu jako ByRef (przez referencje). Taką zmianę naleŜy wykonać samodzielnie.
PoniewaŜ w zadaniu wykonujemy kilkakrotnie konwersję z wartości tekstowej na liczbową i ponownie z liczbowej na tekstową – moŜna te operacje, a takŜe sprawdzanie poprawności danych - umieścić we własnej procedurze, która teraz bardzo się rozbuduje.
Kod aplikacji wersja 2
Private Sub btnOblicz_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnOblicz.Click Call Obliczenia(txtS1.Text, txtT1.Text, lblV1.Text)
Call Obliczenia(txtS2.Text, txtT2.Text, lblV2.Text) Call Obliczenia(txtS3.Text, txtT3.Text, lblV3.Text) End Sub
Private Sub Obliczenia(ByVal strDroga As String, _ ByVal strCzas As String, _ ByRef strPredkosc As String) Dim Droga, Czas, Predkosc As Single
'____Czy wprowadzono wartości liczbowe?
If IsNumeric(strDroga) Then Droga = CSng(strDroga) Else
strPredkosc = "Błąd danych"
Exit Sub End If
If IsNumeric(strCzas) Then Czas = CSng(strCzas) Else
strPredkosc = "Błąd danych"
Exit Sub End If
'___Czy wprowadzono wartości > zera?
If Droga <= 0 Then
strPredkosc = "Błąd danych droga <= 0"
Exit Sub End If
If Czas <= 0 Then
strPredkosc = "Błąd danych czas <= 0"
Exit Sub End If
'___Obliczenia
Predkosc = Droga / Czas strPredkosc = CStr(Predkosc) End Sub
Copyright © 2013 Janusz Bonarowski 3 Visual Basic posiada obiekt Błąd pisany w kodzie jako Err (od error – błąd). Obiekt ten posiada metodę Raise (ang. budować, uzyskać), za pomocą której moŜemy samodzielnie wywołać błąd o przydzielonym przez nas numerze Err.Number, przyczynie Err.Source i opisie Err.Description.
Samodzielne wywołanie błędu
Parametry:Err.Raise(Err.Number,Err.Source,Err.Description) Np.:
Err.Raise(9999, "Błąd danych.", "Długość nie jest liczbą.")
Tak określone parametry metody Raise moŜemy wykorzystać do drukowania komunikacie o błędzie:
MsgBox("Błąd nr: " & Err.Number & vbCrLf & Err.Description, _ MsgBoxStyle.Critical, Err.Source)
Przykład komunikatu:
Rys. 2. Wizualizacja komunikatu funkcją MsgBox
Kod aplikacji wersja 3
'Obliczenia z wykorzystaniem struktury Try...Catch,
'z generowaniem obietów Błąd (Err), własnymi numerami błędów 'i własną ich obsługą.
Private Sub btnOblicz2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnOblicz2.Click
Call KasujWyniki() Try
Call Obliczenia2(txtS1.Text, txtT1.Text, lblV1.Text) Call Obliczenia2(txtS2.Text, txtT2.Text, lblV2.Text) Call Obliczenia2(txtS3.Text, txtT3.Text, lblV3.Text) Catch ex As Exception
'Uniwersalny zapis wyświetlania informacji o błędzie.
MsgBox("Błąd nr: " & Err.Number & vbCrLf & Err.Description, _ MsgBoxStyle.Critical, Err.Source)
End Try End Sub
Copyright © 2013 Janusz Bonarowski 4 Private Sub Obliczenia2(ByVal strDroga As String, ByVal strCzas As String, _ ByRef strPredkosc As String)
Dim Droga, Czas, Predkosc As Single
'Przypomnienie parametrów metody Raise:
'Err.Raise(Err.Number,Err.Source,Err.Description)
'Jeśli dane nie dadzą się konwertować na liczbę generuj błąd.
'---
'____Czy wprowadzono wartości nie liczbowe dla Drogi - błąd nr 9999 If IsNumeric(strDroga) = False Then
Err.Raise(9999, "Błąd danych.", "Długość nie jest liczbą.") End If
'____Czy wprowadzono wartości nie liczbowe dla Czasu - błąd nr 9998 If IsNumeric(strCzas) = False Then
Err.Raise(9998, "Błąd danych.", "Czas nie jest liczbą.") End If
'Dane są liczbami - dokonujemy konwersji na zmienne typu Single.
'--- Droga = CSng(strDroga)
Czas = CSng(strCzas)
'Jeśli wpisane liczby są mniejsze lub równe zero generuj błąd.
'---
'___Czy wprowadzono wartości > zera dla Drogi? - błąd nr 9997 If Droga <= 0 Then
Err.Raise(9997, "Błąd danych.", _
"Długość musi być liczbą większą od zera.") End If
'___Czy wprowadzono wartości > zera dla Czasu? - błąd nr 9996 If Czas <= 0 Then
Err.Raise(9996, "Błąd danych.", _
"Czas musi być liczbą większą od zera.") End If
'___Obliczenia
Predkosc = Droga / Czas strPredkosc = CStr(Predkosc) End Sub
Private Sub KasujWyniki() Handles _
txtS1.TextChanged, txtS2.TextChanged, txtS3.TextChanged, _ txtT1.TextChanged, txtT2.TextChanged, txtT3.TextChanged
'Jedna procedura moŜe obsługiwać róŜne zdarzenia na róŜnych obiektach.
'Tworząc nagłówek procedury jak wyŜej, dopisujemy po nazwie procedury 'słowo kluczowe Handles, a po nim nazwy obiektów i (uwaga!) po kropce ' (a nie dolnym podkreśleniu) nazwy zdarzeń -
'Określamy e ten sposób, Ŝe procedura ta zostanie wykonana za kaŜdym _ 'razem gdy dla obietów txtS1, txtS2, txtS3, txtT1, txtT2, txtT3 _ 'zostanie wygenerowane zdarzenie TextChanged.
lblV1.Text = ""
lblV2.Text = ""
lblV3.Text = ""
End Sub