Podstawy programowania w Visual Basic.Net

Wielkość: px
Rozpocząć pokaz od strony:

Download "Podstawy programowania w Visual Basic.Net"

Transkrypt

1 Wykłady z informa t yki Janusz Górczyński Podstawy programowania w Visual Basic.Net Wyższa Szkoła Zarządzania i Marketingu Sochaczew 20012

2 Zeszyt ten jest ósmą pozycją w serii materiałów dydaktycznych Wykłady z informatyki. Dotychczas ukazały się pozycje: 1. Makropolecenia i aplikacje VBA w MS Excel w 2003 roku. 2. Projektowanie baz danych w MS Access, wykorzystanie VBA w 2005 roku 3. Procedury VBA i MS Excel w badaniach statystycznych w 2006 roku 4. Projektowanie baz danych. Współpraca MS SQL Server i MS Access w 2007 roku 5. Projekt WSZiM, system informatyczny wspomagający zarządzanie Uczelnią w 2007 roku 6. Testy internetowe. Zestaw aplikacji do tworzenia i zarządzania testami w 2008 roku 7. Projekt aplikacji VB.NET i MS SQL Server wspomagającej obsługę biblioteki w 2009 roku 8. Wykorzystanie VBA w aplikacjach MS Office. Część I. WSZiM w 2010 roku; 9. Aplikacja MS SQL Server i MS VB.NET wspomagająca zarządzanie studiami podyplomowymi w 2010 roku Wydanie I Materiały do druku zostały w całości przygotowane przez Autora ISBN Wydawca: Wyższa Szkoła Zarządzania i Marketingu w Sochaczewie Projekt okładki i druk cyfrowy: Poligraphica, Konstantynów Łódzki, ul. Dąbrowska 44 Arkuszy wydawniczych 19,0 Arkuszy drukarskich 19,0

3 Spis treści 1. WSTĘP PROGRAMOWNIE - ELEMENTARZ JĘZYKI PROGRAMOWANIA Kod maszynowy Asembler Języki intrepretowane Języki kompilowane Visual Basic.NET JĘZYKI WYSOKIEGO POZIOMU PRZETWARZANIE SEKWENCYJNE PROGRAMOWANIE STRUKTURALNE Procedury Funkcje Właściwość POWTARZANIE FRAGMENTÓW KODU Pętla For Next Pętla Do Loop Pętla For Each PODEJMOWANIE DECYZJI STRUKTURY WARUNKOWE If Then Else Select Case Choose PRZYKŁADY PROCEDUR, PĘTLI, WARUNKÓW ZMIENNE I STAŁE Typy danych Deklaracja zmiennych i stałych Zmienne tablicowe Tablice typu ArrayList Struktury ALGORYTM, CZYLI PRZEPIS NA KOD ŚRODOWISKO VISUAL STUDIO TWORZENIE NOWEGO PROJEKTU NAJWAŻNIEJSZE OKNA ŚRODOWISKA IDE Okno projektowania Okno Solution Explorer Okno Properties Okno właściwości projektu Okno Tools

4 4 4. KLASY I ICH WYKORZYSTANIE WPROWADZENIE DO KLAS Definiowanie klasy Utworzenie instancji klasy ZDARZENIA GENEROWANIE I ODBIERANIE PRZECIĄŻENIE METODY DZIEDZICZENIE INTERFEJS KLASY POLIMORFIZM Polimorfizm wg dziedziczenia Polimorfizm wg interfejsu DIAGRAM KLAS UML FORMANTY COMBOBOX I LISTBOX ŹRÓDŁA DANYCH Pojedyncze elementy Rekordset Pojedyncze elementy złożone DOSTĘP DO DANYCH, MODEL ADO.NET KOMPONENTY ADO.NET CONNECTION STRING OBIEKT CONNECTION SqlConnection OleDbConnection OBIEKT COMMAND Metoda ExecuteReader Metoda ExecuteScalar Metoda ExecuteNonQuery OBIEKT DATAREADER Metoda Read Metoda NextResult Metoda GetSchemaTable OBIEKT DATAADAPTER DataAdapter, polecenie Select DataAdapter, polecenia modyfikujące DataAdapter i CommandBuilder PROCEDURY PRZECHOWYWANE SQL Procedura bezargumentowa Procedura z parametrami... 71

5 KLASA CFORSTORAGESUB Deklaracja zmiennych i prywatnych procedur klasy Kilka wybranych metod publicznych TRANSAKCJE APLIKACJA ADOANDADONET WYKORZYSTYWANE ŹRÓDŁA DANYCH STRUKTURA APLIKACJI DODATKOWE REFERENCJE MODUŁ WSPÓLNY KLASA CMOJEOLE OPIS POZYCJI OLEDB W MENU Adapter DataReader PRZEGLĄD TABEL OPIS POZYCJI ADO (COM) W MENU Pobieranie tabel i pól, test zapytania Zbudowanie dynamicznego formularza OPIS POZYCJI SQL Adapter Update tabeli via procedura przechowywana (klasycznie) Update tabeli via procedura przechowywana wg JG

6 6 1. Wstęp Znajomość programowania komputerów to jedna z istotniejszych umiejętności na współczesnym rynku pracy. W przypadku znajomości języka Visual Basic for Applications pozwala to na znakomicie lepsze wykorzystanie pakietu biurowego MS Office, od przyspieszenia i automatyzacji wykonywanych prac po autorskie aplikacje 1. Jednym ze współczesnych języków programowania jest Visual Basic.NET, będący kontynuacją języka Visual Basic 6.0, jeden z języków programowania dostępny na platformie.net. Visual Basic.NET jest językiem programowania w pełni obiektowego, a dzięki środowisku FrameWork.NET pozwala na stosunkowo łatwe budowanie aplikacji, zarówno windowsowych jak i webowych. 1 Przykładem może być skoroszyt StatystykaJG.xlsm zawierający bogaty zestaw narzędzi do zastosowań statystycznych i ekonometrycznych.

7 2. Programownie - elementarz Historia programowania komputerowego to kilkadziesiąt ostatnich lat, jego początki to lata sześdziesiąte ubiegłego wieku. Współczesne programowanie zaistniało wraz z pomysłem Johna von Neumanna, który zasugerował zapisywanie instrukcji do wykonania w pamięci komputera Języki programowania Istnieje bardzo wiele różnych języków programowania, cechą każdego z nich jest to, że przed wykonaniem przez procesor komputera ich instrukcje muszą być sprowadzone do takiej postaci, aby były zrozumiałe dla procesora. Tak przetłumaczony kod nosi nazwę kodu maszynowego (machine language) Kod maszynowy Początki kodu maszynowego są ściśle związane z początkami programowania komputerów, z czasami, gdy program komputerowy był tworzony dla konkretnego komputera (procesora). Instrukcja w takim kodzie maszynowym jest sekwencją zer i jedynek opisującą operację, którą ma wykonać procesor. Wykorzystanie zer i jedynek w kodzie maszynowym jest konsekwencją systemu binarnego opisującego stan bitu (najmniejszego składnika pamięci komputerowej), ale tworzenie kodu maszynowego w tym systemie było wyjątkowo skomplikowane. Pewnym rozwiązaniem było tworzenie kodu maszynowego w innych systemach liczbowych niż dwójkowy (binarny), początkowo były to systemy ósemkowe, a później szesnastkowe (heksadecymalne). Systemy szesnastkowe były znaczenie częściej używane niż ósemkowe (w tym ostatnim autor napisał bardzo wiele programów statystycznych w latach siedemdziesiątych). Obojętnie, czy był stosowany system ósemkowy czy też szesnastkowy to programista musiał mieć w głowie numery wszystkich instrukcji przewidzianych przez dany procesor. Przykładowo instrukcja w kodzie ósemkowym: była instrukcją skoku warunkowego do bajtu o numerze 120 w bieżącym module pamieci. W przypadku systemu szesnastkowego podobna instrukcja skoku mogła wygląć następująco: C gdzie C3 to instrukcja skoku, a dalej jest dwubajtowy adres pamięci, do której ma być wykonany skok. 7

8 Asembler Konieczność pamiętania kodów instrukcji jak i używania adresacji ósemkowej czy szesnastkowej były bezpośrednią przyczyną wprowadzenia nowego języka programowania o nazwie Asembler. W tym języku kody poszczególnych operacji zostały zastąpione skrótami, które łatwiej było zapamiętać. Skok pod adres 3000 (68 06 w zapisie hex) można było teraz napisać tak: JUMP 3000 Program komputerowy zawierający zestaw mnemoników nazwano kodem źródłowym (source code). Wprowadzenie asemblera znacznie ułatwiło pisanie programów, ale miało też swoje wady. Pierwszą z nich był fakt, że język ten był ściśle związany z konkretnym procesorem (jego zestawem instrukcji), a druga związana z tym, że nawet proste działania wymagało napisania wielu instrukcji. Mimo swoich ograniczeń język asembler jest cały czas w użyciu Języki intrepretowane W celu usnięcia niedogodności związanych z faktem, że program napisany na jeden typ procesora nie mógł być uruchomiony na innym typie bez jego przepisania zaproponowano stworzenie języka wirtualnej maszyny zawierającego uniwersalny zestaw mnemoników. Od tego momentu programy były tworzone zgodnie z tym wirtualnym językiem, a w momencie jego uruchomienia na konkretnym komputerze jego procesor najpierw tłumaczył instrukcję na swój kod, a następnie ją wykonywał. Od faktu tłumaczenia uniwersalnej instrukcji na własny kod maszynowy wzieła się nazwa języków interpretownych, a samo narzędzie dokonujące tej operacji nazwano interpreterem. Zaletą jesyków interpretowanych było znacznie łatwiejsze ich tworzenie, a wadą znacznie dłuższy czas wykonania (potrzebny na przetłumaczenie każdej instrukcji programu na właściwy kod maszynowy, na dodatek musiało to być wykonywane wielokrotnie, przy każdym uruchomieniu programi) Języki kompilowane W poprzednim podrozdziale jako zasadniczą wadę języków interpretowanych podałem czas ich wykonywania związany z każdorazowym tłumaczeniem kodu źródłowego na kod maszynowy danego procesora. Rozwiązaniem okazało się wprowadzenie jęzkyków kompilowanych, czyli takich, w których proces przekształcenia kody źródłowego w kod maszynowy następuje tylko raz i program zostaje zapisany do dalszego wykorzystania już w postaci pliku wykonywalnego.

9 9 Języki kompilowane są przykładem rozsądnego kompromisu: zachowują łatwość tworzenia programów taką jak języki interpretowane przy jenoczesnym uniknknięciu ich wady związanej z wolnym wykonywaniem programu Visual Basic.NET Jest to przykład języka interpretowanego wyposażonego w kompilator, ale efektem pracy tego kompilatora nie jest kod maszynowy, lecz kod pośredni (Microsoft Intermediate Language MSIL). W momencie uruchamiania programu na danym komputerze ten kod pośredni jest tłumaczony na właściwy kod maszynowy. W rezultacie programy napisane w tym języku działają troszeczkę wolniej niż te, które od razu są skompilowane na właściwy kod maszynowy. Opóźnienie to, przy obecnych procesorach nie ma w praktyce większego znaczenia (jest trudno zauważalne przy większości zadań) Języki wysokiego poziomu Kolejnym etapem w rozwoju programowania było odejście od asemblera (z jego przywiązaniem do kodu maszynowego) na rzecz takich języków programowania, które będą zrozumiałe dla programistów. Przykładowo powstały wtedy takie języki programowania jak Algol, Fortran czy Cobol. Zaletą tych języków był (i jest) fakt, że programy przygotowane na jeden typ procesora mogą być spokojnie przeniesione na inny typ, wystaczy tylko dysponować odpowiednim kompilatorem czy interpreterem Przetwarzanie sekwencyjne Pierwsze programy komputerowe były przetwarzane sekwencyjne, czyli koputer wykonywał pierwszą linię kodu źródłowego, następnie drugą itd, aż dochodził do ostaniej linii. Nie był to zbyt wydajny sposób pisania programu, ponieważ wiele linii kodu było powtórzeniami podobnych fragmentów kodu. Przykład tak napisanego kodu (z sekwencyjnym wykonaniem) pokazny jest niżej: 1. Dim txt As String, i As Integer = 1 2. ' usuwamy wszystkie pozycje z listy 3. Me.ListBox1.Items.Clear() 4. ' kolejno pobieramy dane, badamy, dodajemy do listy lub kończymy 5. txt = InputBox("Podaj " & i.tostring & " pozycję listy") 6. If txt <> "" Then 7. Me.ListBox1.Items.Add(txt) 8. i = i Else 10. GoTo idztu 11. End If 12. ' ---

10 txt = InputBox("Podaj " & i.tostring & " pozycję listy") 14. If txt <> "" Then 15. Me.ListBox1.Items.Add(txt) 16. i = i Else 18. GoTo idztu 19. End If 20. ' txt = InputBox("Podaj " & i.tostring & " pozycję listy") 22. If txt <> "" Then 23. Me.ListBox1.Items.Add(txt) 24. i = i Else 26. GoTo idztu 27. End If 28. ' txt = InputBox("Podaj " & i.tostring & " pozycję listy") 30. If txt <> "" Then 31. Me.ListBox1.Items.Add(txt) 32. i = i Else 34. GoTo idztu 35. End If 36. ' txt = InputBox("Podaj " & i.tostring & " pozycję listy") 38. If txt <> "" Then 39. Me.ListBox1.Items.Add(txt) 40. i = i Else 42. GoTo idztu 43. End If 44. ' txt = InputBox("Podaj " & i.tostring & " pozycję listy") 46. If txt <> "" Then 47. Me.ListBox1.Items.Add(txt) 48. i = i Else 50. GoTo idztu 51. End If 52. ' idztu: 54. MsgBox("ok, mam " & (i - 1).ToString & " pozycji") Kod pokazanego wyżej fragmentu wykonywany jest zaczynając od instrukcji w wierszu 1 i biegnie aż do wiersza 54. Łatwo zauważyć, że kilkakrotnie (maksymalnie 6 razy) wykonywany będzie praktycznie taki sam zestaw instrukcji (wiersze 5-11, 13-19,, 45-51). Porządek ten może być zakłócony wtedy, gdy instrukcja InputBox przekaże

11 11 pusty ciąg znaków, wtedy wykonywanie kodu zostanie przeniesione (skok bezwarunkowy) do miejsca wskazanego etykietą ustawioną w wierszu 53. Jest to oczywiście celowo napisany fragment kodu w celu pokazania ujemnych cech przetważania sekwencyjnego. W praktyce taki sposób pisania programu nie jest stosowany, w jego miejsce stosujemy podział skomplikowanego programu na mniejsze fragmenty odpowiedzialne za realizację konkretnych zadań Programowanie strukturalne Podstawą programowania strukturalnego jest wydzielenie zestawu instrukcji realizujących określone, z reguły powtarzalne operacje. Taki zestaw instrukcji nazywamy podprogramem. Będziemy rozróżniać trzy podstawowe rodzaje podprogramów: a) Procedury, podprogramy identyfikowane słowem (kluczowym) Sub: b) Funkcje, identyfikowane słowem kluczowym Function; c) Właściwości, identyfikowane słowem kluczowym Property Procedury Procedura to zestaw instrukcji przeznaczonych do zrealizowania określonych działań. Instrukcje te zawarte są między słowami kluczowymi oznaczającymi odpowiednio początek i koniec procedury: Private Public Sub NazwaProcedury(ewentualnie lista parametrów) instrukcje procedury End Sub Procedura może być opuszczona wcześniej poprzez umieszczenie w jej ciele instrukcji Exit Sub. Cechą szczególną procedur jest to, że procedura nie zwraca wartości, tym samym nie można jej użyć w przypisaniu (czyli nie można jej użyć w wyrażeniu). Można to sformułować inaczej: procedura zawsze występuje samodzielnie w instrukcji programu Funkcje Jest to zestaw instrukcji przeznaczonych do wykonania określonch działań, ale ich rezultatem jest zwrot wartości. Składnia funkcji ma poniższą postać: Private Public Function NazwaFunkcji(ewentualnie lista parametrów) _ As nazwa_zwracanego_typu_danych instrukcje procedury Return zwracana_wartość lub NazwaFunkcji=zwracana_wartość End Sub

12 12 Procedura może być opuszczona wcześniej poprzez umieszczenie w jej ciele instrukcji Exit Function. Ponieważ funkcja zwraca wartość, to musi wystąpić w wyrażeniu lub w przypisaniu (nie może wystąpić samodzielnie w wierszu instrukcji) Właściwość Jest to specjalny typ procedury związany z programowaniem obiektowym, a jej zadaniem jest zwrócenie lub ustawienie właściwości obiektu (klasy). Zadanie to realizowane jest przez dwa bloki instrukcji: 1. Zwrot wartości realizowany przez blok Get End Get 2. Ustawienie wartości realizowane przez blok Set End Set 2.5. Powtarzanie fragmentów kodu W trakcie tworzenia kodu programu może zajść potrzeba wielokrotnego wykonania tego samego zestawu instrukcji. Zadanie to może być zrealizowane za pomocą pętli. Praktycznie w każdym języku programowania rozróżniamy trzy typy pętli: 1. z tzw. licznikiem (For. Next); 2. wykonywana do spełnienia pewnego warunku (Do Loop); 3. wykorzystywana do przejścia po elementach kolekcji (For Each). Pętle mogą być zagnieżdzone, czyli wewnątrz jednej pętli mogą występować inne pętle dowolnego typu Pętla For Next Pętla tego typu może być wykonana wtedy, gdy znamy liczbę obrotów, które trzeba wykonać. Jej składnia jest następująca (instrukcje w nawiasach kwadratowych są opcjonalne): For licznik=start To Koniec [Step=krok] instrukcje powtarzane Next [licznik] Jeżeli krok nie jest określony, to domyślne licznik pętli jest zwiększany o 1. Pętla może biec w górę lub w dół, w tym ostatnim przypadku krok musi być ujemny. Pętla może być opuszczona wcześniej poprzez umieszczenie w jej ciele instrukcji Exit For Pętla Do Loop Z pętli tego typu korzystamy w tych sytuacjach, w których nie jest znana bezpośrednio liczba obrotów do wykonania, a pętla powinna być wykonywana tak długo, dopóki nie będzie spełniony pewien warunek. Składnia tej pętli może przyjąć kilka wariantów zależnych od miejsca ustawienia warunku (na początku czy na końcu pętli) oraz

13 13 od tego, czy pętla ma być wykonywana tak długo, dopóki warunek nie jest spełniony lub jest spełniony. Kolejno mamy pokazane niżej warianty. a) warunek ustawiany jest po słowie Do (pętla będzie wykonywana tak długo, dopóki warunek nie będzie prawdą, pętla może nie wykonać żadnego obrotu jeżeli warunek jest spełniony): Do While warunek instrukcje pętli Loop b) warunek ustawiany jest po słowie Do (pętla będzie wykonywana tak długo, dopóki warunek będzie fałszem, pętla może nie wykonać żadnego obrotu jeżeli warunek jest prawdą): Do Until warunek instrukcje pętli Loop c) warunek ustawiany jest po słowie Loop (pętla będzie wykonywana tak długo, dopóki warunek nie będzie prawdą, pętla musi być wykonana co najmniej raz warunek będzie sprawdzany po wykonaniu każdego obrotu): Do instrukcje pętli Loop While warunek d) warunek ustawiany jest po słowie Loop (pętla będzie wykonywana tak długo, dopóki warunek będzie fałszem, pętla musi być wykonana co najmniej raz warunek będzie sprawdzany po wykonaniu każdego obrotu): Do instrukcje pętli Loop Until warunek Pętla może być umieszczona przed spełnieniem warunku (wymuszone wyjście) poprzez użycie w jej kodzie instrukcji Exit Do Pętla For Each Pętle tego typu wykorzystawane są do przejrzenia elementów danej kolekcji, przykładowo mogą to być formanty (kontrolki) pewnego formurza. Nie musimy znać liczby obrotów. Pętla wymaga zadeklarowania zmiennej tego samego typu, co elementy kolekcji. Składnia pętli jest następująca: For obiekt In KolekcjaObiektow instrukcje pętli Next

14 14 Poniżej przykład wykorzystania tego typu pętli do usnięcia zawartości pól tekstowych (formantów typu TextBox) umieszczonych w formularzu). For Each ctr As Control In Me.Controls If TypeOf ctr Is TextBox Then ctr.text = vbnullstring End If Next 2.6. Podejmowanie decyzji struktury warunkowe W praktyce trudno sobie wyobrazić taki program komputerowy, w którym nie trzeba by było podejmować decyzji co do tego, który fragment kodu ma być w danej sytuacji realizowany. Zadanie to realizowane jest na podstawie badania stanu pewnego warunku, przy czym może to być warunek prosty (np. jeżeli data urodzenia jest mniejsza niż założona, to zrób to i to, a jeżeli nie, to zrób tamto), ale i złożony z kilku operacji logicznych. Niezależnie od tego jak złożony jest warunek logiczny istotą sterowania kolejności wykonywania programu jest podejmowanie decyzji na podstawie tego, czy warunek jest prawdą (wartość True), czy jest fałszem (False). W zależności od stopnia zróżnicowania możliwych decyzji można stosować trzy, pokazane niżej, konstrukcje warunkowe If Then Else Jest to jedna z podstawowych konstrukcji decyzyjnych używanych w sytuacji, gdy liczba możliwych decyzji jest niewielka. Możliwe są następujące składnie: a) tzw. struktura blokowa stosowana wtedy, gdy zestaw instrukcji wykonywanych przy spełnieniu lub nie warunku zajmuje więcej niż jeden wiersz ; If warunek Then zestaw instrukcji gdy warunek jest prawdą Else zestaw instrukcji gdy warunek jest fałszem End If Fragment z Else i następującym po nim zestawem instrukcji może być pominięty w sytuacji, gdy przy niespełnieniu warunku nie muszą być wykonane żadne działania. b) tzw. struktura jednowierszowa stosowana wtedy, gdy wykonywana jest pojedyncza instrukcja. W takiej sytuacji nie jest konieczne umieszczenie End If; If warunek Then instrukcja_true [Else instrukcja_false] c) wielokrotne użycie If stosowane w sytuacji, gdy musimy zbadać więcej niż dwa stany (więcej niż jeden warunek): If warunek_1 Then

15 zestaw instrukcji gdy warunek_1 jest prawdą ElseIf warunek_2 Then zestaw instrukcji gdy warunek_2 jest prawdą Else zestaw instrukcji, gdy żaden z warunków nie był prawdą End If Select Case 15 Konstrukcja używana w sytuacji, gdy musimy rozważyć więcej niż dwa możliwe stany, jest bardzej efektywna niż użycie If z ElseIf. Składnia jest następująca: Select Case warunek Case kryterium_1 zestaw instrukcji przy spełnieniu kryterium_1 Case kryterium_2 zestaw instrukcji przy spełnieniu kryterium_ Case Else zestaw instrukcji przy niespełnieniu żadnego kryterium End Select Efektywność tej konstrukcji wynika z faktu, że nie są badane wszystkie możliwe stany, lecz wykonywany jest ten fragment kodu, który związany jest z danym warunkiem Choose Stosunkowo rzadziej używana konstrukcja, ale w sytuacjach, gdy jest nam potrzebny zwrot jednej z kilku możliwych wartości jest bardzo wygodna. Jej składnia jest następująca: Choose(wyrażenie, zwrot_1, zwrot_2, zwrot_3, ) Wyrażenie zwraca wartości naturalne zaczynając od 1, zależnie od jego wartości zwracana jest odpowiednia wartość. Warto zauważyć, że Choose to nic innego jak funkcja, przy jej używaniu musimy zadbać o to, aby lista możliwych zwrotów odpowiadała liczbie możliwych wartości początkowego wyrażenia Przykłady procedur, pętli, warunków Wykorzystanie procedury, pętli Do Loop i If Then W rozdziale poświęconym programowaniu sekwencyjnemu pokazałem fragment programu pozwalający na dodanie elementów do kontrolki typu ListBox. Poniżej analogiczny kod, ale wykorzystujący utworzoną pomocniczą procedurę.

16 16 ' pomocnicza procedura Private Sub PobierzDopisz(ByRef i As Integer) Dim txt As String txt = InputBox("Podaj " & i.tostring & " pozycję listy") If txt <> "" Then Me.ListBox1.Items.Add(txt) i = i + 1 End If End Sub ' właściwy kod wykorzystujący procedurę PobierzDopisz Dim i As Integer = 1 ' usuwamy wszystkie pozycje z listy Me.ListBox1.Items.Clear() ' budujemy pętlę Do Loop z warunkiem na zmienną i Do While i < 10 PobierzDopisz(i) Loop ' kod wykonywany po wyjściu z pętli MsgBox("ok, mam " & (i - 1).ToString & " pozycji") Wykorzystanie funkcji, pętli Do Loop i If Then Tym razem zostanie wykorzystana pomocnicza funkcja PobierzDaneDopisz, jej zadaniem jest odebranie informacji od użytkownika, zbadanie, czy nie jest to pusta informacja, jeżeli nie to dopisanie elementu do ListBox1, zwiększenie zmiennej i o jeden oraz zwrócenie wartości True. Jeżeli odebrano pusty ciąg znaków, to funkcja zwraca wartość False. ' kod pomocniczej funkcji Private Function PobierzDaneDopisz(ByRef i As Integer) As Boolean Dim txt As String txt = InputBox("Podaj " & i.tostring & " pozycję listy") If txt <> "" Then Me.ListBox1.Items.Add(txt) i = i + 1 Return True Else Return False End If End Function ' właściwy kod wykorzystujący pomocniczą funkcję Dim i As Integer = 1 ' usuwamy wszystkie pozycje z listy Me.ListBox1.Items.Clear() ' budujemy pętlę Do Loop Do ' w ciele pętli nie ma instrukcji, bo są w funkcji Loop Until Not PobierzDaneDopisz(i)

17 17 ' instrukcja poniżej wykonywana po wyjściu z pętli MsgBox("ok, mam " & (i - 1).ToString & " pozycji") Pętla Do Loop może być zbudowana z użyciem słowa kluczowego While, poniżej taka wersja wykorzystania funkcji PobierzDaneDopisz. ' właściwy kod wykorzystujący pomocniczą funkcję Dim i As Integer = 1 ' usuwamy wszystkie pozycje z listy Me.ListBox1.Items.Clear() ' budujemy pętlę Do Loop Do While PobierzDaneDopisz(i) ' w ciele pętli nie ma instrukcji, bo są w funkcji Loop ' instrukcja poniżej wykonywana po wyjściu z pętli MsgBox("ok, mam " & (i - 1).ToString & " pozycji") 2.8. Zmienne i stałe Istotą każdego programu jest przetwarzanie informacji, które są reprezentowane przez dane. Komputer przechowuje dane w pamięci RAM wykorzystując do tego celu różną liczbę bajtów zależną od typu przechowywanych danych. Będziemy rozróżniać dwa podstawowe rodzaje danych, będą to odpowiednio zmienne i stałe. Zmienne, to taki typ danych, których wartość może być zmieniana w trakcie wykonywania kodu programu. Stałe zaś to taki typ danych, które otrzymują swoją wartość w momencie uruchomienia danego programu i wartość ta nie może być zmieniona na dalszym etapie wykonywania kodu. Oba rodzaje danych identyfikowane są przez system operacyjny poprzez ich nazwę, przy czym przy ich tworzeniu (nazw) musimy przestrzegać kilku reguł: Nazwa musi zaczynać się od litery lub symbolu podkreślenia; Nazwa nie może zawierać znaków specjalnych (np. przecinka, średnika, spacji itd); Nazwa musi być unikalna w jej zasięgu (dokładnie tak samo jak nazwa pliku w folderze); Nazwa nie może być słowem zastrzeżonym w danym języku programowania. Innym wyróżnikiem zmiennych i stałych jest rodzaj przechowywanej informacji (typ danych) i tym samym zapotrzebowanie na pamięć RAM.

18 Typy danych W zasadzie będziemy rozróżniać typy proste i złożone, mogą to być liczby, daty, informacje tekstowe, logiczne itd. W przypadku liczb będziemy rozróżniać liczby całkowite i zmiennoprzecinkowe. Wśród liczb całkowitych będziemy rozróżniać liczby typu Integer (liczba całkowita krótka, zajmuje 4 bajty) oraz Long (liczba całkowita długa, zajmuje 8 bajtów). Wśród liczb zmiennoprzecinkowych będziemy rozróżniać liczby typu Single (pojedynczej precyzji, zajmuje 4 bajty) i typu Double (podwójnej precyzji, zajmuje 8 bajtów). Typ liczby decyduje o zapotrzebowaniu na pamięć RAM oraz o możliwych zakresie wartości danego typu. Inne typy danych liczbowych to Byte (całkowita z zakresu od 0 do 255), Decimal przeznaczonych do przechowywania liczb stałoprzecinkowych (niezbędny do operacji finansowych), Short przechowuje liczby całkowite wykorzystując dwa bajty. Znaki i teksty przechowywane są w typach odpowiednio Char (zajmuje 2 bajty) oraz String (rozmiar potrzebnej pamięci to liczba znaków razy 2). Będziemy także wykorzystywać zmienne typu Object, czyli takie, do których będziemy się odwoływać poprzez ich adres zapisany w pamieci RAM. W praktyce często zdarza się taka sytuacja, że liczba oferowanych typów jest niewystarczająca. Rozwiązaniem jest użycie typu definiowanego samodzielnie przez użytkownika, stąd typ UserDefine Deklaracja zmiennych i stałych Każda zmienna przed jej użyciem musi zostać zadeklarowana, robimy to korzystając ze składni (najczęściej): Public Private Protected Dim nazwazmiennej As JejTyp[=wartosc] Słowa kluczowe występujące przed nazwą zmiennej tzw. specyfikatorami dostępu do zmiennej, określają jej zasięg. Przykładowo słowo kluczowe Dim może być użyte do zadeklarowania zmiennej jedynie wewnątrz procedury (funkcji czy właściowości). Słowo kluczowe Private może być użyte do zadeklarowanie zmiennej na poziomie modułu (formularza, klasy czy modułu ogólnego), zmienna tak zadeklarowana jest dostępna wyłącznie w tym module. Słowo kluczowe Protected wykorzystujemy do deklaracji zmiennych w klasie bazowej, a zmienne tak zadeklarowane są dostępne zarówno w klasie bazowej jak i w klasach pochodnych.

19 19 Słowo kluczowe Public wykorzystujemy do zadeklarowania zmiennej, która będzie dostępna w kodzie całego projektu (jeżeli będzie zadeklarowana w module ogólnym). Istotne jest także miejsce deklaracji zmiennej, określa bowiem jej zasięg. Zmienna zadekalrowana wewnątrz procedury ma character zmiennej lolalnej, z punktu widzenia zajętości pamięci RAM jest to najkorzystniejsze rozwiązanie. Wynika to z faktu, że zmienna taka funkcjonuje tylko w czasie wykonywania procedury, a po jej zakończeniu pamięć RAM jest zwalniana. Inną korzyścią jest fakt, że w różnych procedurach modułu możemy deklarować zmienne o tej samej nazwie. Zmienna zadeklarowana bezpośrednio w module ma zasięg modułowy, jest dostępna dla wszystkich procedure danego modułu. W jednej instrukcji można zadeklarować kilka zmiennych tego samego typu, wystarczy ich nazwy rozdzielić przecinkiem. W przypadku, gdy chcemy zainicjować utworzoną zmienną jakąś wartością początkową deklaracja musi dotyczyć pojedynczej zmiennej. Stałe są dekalrowane za pomocą słowa kluczowego Const, w deklaracji musimy obowiązkowo ustawić wartość stałej zgodnie ze składnią: Const nazwa_stałej As typ_stałej = wartość Zmienne tablicowe W praktyce programowania często zachodzi potrzeba zebrania zmiennych tego samego typu do pewnego opakowania (konteneru). Rolę takiego opakowania może pełnić zmienna tablicowa, jedno czy wielowymiarowa. Deklaracja zmiennej tablicowej jednowymiarowej musi być zgodna ze składnią: Public Private Protected Dim nazwa_tablicy([wymiar]) As typ_danych Do elementów zmiennej tablicowej odwołujemy się poprzez podanie indeksu elementu, przy czym indeksowanie przebiega od zera. Jeżeli w deklaracji zmiennej tablicowej podany jest jej wymiar, to zmienna jest gotowa do wykorzystania. W przypadku, gdy na etapie pisania programu wymiar zmiennej tablicowej nie jest z reguły znany, dlatego też nie może być podany w deklaracji. W takim przypadku przed użyciem zmiennej tablicowej musimy okreslić jej wymiar wykorzystując instrukcję ReDim. Przykład takiej sytuacji pokazany jest niżej. Dim Dane() As Integer, n, i as Integer n = InputBox( Ile elementów zapisać w tabeli? ) Redim Dane(n 1) For i = 0 to n - 1 Dane(i) = InputBox( Podaj kolejną pozycję do zapisania ) Next i

20 20 Deklaracja zmiennych tablicowych wielowymiarowych przebiega podobnie, musimy tylko pamiętać o tym, aby w sytuacji gdy nie są znane wymiary w deklaracji umieścić stosowną liczbę przecinków. Przykładowo zapis: Dim MojaTabelaW2(, ) As Single deklaruje zmienną tablicową dwuwymiarową. Przypisanie do zmiennej tablicowej domyślnych wartości może być zrealizowane jawnie poprzez serie przyporządkowań, np. tak: Dim strstanowiska(3) As String strstanowiska(0) = Dyrektor strstanowiska(1) = Kierownik strstanowiska(2) = Naczelnik strstanowiska(3) = Referent Można to jednak zrobić znacznie efektywniej, choćby tak: Dim strstanowiska() As String = _ { Dyrektor, Kierownik, Naczelnik, Referent } Jak widzimy w jednej instrukcji połączono deklarację zmiennej tablicowej wraz pośrednim określeniem jej wymiaru poprzez wyliczenie jej elementów umieszczzonych wewnątrz nawiasów sześćiennych Tablice typu ArrayList W praktyce programowania często zdarzają się takie sytuacje, że powinniśmy dodać lub usunąć element zmiennej tablicowej. Nie jest to proste, ponieważ wymaga zmiany rozmiarów zmiennej tablicowej. Rozwiązaniem może być użycie tablicy typu ArrayList, która pozwala na dynamiczną modyfikację jej wymiaru (dotyczy to tablic jednowymiarowych). Przykład użycia tego typu tablic: Dim Pracownicy As New ArrayList, txt As String Do txt = InputBox( Podaj nazwę stanowiska lub pusty ciąg znaków If txt = Then Exit Do Else Pracownicy.Add(txt) End If Loop Elementy zapisane w zmiennej typu ArrayList można odczytać (pobrać) wskazując indeks elementu. Dość dużym problem jest fakt, że do zmiennej tego typu można dodawać elementy dowolnego typu.

21 Struktury 21 Jest to kolejny przykład typu złożonego, ciekawego z tego powodu, że można w jednym opakowaniu zawrzeć kilka zmiennych (składowych) dowolnego typu. Poniżej przykład tak zadeklarowanej zmiennej, jej zadaniem jest przechowanie podstawowych informacji o studencie w pojedynczym obiekcie. Jego składowe Nazwisko, Imie, NrAlbumu, DataUrodzenia przechowują dane elementarne, dodatkowo utworzono właściwość FullName, która zwraca połączenie nazwiska z imieniem. Definicja struktury zawiera jeszcze zmodyfikowaną (nadpisaną) implementację systemowej funkcji ToString, po to, aby jej użycie zwracało informację o studencie, a nie nazwę obiektu!. Public Structure Studenci ReadOnly Property FullName() As String Get Return Nazwisko & " " & Imie End Get End Property Public Overrides Function ToString() As String Return FullName & ", nr albumu " & NrAlbumu End Function Dim Nazwisko As String Dim Imie As String Dim NrAlbumu As Integer Dim DataUrodzenia As Date End Structure W kodzie można teraz zadeklarować zmienną tego typu w tradycyjny sposób: Dim danestudenta As Studenci A do poszczególnych składowych możemy się odwołać poprzez użycie kropki po nazwie zmiennej: danestudenta.nazwisko = Kowalski danestudenta.imie = Jan danestudenta.nralbumu = 2345 danestudenta.dataurodzenia = # #

22 Algorytm, czyli przepis na kod Podstawą pracy nad każdym programem jest poprawnie skonstruowany przepis na jego wykonanie, czyli algorytm. Może on mieć character albo bardzo ogólny odnoszący się do większego fragmentu programu, albo bardzo szczegółowy precyzujący sposób rozwiązania określonego fragmentu programu. Przykładowo, algorytm sprawdzania poprawności numeru Pesel można zawrzeć w kilku krokach: 1. Pobierz numer Pesel do sprawdzenia (jako ciąg znaków); 2. Sprawdź, czy jest to 11 znaków; 3. Sprawdź, czy są to znaki reprezentujące cyfry; 4. Utwórz zmienną przechowującą wagi kontrolne (1, 3,7,9,1,3,7,9,1,3); 5. Wyznacz iloczyn skalarny pierwszych dziesieciu cyfr numeru Pesel i wag; 6. Otrzymany wynik podziel całkowicie (modulo) przez 10; 7. Od wyniku dzielenia odejmij 10; 8. Jeżeli wynik odejmowania jest równy 10, to ustaw go na 0; 9. Sprawdź, czy wynik uzyskany w kroku 8 jest równy wartości ostatniego znaku w numerze Pesel? Jeżeli tak, to numer Pesel jest poprawny. Dla numeru poszczególne kroki od 5 do 9 dają takie rezultaty: 5. suma_iloczynow = 1*4+3*9+7*0+9*4+1*0+3*5+7*0+9*1+1*5+3*8 = mod 10 = = (bo w kroku 7 wynik był 10) 9. ostani znak w numerze Pesel to 0, czyli dokładnie to, co uzyskaliśmy w kroku ósmym. Wniosek: sprawdzany numer jest poprawnym numerem Pesel. Implementacja tego algorytmu w postaci funkcji zwracającej wartość logiczną może mieć taką postać: Private Function SprawdzPesel(ByVal txt As String) As Boolean Dim w() As Integer = {1, 3, 7, 9, 1, 3, 7, 9, 1, 3} If txt.length <> 11 Then Return False Else Dim x, y, z As Integer For i As Integer = 0 To 9 x += w(i) * CInt(txt.Substring(i, 1)) Next y = x Mod 10

23 z = 10 - y If z = 10 Then z = 0 If CInt(txt.Substring(10, 1)) = z Then Return True Else Return False End If End If End Function 23

24 24 3. Środowisko Visual Studio 2010 I 3.1. Tworzenie nowego projektu

25 Najważniejsze okna środowiska IDE Okno projektowania Zajmuje największą część okna Visual Studio, może wyświetlać dwojakiego rodzaju informacje. Po pierwsze wyświetla projekty formularzy, raportów i innych obiektów budowanych w środowisku graficznym (np. wirtulane źródła dancych, ikony itd). Poniżej przykładowy widok formularza aplikacji pozwalającej na weryfikację numeru Pesel.

26 26 Po drugie w oknie tym można wyświetlić kod projektowanego obiektu (formularza, raportu, modułu wspólnego, klasy itd). Poniżej widok kodu przykładowego formularza z obsługą zdarzenia KeyPress pola teksowego txtpesel. Możemy się przełączać między tymi dwoma widokami poprzez menu View, gdzie znajdziemy polecenia Code (F7) oraz Designer (Shift-F7). Inną metodą przejścia do okna kodu jest skorzystanie z polecenia View Code w menu kontekstowym wywołanym z okna projektowania Okno Solution Explorer

27 Okno Properties Okno właściwości projektu

28 Okno Tools

29 29

30 30 4. Klasy i ich wykorzystanie Pojęcie klasy jest ściśle związane z obiektowo zorientowanym programowaniem (OOP Object Oriented Programming). Klasy, jako abstrakcyjne wzorce obiektów są podstawą praktycznie wszystkich współczesnych języków programowania wysokiego poziomu, a więc i VB.NET Wprowadzenie do klas Klasa w języku programowania oznacza abstrakcyjny model użyty do zdefiniowania nowego typu danych. Zawiera połączenie zarówno danych jak i kodu operującego na tych danych. Jako przykład można tu podać klasę String w przestrzeni nazw System. Klasa ta zawiera tablicę znaków jako dane oraz kod, który obsługuje różne działania, jakie mogą być wykonane na tych danych. Kod tego typu tworzy tzw. metody (ang. Methods), a ich przykładem mogą być np. Substring() czy Trim(). Klasa może zawierać także kod opisujący właściwości obiektu (ang. Property), przykładem może być np. właściwość Length. VB.NET oferuje uproszczoną strukturę obiektową zapewniając jednocześnie obsługę czterech podstawowych mechanizmów programowania obiektowego. Są to: Abstrakcja czyli możliwość tworzenia kodu w postaci czarnej skrzynki, czyli abstrakcyjnej reprezentacji danej koncepcji w programie; Hermetyzacja jest to mechanizm pozwalający na oddzielenie interfejsu (czyli sposobu dostępu do metody) od implementacji (sposobu jej zaprogramowania). Pozwala na ukrycie szczegółów implementacji metod wewnątrz klasy; Dziedziczenie możliwość tworzenia klas potomnych, które przejmują z klasy bazowej jej interfejs, właściwości, metody i zmienne prywatne; Polimorfizm jest to możliwość tworzenia funkcji, która operuje na obiektach więcej niż jednej klasy Definiowanie klasy W VB.NET klasa definiowana jest z użyciem słów kluczowych Class i End Class, miedzy nimi zawarte są definicje danych i kod tworzący procedury klasy (metody, właściwości, prywatne procedury i funkcje klasy). Dane wykorzystywane w klasie mogą być dowolnego typu, ich deklaracja powinna być poprzedzona słowem kluczowym Private, co zapewnia ich skuteczną hermetyzację. Dane te są wtedy prywatnymi danymi klasy i nie są dostępne bezpośrednio spoza kodu klasy. W praktyce programowania dane te noszą nazwę pól lub zmiennych prywatnych

31 31 klasy. W prezentowanych aplikacjach przyjęto zasadę, że nazwa zmiennych prywatnych klasy będzie zawsze zaczynała się od małej litery m. Kod metod i właściwości poprzedzony jest słowem kluczowym (specyfikatorem dostępu) Public, ponieważ chcemy, aby procedury te były dostępne spoza kodu klasy. Wyjątkiem są tu pomocnicze procedury i funkcje klasy, które będą wykorzystywane jedynie w tej klasie, wtedy poprzedzamy je słowem Private. Innym wyjątkiem jest tworzenie klasy bazowej (takiej, która będzie wykorzystana do utworzenia klas potomnych), dla zapewnienia dziedziczenia jej procedur poprzedzamy je słowem kluczowym Protected. Zadaniem procedur typu Property jest ustawianie lub zwracanie wartości zmiennej prywatnej. Procedura Propery może być poprzedzona słowami kluczowymi ReadOnly lub WriteOnly, co prowadzi do procedury pozwalającej odpowiednio jedynie na odczyt lub zapis danej właściwości. Specjalną rolę w kodzie klasy spełniają procedury publiczne o wspólnej nazwie New, noszą one nazwę konstruktorów, a ich przeznaczeniem jest zainicjowanie klasy w momencie tworzenia jej instancji (obiektu). Przykład definicji klasy pokazany jest niżej. W klasie CStudent zadeklarowano trzy zmienne prywatne, dwa konstruktory (procedury inicjalizujące), jedną metodę o nazwie NazwiskoImie oraz trzy procedury typu Property pozwalającą na ustawienie lub zwrócenie nazwiska studenta, jego imię oraz numer albumu. Public Class CStudent Private mnralbumu as Integer Private mnazwisko as String Private mimie as String Public Sub New() End Sub Public Sub New(ByVal naz As String, _ ByVal imie as String, ByVal idr as Integer) mnazwisko = naz mimie = imie mnralbumu = idr End Sub

32 32 Public Function NazwiskoImie As String() Return mnazwisko & & mimie & nr albumu & _ mnralbumu.tostring End Function Public Property Nazwisko As String() Get Return mnazwisko End Get Set (ByVal value as String) mnazwisko = value End Set End Property Public Property Imie As String() Get Return mimie End Get Set (ByVal value as String) mimie = value End Set End Property Public Property NumerAlbumu As Integer Get Return mnralbumu End Get Set (ByVal value as Integer) mnralbumu = value End Set End Property dalsze instrukcje tej klasy End Class Utworzenie instancji klasy Utworzenie instancji (egzemplarza) klasy wymaga użycia słowa kluczowego New. Kilka możliwych sposobów utworzenia instancji klasy CStudent pokazanych jest niżej. Pierwszy z nich zawiera najpierw deklarację utworzenia obiektu klasy, a w drugim wierszu instrukcję jego utworzenia. Dim student As CStudent Student = New CStudent Obie te instrukcje można zawrzeć w jednej, tak jak to pokazano niżej. Dim student As New CStudent()

33 33 Powyższa instrukcja korzysta z domyślnego konstruktora (bezparametrowego). Jeżeli chcielibyśmy przypisać obiektowi student takie właściwości jak nazwisko, imie czy numer albumu, to korzystamy z pokazanych niżej instrukcji przypisania. student.nazwisko = Kowalski student.imie = Jan student.numeralbumu = 1345 W przypadku, gdyby w klasie CStudent był utworzony konstruktor z trzema parametrami (nazwisko, imie oraz numer albumu), to instrukcja (jednowierszowa) utworzenia instancji tej klasy mogłaby mieć postać jak niżej. Dim student As New CStudent( Kowalski, Jan, 1345) Dwuwierszowa instrukcja utworzenia instancji klasy jest niezbędna wtedy, gdy chcemy wykorzystać jeden ze zdefiniowanych interfejsów. Prześledzimy taką sytuację na przykładzie klasy CStudent z poprzedniego podrozdziału. W kodzie przykładowego formularza spróbujemy teraz utworzyć dwa obiekty w oparciu o klasę CStudnet, pierwszy z wykorzystaniem interfejsu IDaneStudenta, a drugi bez korzystania ze zdefiniowanego interfejsu. Deklaracja i utworzenie instancji klasy CStudnet w oparciu o jeden z jego zdefiniowanych interfejsów wymaga dwóch wierszy instrukcji. W pierwszym wierszu deklarujemy utworzenie obiektu w oparciu o wybrany interfejs klasy, w drugim tworzymy nową instancję z wykorzystaniem jednego z konstruktorów. W pokazanej niżej sytuacji tak zadeklarowano i utworzono obiek w. Dzieki deklaracji z wykorzystaniem interfejsu obiekt w udostępnia tylko te metody, które są udostępnione przez interfejs, w naszym przypadku będą to metody FullName oraz ShortName. A co by było, gdybyśmy utworzyli instancję klasy w oparciu o domyślny interfejs? Sytuacja taka pokazana jest poniżej, został zadeklarowany i utworzony obiekt z w oparciu o pierwszy konstruktor.

34 34 Efektem takiej deklaracji (bez użycia zdefiniowanego interfejsu) jest udostępnienie wszystkich publicznych metod klasy, chociaż tylko trzy z nich mają w tym wypadku sens (FullName, ShortName i Komunikat). W rezultacie mamy szansę popełnienia dość niebezpiecznej pomyłki próbując odwołać się do metod, które przy tym konstruktorze nie są określone (Oceny, Rejestr, SredniaOcen) Zdarzenia generowanie i odbieranie Klasa może generować zdarzenia, które następnie mogą być odebrane przez program tworzący instancję (egzemplarz) klasy. Zdarzenie deklarujemy w klasie za pomocą słów Public Event NazwaZdarzenia(opcjonalnie lista argumentów). Zdarzenie jest generowane (uruchamiane) za pomocą słowa kluczowego RaiseEvent NazwaZdarzenia(opcjonalnie argumenty). Poniżej przykład klasy CStudent z projektu ZdarzeniaOrazPrzeciazanieMetod, zdefiniowano w nim zdarzenie o nazwie ZleDane z dwoma argumentami. Zdarzenie to będzie generowane w sytuacji, gdy dane przekazane do metody klasy będą nieodpowiednie. Public Class CStudent Private mid As Integer Private mnazwisko As String Private mimie As String Private mdataurodzenia As Date Private mkomunikat As String = "" Public Event ZleDane(ByVal komunikat As String, _ ByVal obiekt As Integer) Public Sub KompletDanych(ByVal pnazwisko As String, _ ByVal pimie As String, ByVal pid As Integer, _ ByVal pdatau As Date) If pnazwisko.length < 5 Then ' jeżeli długość nazwiska będzie mniejsza niż 5 znaków, ' to zostanie wywołane zdarzenie

35 35 RaiseEvent ZleDane( _ "Nazwisko zbyt krótkie (min. 5 znaków)", 1) Exit Sub ElseIf pnazwisko.length > 50 Then ' jeżeli długość nazwiska będzie większa niż 50 znaków, to ' zostanie wywołane zdarzenie RaiseEvent ZleDane( _ "Nazwisko zbyt długie (max. 5 znaków)", 1) Exit Sub Else mnazwisko = UCase(mNazwisko.Substring(0, 1)) & _ LCase(mNazwisko.Substring(1, mnazwisko.length - 1)) End If If pimie.length < 3 Then RaiseEvent ZleDane("Imię zbyt krótkie (min. 3 znaki)", 2) Exit Sub ElseIf pimie.length > 25 Then RaiseEvent ZleDane("Imię zbyt długie (max. 25 znaków)", 2) Exit Sub Else mimie = UCase(mImie.Substring(0, 1)) & _ LCase(mImie.Substring(1, mimie.length - 1)) End If If pid < 2000 OrElse pid > 5000 Then RaiseEvent ZleDane( _ "Numer albumu musi być z przedziału ", 3) Exit Sub Else mid = pid End If If pdatau < CDate(" ") OrElse _ pdatau > CDate(" ") Then RaiseEvent ZleDane("Data urodzenia musi być z zakresu " & _ "' '", 4) Exit Sub Else mdataurodzenia = pdatau End If End Sub Public Sub New(ByVal p1 As Integer, ByVal p2 As Integer, _ ByVal p3 As Integer, ByVal p4 As Integer) mkomunikat = (p1 + p2 + p3 + p4).tostring End Sub Public Sub New(ByVal p1 As String, ByVal p2 As String) mnazwisko = p1 mimie = p2 End Sub

36 36 Public Function Komunikat() As String Return mkomunikat End Function ' definicja właściwości Public Property Nazwisko() As String Get Return mnazwisko End Get Set(ByVal value As String) If value.length < 5 Then RaiseEvent ZleDane("Nazwisko zbyt krótkie", 1) Else mnazwisko = value End If End Set End Property Public Property Imie() As String Get Return mimie End Get Set(ByVal value As String) If value.length < 3 Then RaiseEvent ZleDane("Imię zbyt krótkie", 2) Else mimie = value End If End Set End Property End Class W projekcie ZdarzeniaOrazPrzeciazenieMetod utworzono formularz frmtest zawierający cztery pola tekstowe o nazwach odpowiednio txtnazwisko, txtimie, txtnralbumu oraz txtdatau, odpowiadające im etykiety ze stosownymi tekstami, formant listy o nazwie lststudenci oraz cztery przyciski o nazwach btndodaj, btnclear, btnsumatekstow oraz btnsumaliczb. Projekt tego formularza pokazany jest na kolejnej stronie. W kodzie klasy tego formularza wpisano instrukcje niezbędne do obsługi jego formantów. Będziemy korzystać z klasy CStudent tworząc egzemplarz tej klasy, przy czym musimy tak to zrobić, aby mieć możliwość odebrania zdarzenia wygenerowanego w tej klasie. Możemy to zrobić dwojako, deklarując egzemplarz tej klasy z użyciem słowa kluczowego WithEvents lub bez użycia tego słowa.

37 37 W pokazanym niżej kodzie wykorzystano to pierwsze rozwiązanie. Public Class frmtest Dim bflaga As Boolean ' dekalracja instancji klasy CStudent zależy od tego, ' czy do obsługi zdarzenia użyjemy AddHandler czy nie Private WithEvents w As CStudent ' Private w As CStudent Private Sub btndodaj_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btndodaj.click ' zmienna logiczna otrzymuje wartość True, wykorzystamy ją ' do podjęcia decyzji, czy dodać element do listy bflaga = True ' utworzenie instancji klasy w = New CStudent ' AddHandler w.zledane, AddressOf ObslugaZdarzenia w.kompletdanych(me.txtnazwisko.text, Me.txtImie.Text, _ CType(Me.txtNrAlbumu.Text, Integer), _ CType(Me.txtDataU.Text, Date)) ' dodanie do formantu ListBox elementu typu CStudent, ale po ' sprawdzeniu, czy obiekt w został poprawnie zbudowany If bflaga Then Me.lstStudenci.Items.Add(w) End if End Sub Private Sub txtnralbumu_keypress(byval sender As Object, _ ByVal e As System.Windows.Forms.KeyPressEventArgs) _ Handles txtnralbumu.keypress

38 38 ' obsługa zdarzenia KeyPress - chodzi o to, aby nie przyjąć ' innego znaku niż cyfra If e.keychar < "0" Or e.keychar > "9" Then Beep() e.handled = True ' przypisanie właściwości Handled wartości ' True oznacza odrzucenie wprowadzonego znaku End If End Sub ' procedura obsługująca zdarzenie ZleDane zgłoszone przez ' instancję klasy CStudent. Jeżeli obsługujemy zdarzenie z ' użyciem deklaracji WithEvents to fragment Handles w.zledane ' jest konieczny, a jeżeli z użyciem AddHandler, to Handles ' w.zledane musimy zamarkować lub usunąć Private Sub ObslugaZdarzenia(ByVal tekst As String, _ ByVal co As Integer) Handles w.zledane MsgBox(tekst, MsgBoxStyle.Critical, "Obsługa zdarzenia") ' zależenie od wartości zmiennej 'co' ustawiamy fokus Select Case co Case 1 Me.txtNazwisko.Focus() Case 2 Me.txtImie.Focus() Case 3 Me.txtNrAlbumu.Focus() Case 4 Me.txtDataU.Focus() End Select End Sub Private Sub lststudenci_selectedindexchanged(byval sender As _ Object, ByVal e As System.EventArgs) _ Handles lststudenci.selectedindexchanged Dim z As CStudent = _ CType(Me.lstStudenci.SelectedItem, CStudent) MsgBox("Student " & z.nazwiskoimienralbumu, _ MsgBoxStyle.Information, "JG") End Sub Private Sub btnclear_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnclear.click Me.lstStudenci.Items.Clear() End Sub Private Sub btnsumatekstow_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnsumatekstow.click Dim w As New CStudent MsgBox("Suma tekstów to: " & w.dodaj(me.txtnazwisko.text, _ Me.txtImie.Text), MsgBoxStyle.Information, "Przeciążenie") End Sub

39 39 Private Sub btnsumaliczb_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnsumaliczb.click If IsNumeric(Me.txtNazwisko.Text) AndAlso _ IsNumeric(Me.txtImie.Text) Then Dim w As New CStudent MsgBox("Suma liczb = " & _ w.dodaj(cint(me.txtnazwisko.text), _ CInt(Me.txtImie.Text)).ToString, _ MsgBoxStyle.Information, "Przeciążenie") Else MsgBox("Dane nie reprezentują liczb", _ MsgBoxStyle.Critical, "Błąd przygotowania danych") End If End Sub End Class 4.3. Przeciążenie metody Pod tym pojęciem rozumiemy utworzenie więcej niż jednej metody o tej samej nazwie, ale różnym zestawie argumentów co do ich liczby i typu danych. W poprzednim podrozdziale w kodzie klasy CStudent utworzono dwa konstruktory różniące się liczbą argumentów (z założenia mają tę samą nazwę New). Przeciążanie metod pozwala nam na doprowadzenie do sytuacji, w której interfejs klasy jest zwarty (nie zawiera kilku metod realizujących podobne zadania). Inna korzyść, to logiczna możliwość wywołania tej samej metody niezależnie od rodzaju i liczby danych, które chcemy przekazać do metody. Poniżej dwie metody o tej samej nazwie, słowo kluczowe Overloads jest niezbędne do poprawnego przeciążenia metody (wyjątkiem jest konstruktor, który nie potrzebuje tego słowa kluczowego). Public Overloads Function Dodaj(ByVal arg1 As Integer, _ ByVal arg2 As Integer) As Integer Return arg1 + arg2 End Function Public Overloads Function Dodaj(ByVal arg1 As String, _ ByVal arg2 As String) As String Return arg1 & " " & arg2 End Function Metody są poprawnie przeciążone, jeżeli różnica w zestawie argumentów dotyczy innych argumentów niż opcjonalne.

40 Dziedziczenie Pod tym pojęciem rozumiemy możliwość budowania nowej klasy na bazie (podstawie) istniejącej klasy. Klasę, na podstawie której tworzymy nową klasę nazywamy klasą bazową, a powstałą w ten sposób nową klasę klasą potomną. Klasa potomna ma co najmniej te same metody i właściwości, co klasa bazowa. Ta cecha pozwala nam (między innymi) na przekazywanie do procedury czy funkcji instancji klasy potomnej, jeżeli jej argument został określony jako klasa bazowa. Prześledzimy problem dziedziczenia na przykładzie klasy CForStorageSub, która zawiera metody pozwalające na uruchamianie procedur przechowywanych na serwerze MS SQL Server. Poniżej fragment kodu klasy CForStorageSub, prezentuje on zaimportowanie dwóch przestrzeni nazw, definicję wyliczania jgtyp oraz metodę (funkcję) DajRekordset. Zadaniem funkcji DajRekordset jest wykonanie procedury przechowywanej zwracającej odpowiedni rekordset. Funkcja zwraca obiekt typu DataTable, a do jego wypełnienia danymi wykorzystuje obiekt DataReader i metodę ExecuteReader. Imports System.Data Imports System.Data.SqlClient Public Class CForStorageSub ' wyliczenie na potrzeby określania typu parametrów Protected Enum jgtyp As Integer jginteger = 1 jgchar = 2 jgmoney = 3 jgdata = 4 jgstring = 5 jgbit = 6 jgsingle = 7 End Enum Protected Function DajRekordset(ByVal conn As SqlConnection, _ ByVal sp_nazwa As String, _ ByVal ParamArray Par() As Object) As DataTable Dim cmd As SqlCommand, i As Integer, ip As Integer cmd = New SqlCommand ip = fprzygotujcmd(cmd, sp_nazwa, False, Par) cmd.connection = conn Dim dr As SqlDataReader, dt As New DataTable dr = cmd.executereader dt.load(dr) cmd = Nothing DajRekordset = dt

41 41 End Function ' dalsze metody publiczne i prywatne klasy End Class Klasa CForStorageSub będzie podstawą (bazą) do konstrukcji szczegółowych klas potomnych wyspecjalizowanych do rozwiązywania problemów komunikacji z bazą danych dla konkretnych formularzy czy raportów. Poniżej przykład takiej klasy wykorzystywanej w raportach. Słowo kluczowe MyBase daje dostęp do publicznych metod klasy bazowej, w tym przypadku do metody DajRekordset. Zapis MyBase.DajRekordset jest równoważny z zapisem DajRekordset, a użycie słowa kluczowego MyBase zwalnia jedynie z pamiętania nazw metod klasy bazowej. Imports System.Data Imports System.Data.SqlClient Public Class CRaporty Inherits CForStorageSub ' dziedziczenie po klasie bazowej Private mtable As DataTable Private mkomunikat As String = "" Public Sub New(ByVal StrConn As String, ByVal idr As Integer, _ ByVal idw As Integer, ByVal ktoryraport As Integer) ' konstruktor dostarcza źródło danych dla raportu ' określonego przez zmienną ktoryraport Dim conn As New SqlConnection(StrConn) Try conn.open() Select Case ktoryraport Case 1 ' zakupy wartościowo wg lat i wydawnictw mtable = MyBase.DajRekordset(conn, _ "p_zakupylatawydawnictwa", _ "@idr", idr, jgtyp.jginteger, 0, _ "@idw", idw, jgtyp.jginteger, 0) Case 2 ' zakupy ilościowo i wartościowo wg 'wydawnictw w latach, także wg kategorii mtable = MyBase.DajRekordset(conn, _ "p_zbiorczezakupy", _ "@idk", idr, jgtyp.jginteger, 0) Case 3 ' rezerwa na przyszłość End Select Catch ex As Exception mkomunikat = "Błąd pobrania danych" Finally conn.close()

42 42 conn = Nothing End Try End Sub ReadOnly Property DajTabele() As DataTable Get Return mtable End Get End Property ReadOnly Property Komunikat() As String Get Return mkomunikat End Get End Property End Class W książkach, których jestem autorem lub współautorem przedstawiono wiele klas potomnych klasy CForStorageSub związanych z obsługą formularzy czy raportów. W większości z tych klas stosowne były przeciążone konstruktory oraz definiowane interfejsy klas różnicujące dostęp do ich metod publicznych. Prześledzenie ich kodu jak i sposobu wykorzystania klas w kodzie procedur obsługujących formularze powinno pozwolić na poznanie możliwości i zalet klas w programowaniu Interfejs klasy W wielu przypadkach w klasie definiujemy więcej niż jeden konstruktor, przy czym z każdym z nich mogą być związane unikalne właściwości. W takich sytuacjach można w klasie zadeklarować interfejsy klasy, które będą ograniczać dostęp do wybranej części właściwości i metod. Dla prześledzenia tego problemu skupimy się na wspomnianej wcześniej klasie CStudent, w której utworzymy dwa konstruktory i dwa interfejsy klasy.

43 43 Imports System.Data Imports System.Data.SqlClient Public Interface IDaneStudenta Function Komunikat() As String Function FullName() As String Function ShortName() As String Sub DaneStudenta(ByVal Nazwisko As String, _ ByVal Imie As String, ByVal NumerAlbumu As Integer) End Interface Public Interface IDaneRejestrowe Function Komunikat() As String Function Rejestr() As DataTable Function Oceny() As DataTable Function SredniaOcen() As Decimal Sub PobierzDane(ByVal strconn As String, _ ByVal NumerAlbumu As Integer) End Interface Public Class CStudent Implements IDaneStudenta Implements IDaneRejestrowe ' deklaracja zmiennych prywatnych klasy Private mnazwisko As String Private mimie As String Private mnumeralbumu As String Private msredniaocen As Decimal Private mtablerejestr As DataTable Private mtableoceny As DataTable Private mkomunikat As String = "" Public Function FullName() As String Implements _ IDaneStudenta.FullName Return mnazwisko & " " & mimie & " nr alb. " & _ mnumeralbumu.tostring End Function Public Function ShortName() As String Implements _ IDaneStudenta.ShortName Return mimie.substring(0, 1) & ". " & mnazwisko End Function Public Function Rejestr() As System.Data.DataTable Implements _ IDaneRejestrowe.Rejestr Return mtablerejestr End Function Public Function Oceny() As System.Data.DataTable Implements _ IDaneRejestrowe.Oceny Return mtableoceny End Function

44 44 Public Function SredniaOcen() As Decimal Implements _ IDaneRejestrowe.SredniaOcen Return msredniaocen End Function Public Sub DaneStudenta(ByVal Nazwisko As String, _ ByVal Imie As String, ByVal NumerAlbumu As Integer) _ Implements IdaneStudenta.DaneStudenta mnazwisko = Nazwisko mimie = Imie mnumeralbumu = NumerAlbumu End Sub Public Sub PobierzDane(ByVal strconn As String, _ ByVal NumerAlbumu As Integer) _ Implements IdaneRejestrowe.PobierzDane ' utworzenie obiektu SqlConnection w oparciu o przekazany ' łańcuch połączenia Dim conn As New SqlConnection(strConn) Try 'otwarcie połączenia do bazy danych conn.open() ' przypisanie do zmiennej mtablerejestr rekordsetu ' zwróconego przez odpowiednią procedurę przechowywaną ' po przekazaniu do niej numeru albumu mtablerejestr = DajRekordSet(...) ' przypisanie do zmiennej mtableoceny rekordsetu ' zwróconego przez odpowiednią procedurę przechowywaną ' po przekazaniu do niej numeru albumu mtableoceny = DajRekordSet(...) ' pobranie z bazy danych średniej ocen dla danego studenta msrednia = DajWartosc(...) Catch ex As Exception mkomunikat = "Błąd pobrania danych" Finally conn.close() conn = Nothing End Try End Sub ' procedura Property zwraca wartość zmiennej mkomunikat Public Function Komunikat() As String Implemnets _ IdaneStudenta.Komunikat, IdaneRejestrowe.Komunikat Return mkomunikat End Function End Class Warto zwrócić uwagę, że zmienna prywatna mkomunikat, która jest udostępniana przez procedurę typu Property o nazwie Komunikat nie będzie dostępna w żadnym zdefiniowanym interfejsie klasy (ale będzie dostępna w domyślnym interfejsie). Gdybyśmy

45 45 chcieli udostępnić tę zmienną w interfejsach, to konieczne byłoby zadeklarowanie oraz implementacja odpowiednich funkcji w tych interfejsach Polimorfizm Polimorfizm to jedna z ważniejszych cech OOP, jej sens polega na tym, że możemy mieć wiele klas implementujących ten sam interfejs. Możliwa jest realizacja polimorfizmu dwoma drogami: poprzez dziedziczenie oraz poprzez interfejs. Rozważmy taką sytuację, w której chcemy mieć klasy realizujące obliczenie pozycji Do wypłaty na podstawie kwoty wynagrodzenia brutto w kosztach firmy dla dwóch kategorii pracowników: zatrudnionych na umowę o pracę oraz na zlecenie, Projekt TestPolimorfizmu zawiera pełne rozwiązanie tego problemu. W skład tego projektu wchodzi (między innymi) pokazany niżej formularz frmpolimorfizm. Na jego powierzchni umieszczono sześć formantów typu TextBox, są to formanty o nazwach i przeznaczeniu: txtbruttopraca tu wpiszemy kwotę wynagrodzenia brutto przy umowie o pracę; txtbruttozlecenie tu wpiszemy kwotę wynagrodznia brutto przy zleceniu; txtdowyplatypd tu zostanie zwrócona wyliczona kwota wynagrodzenia do wypłaty w przypadku umowy o pracę z wykorzystaniem dziedziczenia; txtdowyplatyzd tu zostanie zwrócona wyliczona kwota wynagrodzenia do wypłaty w przypadku umowy zlecenia z wykorzystaniem dziedziczenia; txtdowyplatypi tu zostanie zwrócona wyliczona kwota wynagrodzenia do wypłaty w przypadku umowy o pracę z wykorzystaniem interfejsu; txtdowyplatyzi tu zostanie zwrócona wyliczona kwota wynagrodzenia do wypłaty w przypadku umowy zlecenia z wykorzystaniem interfejsu;

46 46 Dwa przyciski poleceń uruchamiają procedury wyliczające kwoty wynagrodzenia do wypłaty z wykorzystaniem odpowiedniej formy polimorfizmu: btnwgdziedziczenia btnwginterfejsu Formularz uzupełniają jeszcze etykiety opisujące przeznaczenie poszczególnych pól tekstowych Polimorfizm wg dziedziczenia Utworzymy klasę CPodatekPodstawowy, poza zmiennymi i stałymi zdefiniowano w niej publiczną funkcję DoWyplaty, jej zadaniem jest wyliczenie pozycji do wypłaty w przypadku zatrudnienia na podstawie umowy o pracę. W definicji tej metody użyto słowa kluczowego Overridable po to, aby w klasie potomnej mieć możliwość innego zaimplementowania tej samej metody. Imports System.Math Public Class CPodatekPodstawowy Protected mbruttof As Decimal Protected mbruttop As Decimal Protected mskladkizus As Decimal Protected mskladkiuz As Decimal Protected mpodstawaskladki As Decimal Protected mkosztuzysku As Decimal Protected mpodstawapodatku As Decimal Protected mpodatekus As Decimal Protected Const KosztFirmy As Double = 0.15 Protected Const SkladkiZUS As Double = Protected Const SkladkiUZ As Double = 0.09 ' deklaracja publicznej funkcji DoWyplaty, jej zadaniem jest ' ustalenie kwoty do wypłaty. Jako argument dostaje kwotę wypłaty w ' kosztach firmy, pozycja do wypłaty obliczana jest tak, jak dla ' pracownika zatrudnionego na umowę o pracę ' Specyfikator Overridable pozwala na inną definicję tej funkcji w ' klasie potomnej Public Overridable Function DoWyplaty(ByVal kwota As Decimal) As _ Decimal mbruttop = Round(kwota * (1 - KosztFirmy), 2) mskladkizus = Round(mBruttoP * SkladkiZUS, 2) mpodstawaskladki = mbruttop - mskladkizus mskladkiuz = Round(mPodstawaSkladki * SkladkiUZ, 2) mkosztuzysku = Round(mPodstawaSkladki * 0.5, 2) mpodstawapodatku = mpodstawaskladki - mkosztuzysku mpodatekus = Round(mPodstawaPodatku * _

47 47 mpodstawaskladki * , 0) Return mbruttop - mskladkizus - mskladkiuz - mpodatekus End Function End Class Tworzymy teraz klasę potomną na bazie klasy CPodatekPodstawowy, będziemy ją wykorzystywać przy obliczaniu pozycji do wypłaty w przypadku zatrudnienia na zlecenie. Public Class CPodatekZlecenie ' klasa dziedziczy po klasie CPodatekPodstawowy, co oznacza, że ma 'co najmniej wszystkie właściwości i metody klasy bazowej Inherits CPodatekPodstawowy ' nadpisanie funkcji DoWyplaty, słowo Overrides jest oznaczeniem ' Nadpisania. Inaczej mówiąc chodzi o inną implementację tej funkcji ' niż w klasie bazowej. Warunkiem sine qua non nadpisania jest ' oznaczenie takiej funkcji w klasie bazowej słowem Overridable Public Overrides Function DoWyplaty(ByVal kwota As Decimal) As _ Decimal mbruttop = kwota mskladkizus = 0 mpodstawaskladki = mbruttop - mskladkizus mskladkiuz = 0 mkosztuzysku = Round(mPodstawaSkladki * 0.5, 2) mpodstawapodatku = mpodstawaskladki - mkosztuzysku mpodatekus = Round(mPodstawaPodatku * _ mpodstawaskladki * , 0) Return mbruttop - mskladkizus - mskladkiuz - mpodatekus End Function End Class W kodzie formularza frmpolimorfizm musimy utworzyć dwie procedury realizujące obliczenie kwoty do wypłaty wg dziedziczenia. Pomocnicza procedura ObliczWyplate otrzymuje jako pierwszy argument egzemplarz klasy CPodatekPodstawowy, ale może też otrzymać egzemplarz klasy CPodatekZlecenie. Private Sub ObliczWyplate(ByVal Item As CPodatekPodstawowy, _ ByVal kwota As Decimal, ByVal txttext As TextBox) txttext.text = Format(Item.DoWyplaty(kwota), "# ##0.00 zł") End Sub Kolejna procedura wykonywana jest w reakcji na klik przycisku btnwgdziedziczenia. Private Sub btnwgdziedziczenia_click(byval sender As System.Object, _

48 48 ByVal e As System.EventArgs) Handles btnwgdziedziczenia.click If IsNumeric(Me.txtBruttoPraca.Text) AndAlso _ IsNumeric(Me.txtBruttoZlecenie.Text) Then Dim Item1 As New CPodatekPodstawowy Dim item2 As New CPodatekZlecenie ObliczWyplate(Item1, CDec(Me.txtBruttoPraca.Text), _ Me.txtDoWyplatyPd) ObliczWyplate(item2, CDec(Me.txtBruttoZlecenie.Text), _ Me.txtDoWyplatyZd) Else MsgBox("Co najmniej jedna z pozycji 'brutto' jest źle podana", _ MsgBoxStyle.Critical, _ "Testowanie poliformizu wg dziedziczenia") End If End Sub Efekt działania pokazany jest niżej Polimorfizm wg interfejsu Przy tej metodzie musimy utworzyć w ogólnym module interfejs, który inaczej zaimplementujemy w klasach realizujących obliczenia wg umowy o pracę i wg zlecenia. W tym projekcie interfejs ten został utworzony w pliku typu Module. Module ModulKlasJG Public Interface IObliczWyplate Function ObliczDoWyplaty(ByVal KwotaBrutto As Decimal) As Decimal End Interface End Module Powyższy kod zawiera definicję interfejsu IObliczWyplate zawierającego deklarację funkcji ObliczWyplate. Tworzymy teraz dwie klasy, każda z nich będzie inaczej implementować podany wyżej interfejs.

49 49 Public Class CPraca Implements IObliczWyplate Private mbruttof, mbruttop As Decimal Private mskladkizus, mskladkiuz As Decimal Private mpodstawaskladki, mkosztuzysku As Decimal Private mpodstawapodatku, mpodatekus As Decimal Private Const KosztFirmy As Double = 0.15 Private Const SkladkiZUS As Double = Private Const SkladkiUZ As Double = 0.09 Public Function ObliczDoWyplaty(ByVal KwotaBrutto As Decimal) As _ Decimal Implements ModulKlasJG.IObliczWyplate.ObliczDoWyplaty mbruttop = Round(KwotaBrutto * (1 - KosztFirmy), 2) mskladkizus = Round(mBruttoP * SkladkiZUS, 2) mpodstawaskladki = mbruttop - mskladkizus mskladkiuz = Round(mPodstawaSkladki * SkladkiUZ, 2) mkosztuzysku = Round(mPodstawaSkladki * 0.5, 2) mpodstawapodatku = mpodstawaskladki - mkosztuzysku mpodatekus = Round(mPodstawaPodatku * _ mpodstawaskladki * , 0) Return mbruttop - mskladkizus - mskladkiuz - mpodatekus End Function End Class Public Class CZlecenie Implements IObliczWyplate Private mbruttof, mbruttop As Decimal Private mskladkizus, mskladkiuz As Decimal Private mpodstawaskladki, mkosztuzysku As Decimal Private mpodstawapodatku, mpodatekus As Decimal Private Const KosztFirmy As Double = 0.15 Private Const SkladkiZUS As Double = Private Const SkladkiUZ As Double = 0.09 Public Function ObliczDoWyplaty(ByVal KwotaBrutto As Decimal) As _ Decimal Implements ModulKlasJG.IObliczWyplate.ObliczDoWyplaty mbruttop = KwotaBrutto mskladkizus = 0 mpodstawaskladki = mbruttop - mskladkizus mskladkiuz = 0 mkosztuzysku = Round(mPodstawaSkladki * 0.5, 2) mpodstawapodatku = mpodstawaskladki - mkosztuzysku mpodatekus = Round(mPodstawaPodatku * _ mpodstawaskladki * , 0) Return mbruttop - mskladkizus - mskladkiuz - mpodatekus End Function End Class

50 50 Podobnie jak poprzednio w module klasy formularza frmpolimorfizm musimy dodać potrzebne procedury. Private Sub WyliczWyplate(ByVal IPodatek As IObliczWyplate, _ ByVal kwotabrutto As Decimal, ByVal txttext As TextBox) txttext.text = Format(IPodatek.ObliczDoWyplaty(kwotaBrutto), _ "# ##0.00 zł") End Sub Private Sub btnwginterfejsu_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnwginterfejsu.click If IsNumeric(Me.txtBruttoPraca.Text) AndAlso _ IsNumeric(Me.txtBruttoZlecenie.Text) Then Dim item1 As New CPraca Dim item2 As New CZlecenie WyliczWyplate(item1, CDec(Me.txtBruttoPraca.Text), _ Me.txtDoWyplatyPi) WyliczWyplate(item2, CDec(Me.txtBruttoZlecenie.Text), _ Me.txtDoWyplatyZi) Else MsgBox("Co najmniej jedna z pozycji 'brutto' jest źle podana", _ MsgBoxStyle.Critical, "Testowanie poliformizu wg interfejsu") End If End Sub I efekt działania tego kodu.

51 Diagram klas UML UML (ang. Unified Modeling Language) jest standardowym narzędziem wykorzystywanym do specyfikacji, wizualizacji, konstruowania i dokumentowania składników programu. Zwyczajowo diagram klasy przedstawiany jest jako prostokąt podzielony na kilka części. Na samej górze jest nazwa klasy, dalej mogą wystąpić takie grupy elementów jak: Fields zmienne prywatne czy formanty w przypadku formularza; Properties właściwości; Methods metody; Events zdarzenia. Poza wymienionymi elementami diagram może zawierać informacje o klasie bazowej czy o interfejsach. Poniżej przykład diagramu klas utworzonych w projekcie TestPolimorfizmu.

52 52 I jeszcze jeden przykład diagramów klas projektu

53 53

54 54 5. Formanty ComboBox i ListBox 5.1. Źródła danych Pojedyncze elementy Rekordset Pojedyncze elementy złożone W tym podrozdziale rozpatrzymy taką sytuację, w której na formularzu umieszczone jest pole kombo (powiedzmy, że o nazwie cboprodukty), które ma wyświetlać listę oferowanych produktów. Załóżmy dalej, że informacja wyświetlana ma zawierać nie tylko nazwę produktu, ale także kilka informacji dodatkowych (wielkość opakowania, cenę jednostkową, ewentualnie nazwę producenta). Załóżmy też, że po wyborze danego produktu będziemy chcieli uzyskać takie informacje o nim, jak: jego identyfikator, nazwę, liczbę dostępnych pozycji, cenę jednostkową, stawkę podatku VAT. Wprowadzimy jeszcze jedno, dodatkowe, ale bardzo ważne założenie: w sytuacji, w której liczba dostępnych pozycji spadnie do zera musimy dany produkt usunąć z kolekcji elementów pola kombo czy listy. To ostatnie założenie powoduje, że jako źródła danych nie możemy wykorzystać rekordsetu, ponieważ wymagałoby to zmian w bazie danych (a może być jeszcze za wcześnie na ich dokonanie). W takiej sytuacji można zaproponować następujące podejście: Pobieramy z bazy danych rekordset zawierający potrzebne informacje; W pętli tworzymy obiekt złożony (klasę lub strukturę), który dodajemy do kolekcji elementów danego formantu. Rozpatrzymy taką sytuację na przykładzie formularza frmsprzedaz rozwiązania (projektu) Fifo. Formularz ten ma ułatwić obsługę kupujących różnego rodzaju produkty żywnościowe w hurtowni zajmującej się dystrybucją tego typu produktów. Procedura przechowywana o nazwie pdajdostepneprodukty utworzona w przykladowej bazie o nazwie Fifo zwraca rekordset o polach pokazanych poniżej. Przed utworzeniem z każdego wiersza informacji złożonej (instancji klasy) musimy utworzyć odpowiednią klasę w rozwiązaniu VisualStudio. W naszym przypadku jest to

55 55 klasa o nazwie CProdukty utworzona w pliku CSprzedaz.vb. Kod tej klasy pokazany jest poniżej. Public Class CProdukty Private midp As Integer Private mprodukt As String Private mvat As Decimal Private mcena As Decimal Private mile As Integer ' konstruktor bezparametrowy Public Sub New() End Sub ' konstruktor z parametrami Public Sub New(ByVal idp As Integer, ByVal nazwa As String, _ ByVal cena As Decimal, ByVal vat As Decimal, _ ByVal ile As Integer) midp = idp mprodukt = nazwa mcena = cena mvat = vat mile = ile End Sub ' seria właściwości zwracających wartości zmiennych prywatnych Public ReadOnly Property Idp() As Integer Get Return midp End Get End Property Public ReadOnly Property Produkt() As String Get Return mprodukt End Get End Property Public ReadOnly Property StawkaVat() As Decimal Get Return mvat End Get End Property Public ReadOnly Property Cena() As Decimal Get Return mcena End Get End Property ' właściwość zwracająca lub ustawiająca zmienną mile

56 56 Public Property IleJest() As Integer Get Return mile End Get Set(ByVal value As Integer) mile = value End Set End Property ' nadpisanie funkcji ToStgring Public Overrides Function ToString() As String Return mprodukt End Function End Class Procedura przechowywana pdajdostepneprodukty wywoływana jest przez metodę PrzygotujSprzedaz zdefiniowaną w klasie CSprzedaz. Rekordset przypisywany jest do obiektu typu DataTable, który z kolei jest źródłem danych dla formantu typu DataGridView umieszczonego na formularzu frmsprzedaz. Procedura zdarzenia Load tego formularza przegląda wiersze tego formantu (pomocniczego gridu o nazwie dgvpomoc), tworzy instancje klasy CProdukty i dodaje je do kolekcji elementów kombo cboprodukty. Dodatkowo utworzony obiekt dodawany jest do kolekcji, przy czym kluczem jest numer pozycji (podany jako string). Private Sub frmsprzedaz_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ' deklaracja prywatnych zmiennych procedury Dim w As CProdukty, i As Integer ' przeglądamy rekordy dgvpomoc, tworzymy obiekty klasy CProdukt, ' dodajemy je do cboprodukty oraz do kolekcji With Me.dgvPomoc For i = 0 To Me.dgvPomoc.RowCount - 1 w = New CProdukty(CInt(.Rows(i).Cells(0).Value), _.Rows(i).Cells(1).Value,.Rows(i).Cells(3).Value, _.Rows(i).Cells(4).Value,.Rows(i).Cells(2).Value) ' dodajemy element do cboprodukty Me.cboProdukty.Items.Add(w) ' dodajemy element do kolekcji z kluczem od "0" do "n-1" jgkol.add(w, i.tostring) Next End With w = Nothing End Sub Sposób odebrania informacji wybranej w polu kombo, do którego dodano elementy będące instancjami pewnej klasy demonstruje procedura obsługująca zdarzenie SelectedIndexChange formantu cboprodukty.

57 57 Procedura uzależnia swoje działanie od tego, czy zmienna publiczna bflaga jest prawdą, jeżeli nie, to kończy swoje działanie. Własciwość SelectedItem formantu cboprodukty zwraca informację wybraną w polu kombi, ale aby można było z niej wydzielić potrzebne informacje to musimy ją skonwertować na typ CProdukty (bo takie obiekty były dodawane do tego formantu). Zadanie to realizuje funkcja CType. Z formantu cboprodukty dany obiekt (produkt) może być usunięty, dlatego do ustalenie jego pierwotnego indeksu (położenia) w kolekcji wykorzystywany jest pomocniczy grid dgvpomoc i prywatna funkcja UstalIndex. Po ustaleniu indeksu z kolekcji (instancji klasy CProdukty) pobierany jest odpowiedni element, z którego odczytywana jest informacja o liczbie (dostępnych) opakowań danego produktu (korzystamy z właściwości IleJest). Jest ona przypisywana do właściwości Maximum formantu typu NumericUpDown o nazwie nupile. Private Sub cboprodukty_selectedindexchanged(byval sender _ As Object, _ByVal e As System.EventArgs) _ Handles cboprodukty.selectedindexchanged ' jeżeli bflaga=false to wyjdź z procedury If Not bflaga Then Exit Sub 'deklaracja zmiennych prywatnych procedury Dim w As New CProdukty, ip As Integer ' do obiektu w przypisujemy wybraną pozycję w cboprodukty, ' funkcja CType konwertują ją na typ CProdukty w = CType(Me.cboProdukty.SelectedItem, CProdukty) ' prywatna funkcja UstalIndex ustala, jaki jest indeks wybranego ' produktu w dgvpomoc ip = UstalIndex(w.Produkt) ' zmienna klasy przyjmuje cenę wybranego produktu cena = w.cena ' deklarujemy obiekt CProdukty i przypisujemy mu element kolekcji ' wskazany kluczem ip.tostring Dim u As CProdukty = jgkol.item(ip.tostring) ' blokujemy możliwość obsługi zdarzenia SelectedValueChange ' formantu nupile bflaga = False With Me.nupIle.Minimum = 1.Maximum = u.ilejest.increment = 1.Value =.Minimum ' funkcja KwotaPolska wypisuje kwotę uzupełnioną o symbol zł Me.txtNetto.Text = KwotaPolska((.Value * cena).tostring) End With ' odblokowujemy możliwość obsługi zdarzenia SelectedValueChange ' formantu nupile bflaga = True End Sub

58 58

59 6. Dostęp do danych, model ADO.NET 59 ADO.NET jest opracowaną przez Microsoft technologią dostępową do baz danych, jest to jeden z ważnych składników środowiska.net Framework. Technologia ta zapewnia komunikację z relacyjnymi i nierelacyjnymi źródłami danych poprzez zestaw komponentów. ADO.NET zabezpiecza zarówno model połączeniowy ze źródłem danych jak i model bezpołączeniowy. W przypadku modelu połączeniowego (Connection Oriented Data Access Architecture) aplikacja zestawia połączenie ze źródłem danych, a następnie interaktywnie współpracuje z tym źródłem wykorzystując zapytania języka SQL. W tej technologii połączenie ze źródłem danych cały czas pozostaje otwarte, także wtedy, gdy aplikacja nie wykonuje żadnych operacji na źródle danych. W modelu bezpołączeniowym (Disconnected Data Access Architecture) połączenie jest zestawianie jedynie na moment, kiedy dane są pobierane ze źródła i umieszczane w obiekcie typu DataSet lub zwracane do źródła danych Komponenty ADO.NET Poniżej pokazany jest schemat funkcjonowania dostępu do baz danych z wykorzystaniem modelu ADO.NET (źródło: Dwoma kluczowymi komponentami ADO.NET jest Data Provider oraz DataSet. Pierwszy z nich odpowiada za zestawienie połączenia ze źródłem danych, a drugi za reprezentowanie danych pobranych ze źródła (z bazy danych). Środowisko.Net Framework zabezpiecza trzy główne rodzaje provaiderów dla modelu ADO.NET:

60 60 Microsoft SQL Provider obsługuje dostęp do baz danych MS SQL Server; OLEDB pozwala na dostęp do innych baz danych i innych źródeł danych; ODBC pozwala na tworzenie aplikacji z jednoczesnym dostępem do różnych typów danych. W przypadku zestawiania połączenia z MS SQL Server używamy obiektu SqlConnection, do innych baz danych OleDbConnection, a w przypadku korzystania z ODBC korzystamy z obiektu OdbcConnection. Cztery obiekty wchodzące w skład komponentu DataProvider zabezpieczają jego funkcjonalność. Są to obiekty: Connection odpowiada za fizyczne zestawienie połączenie ze źródłem danych; Command odpowiada za wykonanie zapytania skierowanego do źródła danych, może to być jawne polecenie SQL lub procedura przechowywana, zarówno wybierające jak i akcyjne (modyfikujące informacje w bazie danych); DataReader wyspecjalizowany obiekt do pobierania strumienia danych typu tylko do odczytu i do przeglądania jedynie w przód; DataAdapter obiekt pośredniczący w dostarczenie danych pobranych ze źródła do obiektu DataSet. Obiekt DataSet zabezpiecza bezpołączeniowy dostęp do danych pobranych ze źródła, jest tym samym całkowicie niezależny od tego źródła (poza momentem, gdy dane są pobierane z tego źródła). Obiekt DataSet może zawierać kolekcje obiektów DataTable, z których każdy jest wirtualnym odpowiednikiem danych pozyskanych ze źródła danych. Inną ważną kolekcją jest kolekcja relacji wiążąca obiekty DataTable. Obiekt DataTable zawiera kolekcję wierszy, kolekcję kolumn oraz kolekcję warunków nakładanych na poszczególne pola. Poniżej pokazany jest schemat obiektu DataSet.

61 Connection String Pod tym pojęciem rozumiemy informację tekstową zawierającą dane niezbędne do zestawienia połączenia ze źródłem danych. W zależności od użytego provaidera connection string ma następującą składnię: Microsoft SQL Server Connection String connetionstring ="Data Source = ServerName; Initial Catalog = Databasename; User ID = UserName; Password=Password" OLEDB Data Provider Connection String connetionstring = "Provider = Microsoft.Jet.OLEDB.4.0; Data Source = yourdatabasename.mdb;" ODBC Connection String connetionstring = "Driver = {Microsoft Access Driver (*.mdb)}; DBQ = yourdatabasename.mdb;" 6.3. Obiekt Connection SqlConnection Obiekt SqlConnection odpowiada za utworzenie fizycznego połączenia aplikacji z bazą danych serwera SQL. Instancja klasy SqlConnection otrzymuje jako argument łańcuch połączenia (connection string). Po zestawieniu (otwarciu) połączenia mogą być wykonywane polecenia pobrania czy modyfikacji danych w źródle danych. Poniżej jedna z możliwych instrukcji deklaracji i utworzenia instancji obiektu SqlConnection, kolejna otwiera połączenie z bazą danych.

62 62 Dim conn As New SqlConnection(connection_string) conn.open() Utworzona instancja obiektu Connection nie jest automatycznie zamykana, nawet po wyjściu z procedury, w której nastąpiło zestawienie połączenia. Musimy pamiętać o tym, aby po zakończeniu operacji na bazie danych zamknąć otwarte połączenie, wystarczy skorzystać z metody Close. Przypisanie wartości Nothing jest sygnałem do zwolnienia zasobu (do jego usunięcia z pamięci RAM komputera). conn.close() conn = Nothing OleDbConnection Obiekt OleDbConnection odpowiada za utworzenie fizycznego połączenia aplikacji z bazą danych wskazaną w łańcuchu połączenia. Instancja klasy OleDbConnection otrzymuje jako argument łańcuch połączenia (connection string). Po zestawieniu (otwarciu) połączenia mogą być wykonywane polecenia pobrania czy modyfikacji danych w źródle danych. Instrukcje deklaracji, utworzenia, otwarcia i zamknięcia połączenia są podobne do przedstawionych wyżej, cała różnica dotyczy użycia obiektu OleDbConnection zamiast SqlConnection Obiekt Command Obiekt Command odpowiada za wykonanie jawnego zapytania SQL lub procedury przechowywanej. Wymaga instancji obiektu Connection, otwarcia połączenia do źródła danych, a następnie przypisania go do właściwości Connection obiektu Command. Jeżeli wykonane zapytanie lub procedura przechowywana zwracają dane, to obiekt DataReader jest używany do ich odebrania z obiektu Command. Istotne właściwości tego obiektu to CommandText, który reprezentuje tekst zawierający polecenie do wykonania lub nazwę procedury przechowywanej oraz właściwość CommandType, która określa rodzaj polecenia. Może to być jawne polecenie SQL, procedura przechowywana, może być to także tabela. Polecenie wykonywane jest po wywołaniu jednej z trzech metod, które udostępniane są przez obiekt Command Metoda ExecuteReader Metoda ta używana jest do pobrania ze źródła danych takiego ich zestawu, który chcemy tylko i wyłącznie przeglądać i to jedynie w przód. Zaletą jest szybkość działania tej metody. Wywołanie tej metody dostarcza dane do obiektu DataReader, którego nie można utworzyć programowo w kodzie (chodzi o to, że obiekt tego typu powstaje jako efekt wywołania metody ExecuteReader). Poniżej przykład fragmentu kodu, w którym tworzony jest obiekt DataReader.

63 63 Dim dt As New DataTable Try conn.open() Dim oledbcmd As New OleDbCommand( Select * From Klienci, conn) Dim oledbreader As OleDbDataReader = oledbcmd.executereader dt.load(oledbreader) Metoda ExecuteScalar Metoda ta wykorzystywana jest w tych sytuacjach, w których zapytanie SQL lub procedura przechowywana zwraca pojedynczy wynik z bazy danych. Dokładnie rzecz biorąc metoda ExecuteScalar zwraca wynik z pierwszego pola pierwszego rekordu. Przykładowy fragment kodu wykorzystujący tę metodę pokazany jest niżej. Dim conn As New SqlConnection(connetionString) Try conn.open() Dim cmd As New SqlCommand( Select count(*) From Klienci, conn) Dim count As Integer = CInt(cmd.ExecuteScalar()) Cmd = Nothing conn.close() conn = Nothing Metoda ExecuteNonQuery Metoda uruchamia procedurę akcyjną typu insert (wstawienie rekordu), delete (usunięcie) lub update (aktualizację). Poniższy fragment kodu ilustruje użycie tej metody do usunięcia rekordu o danej wartości klucza. Dim conn As New OleDbConnection(connetionString) Try conn.open() Dim cmd As New _ OleDbCommand( Delete From Klienci Where idk = 1, conn) cmd.executenonquery() conn.close() conn = Nothing 6.5. Obiekt DataReader Jak wcześniej już powiedziałem obiekt DataReader pozwala na bardzo szybkie pobranie z bazy danych rekordestu, który możemy dalej wykorzystać np. jako źródło danych do takich obiektów (formantów) jak ListBox, ComboBox czy DataGridView. Obiekt DataReader udostępnia trzy ważne metody: Read, NextResult oraz GetShemaTable.

64 Metoda Read Metoda Read pozwala na przeczytanie zawartości tego obiektu po pobraniu danych (czyli rekordów) odczytając wskazane pola przy pomocy właściwości Item o podanym indeksie. Musimy pamiętać o tym, że po utworzeniu tego obiektu wskaźnik rekordów ustawiany jest na zerowej pozycji i że możemy te rekordy odczytywać tylko w przód (od zerowego do ostatniego indeksu). Oczywiście nie ma możliwości modyfikacji zestawu rekordów. Poniżej kod procedury odczytującej zawartość obiektu DataReader (procedura ta jest wmontowana w formularz frmoledbdatareader 2 jako reakcja na klik przycisku o nazwie btnmetodaread). ' zaimportowanie potrzebnej przestrzeni nazw Imports System.Data.OleDb Private Sub btnmetodaread_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnmetodaread.click ' deklarujemy i tworzymy obiekt typu OLEDBConnetion ' zmienna publiczna zawiera łańcuch połączenia do bazy Access Dim conn As New OleDbConnection(strconnOle) ' reszta operacji może spowodować błąd, dlatego umieszcamy je w bloku Try-Catch Try conn.open()'otwieramy połączenie ' deklarujemy i tworzymy obiekt typu OleDBCommand ' przekazując do niego zapytanie SQL oraz otwarte połączenie Dim oledbcmd As New _ OleDbCommand("select * from Pracownicy", conn) ' deklarujemy obiekt typu OLEDBReader i wypełniamy go danymi ' poprzez wywołanie metody ExecuteReader obiektu OleDBCommand Dim oledbreader = oledbcmd.executereader ' czytamy obieky oledbreader Dim i As Integer, txt As String, j As Integer = 1 While oledbreader.read txt = "Rekord nr " & j.tostring & ": " For i = 0 To oledbreader.fieldcount - 1 txt &= oledbreader.item(i) & "; " Next MsgBox(txt.Substring(0, txt.length - 2), _ MsgBoxStyle.Information, _ "Ilustaracja metody Read obiektu DataReader") j += 1 End While oledbcmd = Nothing MsgBox("Wszystkie rekordy odczytane", _ MsgBoxStyle.Information, _ "Ilustaracja metody Read obiektu DataReader") 2 Zobacz przykładową aplikację ADOandADONet

65 65 Catch ex As Exception MsgBox("Problem z wykonaniem polecenia", _ MsgBoxStyle.Critical, _ "Ilustracja metody Read obiektu DataReader") Finally conn.close() conn = Nothing End Try End Sub Metoda NextResult Metoda NextResult może być wykorzystywana w tych zapytaniach, w których zależy nam na zwróceniu więcej niż jednego zestawu rekordów przy jednym połączeniu z bazą danych. Poniżej przykładowy kod procedury pokazującej użycie metody NextResult przy pobieraniu danych z bazy SQL. W przypadku MS Access metoda ta nie jest obsługiwana. Imports System.Data.SqlClient Private Sub btnmetodanextresult_click(byval sender As System.Object, ByVal e As System.EventArgs) Handles btnmetodanextresult.click Dim sql1, sql2 As String sql1 = "select * from Klienci;" sql2 = "select * from RodzajSal" ' dekarujemy i tworzymy obiekt typu SqlConnetion Dim conn As New SqlConnection(strconnSqL) ' reszta operacji może spowodować błąd, dlatego umieszcamy je ' w Try-Catch Try ' otwieramy połączenie conn.open() ' deklarujemy i tworzymy obiekt typu sqlcommand ' przekazując do niego zapytanie SQL oraz otwarte połączenie Dim sqlcmd As New SqlCommand(sql1 & sql2, conn) ' deklarujemy obiekt typu DBReader i wypełniamy go danymi ' poprzez wywołanie metody ExecuteReader obiektu OleDBCommand Dim sqlreader = sqlcmd.executereader ' czytamy obieky oledbreader Dim i As Integer, txt As String, j As Integer = 1 While sqlreader.read txt = "Rekord nr " & j.tostring & ": " For i = 0 To sqlreader.fieldcount - 1 txt &= sqlreader.item(i) & "; " Next MsgBox(txt.Substring(0, txt.length - 2), _ MsgBoxStyle.Information, "Tabela Klienci") j += 1 End While

66 66 ' urucgamiamy pobranie rekordsetu z drugiego polecenia sqlreader.nextresult() ' bedziemy czytać rekordy, ustawiamy zmienną j na 1 j = 1 While sqlreader.read txt = "Rekord nr " & j.tostring & ": " For i = 0 To sqlreader.fieldcount - 1 txt &= sqlreader.item(i) & "; " Next MsgBox(txt.Substring(0, txt.length - 2), _ MsgBoxStyle.Information, "Tabela RodzajSal") j += 1 End While sqlcmd = Nothing MsgBox("Wszystkie rekordy odczytane z obu tabel", _ MsgBoxStyle.Information, _ "Ilustaracja metod Read i NextResult obiektu DataReader") Catch ex As Exception MsgBox("Problem z wykonaniem polecenia", _ MsgBoxStyle.Critical, _ "Ilustaracja metod Read i NextResult obiektu DataReader") Finally conn.close() conn = Nothing End Try End Sub Metoda GetSchemaTable W momencie utworzenia obiektu DataReader na podstawie zapytania przekazanego do obiektu Command możemy pobrać informacje o kolumnach tego zapytania poprzez wywołanie metody GetSchemaTable. Metoda ta zwraca obiekt typu DataTable, który zawiera tyle wierszy, ile jest zwracanych w zapytaniu. Z pomocą zagnieżdżonych pętli For Each można przejrzeć kolekcję wierszy i kolumn obiektu DataTable odczytując nazwy właściwości poszczególnych kolumn tabeli bazy danych, do których odnosi się zapytanie oraz ich wartości. Poniżej kod przykładowej procedury zaimplementowanej w formularzu frmoledbdatareader jako reakcji na klik przycisku btngetschematable). Imports System.Data.SqlClient Private Sub btngetschematable_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btngetschematable.click ' dekarujemy i tworzymy obiekt typu SqlConnetion Dim conn As New SqlConnection(strconnSqL) ' reszta operacji może spowodować błąd, dlatego umieszcamy je w Try-Catch Try

67 67 ' otwieramy połączenie conn.open() ' deklarujemy i tworzymy obiekt typu sqlcommand ' przekazując do niego zapytanie SQL oraz otwarte połączenie Dim sqlcmd As New SqlCommand("select * from Klienci", conn) ' deklarujemy obiekt typu DBReader i wypełniamy go danymi ' poprzez wywołanie metody ExecuteReader obiektu OleDBCommand Dim sqlreader = sqlcmd.executereader ' tworzymy obiekt DataTable i pobieramy schemat tabeli Dim schematable As DataTable = sqlreader.getschematable() pomocnicze zmienne dla odczytania schematu Dim row As DataRow Dim column As DataColumn ' przeglądamy wiersz po wierszu obiekt DataTable ' każdy wiersz opisuje jedną kolumnę tabeli bazy danych For Each row In schematable.rows Dim txt As String = "" For Each column In schematable.columns txt &= column.columnname & ",: " & _ row(column).tostring & vbcrlf Next MsgBox(txt) Next sqlreader.close() Catch ex As Exception MsgBox("Problem z wykonaniem polecenia", MsgBoxStyle.Critical, _ "Ilustracja metody GetSchemaTable DataReader") Finally conn.close() conn = Nothing End Try End Sub 6.6. Obiekt DataAdapter Obiekt DataAdapter zabezpiecza komunikację między obiektem DataSet i źródłem danych (DataSource). DataAdapter pozwala, dzięki metodzie Fill, na dostarczenie danych do obiektu DataSet (dokładniej do obiektu DataTable, który jest tworzony w DataSet). Inne metody obiektu DataAdapter pozwalają także na komunikację odwrotną, czyli na wprowadzanie, aktualizację czy usuwanie danych w źródle (w DataSource) DataAdapter, polecenie Select Poniżej fragment kodu realizującego zadanie pobrania danych ze źródła i umieszczeniu ich w obiekcie typu DataSet.

68 68 Imports System.Data.SqlClient ' inne potrzebne instrukcje Dim conn As New SqlConnection(strconn) Dim ds As New DataSet, i As Integer Try conn.open() Dim adapter As New SqlDataAdapter("select * from Klienci", _ conn) adapter.fill(ds) For i = 0 To ds.tables(0).rows.count - 1 MsgBox(ds.Tables(0).Rows(i).Item(1)) Next Catch ex As Exception MsgBox(ex.ToString) Finally conn.close() conn = Nothing End Try DataAdapter, polecenia modyfikujące Poniżej fragment kodu procedury, której zadaniem jest wprowadzenie rekordu do tabeli WykazSal, która zawiera trzy pola: ids jako pole typu integer z automatyczną inkrementacją o jeden (jest kluczem tej tabeli), NrSali, pole typu tekstowego (string) o długości do 5 znaków oraz LiczbaMiejsc, pole typu integer. Imports System.Data.SqlClient Private Sub WprowadzRekord(ByVal strconn As String, _ ByVal txtnumer As String, ByVal Miejsc As Integer) Dim conn As New SqlConnection(strconn) Dim adapter As New SqlDataAdapter Dim sql As String sql = "Insert into WykazSal (NrSali, LiczbaMiejsc) values( " & _ NrSali & ", " & LiczbaMiejsc & ")" Try conn.open() adapter.insertcommand = New SqlCommand(sql, conn) adapter.insertcommand.executenonquery() MsgBox("Wiersz wstawiony") Catch ex As Exception MsgBox(ex.ToString) Finally conn.close() conn = Nothing End Try End Sub

69 DataAdapter i CommandBuilder 69 Z obiektem DataAdapter wykonującym zapytanie wybierającje wszystkie pola z danej tabeli (czyli polecenie select) współpracuje obiekt CommandBuilder, który potrafi wygenerować polecenia delete, update i insert na podstawie zapytania wybierającego. Wygenerowane zapytania aktualizujące można wykorzystać do aktualizacji danych w źródle danych. Poniżej fragment kodu ilustrujący takie działanie. Imports System.Data.OleDb Dim conn As New OleDbConnection(constring) Dim oledbcmdbuilder As OleDbCommandBuilder Dim ds As New DataSet, i As Integer Try conn.open() Dim oledbadapter As New OleDbDataAdapter( _ select * From Pracownicy, conn) oledbcmdbuilder = New OleDbCommandBuilder(oleDbAdapter) oledbadapter.fill(ds) With ds.tables(0) For i = 0 To.Rows.Count - 1.Rows(i).Item(2) &= ".pl" Next End with oledbadapter.update(ds.tables(0)) MsgBox("Adresy mailowe uzupełnione") Catch ex As Exception MsgBox(ex.ToString) Finally conn.close() conn = Nothing End Try 6.7. Procedury przechowywane SQL Bardzo silną stroną serwera SQL jest możliwość zaprojektowania w bazie danych utworzonej na tym serwerze zapytania napisanego w języku Transact-SQL, które następnie jest kompilowane i dopiero w takiej postaci wykonywane. Fakt komilacji zapytania znakomicie przyspiesza jego wykonanie i to jest pierwsza korzyść z procedur przechowywanych. Inna, nie mniej ważna związana jest z bezpieczeństwem bazy danych, a związana jest z faktem, że można tak skonfigurować uprawnienia, aby możliwość manipulowania danymi była jedynie za pośrednictwem procedur przechowywanych. Dzięki temu nie ma żadnej możliwości wykonania jawnego kodu SQL. Procedura przechowywana może być różnego typu, zarówno wybierająca jak i akcyjna. Z reguły będziemy wykorzystywać procedury z argumentami, zarówno wchodzącymi jak i wychodzącymi. Mogą się także zdarzyć procedury bezargumentowe, raczej wybierające niż akcyjne.

70 Procedura bezargumentowa Powiedzmy, że w bazie danych, do której będziemy się odwoływać istnieje tabela Klienci. Powiedzmy dalej, że chcemy z niej odczytać identyfikator klienta oraz jego nazwę. Procedura przechowywana może mieć następującą konstrukcję: Create procedure dbo.ppobierzdane As Select idk, Nazwa From Klienci order by Nazwa Po stronie aplikacji (VB.NET) pobranie tych danych i przypisanie ich jako źródło danych do obiektu typu ComboBox tak, aby pole Nazwa było wyświetlane w rozwijanej liście, a pole idk było zwracane po wybraniu nazwy klienta w liście może być zrealizowane za pomocą niżej pokazanych instrukcji. Imports System.Data.SqlClient Dim conn As New SqlConnection(strconn) Dim cmd As New SqlCommand ' deklarujemy i tworzymy instancję obiektu dataset Dim ds As New DataSet Dim i As Integer ' reszta działań może spowodować błądm stąd użycie bloku ' Tray-Catch Try conn.open() ' przypisanie do właściowości Connection obiektu cmd ' otwartego połączenia cmd.connection = conn ' określenie typu polecenia cmd.commandtype = CommandType.StoredProcedure ' podanie nazwy procedury przechowywanej cmd.commandtext = "dbo.ppobierzdane" ' przygotowania do odebrania danych, które zwróci procedura ' deklarujemy obiekt typu DataReader Dim dr As SqlDataReader ' poprzez wywołanie metody ExecuteReader dostarczamy dane ' do DataReader dr = cmd.executereader ' deklarujemy i tworzymy obiekt typu Dataset Dim dt As New DataTable ' wywołujemy metodę Load utworzonego obiektu wskazując jako ' źródło danych obiekt dr (DataReader) dt.load(dr) ' tworzymy źródło danych dla cboklienci (ComboBox) With Me.cboKlienci.DataSource = dt.displaymember = Nazwa.ValueMember = idk End With

71 71 Catch ex As Exception MsgBox(ex.ToString) Finally conn.close() conn = Nothing End Try Procedura z parametrami Tak jak wspomniałem wcześniej w większości przypadków procedura przechowywana będzie posiadała parametry (argumenty). Przy jej wywoływaniu z aplikacji musimy utworzyć kolekcję parametrów. Dla każdego z nich musimy określić takie elementy jak nazwa parametru, jego typ, kierunek, rozmiar czy wartość. Powiedzmy, że mamy inną procedurę w naszej bazie, ta również zwraca klientów, ale będziemy ich dodatkowo rozróżniać z uwagi na wartość pola StatusKlienta, jest to pole typu integer. Create procedure int As Select idk, Nazwa From Klienci where StatusKlienta order by Nazwa Poniżej pokazany jest fragment kodu wywołujący tę procedurę, zwrócony zestaw rekordów będzie źródłem danych dla formantu typu ListBox. Użytkownikowi pokażemy nazwę klienta (pole Nazwa), po wyborze pozycji z listy chcemy otrzymać wartość pola idk. Będziemy pobierali listę tych klientów, dla których pole StatusKlienta ma wartość np. 2. Imports System.Data.SqlClient Dim conn As New SqlConnection(strconn) Dim cmd As New SqlCommand ' deklarujemy i tworzymy instancję obiektu dataset Dim ds As New DataSet Dim i As Integer ' reszta działań może spowodować błądm stąd użycie bloku ' Tray-Catch Try conn.open() ' przypisanie do właściowości Connection obiektu cmd ' otwartego połączenia cmd.connection = conn ' określenie typu polecenia cmd.commandtype = CommandType.StoredProcedure ' podanie nazwy procedury przechowywanej cmd.commandtext = "dbo.ppobierzdane" ' zerujemy kolekcję parametrów

72 72 cmd.parameters.clear() ' deklarujemy nowy parametr Dim param As SqlParameter param = New SqlParameter("@idk", SqlDbType.Int, 0) param.value = 2 ' określamy, czy parametr jest wchodzący czy wychodzący param.direction = ParameterDirection.Input ' dodajemy utworzony parametr do kolekcji parametrów cmd.parameters.add(param) Dim dr As SqlDataReader dr = cmd.executereader Dim dt As New DataTable dt.load(dr) ' tworzymy źródło danych dla lstklienci (ListBox) With Me.lstKlienci.DataSource = dt.displaymember = Nazwa.ValueMember = idk End With Catch ex As Exception MsgBox(ex.ToString) Finally conn.close() conn = Nothing End Try W aplikacji ADOAndADONET zainteresowany Czytelnik znajdzie wiele przykładów wykorzystania modelu ADO.NET jak i starszego modelu ADO do przetwarzania informacji zgromadzonych w bazach danych Klasa CForStorageSub Klasa CForStorageSub została pomyślana jako zestaw procedur ułatwiających dostęp do procedur przechowywanych SQL, zwłaszcza parametrycznych. Klasa ta będzie wykorzystywana jako klasa bazowa do projektowania klas potomnych znajdujących zastosowanie w tworzonych aplikacjach windowsowych. Standardowo klasa ta powinna być wykorzystywana poprzez bibliotekę DLL, a nie jawny kod klasy. W takich sytuacjach w aplikacji musimy tylko i wyłącznie wskazać w referencjach adres pliku CForStorageSub.dll, bez potrzeby dołączania do rozwiązania pełnego kodu tej klasy. Na potrzeby tego opracowania w aplikacji ADOAndADONET włączony został plik kodu tej klasy, czyli CForStorageSub.vb.

73 Deklaracja zmiennych i prywatnych procedur klasy W kodzie klasy CForStorageSub zaimportowano dwie ważne przestrzenie nazw, co jest konieczne w przypadku odwoływania się do serwera MS SQL. Imports System.Data Imports System.Data.SqlClient Kod klasy rozpoczyna się od zadeklarowania wyliczenia o nazwie jgtyp, jego zadaniem jest umożliwienie symbolicznego określania typu parametru. Rozwiązanie to ma nam umożliwić określenie typu np. parametru tekstowego poprzez wartość jgstring a nie jej odpowiednik 5. Dodatkowo będziemy mogli tę potrzebną wartość wybrać z okienka podpowiedzi. Specyfikator dostępu Protected jest po to, aby to wyliczenie było dostępne w klasie potomnej. Public Class CForStorageSub ' wyliczenie na potrzeby określania typu parametrów Protected Enum jgtyp As Integer jginteger = 1 jgchar = 2 jgmoney = 3 jgdata = 4 jgstring = 5 jgbit = 6 jgsingle = 7 End Enum Prywatna procedura pzbudujparametr odpowiada za zbudowanie parametru i dodanie go do kolekcji parametrów polecenia (obiektu Command). Procedura otrzymuje kolejno obiekt Command, nazwę parametru, jego typ, rozmiar oraz opcjonalnie wartość parametru. Private Sub pzbudujparametr(byval pol As SqlCommand, _ ByVal naz As String, ByVal typ As Integer, _ ByVal roz As Integer, Optional ByVal war As Object = _ Nothing) Dim prm As New SqlParameter, jaki As Boolean If IsNothing(war) Then jaki = False Else jaki = True End If With prm.parametername = naz If jaki Then.Direction = ParameterDirection.Input Else.Direction = ParameterDirection.Output End If

74 74 Select Case typ Case 1 ' integer.sqldbtype = SqlDbType.Int If jaki Then If IsDBNull(war) Then.Value = war Else.Value = CInt(war) End If End If Case 2 ' znak.sqldbtype = SqlDbType.Char.Size = roz If jaki Then.Value = war Case 3 ' waluta.sqldbtype = SqlDbType.Money If jaki Then If IsDBNull(war) Then.Value = war Else.Value = CDec(war) End If End If Case 4 ' data.sqldbtype = SqlDbType.DateTime If jaki Then If IsDBNull(war) Then.Value = war Else.Value = CDate(war) End If End If Case 5 'varchar.sqldbtype = SqlDbType.NVarChar.Size = roz If jaki Then.Value = war Case 6 'bit.sqldbtype = SqlDbType.Bit If jaki Then If IsDBNull(war) Then.Value = war Else.Value = CBool(war) End If End If Case 7 'single.sqldbtype = SqlDbType.Float If jaki Then If IsDBNull(war) Then

75 75.Value = war Else.Value = CSng(war) End If End If End Select End With pol.parameters.add(prm) prm = Nothing End Sub Prywatna funkcja klasy fprzygotujcmd odpowiada za przygotowanie obiektu Command do wykonania procedury przechowywanej. Jako argumenty otrzymuje obiekt Command (przez referencję), nazwę procedury przechowywanej, identyfikator określający czy procedura zwraca jakiś parametr oraz listę parametrów z ich właściwościami przekazaną jako tablica P() typu Object (typ ogólny). Private Function fprzygotujcmd(byref cmd As SqlCommand, _ ByVal sp_nazwa As String, ByVal out As Boolean, _ ByVal Par() As Object) As Integer Dim i, ip As Integer, u As Integer = 0 cmd.commandtext = sp_nazwa cmd.commandtype = CommandType.StoredProcedure ip = 0 If UBound(Par) > 0 Then If out Then u = 1 For i = 1 To CInt((UBound(Par) + 1) / 4) - u ip = (i - 1) * 4 pzbudujparametr(cmd, CStr(Par(0 + ip)), CInt(Par(2 + ip)), _ CInt(Par(3 + ip)), (Par(1 + ip))) Next i If out Then ip = (i - 1) * 4 pzbudujparametr(cmd, CStr(Par(0 + ip)), _ CInt(Par(1 + ip)), CInt(Par(2 + ip))) End If End If Return ip End Function Kilka wybranych metod publicznych Publiczna funkcja DajRekordset odpowiada za wykonanie procedury przechowywanej zwracającej zestaw rekordów z bazy danych (rekordset). Zwracany jest obiekt typu DataSet. Do funkcji przekazujemy otwarte połączenie, nazwę procedury oraz tablicę parametrów.

76 76 Protected Function DajRekordset(ByVal conn As SqlConnection, _ ByVal sp_nazwa As String, _ ByVal ParamArray Par() As Object) As DataTable Dim cmd As SqlCommand, ip As Integer cmd = New SqlCommand ip = fprzygotujcmd(cmd, sp_nazwa, False, Par) cmd.connection = conn Dim dr As SqlDataReader dr = cmd.executereader Dim dt As New DataTable dt.load(dr) cmd = Nothing DajRekordset = dt End Function Publiczna funkcja DajWartosc odpowiada za wykonanie procedury przechowywanej, której zadaniem jest zwrócenie pojedynczej wartości. Zwracana jest wartość typu Object. Protected Function DajWartosc(ByVal conn As SqlConnection, _ ByVal sp_nazwa As String, _ ByVal ParamArray Par() As Object) As Object Dim cmd As SqlCommand, ip As Integer cmd = New SqlCommand ip = fprzygotujcmd(cmd, sp_nazwa, True, Par) cmd.connection = conn cmd.executenonquery() DajWartosc = cmd.parameters(par(0 + ip).tostring).value cmd = Nothing End Function Publiczna funkcja Wykonaj odpowiada za wykonanie procedury przechowywanej typu wykonawczego (czyli Insert, Delete, Update). Zwraca liczbę rekordów zmodyfikowanych. Protected Function Wykonaj(ByVal conn As SqlConnection, _ ByVal sp_nazwa As String, _ ByVal ParamArray Par() As Object) As Integer Dim cmd As SqlCommand, ip As Integer cmd = New SqlCommand ip = fprzygotujcmd(cmd, sp_nazwa, False, Par) cmd.connection = conn Wykonaj = cmd.executenonquery cmd = Nothing End Function Publiczna metoda UpdateWieleRekordow została tak zaprojektowana, aby zoptymalizować aktualizację wielu rekordów. Zauważono, że przy aktualizacji wielu rekordów mamy taki sam zestaw parametrów co do ich nazwy, typu oraz rozmiaru. Jedyna

77 77 zmienna rzecz to ich wartość. To spostrzeżenie doprowadziło do rozdzielenia etapu tworzenia kolekcji parametrów od przypisywania im określonej wartości. Protected Sub UpdateWieleRekordow(ByVal conn As SqlConnection, _ ByVal sp_nazwa As String,ByVal dgvzrodlo As DataGridView, _ ByVal KtoreRekordy() As Boolean, ByVal ParamArray Par() As Object) ' macierz Par() dla każdego z parametrów określa kolejno: nazwę ' parametru, jego typ, rozmiar, nr kolumny gridu skąd będzie ' pochodzić wartość Dim cmd As SqlCommand, ip, i, j As Integer cmd = New SqlCommand cmd.commandtext = sp_nazwa cmd.commandtype = CommandType.StoredProcedure ip = 0 ' tworzymy kolekcję parametrów (bez wartości: nazwa, typ, rozmiar For i = 1 To CInt((UBound(Par) + 1) / 4) ip = (i - 1) * 4 'tworzymy instancję parametru Dim prm As New SqlParameter With prm.parametername = CStr(Par(0 + ip)).direction = ParameterDirection.Input.SqlDbType = Choose(Int(Par(1 + ip)), SqlDbType.Int, _ SqlDbType.Char, SqlDbType.Money, SqlDbType.Date, _ SqlDbType.NVarChar, SqlDbType.Bit, SqlDbType.Float) End With ' trzy elementy parametru są określone (nie ma wartości ' (będzie później), dodajemy parametr do kolekcji cmd.parameters.add(prm) prm = Nothing Next i ' kolekcja zbudowana, wartości będą ustawiane w pętli Dim war As Object, k As Integer cmd.connection = conn For i = 0 To dgvzrodlo.rows.count - 1 If KtoreRekordy(i) Then ' potrzebny update ' ustawiamy wartości poszczególnych parametrów For j = 0 To cmd.parameters.count - 1 k = CInt(Par(j * 4 + 3)) war = dgvzrodlo.rows(i).cells(k).value Select Case Int(Par(j * 4 + 1)) ' w zależności od typu ustalamy sposób konwersji jego wartości Case jgtyp.jginteger If IsDBNull(war) Then cmd.parameters(j).value = war Else

78 78 cmd.parameters(j).value = CInt(war) End If Case jgtyp.jgchar cmd.parameters(j).value = war Case jgtyp.jgmoney If IsDBNull(war) Then cmd.parameters(j).value = war Else cmd.parameters(j).value = CDec(war) End If Case jgtyp.jgdata If IsDBNull(war) Then cmd.parameters(j).value = war Else cmd.parameters(j).value = CDate(war) End If Case jgtyp.jgstring cmd.parameters(j).value = war Case jgtyp.jgbit If IsDBNull(war) Then cmd.parameters(j).value = war Else cmd.parameters(j).value = CBool(war) End If Case jgtyp.jgsingle If IsDBNull(war) Then cmd.parameters(j).value = war Else cmd.parameters(j).value = CSng(war) End If End Select Next ' wartości parametrów ustawione, wykonujemy procedurę cmd.executenonquery() End If Next cmd = Nothing End Sub 6.9. Transakcje Transakcja to jedno z ważniejszych pojęć w dostępie do relacyjnych baz danych. Pod tym pojęciem rozumiemy taki mechanism SZRBD, który pozwala na traktowanie jednej lub więcej operacji na bazie danych jako całość. Transakcja pozwala na kontrolowanie, czy kilka powiązanych z sobą operacji zostało pomyślnie wykonanych, jeżeli tak, to operacje te zostają zatwierdzone, a jeżeli nie, to wszystkie zmiany dokonane w bazie zostają odrzucone.

79 79 Prześledzimy ten problem na przykladzie projektu obsługującego sprzedaż, jest w nim utworzony formularz frmsprzedaz, który obsługuje operacje sprzedaży produktów spożywczych nabywcom. Po wyborze nabywcy oraz produktów, które zostały zadysponowane do sprzedaży operacja sprzedaży musi być zarejestrowana w bazie danych. Kolejno muszą być wykonane trzy operacje: 1. Wstawiony rekord do tabeli Sprzedaz bazy danych Fifo ze zwróceniem identyfikatora sprzedaży (wstawiamy identyfikator nabywcy oraz datę sprzedaży); 2. Wstawienie do tabeli SprzedazDetale tyle rekordów, ile produktów zostało zakupionych (dokładniej tyle, ile ich zostało rozdysponowanych po uwzględnieniu terminu przydatności do spożycia); 3. Aktualizacja stanów magazynowych w tabeli Dostawy. Wszystkie te trzy operacje muszą być wykonane pomyślnie, aby całość rejestracji zakupu w bazie danych można było uznać za zakończoną sukcesem. Pierwsza z operacji wymienionych wyżej realizowana jest poprzez procedurę przechowywaną SQL o nazwie pwstawsprzedaz, której kod pokazany jest niżej. Porcedura wstawia nowy rekord do tabeli Sprzedaz (będzie on identyfikował fakturę), a po wykonaniu tej czynności zwraca identyfikator wstawionego rekordu. Będzie on potrzebny do wstawienia rekordów do tabeli SprzedazDetale. create procedure int out as insert into dbo.sprzedaz (ido, DataS) values Dwa ostatnie zadania realizuje jedna procedura przechowywana SQL o nazwie pwstawdetalesprzedazy, jej kod pokazany jest niżej. Pierwsza instrukcja wstawia rekord do tabeli SprzedazDetale, a druga modyfikuje stan magazynowy. create procedure money as insert into dbo.sprzedazdetale (ids, idd, idp, ileopakowan, wartoscnetto) update dbo.dostawy set Pozostalo = Pozostalo where id=@idd Po stronie interfejsu aplikacji obsługującej bazę danych procedury te są wywoływane w metodzie ZapiszSprzedaz klasy CSprzedaz. Metoda ta dostaje jako argument łańcuch połączenia do bazy danych oraz instancję formularza frmsprzedaz, co daje nam dopstęp do jego formantow. Działania na bazie danych muszą być wykonywane pod kontrolą transakcji, zadanie to realizują dwie metody klasy bazowej dla

80 80 klasy CSprzedaz, czyli klasy CForStorageSub. Przed ich wywołaniem definiowany jest obiekt klasy SqlTransaction oraz SqlCommand wraz ze zdefiniowaniem ich właściwości. Public Sub ZapiszSprzedaz(ByVal strconn As String, ByVal frm As _ frmsprzedaz) Implements ISprzedaz.ZapiszSprzedaz Dim conn As New SqlConnection(strConn), ids, i As Integer Dim sqltran As SqlTransaction Try conn.open() ' tworzymy obiekt SqlTransaction sqltran = conn.begintransaction() 'tworzymy obiekt SqlCommand Dim cmd As New SqlCommand cmd.connection = conn cmd.transaction = sqltran ' zapisujemy identyfaktor odbiorcy do tabeli Sprzedaz ids = MyBase.InsertDajIdWithTrans(cmd, "dbo.pwstawsprzedaz", _ "@ido", frm.cbonabywca.selectedvalue, jgtyp.jginteger, 0, _ "@datas", Now().ToShortDateString, jgtyp.jgdata, 0, _ ' w pętli wstawiamy dane z dgvdlamagazynu oraz modyfikujemy ' stan magazynowy With frm.dgvdlamagazynu For i = 0 To.Rows.Count - 1 MyBase.InsertWithTrans(cmd, _ "dbo.pwstawdetalesprzedazy", _ "@ids", ids, jgtyp.jginteger, 0, _ "@idd",.rows(i).cells(1).value, jgtyp.jginteger, 0, _ "@idp",.rows(i).cells(5).value, jgtyp.jginteger, 0, _ "@ileop",.rows(i).cells(4).value, jgtyp.jginteger, _ 0, _ "@cenaop",.rows(i).cells(6).value, jgtyp.jgmoney, 0) Next End With ' jeżeli program został wykonany do tego miejsca, to ' zatwierdzamy transakcje sqltran.commit() cmd = Nothing MsgBox("Operacja zakupu zarejestrowana w bazie", _ MsgBoxStyle.Information, "Rejestracja sprzedaży") ' przygotowanie formularza do nowej rejestracji For i = frm.dgvdlamagazynu.rows.count - 1 To 0 Step -1 frm.dgvdlamagazynu.rows.removeat(i) Next ' For i = frm.dgvkoszyk.rows.count - 1 To 0 Step -1 frm.dgvkoszyk.rows.removeat(i) Next frm.txtnetto.text = vbnullstring

81 frm.txtrazem.text = vbnullstring Catch ex As Exception ' jeżeli wystąpił błąd po otwarciu połączenia, to trzeba ' wycofać transakcje If conn.state = ConnectionState.Open Then sqltran.rollback() End If mkomunikat = "Błąd rejestracji zakupu, operacja analowana" Finally conn.close() conn = Nothing End Try End Sub 81

82 82 7. Aplikacja ADOandADONET Aplikacja została przygotowana w celu zademonstrowania podstawowych metod modelu ADO.NET oraz jego poprzednika ADO w zakresie dostępu do baz danych typu MS Access oraz MS SQL Server Wykorzystywane źródła danych. Aplikacja korzysta z bazy danych TestSP.mdb zawierającej trzy przykładowe tabele o nazwach Studenci, Pracownicy i Przedmioty. Definicje tych tabel pokazane są niżej. Dla zademonstrowania współpracy z bazą SQL wykorzystywana będzie tabela o nazwie Klienci i definicji jak niżej. Tabela ta może być umieszczona w dowolnej bazie danych na lokalnym czy zdalnym serwerze MS SQL Server. Istotne jest, abyśmy mieli prawo modyfikowania danych w tej tabeli. Będziemy także korzystać z trzech procedur przechowywanych, ich definicje pokazane są niżej. Pierwsza z nich pobiera wszystkie dane z tej tabeli (instrukcją select), druga wykonuje instrukcję update (aktualizacji), a ostatnia odpowiada za wstawienie danych nowego klienta (instrukcja insert). Create procedure [dbo].[pdajdaneklientow] as select * from dbo.klienci order by Nazwa

83 83 Create procedure nvarchar(100) as update dbo.klienci set where Create procedure int out as insert into dbo.klienci (Nazwa, Adres, NIP, mail, telefon, @osoba) 7.2. Struktura aplikacji Aplikacja została zaprojektowana jako wieloformularzowa, zawiera formularz główny o nazwie frmmdiform, będzie on pełnił rolę kontenera dla pozostałych formularzy. Dodano do niego formant MenuStrip w celu zbudowania menu aplikacji. Poniżej widok projektu tego formularza z projektem menu. Jako główne pozycje w pasku menu umieszczono: SQL będzie zawierał polecenia związane z wykorzystaniem modelu ADO.NET do współpracy z bazą MS SQL Server; OLEDB tu będą zgromadzone polecenia demonstrujące różne aspekty wykorzystania modelu ADO.NET do manipulowania danymi przykładowej bazy danych (TestSP.mdb);

84 84 ADO (COM) dwa polecenia podrzędne w tej grupie pokażą jak można korzystać z starego modelu ADO do uzyskiwania informacji o strukturze bazy danych (o tabelach i polach wybranej tabeli). Będzie tu także pokazany sposób dynamicznego zbudowania formularzy ekranowych dla tabeli o nieznanej wcześniej strukturze (w pewnym sensie jako ciekawostka programistyczna). Do rozwiązania dodano plik modułu wspólnego o nazwie ADOWspolny.vb, będzie on zawierał deklaracje stałych i zmiennych o charakterze publicznym dla projektu, czyli takich, które muszą być dostępne dla pozostałych klas wykorzystywanych w tym rozwiązaniu. W projekcie umieszczono autorską klasę CForStorageSub zawierającą szereg metod ułatwiających dostęp do procedur przechowywanych oraz klasę CTestSQL jako jej klasę pochodną. Instancje klasy CTestSQL będą odpowiedzialne za wykonanie poleceń związanych z pozycją SQL w menu aplikacji. Klasa CMojeOle definiuje metody i właściwości związane z wykonywaniem poleceń związanych z pozycją OLEDB w menu aplikacji Dodatkowe referencje. Z uwagi na zamiar wykorzystywania modelu ADO musimy dodać do naszego rozwiązania referencje do odpowiednich bibliotek (jak pokazano niżej).

85 85 Po ich dodaniu lista referencji naszego rozwiązania powinna wyglądać tak, jak jest to pokazane niżej (ważne, aby były tam dwie pokazane wcześniej pozycje: adodb oraz Microsoft ADO Ext. 6.0 for DDL and security).

86 Moduł wspólny Jak wspomniałem wcześniej mamy tu deklaracje stałych i zmiennych publicznych, czyli takich, które muszą być dostępne we wszystkich innych obiektach tej aplikacji Klasa CMojeOle Klasa ta przeznaczona jest do obsługi baz danych typu MS Access, dlatego pierwsze jej dwie instrukcje importują odpowiednie przestrzenie nazw. W kodzie klasy zadeklarowano trzy zmienne prywatne, będą one wykorzystywane przez metody tej klasy. Widoczny jest także konstruktor bezparametrowy tej klasy. Kolejny konstruktor (procedura publiczna o nazwie New) odpowiada za połączenie ze źródłem danych wskazanym informacją zawartą w argumencie strconn oraz wykonanie polecenia SQL przekazanego argumentem strsql.

87 87 Kolejny konstruktor New będzie odpowiadał za powiązanie formularza zawierającego etykiety i pola tekstowe odpowiadające konkretnej tabeli bazy danych z danymi pobranymi z tej tabeli. Zakładamy, że nazwy pól tekstowych odpowiadających polom tej tabeli zaczynają się od prefiksu txt, jest to bardzo ważne, jeżeli mamy je powiązać z danymi (inaczej będzie błąd czasu wykonania). Z tego warunku wynika także ograniczenie na nazwy pól bazy danych nazwy te nie mogą zawierać spacji!.

88 88 Kolejny konstruktor będzie tworzył instancję klasy CMojeOle wykorzystywaną do pobrania ze źródła danych informacji, które mają być dostarczone do formantu typu ListBox jako jego źródło danych z jednoczesnym wskazaniem, jakie informacje mają być widoczne dla użytkownika oraz jaka informacja ma być zwrócona w momencie kliku danej pozycji listy. Z reguły w formularzu zawierającym formanty typu ListBox, ComboBox czy CheckedListBox tworzona jest procedura umożliwiające pobranie informacji o wskazanej przez użytkownika pozycji. Procedura taka obsługuje zdarzenie SelectedIndexChange, a jest wywoływana nie tylko w momencie kliku wybranej pozycji, lecz także w momencie definiowania źródła danych takiego formantu. W celu zablokowania takiej niepożądanej reakcji wykorzystamy zmienną publiczną flaga ustawiając jej wartość na False na czas definiowania źródła danych.

89 89 W klasie CMojeOle utworzyłem jeszcze jeden konstruktor, instancja klasy utworzona z jego pomocą buduje obiekt typu DataTable będący połączeniem dwóch tabel. Konstruktor został wymyślony po to, aby można było uzyskać źródło danych dla formantu typu ComboBox, gdzie na pierwszej pozycji będzie pozycja opisująca symbolicznie wszystkie pozostałe pozycje. Z reguły polega to na umieszczeniu na początku listy informacji typu (wszystko) czy (uwzględniając wymogi języka polskiego) (wszyscy) lub (wszystkie). Wybranie takiej pozycji jest wtedy odpowiednikiem zapytania select lista_kolumn from nazwa_tabeli. Z kolei wybranie innej pozycji jest odpowiednikiem zapytania jak wyżej, ale uzupełnionego warunkiem where. Przedstawiony niżej konstruktor realizuje przygotowanie odpowiedniego źródła danych. Przy okazji jego kod pokazuje, jak można manipulować takim obiektem jak DataTable poprzez dodawanie nowych kolumn i wierszy, a także dołączenie do jednej tabeli innej tabeli o takiej samej strukturze.

90 90 Uzupełnieniem kodu klasy CMojeOle są jeszcze trzy procedury typu Property zwracające wartości wybranych zmiennych prywatnych.

91 91 Poniżej widok diagramu UML klasy CMojeOle, jest na nim widoczna metoda o nazwie MergeDataTable, została ona zastąpiona przez ostatni z przedstawionych konstruktorów jako bardziej uniwersalne rozwiązanie. W grupie Methods widzimy informację o konstruktorach, o tym, że istnieje w sumie pięć konstruktorów (czyli mamy do czynienia z przeciążeniem metod).

92 Opis pozycji OLEDB w menu Adapter Wskazana pozycja menu otrzymała nazwę mnuapapterpracownicy, a jej klik spowoduje wykonanie pokazanej niżej procedury. Procedura deklaruje i tworzy nowy egzemplarz formularza frmoleadaptercmdb. W kolejnej instrukcji do zmiennej publicznej strcostam przypisywane jest zapytanie wybierające z tabeli Pracownicy wszystkie rekordy zawierające komplet pól. Treść tego zapytania jest także przypisywana do tytułu utworzonego formularza. Ostatnie dwie instrukcje określają formularz nadrzędny dla utworzonego formularza oraz nakazują jego wyświetlenie. Formularz frmoleadaptercmd jest stosunkowo prosty w sensie użytych formantów, zawiera bowiem tylko dwa formanty o nazwach: dane; dgvdane formant typu DataGridView, będziemy w nim wyświetlać pobrane btnaktualizuj przycisk polecenia, jego klik wywoła procedurę zdarzeniową odpowiedzialną za aktualizację danych.

93 93 Znacznie ciekawszy jest kod tego formularza. Klik przycisku btnaktualizuj uruchamia poniższą procedurę.

94 94 A tak wygląda ten formularz w trakcie pracy, do ostatniego wiersza w polu Adres dopisano dwa końcowe znaki. Klik przycisku Aktualizuj zmodyfikował dane w bazie danych DataReader Polecenia zebrane w tej pozycji menu demonstrują sposób pobrania danych z bazy w celu zbudowania źródła danych dla takiego formantu jak ListBox (analogicznie będzie dla ComboBox). Klik podpozycji Studenci (nazwa mnudrstudenci) uruchamia poniższą procedurę (w frmmdiform.vb).

95 95 Pierwsza instrukcja tej procedury deklaruje i tworzy nowy egzemplarz formularza o nazwie frmoledatareader. Formularz ten zawiera jeden formant typu ListBox o nazwie cbopracownik. Do zmiennej globalnej strcostam przypisywane jest zapytanie zwracające dwie kolumny danych, pierwsza z nich zwraca identyfikator studenta, drugie kombinację dwóch pól (nazwisko i imię). Istotne są tutaj nazwy tych kolumn, w przypadku pierwszej będzie to nazwa pola, dla drugiej kolumny tworzymy nazwę (tu jest to Kto ). Kolejna instrukcja deklaruje i tworzy nowy egzemplarz klasy CMojeOle wykorzystując odpowiedni kontruktor. W efekcie tworzone i otwierane jest połączenie z bazą danych, za pomocą obiektu DataReader odczytywane są potrzebne dane i przypisywane do formantu listy. Jeżeli wszystko przebiegło poprawnie, to własność Komunikat jest pustym ciągiem znaków. Wykorzystując warunek If Then Else End if badamy, czy operacja pobrania danych i zbudowania źródła danych dla cbopracownik przebiegła poprawnie. Jeżeli tak, to pokazujemy formularz na ekranie, jak nie, to wyświetlamy stosowny komunikat. W kodzie formularza frmoledatareader mamy tylko jedną procedurę, jej zadaniem jest zwrócenie informacji o identyfikatorze wybranej przez użytkownika pozycji listy. Warto zwrócić uwagę na pierwszą instrukcję tej procedury, jest tu badanie, czy zdarzenie ma być obsługiwane czy też nie. Jeżeli zmienna globalna flaga nie jest True, to opuszczamy procedurę.

96 96 Tradycyjnie na zakończenie tego podrozdziału zrzut ekranowy pokazujący pracę tego formularza Przegląd tabel Ta pozycja menu OLEDB daje dostęp do trzech poleceń odpowiedzialnych za wyświetlenie indywidualnie zaprojektowanych formularzy dla tabel Pracownicy, Studenci i Przedmioty. Każdy z tych formularzy wyposażony jest w zestaw przycisków pozwalających na poruszanie się po rekordach tych tabel. Podpozycja Pracownicy w menu Przegląd tabel jest identyfikowana poprzez nazwę mnuppracownicy, a jej klik uruchamia pokazaną niżej procedurę.

97 97 Pierwsza instrukcja tej procedury deklaruje i tworzy instancję (egzemplarz) formularza frmpracownicy (jego projekt będzie pokazany za chwilę). Kolejna instrukcja przypisuje do zmiennej prywatnej sql treść zapytania zwracającego wszystkie rekordy z tabeli Pracownicy. Deklarowany i tworzony jest egzemplarz klasy CMojeOle wykorzystujący jeden z konstruktorów tej klasy. Przekazujemy do niego łańcuch połączenia, treść zapytania oraz utworzony przed chwilą formularz. W klasie nastąpi otwarcie połączenia, pobranie potrzebnych danych, zwrócenie ich do obiektu typu DataSet oraz ustanowienie połączenia między polami tekstowymi formularza a odpowiadającymi im kolumnami w tabeli o nazwie Test w DataSet. Utworzony obiekt DataSet będzie dostępny poprzez właściwość DajDS tej klasy. Jeżeli wszystko przebiegło poprawnie, to zmienna globalna mydataset otrzymuje potrzebny obiekt z instancji klasy, tworzony jest tytuł formularza i na końcu pokazujemy formularz. Gdyby coś poszło nie tak, to zamiast formularza wyświetlany jest stosowny komunikat. Poniżej pokazany jest projekt formularza frmpracownicy.

98 98 Na jego powierzchni umieszczono pola tekstowe (TextBox) odpowiadające polom tabeli Pracownicy. Kolejno są to: txtid tu będzie wyświetlany identyfikator pracownika txtnazwisko jego nazwisko; txtimie i imię; txtadres oraz adres. Pola te poprzedzone są etykietami (Label), których właściwości Text zostały tak skomponowane, aby odpowiadały poszczególnym polom. Poniżej tych formantów umieszczono cztery przyciski o nazwach odpowiednio btnpierwszy, btnnastepny, btnpoprzedni oraz btnostatni. Właściwości Text tych przycisków zostały dostosowane do ich przeznaczenia, którym jest wymuszenie przejścia do wskazanego rekordu. Między tymi przyciskami umieszczono jeszcze jedno pole tekstowe, jego nazwa to NrRekordu (nie może zaczynać się od txt, bo wtedy była by próba skojarzenia tego pola z kolumną w obiekcie DataSet, a takiej kolumny nie ma). W polu tym będziemy wyświetlać numer bieżącego rekordu. W kodzie klasy formularza frmpracownicy znajdziemy wiele ciekawych procedur. Prywatna procedura KtoryRekord ustala, jaki jest numer bieżącego rekordu, a następnie wyświetla go w polu tekstowym NrRekordu. Jej kolejnym zadaniem jest ustalenie, które z przycisków nawigacyjnych mają być dostępne, a które nie. Procedura obsługująca załadowanie formularza wywołuje tylko tę prywatną procedurę KtoryRekord.

99 99 Kolejno budujemy procedury obsługujące poruszanie się po rekordach. Tradycyjnie dwa zrzuty ekranowe tego formularza w pracy.

100 Opis pozycji ADO (COM) w menu Znajdziemy tu dwa polecenia, tak jak pokazano to niżej. Pierwsze z nich jest dostępne i pozwala na wskazanie pliku bazy danych MS Access w wersji 2003 (plik z rozszerzeniem *.mdb), jego otwarcie, pobranie listy tabel, a dla wybranej tabeli listy jej pól. Będziemy także mogli zbudować zapytanie SQL i zobaczyć efekt jego działania. Drugie z poleceń jest chwilo niedostępne, a będzie udostępnione dopiero po wskazaniu pliku bazy danych w pierwszym z pokazanych poleceń. Polecenie to jest ciekawe programistycznie, pokazuje bowiem jak programowo (dynamicznie) można budować formularze Pobieranie tabel i pól, test zapytania Klik tego polecenia powoduje wykonanie pokazanej niżej procedury. Jak widzimy nic ciekawego tu nie, pierwsza instrukcja tworzy instancję klasy formularza frmtestsql, a dwie kolejne odpowiadają za wyświetlenie formularza.

101 101 Formularz frmtestsql jest dość skomplikowany, zawiera dwie listy, pole tekstowe do wyświetlenia treści zapytania, formant typu DataGridView do wyświetlenia wyników zapytania oraz kilka przycisków poleceń i etykiet opisujących niektóre formanty. Projekt formularza wraz z nazwami i przeznaczeniem poszczególnych formantów pokazany jest niżej. lsttabele formant typu ListBox, będzie wyświetlał tabele wybranej bazy danych; lstpola także lista, będą tu pokazywane nazwy pól wybranej tabeli; txtsql pole tekstowe (TextBox), wyświetlimy w nim zapytanie. Jego właściwość Multiline została ustawiona na True, a wysokość formantu na 45 pkt (tak, aby można było pokazać dwa wiersze); dgvdane formant typu DataGridView, tu będziemy prezentować wyniki zapytania; btnaddwhere przycisk polecenia (Button), uruchamia dodanie do zapytania nazwy tabeli i słowa kluczowego Where;

102 102 btnwykonaj przycisk uruchamiający procedurę odpowiedzialną za wykonanie zapytania; btnclearsql przycisk polecenia usuwający wszelkie informacje z pola txtsql. W kodzie klasy tego formularza umieszczono dość dużą liczbę procedur i funkcji odpowiedzialnych za jego funkcjonowanie. Kolejno będę je prezentował. Zaczynamy od zaimportowania niezbędnych przestrzeni nazw (do współpracy z bazą danych MS Access. Pierwszą ważną funkcją w tej klasie jest GetFileName, funkcja odpowiedzialna za wyświetlenie okna dialogowe typu OpenFileDialog i pobranie od użytkownika pełnej nazwy pliku bazy danych (nazwy i ścieżki do niego wiodącej). Procedura obsługujące zdarzenia Load formularza korzysta z funkcji GetFileName. Jeżeli użytkownik wskazał plik bazy danych, to wykorzystując obiekt

103 103 ADOX modelu ADO pobierane są informacje o tabelach tej bazy i umieszczane w liście lsttabele. Ustalana jest liczna tabel dla wybranej bazy, ścieżka dostępu do niej umieszczane jest w zmiennej globalnej strconndynamic, a polecenie Zbudowanie dynamicznego formularza zostaje udostępnione.

104 104 Pokazana niżej procedura wykonywana jest w momencie, gdy użytkownik wybrał jedną z tabel. Musimy wtedy przejrzeć kolekcję tabel tej bazy, znaleźć tę tabelę, która została wybrana, a następnie pobrać listę pól dla tej wybranej tabeli. Nazwa pola (kolumny) może (choć lepiej byłoby gdyby nie) zawierać spację. W zapytaniu taka nazwa musi być opakowana w nawiasy kwadratowe. Pokazana niże funkcja realizuje właśnie to zadanie.

105 105 Kolejna procedura reaguje na klik jednej z pozycji w liście lstpola. Jej zadaniem jest skomponowanie treści zapytania wybierającego umieszczonego w polu txtsql. Klik przycisku Dodaj Where uruchamia procedurę, której zadaniem jest sprawdzenie, czy dotychczas skonstruowane zapytanie zawiera frazę From, jeżeli nie, to taka fraza jest dodawana do zapytania, następnie dodawana jest nazwa tabeli pobrana z lsttabele (czyli wybór użytkownika). Do sprawdzenia, czy w zapytaniu występowała fraza From została właściwość LastIndexOf zmiennej typu String. wykorzystana Inną przydatną ciekawostką jest ustawienia fokusa (kursora) w polu tekstowym w taki sposób, aby jego zawartość nie została zaznaczona.

106 106 Zadaniem prywatnej funkcji SprawdzZapytanie jest zbadanie, czy w treści zapytania mamy podaną informację z jakiej tabeli będziemy pobierać dane. Jeżeli wszystko jest OK., to funkcja zwraca True, jeżeli nie, to wyświetla stosowny komunikat i zwraca False. Po skomponowaniu zapytania możemy sprawdzić jego funkcjonowanie poprzez klik przycisku opisanego jako Wykonaj (btnwykonaj), co powoduje wykonanie poniższej

107 107 procedury. Pierwsza instrukcja tej procedury wywołuje funkcję SprawdzZapytanie, jeżeli funkcja zwraca False, to następuje wyjście z procedury. Do właściwości Text etykiety lblwynikzapytania chcemy zwrócić informację o liczbie zwróconych rekordów. Z uwago na język polski korzystamy z pomocniczej funkcji o nazwie OdmienRekordow, której zadaniem jest zwrócenie poprawnej odmiany słowa rekordów. Podobnie jak wcześniej pozostało już tylko pokazanie działania tego formularza. Poniżej dwa przykładowe zrzuty ekranowe. E:\. Zaczynamy od wskazania pliku bazy danych, tu jest to plik TestSP.mdb z dysku

108 108 Klik przycisku Otwórz wyświetla instancję formularza frmtestsql. Proszę zauważyć, że lista Dostępne tabele zawiera już tabele (użytkownika) utworzone w wybranej bazie danych. Klik jednej z tych tabel powoduje pobranie jej listy pól i umieszczenie ich nazw w liście Pola wybranej tabeli.

109 109 Jeżeli w liście pól klikniemy np. symbol gwiazdki, to do pola Budowane zapytanie zostanie wstawiony poniższy tekst. Klik przycisku Wykonaj (przy niekompletnym zapytaniu brakuje From Studenci ) może spowodować dwojaką reakcję. Albo zostanie zgłoszony błąd wynikający z konstrukcji zapytania albo funkcja SprawdzZapytanie poprawnie uzupełni zapytanie. Klik przycisku powoduje taki efekt jak poniżej. Wyraźnie widzimy, że funkcja SprawdzZapytanie niezbyt poprawnie skorygowała nasze zapytanie, w rezultacie wystąpił błąd czasu wykonania, skwitowany pokazanym komunikatem.

110 110 Możemy ręcznie poprawić zapytanie lub zastanowić się, jaki błąd został popełniony w funkcji SprawdzZapytanie. Drugi sposób jest trudniejszy, ale my zajmiemy się poprawieniem funkcjonowania tej funkcji. Co się stało i dlaczego wywołanie tej funkcji zmieniło wyjściowy tekst zapytania Select * na Select From Studenci zamiast Select * From Studenci? Przyczyna jest stosunkowo prosta. W procedurze obsługującej klik pozycji w liście lstpola jest fragment wskazany strzałką. Jeżeli użytkownik wybrał symbol gwiazdki, to do pola txtsql został wstawiony tekst Select * (po gwiazdce jest jeszcze spacja). Z kolei w oryginalnej funkcji SprawdzZapytanie jest taki fragment:

111 111 Jeżeli w treści zapytania nie było frazy From (a w naszym przykładzie nie było), to treść zapytania została skrócona o dwa znaki w naszym przypadku została skasowana *! Dotychczasowy fragment był dobrze pomyślany w tych sytuacjach, gdy użytkownik wybrał nie gwiazdkę, ale konkretne pole. Wtedy do pola txtsql wstawiany jest tekst Select nazwa_pola, (po nazwie pola dodawany jest przecinek i spacja). W takich sytuacjach poprawienie zapytania polegające na usunięciu dwóch ostatnich znaków i dodanie frazy From jest poprawne! Rozwiązanie jest banalnie proste, wystarczy w przypadku wybrania gwiazdki dodać do instrukcji select nie gwiazdkę i spację, lecz dwie spacje!. Po tej korekcie wszystko jest OK Zbudowanie dynamicznego formularza Korzystając z obiektu ADOX możemy pobrać informacje o strukturze bazy MS Access (o jej tabelach i polach tych tabel), co daje nam możliwość zbudowania formularza z formantem typu TabControl, gdzie w poszczególnych zakładkach umieścimy zestaw etykiet i pól tekstowych wyświetlających pojedyncze rekordy dla każdej z tabel Projekt formularza frmpojedynczyrekord jest stosunkowo prosty, umieszczono w nim wspomniany wyżej formant TabControl nadając mu nazwę tbczakladki.

112 112 Wysokość formantu tbczakladki została tak dobrana, aby na dole formularza pozostał wolny pasek, w którym umieszczono cztery przyciski do obsługi nawigacji po rekordach oraz pole tekstowe do wyświetlenia numeru bieżącego rekordu. W prezentowanym rozwiązaniu wysokość formularza została ustawiona na 300 pkt, szerokość na 496 pkt. Z kolei wysokość formantu tbczakladki ustawiono na 227 pkt przy szerokości 475 pkt. Formant ten został ustawiony na pozycji 2, 2 względem lewego górnego narożnika formularza. Przyciski btnpierwszy, btnnastepny, btnpoprzedni oraz btnostatni będą funkcjonować jako wspólne przyciski nawigacyjne pozwalając na przemieszczanie kursora po zestawie rekordów danej tabeli. Między nimi umieszczono pole txtnrrekordu, będzie w nim wyświetlany numer bieżącego rekordu dla bieżącej zakładki (dokładniej: dla tabeli prezentowanej na bieżącej zakładki). Poniżej pełny kod klasy formularza frmpojedynczyrekord, prezentowane są wszystkie procedury i funkcje zabezpieczające funkcjonowanie tego formularza. Imports System Imports System.Data ' import przestrzeni nazw niezbędnej do współpracy z bazą MS Access Imports System.Data.OleDb Public Class frmpojedynczyrekord Private nrzakladki As Integer Private mydataset As New DataSet Private myadapter As OleDbDataAdapter ' tablica X() będzie przechowywać numery bieżących ' rekordów dla każdego z formularzy (tabeli) Private X() As Long Private tabela As String Private Sub frmpojedynczyrekord_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load

113 113 Dim adoconn As New ADODB.Connection, i As Integer = 0 ' deklaracja i utworzenie obiektu ADOX.Catalog Dim mycat As New ADOX.Catalog ' deklaracja zmiennej tbl typu tabela obiektu ADOX na ' potrzeby pętli For Each Dim tbl As ADOX.Table, col As ADOX.Column ' otwieramy połączenie z bazą danych, wywołujemy metodę ' Open obiektu adoconn adoconn.open(strconndynamic) ' wskazujemy aktywne połączenie dla obiektu mycat mycat.activeconnection = adoconn ' deklaracja formantów Dim mylbl As Label Dim mytxt As TextBox Dim j, nrz As Integer, yl As Integer = 10 Dim yt As Integer = 10 ' deklaracja zakładki formantu TabControl Dim mytab As TabPage nrz = -1 For Each tbl In mycat.tables ' jeżeli nie jest to tabela systemowa MS Access If tbl.name.substring(0, 2) <> "MS" Then nrz += 1 ' tworzymy egzemplarz nowej zakładki mytab = New TabPage ' komponujemy jej nazwę mytab.name = "tab" & tbl.name & "_" & nrz.tostring ' definuyjemy jej tytuł mytab.text = tbl.name ' dodajemy utworzoną zakładkę do formantu TabControl Me.tbcZakladki.Controls.Add(myTab) ' a teraz dodajemy pola tekstowe i etykiety pól dla danej tabeli j = 0 For Each col In tbl.columns ' tworzymy egzemplarz etykiety mylbl = New Label ' właściwości Text przypisujemy nazwę kolumny mylbl.text = col.name ' tworzymy nazwę etykiety mylbl.name = "lbl" & UsunSpacje(col.Name) ' definiujemy wyrównanie tekstu w etykiecie mylbl.textalign = ContentAlignment.MiddleRight ' ustawiamy właściowość Location ' pierwszy argument jest stały i określa odsunięcie ' etykiety w poziomie od lewej krawędzi formantu ' drugi argument określa położenie pionowe i jest ' dynamicznie zmieniany

114 114 mylbl.location = New System.Drawing.Point(15, j * 30 _ + 13) ' ustawiamy także rozmiar etykiety (stały, bo nie ' wiadomo jaki będzie potrzebny) mylbl.size = New System.Drawing.Size(80, 13) ' tworzymy nowy egzemplarz formantu TextBox mytxt = New TextBox ' dynamicznie ustalamy jego położenie mytxt.location = _ New System.Drawing.Point(100, j * ) ' określamy rozmiar (szerokość, wysokość) tego formantu mytxt.size = New System.Drawing.Size(330, 20) ' nadajemy mu nazwę skomponowaną z prefiksu 'txt' i ' nazwy kolumny mytxt.name = "txt" & col.name ' dodajemy oba formanty do kolekcji formantów ' utworzonej zakładki mytab.controls.add(mylbl) mytab.controls.add(mytxt) ' powiększamy zmienną j o jeden (liczba par pól ' tekstowych i etykiet j += 1 Next ' wywołujemy prywatną procedurę, jej zadaniem jest ' pobranie danych z bazy i przypięcie ich do odpowiednich ' pól tekstowych PobierzDane(nrZ) End If ' pobranie danych z tabeli zakończone, uruchamiamy kolejną ' Pętlę (obrót) Next ' sprzątamy po sobie adoconn.close() adoconn = Nothing ' jeżeli w bazie była co najmniej jedna kolumna, to If nrz > -1 Then ' zmieniamy rozmiar tablicy X() ReDim X(nrZ) ' w pętli ustawiamy zero na każdej pozycji tej tablicy For i = 0 To nrz X(i) = 0 ' ustawienie zerowego rekordu dla każej zakładki Next ' zakładką bieżącą będzie ta o indeksie 0 nrzakladki = 0 Me.tbcZakladki.TabPages.Item(nrZakladki).Select() ' wywołujemy procedurę wyświetlającą numer aktualnego ' rekordu dla bieżącej zakładki KtoryRekord() Else

115 115 MsgBox("Nie odczytano żadnej tabeli użytkownika") End If End Sub Private Function UsunSpacje(ByVal nazwa As String) As String ' jeżeli nazwa pola zawiera spacje, to będą zastąpione podkreśleniem Return nazwa.replace(" ", "_") End Function Private Sub PobierzDane(ByVal nrz As Integer) ' ustawiamy zakładkę o indeksie nrz jako aktywną Me.tbcZakladki.TabPages(nrZ).Select() Dim txtsql As String, i As Integer tabela = tbczakladki.tabpages(nrz).text ' zbudowanie dynamicznego zapytania select * from nazwa_tabeli txtsql = "select * from " & tabela ' deklarujemy i tworzymy instancję obiektu Connection Dim jg As New OleDbConnection(strConnDynamic) ' kolejne instrukcje w bloku Try - Catch Try jg.open() ' otwarcie połączenia ' zbudowanie egzemplarza obiektu Adapter w oparciu ' o zdefiniowane zapytanie i otwarte połączenie myadapter = New OleDbDataAdapter(txtSql, jg) ' wywołanie metody Fill z poleceniem przeniesienia do ' obiektu mydataset pobranych rekordów, zaczynając od ' rekordu o numerze 0, z określeniem maksymalnej liczby, ' rekordów pobrane dane mają utworzyć obiekt DataSet o ' nazwie tabela do zmiennej 'i' metoda Fill zwraca liczbę ' pobranych rekordów i = myadapter.fill(mydataset, 0, MaxLiczbaRekordow, tabela) ' jeżeli pobrano jakieś rekordy,... If i > 0 Then ' deklaracja obiektu ctl na potrzeby pętli For Each Dim ctl As Control ' przeglądamy kolekcję kontrolek wskazanej zakładki For Each ctl In tbczakladki.tabpages(nrz).controls ' jeżeli aktualny formant jest polem tekstowym, to... If TypeOf (ctl) Is TextBox Then ' wywołujemy metodę DataBindings tego formantu ' nakazując przypięcie do właściwości Text danych, ' Które będą pobierane z obiektu mydataset z obiektu ' typu DataTable o nazwie 'tabela' z kolumny, której ' nazwa jest zgodna z nazwą formantu ctl po ' odrzuceniu prefiksu txt ctl.databindings.add("text", mydataset, _ tabela & "." & ctl.name.substring(3, _ ctl.name.length - 3)) End If

116 116 Next End If Catch ex As Exception MsgBox("Problem z pobraniem lub przypięciem danych _ do pól tekstowych", MsgBoxStyle.Critical, _ "Dynamiczne formularze") Finally jg.close()' sprzątamy po sobie jg = Nothing End Try End Sub Private Sub btnpoprzedni_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnpoprzedni.click ' Dim tabela As String = tbczakladki.selectedtab.text Me.BindingContext(myDataSet, tabela).position -= 1 KtoryRekord() End Sub Private Sub tbczakladki_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles tbczakladki.click tabela = tbczakladki.selectedtab.text nrzakladki = Me.tbcZakladki.SelectedIndex Me.BindingContext(myDataSet, tabela).position = X(nrZakladki) KtoryRekord() End Sub Private Sub btnnastepny_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnnastepny.click Dim tabela As String = tbczakladki.selectedtab.text Me.BindingContext(myDataSet, tabela).position += 1 KtoryRekord() End Sub Private Sub btnpierwszy_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnpierwszy.click Dim tabela As String = tbczakladki.selectedtab.text Me.BindingContext(myDataSet, tabela).position = 0 KtoryRekord() End Sub Private Sub btnostatni_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnostatni.click Dim tabela As String = tbczakladki.selectedtab.text Me.BindingContext(myDataSet, tabela).position = _ mydataset.tables(tabela).rows.count KtoryRekord() End Sub

117 117 Private Sub KtoryRekord() Dim pozycja As Long = _ Me.BindingContext(myDataSet, tabela).position X(nrZakladki) = pozycja Me.txtNrRekordu.Text = "Rekord nr " & (pozycja + 1).ToString If pozycja + 1 = mydataset.tables(tabela).rows.count Then Me.btnOstatni.Enabled = False Me.btnNastepny.Enabled = False Else Me.btnOstatni.Enabled = True Me.btnNastepny.Enabled = True End If If pozycja = 0 Then Me.btnPierwszy.Enabled = False Me.btnPoprzedni.Enabled = False Else Me.btnPierwszy.Enabled = True Me.btnPoprzedni.Enabled = True End If End Sub End Class Instancja formularza frmpojedynczyrekord jest uruchamiana tylko wtedy, gdy wcześnie wykonane zostało polecenie Pobranie tabel i pól, test zapytania z menu ADO (COM), ponieważ wtedy do zmiennej globalnej strconndynamic zostanie przypisana ścieżka do pliku bazy danych MS Access. Poniżej stosowny fragment kodu z klasy formularza głównego naszej aplikacji (czyli frmmdiform). Private Sub mnudynamiczneformularze_click(byval sender As _ System.Object, ByVal e As System.EventArgs) _ Handles mnudynamiczneformularze.click If strconndynamic.length > 0 Then Dim frm As New frmpojedynczyrekord frm.mdiparent = Me frm.show() Else MsgBox("Polecenie niedostępne, baza danych nie jest znana") End If End Sub Poniżej widok zbudowanego formularza w tracie pracy, pokazany jest formularz ekranowy tabeli Pracownicy.

118 Opis pozycji SQL Ten fragment aplikacji wykorzystuje przykładową tabelę o nazwie Klienci, której definicję przedstawiono w rozdziale 2.1 tej pozycji. Kolejno zostanie przedstawione wykorzystanie obiektu Adapter do przeglądania i modyfikowania rekordów tej tabeli oraz bardziej zaawansowane przetwarzanie informacji z tej tabeli z pomocą procedur przechowywanych Adapter Formularz frmadaptersqlcmdb zawiera dwa formanty: DataGridView o nazwie dgvdane, w którym będziemy prezentować rekordy tabeli Klienci oraz przycisk polecenia (Button) o nazwie btnupdate. Przyciski minimalizacji i maksymalizacji formularza zostały pozostawione po to, aby użytkownik mógł modyfikować rozmiar tego formularza, jeżeli będzie zachodziła taka potrzeba. Z tych samych powodów pozostawiono możliwość ręcznego zmodyfikowania

119 119 rozmiarów tego formularza (właściwość FormBorderStyle ustawiona na Sizable). Z tych powodów (dopuszczenia modyfikacji rozmiarów formularza) zmodyfikowano właściwość Anchor obu formantów. W przypadku dgvdane została ona ustawiona na zakotwiczenie tego formantu wg wszystkich czterech krawędzi formularza. W przypadku przycisku btnupdate właściwość Anchor ustawiono wg prawej i dolnej krawędzi formularza. W kodzie klasy formularza zadeklarowano potrzebne zmienne oraz utworzono dwie procedury odpowiedzialne za jego funkcjonowanie. Poniżej kod tych procedur wraz z obszernymi komentarzami. ' Import potrzebnych przestrzeni nazw Imports System.Data Imports System.Data.SqlClient Public Class frmsqlupdateklienci ' deklaracja zmiennych modułu dla klasy formularza ' ich deklaracja w tym miejscu powoduje, że będą dostępne ' dla wszystkich procedur i funkcji w tej klasie Dim sqladapter As SqlDataAdapter Dim ds As DataSet ' tablica xupdate ma pełnić rolę wskaźnika czy jest potrzebna ' aktualizacja Dim xupdate() As Boolean Private Sub frmsqladaptercmdb_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ' dekalracja i utworzenie obiektu SQLConnection ' zmienna globalna strconnsql zawiera łańcuch połączenia do ' bazy SQL Dim conn As New SqlConnection(strconnSqL) ' utworzenie nowego egzemplarza obiektu DataSet ds = New DataSet ' dalsze instrukcje mogą spowodować błąd, stąd są w bloku ' Try-Catch

120 120 Try ' otwieramy połaczenie z bazą conn.open() ' tworzymy nowy obiekt SqlDataAdapter przekazując do niego ' polecenie SQL i otwarte połączenie. Efektem jest ' dostarczenie do niego danych zgodnie z zapytaniem sqladapter = _ New SqlDataAdapter("select * from dbo.klienci", conn) ' utworzenie egzemplarza obiektu SqlCommandBuilder ' przekazując mu obiekt Adapter ' rezultatem jest utworzenie 3 poleceń wykonujących Insert, ' Update i Delete Dim cmdbuilder As New SqlCommandBuilder(sqlAdapter) ' wywołanie metody Fill nakazujacej wypełnienie pobranymi ' danymi obiektu ds (DataSet) sqladapter.fill(ds) ' określamy żródło danych obiektu DataGridView Me.dgvDane.DataSource = ds.tables(0) ' zerowa kolumnna ma być niewidoczna Me.dgvDane.Columns(0).Visible = False Catch ex As Exception ' wystąpił błąd, zwracamy komunikat MsgBox("Problem z dostępem do bazy damych") Finally ' ten fragment jest wykonywany zawsze ' zamykamy połączenie conn.close() ' i zwalniamy zasób conn = Nothing End Try End Sub Private Sub btnupdate_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnupdate.click Dim conn As New SqlConnection(strconnSqL) ' deklaracja i utworzenie nowego obiektu typu DataTable Dim dtzmiany As New DataTable Try conn.open() ' do obiektu DataTable pobieramy zmiany z tabeli o ' indeksie 0 z DataSet dtzmiany = ds.tables(0).getchanges ' jeżeli były zmienione rekordy to... If dtzmiany IsNot Nothing Then ' wywołujemy metodę Update obiektu Adapter ' metoda aktualizuje dane w bazie danych wykorzystując ' obiekt dtzmiany sqladapter.update(dtzmiany) ' komunikat na ekran

121 121 MsgBox("AKtualizacja tabeli w bazie SQL zrobiona") End If Catch ex As Exception ' ewentualny komunikat o błędzie MsgBox(ex.ToString) Finally 'sprzątamy conn.close() conn = Nothing End Try End Sub End Class Poniżej widok tego formularza w pracy. Pierwszy zrzut ekranowy pokazuje ten formularz w takich rozmiarach, jak został zaprojektowany. Efekt jest taki, że w formancie dgvdane został uaktywniony pasek poziomego przewijania, ponieważ część informacji (kolumn) pobranych z bazy danych nie jest widoczna. Możemy za pomocą myszy zmodyfikować rozmiar tego formularza tak, aby wyświetlał komplet kolumn (zniknie wtedy pasek poziomego przewijania). Dzięki ustawieniu właściwości Anchor dla formantu dgvdane tak, aby były zachowane jego odległości od wszystkich krawędzi formularza oraz ustawieniu tej samej właściwości dla przycisku btnupdate na trzymanie odległości względem prawej i dolnej krawędzi formularza jego wygląd po zmianie rozmiaru jest dokładnie taki, jakiego oczekujemy.

122 122 A co by było, gdybyśmy nie zmienili właściwości Anchor dla obu formantów? Konsekwencje pokazane są poniżej. Bez problemy zmieniamy rozmiar formularza, ale rozmiary i położenie obu formantów pozostały bez zmian. W przypadku dgvdane nic nam nie dało powiększenie rozmiarów formularza, ponieważ nie nastąpiło powieszenie rozmiarów tego formantu (aby zachować stałe, nadane na etapie projektowania, odległości od krawędzi formularza). Z kolei przycisk btnupdate pozostał na swoim miejscu, efekt jest taki, że albo będzie dla nas niedostępny, albo będzie nam przeszkadzał (wtedy, gdybyśmy ustawili poprawnie właściwość Anchor dla dgvdane) Update tabeli via procedura przechowywana (klasycznie) Kolejna pozycja w menu SQL dotyczy wykonania aktualizacji danych w bazie za pośrednictwem procedury przechowywanej SQL. Działanie takie jest zdecydowanie lepsze od wykorzystania możliwości, jakie daje obiekt CommandBuilder, zwłaszcza w sytuacjach, gdy aktualizacja dotyczy tabeli powiązanej relacjami z innymi tabelami.

123 123 Dla zademonstrowania takiego podejścia potrzebna nam będzie procedura przechowywana SQL realizująca zadanie aktualizacji wskazanego rekordu danej tabeli. Kod takiej procedury o nazwie pupdateklienci został zaprezentowany w rozdziale 2.1. Procedura pupdateklienci jest procedurą z parametrami, dla jej wykonania musimy przekazać do obiektu Command w modelu ADO.NET nie tylko nazwę procedury, lecz także szereg właściwości charakteryzujących poszczególne parametry. Będą to takie informacje jak nazwa parametru, jego typ, rozmiar, wartość oraz kierunek (może być parametr typu input lub output). Parametry te będą tworzyć kolekcję parametrów, która będzie elementem obiektu Command. Wykorzystamy w sensie projektu analogiczny formularz jak w poprzednim rozdziale, tym razem jego nazwa to frmsqlupdateklienci. Umieszczono na nim formant typu DataGridView o nazwie dgvdane oraz przycisk polecenie o nazwie btnupdate. Oba formanty mają, podobnie jak w formularzu frmadaptersqlcmdb, zmodyfikowaną właściwość Anchor w celu umożliwienia swobodnej zmiany rozmiaru formularza. Zasadnicza różnica kryje się w kodzie klasy tego formularza. Poniżej wszystkie instrukcje tej klasy wraz ze stosownymi komentarzami. Imports System.Data Imports System.Data.SqlClient Public Class frmsqlupdateklienci ' delaracja potrzebnych stałych i zmiennych Const txtkom As String = "Klasyczne wywołanie procedury SQL" Dim sqladapter As SqlDataAdapter Dim ds As DataSet ' tablica ta będzie wykorzystana jako wskaźnikowa ' w tym sensie, czy mamy robić update czy nie danego rekordu Dim xupdate() As Boolean Private Sub frmsqladaptercmdb_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ' deklarujemy i tworzymy instancję obiektu connection Dim conn As New SqlConnection(strconnSqL) ' deklarujemy i tworzymy instację obiektu Command Dim cmd As New SqlCommand ' deklarujemy i tworzymy instancję obiektu dataset Dim ds As New DataSet Dim i As Integer ' reszta działań może spowodować błądm stąd użycie bloku ' Tray-Catch Try conn.open() ' przypisanie do właściowości Connection obiektu cmd

124 124 ' otwartego połączenia cmd.connection = conn ' określenie typu polecenia cmd.commandtype = CommandType.StoredProcedure ' podanie nazwy procedury przechowywanej cmd.commandtext = "dbo.pdajdaneklientow" ' przygotowania do odebrania danych, które zwróci procedura ' deklarujemy obiekt typu DataReader Dim dr As SqlDataReader ' poprzez wywołanie metody ExecuteReader dostarczamy dane ' do DataReader dr = cmd.executereader ' deklarujemy i tworzymy obiekt typu Dataset Dim dt As New DataTable ' wywołujemy metodę Load utworzonego obiektu wskazując jako ' źródło danych obiekt dr (DataReader) dt.load(dr) ' tworzymy źródło danych dla obiektu DataGridView Me.dgvDane.DataSource = dt ' ukrywamy zerową kolumnę Me.dgvDane.Columns(0).Visible = False ' deklarujemy wymiary tablicy ReDim xupdate(dt.rows.count - 1) ' na wszystkich pozycjach tablicy ustawiamy wartość False For i = 0 To UBound(xUpdate) xupdate(i) = False Next Catch ex As Exception MsgBox("Problem z wykonaniem procedury pdajdaneklientow") Finally conn.close() cmd = Nothing conn = Nothing End Try ' ustawienie zmiennej globalnej flaga na True flaga = True End Sub Private Sub btnupdate_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnupdate.click Dim conn As New SqlConnection(strconnSqL), i, j As Integer Try conn.open() ' deklaracja i utworzenie egzemplarza (instancji) ' obiektu Command Dim cmd As New SqlCommand ' przypisanie mu potrzebnych informacji cmd.connection = conn cmd.commandtype = CommandType.StoredProcedure

125 125 cmd.commandtext = "dbo.pupdateklienci" ' zerujemy kolekcję parametrów cmd.parameters.clear() ' deklarujemy nowy parametr Dim param As SqlParameter ' w pętli po wszystkich rekordach badamy, czy jest potrzebna ' aktualizacja For i = 0 To UBound(xUpdate) If xupdate(i) Then ' jest potrzebna, a więc... ' tworzymy kolekcję parametrów ' obiekt param staje się nowym parametrem o określonej ' nazwie. typie danych i rozmiarze ' rozmiar (ostatni parametr) jest niezerowy dla zmiennych typu String param = New SqlParameter("@idk", SqlDbType.Int, 0) ' do właściwości Value przypisujemy wartość parametru ' pobraną z odpowiedniej kolumny i wiersza obiektu typu ' DataGridView. Musimy pamiętać o tym, ' że rekordy i kolumny są indeksowane od zera param.value = Me.dgvDane.Rows(i).Cells(0).Value ' określamy, czy parametr jest wchodzący czy wychodzący param.direction = ParameterDirection.Input ' dodajemy utworzony parametr do kolekcji parametrów cmd.parameters.add(param) ' param = New SqlParameter("@nazwa", _ SqlDbType.NVarChar, 100) param.value = Me.dgvDane.Rows(i).Cells(1).Value param.direction = ParameterDirection.Input cmd.parameters.add(param) ' param = New SqlParameter("@adres", _ SqlDbType.NVarChar, 100) param.value = Me.dgvDane.Rows(i).Cells(2).Value param.direction = ParameterDirection.Input cmd.parameters.add(param) ' param = New SqlParameter("@nip", _ SqlDbType.NVarChar, 13) param.value = Me.dgvDane.Rows(i).Cells(3).Value param.direction = ParameterDirection.Input cmd.parameters.add(param) ' param = New SqlParameter("@mail", _ SqlDbType.NVarChar, 50) param.value = Me.dgvDane.Rows(i).Cells(4).Value param.direction = ParameterDirection.Input cmd.parameters.add(param) '

126 126 param = New SqlParameter("@telefon", _ SqlDbType.NVarChar, 50) param.value = Me.dgvDane.Rows(i).Cells(5).Value param.direction = ParameterDirection.Input cmd.parameters.add(param) ' param = New SqlParameter("@osoba", _ SqlDbType.NVarChar, 100) param.value = Me.dgvDane.Rows(i).Cells(6).Value param.direction = ParameterDirection.Input cmd.parameters.add(param) ' wszystkie parametry dla danego wiersza są już ' określone wywołujemy więc polecenie (metodę) ' ExewcuteNonQuery która odpowiedzialna jest za ' wykonanie polecenia modyfikującego cmd.executenonquery() End If Next ' wszystkie rekordy wymagające aktualizacji zostały ' zmodyfikowane, sprzątamy po sobie param = Nothing cmd = Nothing MsgBox("Aktualizacja zakończona", MsgBoxStyle.Information, _ txtkom) Catch ex As Exception ' komunikat o błędzie MsgBox("problem z wykonaiem procedury przechowywanej", _ MsgBoxStyle.Critical, txtkom) Finally ' zamykamy i zwalniamy obiekt Connection conn.close() conn = Nothing End Try End Sub Private Sub dgvdane_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvdane.cellendedit ' procedura wywoływana jest w momencie zakończenia edycji ' dowolnej komórki w danym wierszu DataGridView ' jeżeli flaga nie jest True to wyjdź If Not flaga Then Exit Sub ' konieczna jest zmiana w tabeli xupdate na pozycji, która ' jest Określona właściwością RowIndex argumentu e ' przekazanego do tej procedury z obiektu DataGridView. Inną ' właściwością argumentu e jest ColumnIndex, w sumie obie ' właściwości dają nam pełną informację o komórce, która ' została zaktualizowana ' poniższa instrukcja najpierw sprawdza, czy ten wiersz już

127 127 ' nie został oznaczony jako wymagający aktualizacji, jeżeli ' nie, to na pozycji e.rowindex wpisujemy True If Not xupdate(e.rowindex) Then xupdate(e.rowindex) = True End Sub End Class Poniżej widok tego formularza w trakcie pracy. Po jego otwarciu został zmodyfikowany jego rozmiar tak, aby pola (kolumny) Adres oraz OsobaKontaktowa były w pełni widoczne. W ostatniej kolumnie pierwszego wiersza dopiszemy imiona do istniejącego nazwiska Abacki. Dane zostały uzupełnione, symbol ołówka na początku gridu identyfikuje aktualnie modyfikowany rekord (wiersz). Klik przycisku Aktualizuj uruchamia procedurę aktualizującą. Po jej zakończeniu wyświetlany jest stosowny komunikat.

128 128 Dla pokazania, że faktycznie zmiany w tabeli Klienci zostały utrwalone formularz został zamknięty i ponownie otwarty, jak widzimy pierwszy rekord został zmodyfikowany. Z przedstawionego kodu wynika, że taka standardowa (klasyczna) metoda wywołania procedury przechowywanej, zwłaszcza z dużą liczbą parametrów, jest dość uciążliwa. W kolejnym podrozdziale pokazana zostanie rozwiązanie, które znacznie ułatwia tworzenie takiego kodu (obsługującego wywołanie procedur przechowywanych SQL) Update tabeli via procedura przechowywana wg JG W tym przykładzie wykorzystamy formularz o nazwie frmsqlupdateklienci2, ma on dokładnie taki sam zestaw formantów jak swój poprzednik, ale całkowicie inny kod. Wynika on między innymi z tego, że zaprojektujemy klasę, z pomocą której będziemy obsługiwać funkcjonowanie tego formularza. Klasa CTestSql Jest to klasa potomna (dziedzicząca) po klasie bazowej CForStorageSub, której kod będzie omówiony w kolejnym rozdziale. W klasie na potrzeby tego przykładu utworzono jeden interfejs z trzema metodami. Pełny kod wraz z komentarzami pokazany jest niżej. Imports System.Data Imports System.Data.SqlClient ' dekalrujemy interfejs klasy Public Interface IKlienci ' ten interfejs będzie obsługiwał operacje na tabeli Klienci ' deklarujemy funkcję, która będzie zwracać komunikat o ' ewentualnym błędzie Function Komunikat() As String ' dekalrujemy metodę odpowiedzialną za pobranie danych z ' tabeli Klienci Sub PrzygotujDaneDoEdycji(ByVal strconn As String, _ ByVal frm As frmsqlupdateklienci2) ' deklarujemy metodę odpowiedzialną za wykonanie aktualizacji

129 129 ' danychx Sub WykonajUpdate(ByVal strconn As String, ByVal Xb() _ As Boolean, ByVal dgv As DataGridView) End Interface Public Class CTestSql ' tworzona klasa dziedziczy po klasie bazowej CForStorageSub Inherits CForStorageSub ' kod będzie implementował interfejs IKlienci Implements IKlienci ' deklarujemy prywatną zmienną mkomunikat i inicjalizujemy ją ' pustym ciągiem znaków Private mkomunikat As String = "" Public Function Komunikat() As String Implements IKlienci.Komunikat ' funkcja (metoda) zwraca zmienną prywatną mkomunikat Return mkomunikat End Function Public Sub PrzygotujDaneDoEdycji(ByVal strconn As String, _ ByVal frm As frmsqlupdateklienci2) _ Implements IKlienci.PrzygotujDaneDoEdycji ' do metody przekazujemy jako parametry (argumenty) łańcuch ' połączenia oraz formularz będący instancją formularza ' frmsqlupdateklienci2 ' ' deklarujemy i tworzymy instancję obiektu Connection Dim conn As New SqlConnection(strconn) ' dekalrujemy obiekt typu DataTable Dim dt As DataTable ' reszta instrukcji w bloku obsługi ewentualnego błędu Try ' otwracie połączenia z bazą SQL conn.open() ' korzystamy z metody klasy bazowej i wywołujemy funkcję ' DajRekordset. Lista publicznych zmiennych, metod i ' właściwości klasy bazowej jest dostępna po słowie ' kluczowym MyBase i kropce. Wszystkie metody klasy bazowej, ' które wykorzystują pojedynczą procedurę przechowywaną mają ' podobny zestaw argumentów. Jest to składnia: ' Nazwa_Metody(obiekt_Connection, nazwa_procedury, ' lista_parametrow) ' jeżeli procedura nie ma parametrów, to ostatni składnik ' jest słowem "brak" ' w tym przypadku przekazujemy obiekt conn, nazwę procedury ' wraz z jej prefiksem oraz wyraz "brak" jako sygnał, że ' procedura nie ma argumentów. ' Metoda DajRekordset zwraca obiekt typu DataTabel, który ' przypisujemy do zmiennej dt

130 130 dt = MyBase.DajRekordset(conn, "dbo.pdajdaneklientow", _ "brak") ' definiujemy teraz żródło danych dla formantu dgvdane frm.dgvdane.datasource = dt ' ukrywamy kolumnę zerową z kluczem tabeli frm.dgvdane.columns(0).visible = False Catch ex As Exception mkomunikat = _ "Problem z wykonaniem procedury pdajdaneklientow" Finally ' sprzątamy po sobie conn.close() conn = Nothing End Try End Sub Public Sub WykonajUpdate(ByVal strconn As String, ByVal Xb() As _ Boolean, ByVal dgv As DataGridView) _ Implements IKlienci.WykonajUpdate ' ta metoda odpowiada za aktualizację tych rekordów gridu dgv, ' które wymagają aktualizacji. Informacja o tym, które rekordy ' zawarte jest w tablicy Xb Dim conn As New SqlConnection(strconn) Try conn.open() ' wywołujemy metodę UpdateWieleRekordow z klasy bazowej ' przekazujemy do niej argumenty: otwarte połączenie, nazwę ' procedury SQL, obiekt typu DataGridView jako źródło ' rekordów do aktualizacji, tablicę logiczną oraz zestaw ' nazw parametrów zawierających dla każdego z nich ' następujące informacje: nazwa parametru, jego typ, rozmiar ' oraz numer kolumny gridu z której ma być pobrana wartość MyBase.UpdateWieleRekordow(conn, "dbo.pupdateklienci", _ dgv, Xb, _ "@idk", jgtyp.jginteger, 0, 0, _ "@nazwa", jgtyp.jgstring, 100, 1, _ "@adres", jgtyp.jgstring, 100, 2, _ "@nip", jgtyp.jgstring, 13, 3, _ "@mail", jgtyp.jgstring, 50, 4, _ "@telefon", jgtyp.jgstring, 50, 5, _ "@osoba", jgtyp.jgstring, 100, 6) Catch ex As Exception mkomunikat = "Problem z update wielu rekordów" Finally conn.close() conn = Nothing End Try End Sub End Class

131 131 Kod formularza frmsqlupdateklienci2 Fakt utworzenia klasy CTestSql znakomicie skraca i upraszcza kod, który musimy utworzyć w klasie tego formularza dla zabezpieczenia jego poprawnego funkcjonowania. Public Class frmsqlupdateklienci2 'deklaracja stałej i tablicy Const txtkom As String = "Wywołanie procedury SQL wg JG" Dim xupdate() As Boolean do Private Sub frmsqlupdateklienci2_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load 'przedefiniowanie rozmiarów tablicy xupdate ReDim xupdate(me.dgvdane.rows.count - 1) ' ustawienie na każdej składowej wartości False For i As Integer = 0 To Me.dgvDane.Rows.Count - 1 xupdate(i) = False Next ' przypisanie wartości True do zmiennej globalnej flaga ' umożliwi rejestrowanie ewentualnych aktualizacji w gridzie flaga = True End Sub Private Sub btnupdate_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnupdate.click ' deklarujemy obiekt klasy CTestSql wykorzystując interfejs ' IKlienci Dim w As IKlienci ' tworzymy instancję klasy CTestSql z ogranieczeniem dostępu ' metod udostępnionych przez interfejs IKlienci w = New CTestSql ' wywołujemy metodę WykonajUpdate przekazując do niej ' potrzebne argumenty, czyli łańcuch połączenia, tablicę ' xupdate oraz grid dgvdane w.wykonajupdate(strconnsql, xupdate, Me.dgvDane) ' sprawdzamy, czy wszystko przebiegło poprawnie If w.komunikat.length > 0 Then ' niestety nie, komunikat na ekran, jego treść została ' przygotowana w klasie CTestSql MsgBox(w.Komunikat, MsgBoxStyle.Critical, txtkom) Else MsgBox("Aktualizacja rekordów zakończona", _ MsgBoxStyle.Information, txtkom) End If End Sub Private Sub dgvdane_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvdane.cellendedit

132 132 If Not flaga Then Exit Sub ' jeżeli jeszcze nie odnotowano, że wiersz (rekord) o indeksie ' e.rowindex jest aktualizowany, to ustaw na jego pozycji True If Not xupdate(e.rowindex) Then xupdate(e.rowindex) = True End Sub End Class Kod uruchamiający formularz Formualarz frmsqlupdateklienci2 będzie uruchamiany poprzez klik odpowiedniego polecenia w menu SQL tej aplikacji. Musimy zadbać o to, aby formularz był pokazany dopiero wtedy, gdy pomyślnie pobrano dane z bazy danych. Jeżeli nie, to formularz nie jest pokazywany, a w jego miejsce wyświetlamy stosowny komunikat wyjaśniający sytuację. Poniżej kod procedury obsługującej klik polecenia mnuupdatejg z formularza frmmdiform. Private Sub mnuupdatejg_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles mnuupdatejg.click Dim frm As New frmsqlupdateklienci2 flaga = False ' dekalracja obiektu klasy CTestSql ' z wykorzystaniem interfejsu IKlienci Dim w As IKlienci ' utworzenie instancji klasy CTestSql ' z uwagi na sposób deklaracji dostępne będa ' metody zadekalrowane w interfejsie IKlienci w = New CTestSql ' wywołanie metody PrzygotujDaneDoEdycji w.przygotujdanedoedycji(strconnsql, frm) ' sprawdzenie, czy pomyślnie pobrano dane z bazy ' i czy zostały przypisane do gridu formularza If w.komunikat.length = 0 Then ' tak, pokazujemy formularz ' ale obiekt w nie jest już potrzebny, zwalniamy zasób w = Nothing frm.mdiparent = Me frm.show() Else ' nie, komunikat na ekran MsgBox(w.Komunikat, MsgBoxStyle.Critical, _ "Błąd przygotowania danych") End If End Sub

133 133 Klika zrzutów pokazujących pracę tego formularza Na zakończenie klika zrzutów pokazujących formularz w trakcie edycji danych zapisanych w tabeli Klienci. Powiedzmy, że w ostatniej kolumnie drugie imię Kamil dopisano pomyłkowo w pierwszym rekordzie zamiast w drugim. Poprawiamy błąd kasując Kamil w pierwszym rekordzie i dopisując to imię w drugim. Błędy poprawione, wykonujemy klik przycisku Aktualizuj. Procedura aktualizująca wykonuje swoją pracę i wyświetla stosowny komunikat. Na zakończenie zamykamy formularz i ponownie go otwieramy, jak widzimy zmiany są w bazie.

Uwagi dotyczące notacji kodu! Moduły. Struktura modułu. Procedury. Opcje modułu (niektóre)

Uwagi dotyczące notacji kodu! Moduły. Struktura modułu. Procedury. Opcje modułu (niektóre) Uwagi dotyczące notacji kodu! Wyrazy drukiem prostym -- słowami języka VBA. Wyrazy drukiem pochyłym -- inne fragmenty kodu. Wyrazy w [nawiasach kwadratowych] opcjonalne fragmenty kodu (mogą być, ale nie

Bardziej szczegółowo

Janusz Górczyński. Wprowadzenie do programowania obiektowego w VB.NET

Janusz Górczyński. Wprowadzenie do programowania obiektowego w VB.NET Janusz Górczyński Wprowadzenie do programowania obiektowego w VB.NET WSZiM w Sochaczewie, 2011 Spis treści 1 KLASY I ICH WYKORZYSTANIE...3 1.1 WPROWADZENIE DO KLAS...3 1.1.1 Definiowanie klasy...3 1.1.2

Bardziej szczegółowo

1 Podstawy c++ w pigułce.

1 Podstawy c++ w pigułce. 1 Podstawy c++ w pigułce. 1.1 Struktura dokumentu. Kod programu c++ jest zwykłym tekstem napisanym w dowolnym edytorze. Plikowi takiemu nadaje się zwykle rozszerzenie.cpp i kompiluje za pomocą kompilatora,

Bardziej szczegółowo

Materiały do laboratorium MS ACCESS BASIC

Materiały do laboratorium MS ACCESS BASIC Materiały do laboratorium MS ACCESS BASIC Opracowała: Katarzyna Harężlak Access Basic jest językiem programowania wykorzystywanym w celu powiązania obiektów aplikacji w jeden spójny system. PROCEDURY I

Bardziej szczegółowo

LibreOffice Calc VBA

LibreOffice Calc VBA LibreOffice Calc VBA LibreOffice Calc umożliwia tworzenie własnych funkcji i procedur przy użyciu składni języka VBA. Dostęp do edytora makr: Narzędzia->Makra->Zarządaj makrami->libreoffice Calc Aby rozpocząć

Bardziej szczegółowo

Programowanie obiektowe. Obiekt Klasa Składnia klasy: Interfejsy Składnia interfejsu: Metody Składnia instrukcji Sub: Składnia instrukcji function:

Programowanie obiektowe. Obiekt Klasa Składnia klasy: Interfejsy Składnia interfejsu: Metody Składnia instrukcji Sub: Składnia instrukcji function: Programowanie obiektowe. Obiekt Obiekt to dowolny element, który możemy wydzielić i którym możemy manipulować. W terminologii informatycznej obiekt to samodzielna jednostka zawierająca zarówno dane, jak

Bardziej szczegółowo

1 Podstawy c++ w pigułce.

1 Podstawy c++ w pigułce. 1 Podstawy c++ w pigułce. 1.1 Struktura dokumentu. Kod programu c++ jest zwykłym tekstem napisanym w dowolnym edytorze. Plikowi takiemu nadaje się zwykle rozszerzenie.cpp i kompiluje za pomocą kompilatora,

Bardziej szczegółowo

Tablice, DataGridView

Tablice, DataGridView Tablice, DataGridView Gdy rośnie liczba danych do przechowywania w programie, a następnie ich obrobienia - pojawiają się nowe struktury danych (moŝna by powiedzieć pojemniki na dane) zwane tablicami. Tablica

Bardziej szczegółowo

Projekt Hurtownia, realizacja skojarzeń dostawców i produktów

Projekt Hurtownia, realizacja skojarzeń dostawców i produktów niżej. Projekt Hurtownia, realizacja skojarzeń dostawców i produktów W bazie danych HurtowniaSP istnieją tabele Dostawcy oraz Produkty, ich definicje przypomniane są W bazie zdefiniowano także tabelę DostawcyProdukty,

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Laboratorium z przedmiotu Programowanie obiektowe - zestaw 02 Cel zajęć. Celem zajęć jest zapoznanie z praktycznymi aspektami projektowania oraz implementacji klas i obiektów z wykorzystaniem dziedziczenia.

Bardziej szczegółowo

Visual Basic for Applications. Wstęp

Visual Basic for Applications. Wstęp Visual Basic for Applications Materiały źródłowe: http://www.vbamania.estrefa.pl 2008-01-14 Wstęp Visual Basic for Applications to język programowania, dołączony do wielu aplikacji. Wspierają go między

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Laboratorium z przedmiotu - zestaw 02 Cel zajęć. Celem zajęć jest zapoznanie z praktycznymi aspektami projektowania oraz implementacji klas i obiektów z wykorzystaniem dziedziczenia. Wprowadzenie teoretyczne.

Bardziej szczegółowo

Wydział Zarządzania AGH. Katedra Informatyki Stosowanej. Podstawy VBA cz. 1. Programowanie komputerowe

Wydział Zarządzania AGH. Katedra Informatyki Stosowanej. Podstawy VBA cz. 1. Programowanie komputerowe Wydział Zarządzania AGH Katedra Informatyki Stosowanej Podstawy VBA cz. 1 Programowanie 1 Program wykładu Struktura programu Instrukcja przypisania Wprowadzanie danych Wyprowadzanie wyników Instrukcja

Bardziej szczegółowo

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Program, to lista poleceń zapisana w jednym języku programowania zgodnie z obowiązującymi w nim zasadami. Celem programu jest przetwarzanie

Bardziej szczegółowo

Zakres tematyczny dotyczący podstaw programowania Microsoft Office Excel za pomocą VBA

Zakres tematyczny dotyczący podstaw programowania Microsoft Office Excel za pomocą VBA Zakres tematyczny dotyczący podstaw programowania Microsoft Office Excel za pomocą VBA 1 Rozdział 1 Praca z makropoleceniami Opis: W tym rozdziale kursanci przechodzą przez wprowadzenie do programowania

Bardziej szczegółowo

Podstawy programowania skrót z wykładów:

Podstawy programowania skrót z wykładów: Podstawy programowania skrót z wykładów: // komentarz jednowierszowy. /* */ komentarz wielowierszowy. # include dyrektywa preprocesora, załączająca biblioteki (pliki nagłówkowe). using namespace

Bardziej szczegółowo

Podstawy programowania w języku Visual Basic dla Aplikacji (VBA)

Podstawy programowania w języku Visual Basic dla Aplikacji (VBA) Podstawy programowania w języku Visual Basic dla Aplikacji (VBA) Instrukcje Język Basic został stworzony w 1964 roku przez J.G. Kemeny ego i T.F. Kurtza z Uniwersytetu w Darthmouth (USA). Nazwa Basic jest

Bardziej szczegółowo

Aplikacje w środowisku VBA. Visual Basic for Aplications

Aplikacje w środowisku VBA. Visual Basic for Aplications Aplikacje w środowisku VBA Visual Basic for Aplications Podstawowe informacje o VBA Visual Basic for Aplications, w skrócie VBA, to język programowania rozwijany przez Microsoft, którego zastosowanie pozwala

Bardziej szczegółowo

Programowanie w języku Python. Grażyna Koba

Programowanie w języku Python. Grażyna Koba Programowanie w języku Python Grażyna Koba Kilka definicji Program komputerowy to ciąg instrukcji języka programowania, realizujący dany algorytm. Język programowania to zbiór określonych instrukcji i

Bardziej szczegółowo

Platforma.NET laboratorium 4 Aktualizacja: 15/11/2013. Visual Basic.NET dostęp do bazy danych. Baza Microsoft SQL Server Compact

Platforma.NET laboratorium 4 Aktualizacja: 15/11/2013. Visual Basic.NET dostęp do bazy danych. Baza Microsoft SQL Server Compact Platforma.NET laboratorium 4 Aktualizacja: 15/11/2013 Prowadzący: mgr inż. Tomasz Jaworski Strona WWW: http://tjaworski.kis.p.lodz.pl/ Visual Basic.NET dostęp do bazy danych Baza Microsoft SQL Server Compact

Bardziej szczegółowo

3 Delegacje. 3.1 Tworzenie delegacji. 3.2 Skojarzenie delegacji z procedurą czy funkcją

3 Delegacje. 3.1 Tworzenie delegacji. 3.2 Skojarzenie delegacji z procedurą czy funkcją 3 Delegacje Delegacja to specjalny typ danych, który przechowuje referencję (adres) do procedury lub funkcji. W środowisku.net delegacja jest odpowiednikiem wskaźnika (pointer) do funkcji znanego z języka

Bardziej szczegółowo

TABLICA (ang. array) pojedyncza zmienna z wieloma komórkami, w których można zapamiętać wiele wartości tego samego typu danych.

TABLICA (ang. array) pojedyncza zmienna z wieloma komórkami, w których można zapamiętać wiele wartości tego samego typu danych. Złożone typy danych - TABLICE TABLICA (ang. array) pojedyncza zmienna z wieloma komórkami, w których można zapamiętać wiele wartości tego samego typu danych. * Może przechowywać dowolny typ danych, typ

Bardziej szczegółowo

Projekt Hurtownia, realizacja rejestracji dostaw produktów

Projekt Hurtownia, realizacja rejestracji dostaw produktów Projekt Hurtownia, realizacja rejestracji dostaw produktów Ćwiczenie to będzie poświęcone zaprojektowaniu formularza pozwalającego na rejestrację dostaw produktów dla naszej hurtowni. Dane identyfikujące

Bardziej szczegółowo

Wprowadzenie do programowania w VBA

Wprowadzenie do programowania w VBA Wprowadzenie do programowania w VBA Spis treści Struktura programu... 1 Typy danych... 2 Deklaracja zmiennych i stałych... 2 Deklaracja tablic... 3 Instrukcja przypisania... 3 Wprowadzanie danych... 3

Bardziej szczegółowo

Automatyzacja pracy w AutoCAD

Automatyzacja pracy w AutoCAD Automatyzacja pracy w AutoCAD 1 Informacje wstępne BASIC (Beginners All-Purpose Symbolic Instruction Code) Rok powstania: 1963 r. Cel realizacji: nauczanie studentów programowania umożliwienie programowania

Bardziej szczegółowo

Podstawy Programowania C++

Podstawy Programowania C++ Wykład 3 - podstawowe konstrukcje Instytut Automatyki i Robotyki Warszawa, 2014 Wstęp Plan wykładu Struktura programu, instrukcja przypisania, podstawowe typy danych, zapis i odczyt danych, wyrażenia:

Bardziej szczegółowo

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02 METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE Wykład 02 NAJPROSTSZY PROGRAM /* (Prawie) najprostszy przykład programu w C */ /*==================*/ /* Między tymi znaczkami można pisać, co się

Bardziej szczegółowo

Instrukcje cykliczne (pętle) WHILE...END WHILE

Instrukcje cykliczne (pętle) WHILE...END WHILE Instrukcje cykliczne (pętle) Pętle pozwalają na powtarzanie fragmentu kodu programu. PĘTLE LOGICZNE WHILE...END WHILE While (warunek)...... End While Pętla będzie się wykonywała dopóki warunek jest spełniony.

Bardziej szczegółowo

Klasa bazowa i klasy potomne - doskonalenie umiejtnoci projektowania i wykorzystania klas (45 min)

Klasa bazowa i klasy potomne - doskonalenie umiejtnoci projektowania i wykorzystania klas (45 min) Zadanie5_28 Klasa bazowa i klasy potomne - doskonalenie umiejtnoci projektowania i wykorzystania klas (45 min) Opis zadania Wykorzystaj gotowy projekt Nowe auto, a nastpnie zaprojektuj klas bazow NoweAuto

Bardziej szczegółowo

Projekt Hurtownia, realizacja rejestracji dostaw produktów

Projekt Hurtownia, realizacja rejestracji dostaw produktów Projekt Hurtownia, realizacja rejestracji dostaw produktów Ćwiczenie to będzie poświęcone zaprojektowaniu formularza pozwalającego na rejestrację dostaw produktów dla naszej hurtowni. Dane identyfikujące

Bardziej szczegółowo

Algorytmika i Programowanie VBA 1 - podstawy

Algorytmika i Programowanie VBA 1 - podstawy Algorytmika i Programowanie VBA 1 - podstawy Tomasz Sokół ZZI, IL, PW Czas START uruchamianie środowiska VBA w Excelu Alt-F11 lub Narzędzia / Makra / Edytor Visual Basic konfiguracja środowiska VBA przy

Bardziej szczegółowo

Wykład 8: klasy cz. 4

Wykład 8: klasy cz. 4 Programowanie obiektowe Wykład 8: klasy cz. 4 Dynamiczne tworzenie obiektów klas Składniki statyczne klas Konstruktor i destruktory c.d. 1 dr Artur Bartoszewski - Programowanie obiektowe, sem. 1I- WYKŁAD

Bardziej szczegółowo

Program szkolenia PODSTAWY VBA (VISUAL BASIC FOR APPLICATIONS) I FORMULARZE.

Program szkolenia PODSTAWY VBA (VISUAL BASIC FOR APPLICATIONS) I FORMULARZE. Program szkolenia PODSTAWY VBA (VISUAL BASIC FOR APPLICATIONS) I FORMULARZE SZKOLENIE JEST DLA OSÓB, KTÓRE: znają program Microsoft Excel na poziomie średniozaawansowanym, chcą poznać ogólne zasady tworzenia

Bardziej szczegółowo

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody Obiektowy PHP Czym jest obiekt? W programowaniu obiektem można nazwać każdy abstrakcyjny byt, który programista utworzy w pamięci komputera. Jeszcze bardziej upraszczając to zagadnienie, można powiedzieć,

Bardziej szczegółowo

Języki skryptowe w programie Plans

Języki skryptowe w programie Plans Języki skryptowe w programie Plans Warsztaty uŝytkowników programu PLANS Kościelisko 2010 Zalety skryptów Automatyzacja powtarzających się czynności Rozszerzenie moŝliwości programu Budowa własnych algorytmów

Bardziej szczegółowo

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu. Część XIX C++ w Każda poznana do tej pory zmienna może przechowywać jedną liczbę. Jeśli zaczniemy pisać bardziej rozbudowane programy, okaże się to niewystarczające. Warto więc poznać zmienne, które mogą

Bardziej szczegółowo

Rozdział 4 KLASY, OBIEKTY, METODY

Rozdział 4 KLASY, OBIEKTY, METODY Rozdział 4 KLASY, OBIEKTY, METODY Java jest językiem w pełni zorientowanym obiektowo. Wszystkie elementy opisujące dane, za wyjątkiem zmiennych prostych są obiektami. Sam program też jest obiektem pewnej

Bardziej szczegółowo

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static), Tworzenie obiektów Dostęp do obiektów jest realizowany przez referencje. Obiekty w języku Java są tworzone poprzez użycie słowa kluczowego new. String lan = new String( Lancuch ); Obszary pamięci w których

Bardziej szczegółowo

Technologie i usługi internetowe cz. 2

Technologie i usługi internetowe cz. 2 Technologie i usługi internetowe cz. 2 Katedra Analizy Nieliniowej, WMiI UŁ Łódź, 15 luty 2014 r. 1 Programowanie obiektowe Programowanie obiektowe (z ang. object-oriented programming), to paradygmat programowania,

Bardziej szczegółowo

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta 16.09.2006. Strona 1 z 26. Powrót. Full Screen. Zamknij.

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta 16.09.2006. Strona 1 z 26. Powrót. Full Screen. Zamknij. Programowanie Sobera Jolanta 16.09.2006 Strona 1 z 26 1 Wprowadzenie do programowania 4 2 Pierwsza aplikacja 5 3 Typy danych 6 4 Operatory 9 Strona 2 z 26 5 Instrukcje sterujące 12 6 Podprogramy 15 7 Tablice

Bardziej szczegółowo

Programowanie w języku C++ Grażyna Koba

Programowanie w języku C++ Grażyna Koba Programowanie w języku C++ Grażyna Koba Kilka definicji: Program komputerowy to ciąg instrukcji języka programowania, realizujący dany algorytm. Język programowania to zbiór określonych instrukcji i zasad

Bardziej szczegółowo

Wykład 4. Tablice. Pliki

Wykład 4. Tablice. Pliki Informatyka I Wykład 4. Tablice. Pliki Dr inż. Andrzej Czerepicki Politechnika Warszawska Wydział Transportu 2017 Tablice Tablica uporządkowany zbiór elementów określonego typu Każdy element tablicy posiada

Bardziej szczegółowo

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost; Klasy w C++ są bardzo ważnym narzędziem w rękach programisty. Klasy są fundamentem programowania obiektowego. Z pomocą klas będziesz mógł tworzyć lepszy kod, a co najważniejsze będzie on bardzo dobrze

Bardziej szczegółowo

Informatyka I. Typy danych. Operacje arytmetyczne. Konwersje typów. Zmienne. Wczytywanie danych z klawiatury. dr hab. inż. Andrzej Czerepicki

Informatyka I. Typy danych. Operacje arytmetyczne. Konwersje typów. Zmienne. Wczytywanie danych z klawiatury. dr hab. inż. Andrzej Czerepicki Informatyka I Typy danych. Operacje arytmetyczne. Konwersje typów. Zmienne. Wczytywanie danych z klawiatury. dr hab. inż. Andrzej Czerepicki Politechnika Warszawska Wydział Transportu 2019 1 Plan wykładu

Bardziej szczegółowo

Opis: Instrukcja warunkowa Składnia: IF [NOT] warunek [AND [NOT] warunek] [OR [NOT] warunek].

Opis: Instrukcja warunkowa Składnia: IF [NOT] warunek [AND [NOT] warunek] [OR [NOT] warunek]. ABAP/4 Instrukcja IF Opis: Instrukcja warunkowa Składnia: IF [NOT] warunek [AND [NOT] warunek] [OR [NOT] warunek]. [ELSEIF warunek. ] [ELSE. ] ENDIF. gdzie: warunek dowolne wyrażenie logiczne o wartości

Bardziej szczegółowo

Programowanie. programowania. Klasa 3 Lekcja 9 PASCAL & C++

Programowanie. programowania. Klasa 3 Lekcja 9 PASCAL & C++ Programowanie Wstęp p do programowania Klasa 3 Lekcja 9 PASCAL & C++ Język programowania Do przedstawiania algorytmów w postaci programów służą języki programowania. Tylko algorytm zapisany w postaci programu

Bardziej szczegółowo

Programowanie. Projektowanie funkcje programu tworzenie algorytmu i struktur danych. Programowanie implementacja algorytmu kompilacja programu

Programowanie. Projektowanie funkcje programu tworzenie algorytmu i struktur danych. Programowanie implementacja algorytmu kompilacja programu Programowanie V Dariusz Skibicki Wydział Inżynierii Mechanicznej Uniwersytet Technologiczno-Przyrodniczy im. Jana i Jędrzeja Śniadeckich w Bydgoszczy dariusz.skibicki(at)utp.edu.pl Programowanie Projektowanie

Bardziej szczegółowo

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut.

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut. Dziedziczenie Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut. Rozpatrzmy przykład przedstawiający klasy Student oraz Pracownik: class Student class Pracownik

Bardziej szczegółowo

Ten odcinek Akademii PC Kuriera poświęcony zostanie tworzeniu i wykorzystaniu funkcji i procedur w języku Visual Basic.NET.

Ten odcinek Akademii PC Kuriera poświęcony zostanie tworzeniu i wykorzystaniu funkcji i procedur w języku Visual Basic.NET. Ten odcinek Akademii PC Kuriera poświęcony zostanie tworzeniu i wykorzystaniu funkcji i procedur w języku Visual Basic.NET. Czym są procedury? Efektywne tworzenie często polegać będzie na ponownym wykorzystywaniu

Bardziej szczegółowo

Bloki anonimowe w PL/SQL

Bloki anonimowe w PL/SQL Język PL/SQL PL/SQL to specjalny język proceduralny stosowany w bazach danych Oracle. Język ten stanowi rozszerzenie SQL o szereg instrukcji, znanych w proceduralnych językach programowania. Umożliwia

Bardziej szczegółowo

LABORATORIUM 3 ALGORYTMY OBLICZENIOWE W ELEKTRONICE I TELEKOMUNIKACJI. Wprowadzenie do środowiska Matlab

LABORATORIUM 3 ALGORYTMY OBLICZENIOWE W ELEKTRONICE I TELEKOMUNIKACJI. Wprowadzenie do środowiska Matlab LABORATORIUM 3 ALGORYTMY OBLICZENIOWE W ELEKTRONICE I TELEKOMUNIKACJI Wprowadzenie do środowiska Matlab 1. Podstawowe informacje Przedstawione poniżej informacje maja wprowadzić i zapoznać ze środowiskiem

Bardziej szczegółowo

Wprowadzenie do programowania w języku Visual Basic. Podstawowe instrukcje języka

Wprowadzenie do programowania w języku Visual Basic. Podstawowe instrukcje języka Wprowadzenie do programowania w języku Visual Basic. Podstawowe instrukcje języka 1. Kompilacja aplikacji konsolowych w środowisku programistycznym Microsoft Visual Basic. Odszukaj w menu startowym systemu

Bardziej szczegółowo

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie? 1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie? a) konstruktor b) referencje c) destruktor d) typy 2. Które z poniższych wyrażeń są poprawne dla klasy o nazwie

Bardziej szczegółowo

Algorytm. a programowanie -

Algorytm. a programowanie - Algorytm a programowanie - Program komputerowy: Program komputerowy można rozumieć jako: kod źródłowy - program komputerowy zapisany w pewnym języku programowania, zestaw poszczególnych instrukcji, plik

Bardziej szczegółowo

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej. Polimorfizm jest filarem programowania obiektowego, nie tylko jeżeli chodzi o język C++. Daje on programiście dużą elastyczność podczas pisania programu. Polimorfizm jest ściśle związany z metodami wirtualnymi.

Bardziej szczegółowo

Materiały pomocnicze do zajęć z przedmiotu Projekt ADP

Materiały pomocnicze do zajęć z przedmiotu Projekt ADP Dr Janusz Górczyński Materiały pomocnicze do zajęć z przedmiotu Projekt ADP Czym jest projekt ADP? Projekt Microsoft Access (.adp) jest typem pliku programu Access, który zapewnia skuteczny dostęp w trybie

Bardziej szczegółowo

Kiedy i czy konieczne?

Kiedy i czy konieczne? Bazy Danych Kiedy i czy konieczne? Zastanów się: czy często wykonujesz te same czynności? czy wielokrotnie musisz tworzyć i wypełniać dokumenty do siebie podobne (faktury, oferty, raporty itp.) czy ciągle

Bardziej szczegółowo

Pascal - wprowadzenie

Pascal - wprowadzenie Pascal - wprowadzenie Ogólne informacje o specyfice języka i budowaniu programów Filip Jarmuszczak kl. III c Historia Pascal dawniej jeden z najpopularniejszych języków programowania, uniwersalny, wysokiego

Bardziej szczegółowo

Tablice. Jones Stygar na tropie zmiennych

Tablice. Jones Stygar na tropie zmiennych Tablice Jones Stygar na tropie zmiennych Czym jest tablica? Obecnie praktycznie wszystkie języki programowania obsługują tablice. W matematyce odpowiednikiem tablicy jednowymiarowej jest ciąg (lub wektor),

Bardziej szczegółowo

Wydział Zarządzania AGH. Katedra Informatyki Stosowanej. Podstawy VBA cz. 2. Programowanie komputerowe

Wydział Zarządzania AGH. Katedra Informatyki Stosowanej. Podstawy VBA cz. 2. Programowanie komputerowe Wydział Zarządzania AGH Katedra Informatyki Stosowanej Podstawy VBA cz. 2 Programowanie 1 Program wykładu Typy danych Wyrażenia Operatory 2 VBA Visual Basic dla aplikacji (VBA) firmy Microsoft jest językiem

Bardziej szczegółowo

PHP 5 język obiektowy

PHP 5 język obiektowy PHP 5 język obiektowy Wprowadzenie Klasa w PHP jest traktowana jak zbiór, rodzaj różnych typów danych. Stanowi przepis jak stworzyć konkretne obiekty (instancje klasy), jest definicją obiektów. Klasa reprezentuje

Bardziej szczegółowo

Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie

Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie Część X C++ Typ znakowy służy do reprezentacji pojedynczych znaków ASCII, czyli liter, cyfr, znaków przestankowych i innych specjalnych znaków widocznych na naszej klawiaturze (oraz wielu innych, których

Bardziej szczegółowo

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość 1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość 2. Poprawna definicja wskażnika b to: a) float *a, **b = &a; b) float

Bardziej szczegółowo

Programowanie obiektowe - 1.

Programowanie obiektowe - 1. Programowanie obiektowe - 1 Mariusz.Masewicz@cs.put.poznan.pl Programowanie obiektowe Programowanie obiektowe (ang. object-oriented programming) to metodologia tworzenia programów komputerowych, która

Bardziej szczegółowo

Skrypty powłoki Skrypty Najcz ciej u ywane polecenia w skryptach:

Skrypty powłoki Skrypty Najcz ciej u ywane polecenia w skryptach: Skrypty powłoki Skrypty są zwykłymi plikami tekstowymi, w których są zapisane polecenia zrozumiałe dla powłoki. Zadaniem powłoki jest przetłumaczenie ich na polecenia systemu. Aby przygotować skrypt, należy:

Bardziej szczegółowo

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę.

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę. Języki C i C++ to bardzo uniwersalne platformy programistyczne o ogromnych możliwościach. Wykorzystywane są do tworzenia systemów operacyjnych i oprogramowania użytkowego. Dzięki niskiemu poziomowi abstrakcji

Bardziej szczegółowo

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main. Część XVI C++ Funkcje Jeśli nasz program rozrósł się już do kilkudziesięciu linijek, warto pomyśleć o jego podziale na mniejsze części. Poznajmy więc funkcje. Szybko się przekonamy, że funkcja to bardzo

Bardziej szczegółowo

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami. UML a kod w C++ i Javie Projektowanie oprogramowania Dokumentowanie oprogramowania Diagramy przypadków użycia Przewoznik Zarzadzanie pojazdami Optymalizacja Uzytkownik Wydawanie opinii Zarzadzanie uzytkownikami

Bardziej szczegółowo

Java EE produkcja oprogramowania

Java EE produkcja oprogramowania Java EE produkcja oprogramowania PPJ PODSTAWY PROGRAMOWANIA W JAVIE PODSTAWY JĘZYKA JAVA 1 Warszawa, 2016Z 2 Ogólna charakterystyka języka Java 3 Java 1/2 Język programowania Java został opracowany przez

Bardziej szczegółowo

Technologia informacyjna programowanie Janusz Uriasz

Technologia informacyjna programowanie Janusz Uriasz Technologia informacyjna programowanie Janusz Uriasz 2. Programowanie 2.1. Struktura programu, edycja, kompilacja, uruchomienie programu. Śledzenie programu VB- cd Składowe programu Procedura jest bardzo

Bardziej szczegółowo

Podstawy Programowania Obiektowego

Podstawy Programowania Obiektowego Podstawy Programowania Obiektowego Wprowadzenie do programowania obiektowego. Pojęcie struktury i klasy. Spotkanie 03 Dr inż. Dariusz JĘDRZEJCZYK Tematyka wykładu Idea programowania obiektowego Definicja

Bardziej szczegółowo

Programowanie w Javie 1 Wykład i Ćwiczenia 3 Programowanie obiektowe w Javie cd. Płock, 16 października 2013 r.

Programowanie w Javie 1 Wykład i Ćwiczenia 3 Programowanie obiektowe w Javie cd. Płock, 16 października 2013 r. Programowanie w Javie 1 Wykład i Ćwiczenia 3 Programowanie obiektowe w Javie cd. Płock, 16 października 2013 r. Programowanie obiektowe Programowanie obiektowe (z ang. object-oriented programming), to

Bardziej szczegółowo

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk Podstawy informatyki Informatyka stosowana - studia niestacjonarne Grzegorz Smyk Wydział Inżynierii Metali i Informatyki Przemysłowej Akademia Górniczo Hutnicza im. Stanisława Staszica w Krakowie, Materiał

Bardziej szczegółowo

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6 JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM Wykład 6 1 SPECYFIKATOR static Specyfikator static: Specyfikator ten powoduje, że zmienna lokalna definiowana w obrębie danej funkcji nie jest niszczona

Bardziej szczegółowo

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego Iwona Kochaoska Programowanie Obiektowe Programowanie obiektowe (ang. object-oriented programming) - metodyka tworzenia programów komputerowych,

Bardziej szczegółowo

Programowanie strukturalne. Opis ogólny programu w Turbo Pascalu

Programowanie strukturalne. Opis ogólny programu w Turbo Pascalu Programowanie strukturalne Opis ogólny programu w Turbo Pascalu STRUKTURA PROGRAMU W TURBO PASCALU Program nazwa; } nagłówek programu uses nazwy modułów; } blok deklaracji modułów const } blok deklaracji

Bardziej szczegółowo

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1 Podstawy programowania. Wykład Funkcje Krzysztof Banaś Podstawy programowania 1 Programowanie proceduralne Pojęcie procedury (funkcji) programowanie proceduralne realizacja określonego zadania specyfikacja

Bardziej szczegółowo

.NET Klasy, obiekty. ciąg dalszy

.NET Klasy, obiekty. ciąg dalszy .NET Klasy, obiekty ciąg dalszy Przeciążanie operatorów 1 W języku C# istnieje możliwość zdefiniowania funkcjonalności dużej części operatorów dla typów stworzonych przez użytkownika. Dzięki takiemu zabiegowi,

Bardziej szczegółowo

lekcja 8a Gry komputerowe MasterMind

lekcja 8a Gry komputerowe MasterMind lekcja 8a Gry komputerowe MasterMind Posiadamy już elementarną wiedzę w zakresie programowania. Pora więc zabrać się za rozwiązywanie problemów bardziej złożonych, które wymagają zastosowania typowych

Bardziej szczegółowo

Język ludzki kod maszynowy

Język ludzki kod maszynowy Język ludzki kod maszynowy poziom wysoki Język ludzki (mowa) Język programowania wysokiego poziomu Jeśli liczba punktów jest większa niż 50, test zostaje zaliczony; w przeciwnym razie testu nie zalicza

Bardziej szczegółowo

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Java - tablice, konstruktory, dziedziczenie i hermetyzacja Java - tablice, konstruktory, dziedziczenie i hermetyzacja Programowanie w językach wysokiego poziomu mgr inż. Anna Wawszczak PLAN WYKŁADU zmienne tablicowe konstruktory klas dziedziczenie hermetyzacja

Bardziej szczegółowo

Języki programowania zasady ich tworzenia

Języki programowania zasady ich tworzenia Strona 1 z 18 Języki programowania zasady ich tworzenia Definicja 5 Językami formalnymi nazywamy każdy system, w którym stosując dobrze określone reguły należące do ustalonego zbioru, możemy uzyskać wszystkie

Bardziej szczegółowo

Typy zmiennych proste i złożone. Programowanie komputerów. Tablica. Złożone typy zmiennych. Klasa. Struktura

Typy zmiennych proste i złożone. Programowanie komputerów. Tablica. Złożone typy zmiennych. Klasa. Struktura Programowanie komputerów Programowanie obiektowe. Typy zmiennych proste i złożone Typy zmiennych "wbudowane", tj. identyfikowane przez słowa kluczowe, są określane jako proste: int short long float double

Bardziej szczegółowo

Podstawy programowania. Ćwiczenie. Pojęcia bazowe. Języki programowania. Środowisko programowania Visual Studio

Podstawy programowania. Ćwiczenie. Pojęcia bazowe. Języki programowania. Środowisko programowania Visual Studio Podstawy programowania Ćwiczenie Pojęcia bazowe. Języki programowania. Środowisko programowania Visual Studio Tematy ćwiczenia algorytm, opis języka programowania praca ze środowiskiem, formularz, obiekty

Bardziej szczegółowo

Programowanie komputerów

Programowanie komputerów Programowanie komputerów Wykład 1-2. Podstawowe pojęcia Plan wykładu Omówienie programu wykładów, laboratoriów oraz egzaminu Etapy rozwiązywania problemów dr Helena Dudycz Katedra Technologii Informacyjnych

Bardziej szczegółowo

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna Język JAVA podstawy Wykład 3, część 3 1 Język JAVA podstawy Plan wykładu: 1. Konstrukcja kodu programów w Javie 2. Identyfikatory, zmienne 3. Typy danych 4. Operatory, instrukcje sterujące instrukcja warunkowe,

Bardziej szczegółowo

Podstawy programowania w języku C

Podstawy programowania w języku C Podstawy programowania w języku C WYKŁAD 1 Proces tworzenia i uruchamiania programów Algorytm, program Algorytm przepis postępowania prowadzący do rozwiązania określonego zadania. Program zapis algorytmu

Bardziej szczegółowo

Aplikacje geodezyjne

Aplikacje geodezyjne Aplikacje geodezyjne 1. Azymut ze współrzędnych Utwórz nowy projekt o nazwie Azymut. W oknie rozmieść kontrolki mniej więcej zgodnie z rysunkiem. Obiekty mają zmienione następujące wartości cech: cecha

Bardziej szczegółowo

Program szkolenia VBA (VISUAL BASIC FOR APPLICATIONS) W EXCELU PRZEKROJOWY.

Program szkolenia VBA (VISUAL BASIC FOR APPLICATIONS) W EXCELU PRZEKROJOWY. Program szkolenia VBA (VISUAL BASIC FOR APPLICATIONS) W EXCELU PRZEKROJOWY SZKOLENIE JEST DLA OSÓB, KTÓRE: chcą podnieść swoje umiejętności pracy w języku VBA do poziomu średniozaawansowanego, nigdy wcześniej

Bardziej szczegółowo

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Tablice (jedno i wielowymiarowe), łańcuchy znaków Tablice (jedno i wielowymiarowe), łańcuchy znaków wer. 8 z drobnymi modyfikacjami! Wojciech Myszka Katedra Mechaniki i Inżynierii Materiałowej 2017-04-07 09:35:32 +0200 Zmienne Przypomnienie/podsumowanie

Bardziej szczegółowo

Elementy języka C. ACprogramislikeafastdanceonanewlywaxeddancefloorbypeople carrying razors.

Elementy języka C. ACprogramislikeafastdanceonanewlywaxeddancefloorbypeople carrying razors. Wykład 3 ACprogramislikeafastdanceonanewlywaxeddancefloorbypeople carrying razors. Waldi Ravens J. Cichoń, P. Kobylański Wstęp do Informatyki i Programowania 75 / 146 deklaracje zmiennych instrukcja podstawienia

Bardziej szczegółowo

Zadanie. Menu Plik niech posiada dwie pozycje: Tekstowy i Excel, a każda z nich niech posiada dwie pozycje Otwórz i Zapisz, patrz rys. 2.

Zadanie. Menu Plik niech posiada dwie pozycje: Tekstowy i Excel, a każda z nich niech posiada dwie pozycje Otwórz i Zapisz, patrz rys. 2. Zadanie Wykonać aplikację posiadającą możliwość komunikowania się (zapis/odczyt) pomiędzy obiektem DataGridView, a plikiem tekstowym i plikiem MS Excel. Niech formularz ma postać jak na rys. 1. Rysunek

Bardziej szczegółowo

Wstęp do programowania

Wstęp do programowania Wstęp do programowania wykład 2 Piotr Cybula Wydział Matematyki i Informatyki UŁ 2012/2013 http://www.math.uni.lodz.pl/~cybula Język programowania Każdy język ma swoją składnię: słowa kluczowe instrukcje

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Programowanie obiektowe Wykład 2: Wstęp do języka Java 3/4/2013 S.Deniziak: Programowanie obiektowe - Java 1 Cechy języka Java Wszystko jest obiektem Nie ma zmiennych globalnych Nie ma funkcji globalnych

Bardziej szczegółowo

Deklaracja struktury w C++

Deklaracja struktury w C++ Struktury to złożone typy danych pozwalające przechowywać różne informacje. Za pomocą struktur możliwe jest grupowanie wielu zmiennych o różnych typach w jeden obiekt. Strukturę można nazywać obiektem

Bardziej szczegółowo

Kurs WWW. Paweł Rajba. pawel@ii.uni.wroc.pl http://pawel.ii.uni.wroc.pl/

Kurs WWW. Paweł Rajba. pawel@ii.uni.wroc.pl http://pawel.ii.uni.wroc.pl/ Paweł Rajba pawel@ii.uni.wroc.pl http://pawel.ii.uni.wroc.pl/ Spis treści Wprowadzenie Automatyczne ładowanie klas Składowe klasy, widoczność składowych Konstruktory i tworzenie obiektów Destruktory i

Bardziej szczegółowo

Podstawy Programowania 2

Podstawy Programowania 2 Podstawy Programowania 2 Laboratorium 7 Instrukcja 6 Object Pascal Opracował: mgr inż. Leszek Ciopiński Wstęp: Programowanie obiektowe a programowanie strukturalne. W programowaniu strukturalnym, któremu

Bardziej szczegółowo

Program szkoleniowy. 24 h dydaktycznych (18 h zegarowych) NAZWA SZCZEGÓŁY CZAS

Program szkoleniowy. 24 h dydaktycznych (18 h zegarowych) NAZWA SZCZEGÓŁY CZAS Program szkoleniowy Microsoft Excel VBA Poziom Podstawowy 24 h dydaktycznych (18 h zegarowych) NAZWA SZCZEGÓŁY CZAS 1. Nagrywanie makr Procedura nagrywania makra Nadanie odpowiedniej nazwy Przypisanie

Bardziej szczegółowo

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak Java język programowania obiektowego Programowanie w językach wysokiego poziomu mgr inż. Anna Wawszczak 1 Język Java Język Java powstał w roku 1995 w firmie SUN Microsystems Java jest językiem: wysokiego

Bardziej szczegółowo

VBA praca z makrami w Excelu

VBA praca z makrami w Excelu VBA praca z makrami w Excelu Dariusz Aksamit Wydział Fizyki Politechniki Warszawskiej Szkolenie Programowanie w języku Visual Basic for Application (VBA) Zajęcia 1 i 2 VBA praca z makrami w Excelu 1. Jak

Bardziej szczegółowo