Paweł Górczyński, Janusz Górczyński. Aplikacja MS SQL Server i MS VB.NET do zarządzania studiami podyplomowymi

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

Download "Paweł Górczyński, Janusz Górczyński. Aplikacja MS SQL Server i MS VB.NET do zarządzania studiami podyplomowymi"

Transkrypt

1 W ykłady z infor matyki Paweł Górczyński, Janusz Górczyński Aplikacja MS SQL Server i MS VB.NET do zarządzania studiami podyplomowymi Wyższa Szkoła Zarządzania i Marketingu Sochaczew 2010

2 Książka ta jest dziewiątą 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 w 2010 roku Wydanie I Materiały do druku zostały w całości przygotowane przez Autorów 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 3 Spis treści 1. WSTĘP MODUŁ WSPÓLNY FORMULARZ GŁÓWNY APLIKACJI PROJEKT FORMULARZA FRMMDISTUDIA KOD FORMULARZA FRMMDISTUDIA PLIK KONFIGURACYJNY APLIKACJI WŁASNE FORMANTY W VB.NET FORMANT NUMERU RACHUNKU BANKOWEGO Projekt formantu NrRachunkuB ankowego Dodanie formantu do przybornika Testowanie utworzonego formantu FORMANT ADRESU MAILOWEGO Projekt formantu Kod formantu AdresMailowy Testowanie formantu i dodanie do Toolboxa FORMANT PRZEŁĄCZNIKA TOGGLENUD Projekt formantu ToggleNUD Kod formantu ToggleNUD Testowanie formantu i dodanie do przybornika FORMANT NUMERU PESEL Projekt formantu Pesel Kod formantu Pesel Testowanie formantu Pesel EDYCJE STUDIÓW PODYPLOMOWYCH TABELE I RELACJE MIĘDZY NIMI PROCEDURY I FUNKCJE PRZECHOWYWANE Wykorzystane w IEdycjeStudiow Wykorzystane w IKierunkiStudiow Wykorzystane w IPrzedmioty Wykorzystane w IEdycjeKierunki Wykorzystane w IKierunekPrzedmioty Wykorzystane w IWykladowcyPrzedmioty Wykorzystane w IEdycjeLimituMiejsc... 70

4 KLASA CEDYCJAKIERUNEKPRZEDMIOT Interfejs IEdycjaStudiow Interfejs IKierunkiStudiow Interfejs IPrzedmioty Interfejs IEdycjeKierunki Interfejs IEdycjaLimituMiejsc Interfejs IKierunkiPrzedmioty Interfejs IWykladowcyPrzedmioty OBSŁUGA EDYCJI STUDIÓW Rejestracja nowej edycji Modyfikacja istniejących edycji OBSŁUGA KIERUNKU STUDIÓW Rejestracja nowego kierunku studiów Aktualizacja istniejących kierunków Edycja limitu miejsc i kosztu studiów OBSŁUGA PRZEDMIOTÓW Rejestracja nowego przedmiotu Edycja przedmiotów SKOJARZENIA Skojarzenie edycji i kierunków studiów Skojarzenie kierunku studiów i przedmiotów Skojarzenie wykładowcy i przedmiotów USUNIĘCIE SKOJARZEŃ Edycji studiów i kierunków Kierunków studiów i przedmiotów Wykładowców i przedmiotów REALIZACJA ZAJĘĆ TABELE BAZY DANYCH PROCEDURY PRZECHOWYWANE Wykorzystywane w IRejestracjaTerminow Wykorzystywane w IRejestracjaPlanow Wykorzystywane w IObecnosci Wykorzystywane w ITesty Wykorzystywane w ISzkolenia Wykorzystywane w IDaneAnkiet KLASA CREALIZACJA Interfejs IRejestracjaTerminow Interfejs IRejestracjaPlanow Interfejs IObecnosci Interfejsc ITesty

5 Interfejs ISzkolenia Interfejs IDaneAnkiet REJESTRACJA TERMINÓW ZAJĘĆ Projekt formularza frmterminy Modyfikacja menu aplikacji Kod formularza frmterminy EDYCJA TERMINÓW ZAJĘĆ REJESTRACJA PLANÓW ZAJĘĆ Projekt formularza frmplanyzajec Modyfikacja menu aplikacji Kod formularza frmplanyzajec EDYCJA PLANÓW ZAJĘĆ Formularz frmedycjaplanow Kod formularza frmedycjaplanow Formularz edycji pola tekstowego typu Dialog Wykorzystanie formularza frmedytujtextbox REJESTRACJA OBECNOŚCI Projekt formularza frmrejestrobecnosci Kod formularza frmrejestrobecnosci EDYCJA OBECNOŚCI Projekt formularza frmedycjaobecnosci Kod formularza frmedycjaobecnosci REJESTRACJA TESTÓW PRZEDMIOTOWYCH Projekt formularza frmrejestrtestowp Kod formularza frmrejestrtestowp Rejestracja wyników testu przedmiotowego Edycja wyników testu przedmiotowego REJESTRACJA TESTÓW SEMESTRALNYCH Projekt formularza frmrejestrtestus Kod formularza frmrejestrtestus Rejestrowanie wyników testu semestralnego Aktualizowanie wyników testu semestralnego ZGŁOSZENIE SZKOLEŃ Projekt formularza frmzgloszenieszkolen Kod formularza frmzgloszenieszkolen REJESTRACJA WYNIKÓW ANKIET Formularz frmankieta Kod formularza frmankieta

6 6 7. RAPORTY PROCEDURY PRZECHOWYWANE Wykorzystane w IRaportyObecnosci Wykorzystane w IRaportyTestow Wykorzystane w IRaportyAnkiet Wykorzystane w IWzorceAnkiet KLASA CRAPORTY Interfejs IRaportyObecnosci Interfejs IRaportyTestow Interfejs IRaportyAnkiet Interfejs IWzorceAnkiet RAPORTY OBECNOŚCI Projekt formularza frmprzygotujraportobecnosci Projekt formularza frmraportobecnosci RAPORTY TESTÓW PRZEDMIOTOWYCH Projekt formularza frmraporttestup Kod formularza frmraporttestup RAPORTY TESTÓW SEMESTRALNYCH Projekt formularza frmraporttestowsemestralnych Kod formularza frmraporttestowsemestralnych RAPORTY ANKIET PRZEDMIOTOWYCH Wg kierunków studiów i zjazdów Utworzenie DataSet i DataTable Przygotowanie szablonu raportu Przygotowanie formularza prezentującego raport Kod formularza prezentującego raport Widok gotowych raportów ankiet przedmiotowych PRZYGOTOWANIE WZORCÓW ANKIET PRZEDMIOTOWYCH Projekt formularza frmprzygotowanieankiet Utworzenie obiektu DataTable Projekt szablonu crwzorzecankiety Projekt formularza frmankietyzjazdu Prezentacja raportu wzorców ankiet ROZLICZENIA FINANSOWE KLASA CSKLADKI TABELE WYKORZYSTANE DO ROZLICZEŃ PROCEDURY PRZECHOWYWANE I FUNKCJE SKALARNE Wykorzystywane w IRozliczenieWykladowcow Wykorzystywane w IRozliczeniaAdministracji

7 KLASA CROZLICZENIA Interfejsy klasy CRozliczenia Interfejs IRozliczenieWykladowcow Interfejs IRozlicznieAdministracji Kod klasy CRozliczenia SZABLON RAPORTU PRZELEWU BANKOWEGO FORMULARZ PREZENTUJĄCY RAPORT PRZELEWU ROZLICZENIE WYKŁADOWCÓW Formularz frmrozliczeniewykladowcow Kod formularza frmrozliczeniewykladowcow ROZLICZENIE PRACOWNIKÓW ADMINISTRACYJNYCH Projekt formularza frmwyplataadministracyjna Kod formularza frmwyplataadministracyjna RAPORT SKŁADEK Formularza frmraportskladek Kod formularza frmraportskladek Widok raportu składek LITERATURA INDEKS

8 8

9 1. Wstęp Od 2008 roku Uczelnia nasza rozpoczęła realizację studiów podyplomowych we współpracy z PARP, między innymi w ramach kierunku Projektowanie aplikacji bazodanowych w środowisku Windows. Książka, którą prezentujemy opisuje proces projektowania aplikacji zarządzającej realizacją tego typu studiów. Aplikacja została przygotowana w środowisku MS SQL Server (bazy danych) oraz VisualStudio.NET (interfejs). Dla ułatwienia przeglądania prezentowanych treści przyjeliśmy następującą konwencję: Kod procedur i funkcji wypisywany jest czcionką Courier New w rozmiarze 9 punktów; Komentarze w instrukcjach SQL procedur przechowywanych, funkcji i widoków poprzedzone są dwoma symbolami minus; -- to jest przykład komentarza w SQL Nazwy zmiennych prywatnych klas poprzedzone są prefiksem m ; Nazwy procedur, funkcji, tabel i ich pól w tekście wypisywane są czcionką Courier New w rozmiarze 10 punktów; Nazwy właściwości formantów oraz ich tytuły w formularzach wypisywane są czcionką pochyloną; Nazwy poleceń w menu także wypisywane są czcionką pochyloną; W prezentowanych zrzutach ekranowych tabel, widoków, formularzy i raportów dane studentów i większości pracowników są fikcyjne. Pozycja, którą oddajemy Czytelnikom nie jest klasycznym podręcznikiem programowania języka Transact-SQL ani języka Visual Basic w wersji.net. Naszym celem było pokazanie zastosowania tych języków do rozwiązania konkretnego problemu praktycznego przygotowania w środowisku VB.NET aplikacji wspierającej zarządzanie studiami podyplomowymi. W książce zawarliśmy projekt bazy danych utworzonej na serwerze MS SQL Server wraz z kodami procedur przechowywanych umożliwiających dostęp do informacji gromadzonych w tabelach tej bazy.. Dostęp ten realizowany jest poprzez interfejs napisany w VisualBasic.NET. Opis tego interfejsu zawiera szereg autorskich rozwiązań w zakresie programowania baz danych, w szczególności w dostępie do procedur przechowywanych SQL. Oddawana do rąk Czytelników pozycja nie jest opisem handlowym gotowej, w pełni profesjonalnej aplikacji, którą można bezpośrednio wykorzystać do zarządzania tego typu studiami. Jest raczej opisem pewnej koncepcji, jak to zarządzanie powinno być wspomagane, większość funkcjonalności jest praktycznie opracowana całkowicie, ale są też 9

10 10 takie, które są tylko zarysowane, a niektóre pominięte (np. rejestracja pracowników i edycja ich danych, rejestracja danych studentów, ich wpłat czesnego z raportowaniem). Na dołączonym krążku CD znajduje się projekt baz danych z przykładowymi danymi, kod źródłowy interfejsu aplikacji oraz pełny tekst niniejszej pozycji w formacie pliku PDF.

11 2. Moduł wspólny 11 Praktycznie w każdej aplikacji składającej się z wielu różnych modułów pojawia się konieczność zaprojektowania takich funkcji i procedur, które mogą być wykorzystywane w pozostałych modułach tworzonej aplikacji. Taki charakter ma moduł o nazwie Parp.vb, w którym utworzono szereg pomocniczych funkcji i procedur, które będą dostępne w każdym innym module naszej aplikacji. W module tym zadeklarowano także szereg stałych i zmiennych, które będą zmiennymi globalnymi dla naszej aplikacji, czyli będzie można z nich korzystać w dowolnym miejscu tworzonej aplikacji. Poniżej pełny kod tego modułu wraz ze stosownymi komentarzami. Imports System.Math ' na potrzeby funkcji Round Module Parp ' deklaracja globalnych zmiennych i stałych Public strtytul As String, strbaza As String = "", _ bsqlok As Boolean = False Public Const conmsgerr As String = _ "Studia podyplomowe, obsługa błędu czasu wykonania" Public Const conmsgok As String = _ "Studia podyplopmowe WSZiM w Sochaczewie" Public flaga As Boolean, KtoryRaport, FolderAnkiet As String Public MojaTabela As DataTable Dim MyDataGridViewPrinter As CDataGridPrint Dim WithEvents MyPrintDocument As PrintDocument Funkcja UstalGrb zwraca, na podstawie ostatniego znaku nazwy formantu typu RadioButton, wartość przycisków radiowych umieszczonych w kontenerze typu GroupBox, a jeżeli jest to niemożliwe to zwraca wartość -1. Public Function UstalGrb(ByVal grb As GroupBox) As Integer Dim rdb As RadioButton ' przeglądamy kolekcję przycisków radiowych w kontenerze For Each rdb In grb.controls If rdb.checked Then ' jest zaznaczony, próbujemy pobrać ostatni znak z nazwy ' i skonwertować go na cyfrę, robimy to w bloku ' Try Catch, ponieważ nie mamy gwarancji, że znak ten ' reprezentuje cyfrę Try Return CInt(rdb.Name.Substring(rdb.Name.Length - 1, 1)) Catch ex As Exception ' mamy błąd konwersji, zwracamy -1 Return -1 End Try Next End Function

12 12 Procedura UstawComboBox będzie wykorzystywana do zbudowania źródła danych dla wskazanego formantu, przy czym będzie to wykonywane tylko wtedy, gdy takie dane zostały poprawnie przygotowane. Public Sub UstawComboBox(ByRef cbo As ComboBox, ByVal tb As _ DataTable, ByVal txtdisplay As String, _ ByVal txtvalue As String, _ Optional ByVal txtkom As String = "") If txtkom.length > 0 Then ' nie można utworzyć źródła danych, komunikat na ekran MsgBox(txtKom, MsgBoxStyle.Critical, conmsgerr) Else ' można, zaczynamy od wyłączenia obsługi zdarzenia ' SelectedValueChanged tego formantu poprzez ustawienie ' zmiennej flaga na False flaga = False With cbo.datasource = tb ' źródło danych.displaymember = txtdisplay ' pole wyświetlane.valuemember = txtvalue ' pole zwracane.selectedvalue = -1 ' brak wybranej pozycji End With ' włączenie obsługi zdarzenia SelectedValueChanged flaga = True Procedura UstawComboBoxColumn będzie wykorzystywana do zbudowania źródła danych dla wskazanego formantu. Public Sub UstawComboBoxColumn(ByRef cbo As _ DataGridViewComboBoxColumn, ByVal tb As DataTable, _ ByVal txtdpn As String, ByVal txtdisplay As String, _ ByVal txtvalue As String, ByVal txttytul As String, _ Optional ByVal szer As Integer = 0) flaga = False With cbo.datapropertyname = txtdpn.datasource = tb.displaymember = txtdisplay.valuemember = txtvalue.headertext = txttytul If szer > 0 Then.Width = szer End With flaga = True Funkcja ObslugaBledu ustawia stan błędu w formancie ctl, będziemy ją wykorzystywać dla uproszczenia kodu sprawdzającego poprawność wprowadzonych

13 13 danych w polu tekstowym albo do sprawdzenia, czy dokonano wyboru w polu kombo czy w liście. Public Function ObslugaBledu(ByRef ctl As Object, _ ByVal txtkom As String, ByRef erp As ErrorProvider, _ Optional ByVal fokus As Boolean = False) As Boolean erp.seterror(ctl, txtkom) Beep() If fokus Then ctl.focus() Return True End Function Funkcja CzyTextBoxDobry bada, czy informacja wpisana do pola tekstowego spełnia wymagania co do długości tekstu. Jeżeli nie, to wyświetlane są stosowne komunikaty i zwracana wartość True. Opcjonalnie fokus może być ustawiony w sprawdzanym polu tekstowym. Public Function CzyTextBoxDobry(ByRef txtbox As TextBox, _ ByRef errpro As ErrorProvider, _ ByVal txtkom As String, Optional ByVal lenmin As _ Integer = 0, Optional ByVal lenmax As Integer = 0, _ Optional ByVal fokus As Boolean = False) As Boolean txtbox.text = Trim(txtBox.Text) If txtbox.text.length = 0 Then Return ObslugaBledu(txtBox, txtkom, errpro, fokus) ' nie jest to pusty ciąg znaków, czy mamy sprawdzać długość? ' jezeli lenmax <> 0, to sprawdzamy, czy długość jest między ' lenmin i lenmax If lenmax > 0 Then If txtbox.text.length < lenmin Then Return ObslugaBledu(txtBox, _ "Długość tekstu nie może być mniejsza niż " & _ lenmin.tostring & " znaków", errpro, fokus) If txtbox.text.length > lenmax Then Return ObslugaBledu(txtBox, _ "Długość tekstu nie może być większa niż " & _ lenmax.tostring & " znaków", errpro, fokus) errpro.seterror(txtbox, "") Return False End Function Funkcja CzyTextBoxNumeryczny bada, czy informacja wpisana do pola tekstowego jest liczbą, opcjonalnie także czy jest to liczba z podanego przedziału.

14 14 Public Function CzyTextBoxNumeryczny(ByRef txtbox As TextBox, _ ByRef errpro As ErrorProvider, ByVal txtkom As String, _ Optional ByVal MinValue As Decimal = 0, _ Optional ByVal MaxValue As Decimal = 0, _ Optional ByVal fokus As Boolean = False) As Boolean txtbox.text = Trim(txtBox.Text) If txtbox.text.length = 0 Then Return ObslugaBledu(txtBox, txtkom, errpro, fokus) ' nie jest to pusty ciąg znaków, czy jest to liczba? If Not IsNumeric(txtBox.Text) Then Return ObslugaBledu(txtBox, _ "Wprowadzony ciąg znaków nie jest liczbą", errpro, fokus) Dim xp As Decimal = CDec(txtBox.Text) If minvalue < MaxValue Then If xp < MinValue Then Return ObslugaBledu(txtBox, _ "Wprowadzona wartość nie może być większa od " & _ MaxValue.ToString, errpro, fokus) ElseIf xp > MaxValue Then Return ObslugaBledu(txtBox, _ "Wprowadzona wartość nie może być większa od " & _ MaxValue.ToString, errpro, fokus) errpro.seterror(txtbox, "") Return False End Function Funkcja CzyDobreCombo bada, czy w polu kombo dokonano wyboru, jeżeli nie, to wyświetlany jest stosowny komunikat i zwracana wartość True. Public Function CzyDobreCombo(ByRef cbo As ComboBox, _ ByVal txtkom As String, ByRef errpro As ErrorProvider, _ Optional ByVal fokus As Boolean = False) As Boolean If cbo.selectedvalue = Nothing Then Return ObslugaBledu(cbo, txtkom, errpro, fokus) errpro.seterror(cbo, "") Return False End Function Funkcja CzyDobraLista bada, czy w polu listy dokonano wyboru, jeżeli nie, to wyświetlany jest stosowny komunikat i zwracana wartość True. Public Function CzyDobraLista(ByRef lst As ListBox, _ ByVal txtkom As String, ByRef errpro As ErrorProvider, _ Optional ByVal fokus As Boolean = False) As Boolean

15 15 If lst.items.count = 0 Then Return ObslugaBledu(lst, txtkom, errpro, fokus) errpro.seterror(lst, "") Return False End Function Procedura ZaznaczRdb selekcjonuje wskazany przycisk radiowy. Public Sub ZaznaczRdb(ByRef rdb As RadioButton) flaga = False rdb.checked = True flaga = True Procedura ZdejmijZaznaczenieGrb zdejmuje zaznaczenie z przycisków radiowych w grupie opcji. Public Sub ZdejmijZaznaczenieGrb(ByRef grb As GroupBox) Dim rdb As RadioButton For Each rdb In grb.controls If rdb.checked Then rdb.checked = False Next Funkcja ZbudujTabele jest dość skomplikowana, a potrzeba jej zaprojektowania wynikła z trudności w zbudowaniu po stronie SQL tabeli przestawnej przy nieznanej liczbie kolumn. W tej sytuacji zdecydowaliśmy się to zrobić po stronie VB.NET, ponieważ korzyści z posiadania takiego zestawienia są bardzo duże. Przy jej konstrukcji założyliśmy, że do funkcji zostanie przekazana tabela rekordsetu z trzema kolumnami, pierwsza zawiera opisy wierszy przyszłej tabeli, druga opisy kolumn, a trzecia wartości zestawiane w komórkach tabeli. Problem polega na tym, że liczba wierszy jak i liczba kolumn nie są znane i muszą być ustalane w trakcie budowania takiej tabeli (przestawnej). Public Function ZbudujTabele(ByVal mtabela As DataTable, ByVal _ OpisKolumnyZero As String, Optional ByVal jakie As _ Integer = 1) As DataTable ' zakładamy, że wierszy może być max. 100, a kolumn 20 Dim W(100) As String, K(20) As String Dim i, j As Integer, tw, tk As String, f As Boolean Dim ilew As Integer = 0, ilek As Integer = 0 With mtabela W(0) =.Rows(0).Item(0).ToString K(0) =.Rows(0).Item(1).ToString ' przejrzymy teraz resztę wierszy For i = 1 To.Rows.Count - 1 tw =.Rows(i).Item(0).ToString f = False

16 16 ' sprawdzamy, czy już nie ma takiej pozycji w W() For j = 0 To ilew If tw = W(j) Then f = True Exit For Next If Not f Then ' dodajemy ilew += 1 W(ileW) = tw ' w ilew mamy liczbę różnych wierszy ' teraz kolumny tk =.Rows(i).Item(1).ToString f = False ' sprawdzamy, czy już nie ma takiej pozycji w K() For j = 0 To ilek If tk = K(j) Then f = True Exit For Next If Not f Then ' dodajemy ilek += 1 K(ileK) = tk Next End With 'musimy posortować obie macierze Dim Wiersze() As String, Kolumny() As String ReDim Wiersze(ileW) For i = 0 To ilew Wiersze(i) = W(i) Next Array.Sort(Wiersze) ReDim Kolumny(ileK) For i = 0 To ilek Kolumny(i) = K(i) Next Array.Sort(Kolumny) ReDim Preserve Kolumny(ileK + 1) If jakie = 1 Then Kolumny(ileK + 1) = "Razem" Else Kolumny(ileK + 1) = "Średnio" Dim x(,) As Decimal ReDim x(ilew + 1, ilek + 1) ' czytamy teraz wszystkie wiersze ustawiając pozycję z

17 17 ' trzeciej kolumny na właściwym przecięciu With mtabela For i = 0 To.Rows.Count - 1 tw =.Rows(i).Item(0).ToString tk =.Rows(i).Item(1).ToString x(ustalindex(tw, Wiersze), UstalIndex(tk, Kolumny)) = _.Rows(i).Item(2) Next ' podsumowania w wierszach macierzy x For i = 0 To ilew For j = 0 To ilek x(i, ilek + 1) += x(i, j) Next Next End With Dim tb As New DataTable tb.columns.add(new DataColumn(OpisKolumnyZero, _ GetType(String))) If jakie = 1 Then For i = 0 To ilek + 1 tb.columns.add(new DataColumn(Kolumny(i), _ GetType(Integer))) Next Else For i = 0 To ilek + 1 tb.columns.add(new DataColumn(Kolumny(i), _ GetType(Decimal))) Next Dim objw() As Object ReDim objw(ilek + 2) For i = 0 To ilew objw(0) = Wiersze(i) For j = 0 To ilek + 1 objw(j + 1) = x(i, j) Next tb.rows.add(objw) Next Return tb End Function Funkcja ZbudujTabele korzysta z prywatnej, pomocniczej funkcji pokazanej niżej, jej zadaniem jest ustalenie indeksu danego tekstu w zmiennej tablicowej. Private Function UstalIndex(ByVal tt As String, ByRef u() As _ String) As Integer Dim i As Integer For i = 0 To UBound(u) If u(i) = tt Then

18 18 Exit For Next Return i End Function Trzy kolejne funkcje zostały napisane na potrzeby obsługi bankowości elektronicznej. Pierwsza z nich przekształca rachunek bankowy zapisany w grupach cyfr ze spacjami w jednolity ciąg cyfr. Public Function RachunekBezSpacji(ByVal t As String) As String Dim z() As String, i As Integer t = Trim(t) If Len(t) > 26 Then z = Split(t, " ") t = "" For i = 0 To UBound(z) t = t & z(i) Next i Return t End Function W trakcie przygotowywania przelewów z rachunków firmowych konieczne jest zapisanie informacji opisowych w tzw. blokach po 35 znaków z użyciem separatora w postaci znaku. Public Function Tekst35znakow(ByVal t As String) As String If Len(t) > 35 Then Tekst35znakow = Chr(34) & Left(t, 35) ' pierwsze pole t = Right(t, Len(t) - 35) If Len(t) > 35 Then ' drugie pole Tekst35znakow &= " " & Left(t, 35) t = Right(t, Len(t) - 35) If Len(t) > 35 Then ' trzecie pole Tekst35znakow &= " " & Left(t, 35) t = Right(t, Len(t) - 35) If Len(t) > 35 Then ' czwarte pole Tekst35znakow &= " " & Left(t, 35) Else Tekst35znakow &= " " & t Else Tekst35znakow %= " " & t Else Tekst35znakow &= " " & t

19 19 Else Tekst35znakow = Chr(34) & t Tekst35znakow = Tekst35znakow & Chr(34) End Function Public Function DajWierszDoHomeBanking(ByVal mtable As _ DataTable, ByVal td As String) As String Dim tp, kw, rp, rb, kc As String, Kwota As Decimal kc = Chr(34) rp = mtable.rows(0).item(3).tostring rb = mtable.rows(0).item(8) Kwota = Round(mtable.Rows(0).Item(4) * 100, 0) kw = Kwota.ToString tp = td & "," & kw & "," & "0" & "," & "0" & "," & kc & _ rb & kc & "," & kc & rp & kc & "," tp &= Tekst35znakow("WSZiM w Sochaczewie ul. " & _ "Stadionowa Sochaczew") & "," tp &= Tekst35znakow(Trim(mtable.Rows(0).Item(1)) & " " & _ Trim(mtable.Rows(0).Item(6)) & " " & _ Trim(mtable.Rows(0).Item(5))) & "," tp &= Mid(rb, 3, 8) & "," & Mid(rp, 3, 8) & "," & _ Tekst35znakow(Trim(mtable.Rows(0).Item(7))) & "," tp = tp & kc & kc & "," & kc & kc & "," & kc & "51" & kc & _ "," & kc & "0" & kc Return tp End Function Funkcja GridDoSchowka odpowiada za wstawienie zawartości wskazanego formantu typu DataGridView do schowka Windows. Public Function GridDoSchowka(ByVal dgv As DataGridView, _ ByVal ilekolumn As Integer) As String Dim txt As String = "", i, j As Integer With dgv If.RowCount > 0 Then For i = 0 To ilekolumn - 1 txt &=.Columns(i).DataPropertyName & vbtab Next txt &= vbcr For i = 0 To.RowCount - 1 For j = 0 To ilekolumn - 1 txt &=.Rows(i).Cells(j).Value.ToString & vbtab Next j txt &= vbcr Next i End With

20 20 Return txt End Function Funkcja ZapiszGridDoExcela odpowiada za zapisanie zawartości wskazanego gridu w skoroszycie MS Excel. Public Sub ZapiszGridDoExcela(ByVal dgv As DataGridView, _ ByVal txtod As String, ByVal ilekolumn As Integer) If dgv.rowcount = 0 Then Exit Sub Dim oexcel, obook, osheet As Object, i, j As Integer, _ x As Integer = 0 Dim f As New SaveFileDialog Try ' uruchomienie nowego skoroszytu w programie Excel oexcel = CreateObject("Excel.Application") obook = oexcel.workbooks.add ' dodanie nagłówków do arkusza w wierszu 1 osheet = obook.worksheets(1) With dgv For i = 0 To ilekolumn - 1 osheet.range(txtod).offset(x, i) = _.Columns(i).DataPropertyName Next For i = 0 To.RowCount - 1 For j = 0 To ilekolumn - 1 osheet.range(txtod).offset(i x, j).value = _.Rows(i).Cells(j).Value Next j Next i End With f.filter = "Pliki MS Excel (*.xls) *.xls" If f.showdialog = DialogResult.OK Then obook.saveas(f.filename) 'Zapisanie skoroszytu i zakończenie pracy programu Excel obook.close() oexcel.quit() ' zwolnienie obiektów ZwolnijObiekt(oExcel) ZwolnijObiekt(oBook) ZwolnijObiekt(oSheet) Catch ex As Exception MsgBox("Pojawił się problem z zapisem danych do Excela", _ MsgBoxStyle.Critical, conmsgok) End Try Zadaniem procedury ZwolnijObiekt jest siłowe usunięcie z pamięci RAM niepotrzebnego już obiektu.

21 21 Public Sub ZwolnijObiekt(ByVal obj As Object) Try System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) obj = Nothing Catch ex As Exception obj = Nothing Finally GC.Collect() End Try Funkcja UstawDrukGridu będzie wykorzystywana przy wydrukowaniu zawartości formantu typu DataGridView. Public Function UstawDrukGridu(ByVal dgv As DataGridView, _ ByVal tytul As String) As TypBooleanPrintPage Dim w As TypBooleanPrintPage w.f = False w.p = MyPrintDocument Dim MyPrintDialog As PrintDialog = New PrintDialog() With MyPrintDialog.AllowCurrentPage = False.AllowPrintToFile = False.AllowSelection = False.AllowSomePages = False.PrintToFile = False.ShowHelp = False.ShowNetwork = False End With If MyPrintDialog.ShowDialog() = DialogResult.OK Then MyPrintDocument = New PrintDocument With MyPrintDocument.DocumentName = "RaportGridu".PrinterSettings = MyPrintDialog.PrinterSettings.DefaultPageSettings = _ MyPrintDialog.PrinterSettings.DefaultPageSettings.DefaultPageSettings.Margins = _ New Margins(40, 40, 40, 40) End With If MsgBox("Czy raport ma być wycentrowany na stronie?", _ MsgBoxStyle.Question, "Wydruk gridu") = _ MsgBoxResult.Yes Then MyDataGridViewPrinter = New CDataGridPrint(dgv, _ MyPrintDocument, True, True, tytul, _ New Font("Times New Roman", 10, FontStyle.Bold, _ GraphicsUnit.Point), Color.Black, True) Else MyDataGridViewPrinter = New CDataGridPrint(dgv, _ MyPrintDocument, False, True, tytul, _

22 22 New Font("Times New Roman", 10, FontStyle.Bold, _ GraphicsUnit.Point), Color.Black, True) w.f = True w.p = MyPrintDocument Return w End Function Procedura poniższa obsługuje zdarzenie wydruku strony gridu w zakresie ustalenia, czy są dalsze strony do wydruku. Private Sub GridPrintPage(ByVal sender As _ System.Object, ByVal e As _ System.Drawing.Printing.PrintPageEventArgs) _ Handles MyPrintDocument.PrintPage Dim more As Boolean more = MyDataGridViewPrinter.DrawDataGridView(e.Graphics) If more = True Then e.hasmorepages = True Else e.hasmorepages = False Publiczna struktura (typ danych użytkownika) będzie wykorzystywana przez funkcję UstawDrukGridu. Public Structure TypBooleanPrintPage Dim f As Boolean Dim p As PrintDocument End Structure Procedura DodajKolumneDoDataTable odpowiada za dodanie do obiektu typu DataTable nowej kolumny jednego z trzech typów danych. Opcjonalnie kolumna ta wypełniana jest danymi określonego typu. Public Sub DodajKolumneDoDataTable(ByRef dt As DataTable, ByVal _ NazwaKolumny As String, ByVal JakiTyp As String, _ Optional ByVal WpiszWartosc As String = "") Dim i As Integer, newvalue As Object Select Case JakiTyp Case "S" dt.columns.add(new DataColumn(NazwaKolumny, _ GetType(String))) If WpiszWartosc.Length > 0 Then newvalue = WpiszWartosc Case "I" dt.columns.add(new DataColumn(NazwaKolumny, _ GetType(Integer))) If WpiszWartosc.Length > 0 Then newvalue = _

23 23 CInt(WpiszWartosc) Case "D" dt.columns.add(new DataColumn(NazwaKolumny, _ GetType(Decimal))) If WpiszWartosc.Length > 0 Then newvalue = _ CDec(WpiszWartosc) End Select ' jeżeli WpiszWartosc nie jest pusta If WpiszWartosc.Length > 0 Then For i = 0 To dt.rows.count - 1 dt.rows(i).item(nazwakolumny) = newvalue Next Kolejna procedura odpowiada za dodanie do obiektu typu DataTable wiersza podsumowania wraz z jego tytułem. Public Sub DodajWierszPodsumowaniaDoDataTable(ByRef dt As _ DataTable, ByVal txttytulpodsumowania As String) Dim objw() As Object, i, j As Integer, xp As Single With dt ReDim objw(.columns.count - 1) ' sumujemy kolumny dt od 1 kolumny objw(0) = txttytulpodsumowania For j = 1 To.Columns.Count - 1 xp = 0 For i = 0 To.Rows.Count - 1 xp +=.Rows(i).Item(j) Next objw(j) = xp Next ' dodajemy wiersz do obiektu datatable.rows.add(objw) End With Procedura UstawListBox odpowiada za zdefiniowanie źródła danych formantu typu ListBox, oczywiście wtedy, gdy z bazy danych zostały pobrane potrzebne dane. Jeżeli nie, to wyświetlany jest stosowny komunikat. Public Sub UstawListBox(ByRef lst As ListBox, ByVal tb As _ DataTable, ByVal txtdisplay As String, _ ByVal txtvalue As String, Optional ByVal txtkom As _ String = "") If txtkom.length > 0 Then MsgBox(txtKom, MsgBoxStyle.Critical, conmsgerr) Else flaga = False With lst

24 24.DataSource = tb.displaymember = txtdisplay.valuemember = txtvalue.selectedvalue = -1 End With flaga = True Procedura UstawChdListBox odpowiada za zdefiniowanie źródła danych formantu typu CheckedListBox, oczywiście wtedy, gdy z bazy danych zostały pobrane potrzebne dane. Jeżeli nie, to wyświetlany jest stosowny komunikat. Public Sub UstawChdListBox(ByRef chd As CheckedListBox, _ ByVal tb As DataTable, ByVal txtdisplay As String, _ ByVal txtvalue As String, Optional ByVal txtkom As _ String = "") If txtkom.length > 0 Then MsgBox(txtKom, MsgBoxStyle.Critical, conmsgerr) Else flaga = False With chd.datasource = tb.displaymember = txtdisplay.valuemember = txtvalue.selectedindex = Nothing End With flaga = True Funkcja DecimalLikeMoney może być wykorzystywana do konwersji danych typu Decimal do postaci polskiej waluty. Public Function DecimalLikeMoney(ByVal t As String) As String Return t.substring(0, t.length - 2) & " zł" End Function W trakcie dalszej pracy nad aplikacją być może zostaną napisane inne jeszcze funkcje i porcedury o charakterze globalnym dla prezentowanej aplikacji, wtedy dopiszemy je także do tego modułu.

25 3. Formularz główny aplikacji 3.1. Projekt formularza frmmdistudia 25 Formularz frmmdistudia został zaprojektowany jako kontener dla pozostałych formularzy aplikacji, a jego jedynym formantem jest MenuStrip1, formant pozwalający na zbudowanie rozwijanego menu. Projekt tego formularza pokazany jest niżej, widoczne jest menu główne i częściowo rozwinięta pierwsza jego pozycja. W oknie właściwości aplikacji ten formularz został wskazany jako formularz startowy, a jego właściwość WindowsState została ustawiona na Maximized, czyli na zmaksymalizowanie. Z większością pozycji menu aplikacji będą skojarzone procedury zdarzeniowe, które będą definować dalsze zachowanie naszej aplikacji Kod formularza frmmdistudia Imports System Imports System.Configuration Imports System.Configuration.ConfigurationSettings Public Class frmmdistudia ' procedura zdarzenia Load tego formularza odpowiada za pobranie ' z pliku kongiguracyjnego trzech potrzebnych informacji, które ' będą przypisane do zmiennych publicznych aplikacji Private Sub Form1_Load(ByVal sender As Object, ByVal e As _ System.EventArgs) Handles Me.Load Try strtytul = ConfigurationSettings.AppSettings("Tytul") strbaza = ConfigurationSettings.AppSettings("BazaSQL") FolderParp = ConfigurationSettings.AppSettings("FolderParp")

26 26 EmerytalnaPracownika = _ CSng(ConfigurationSettings.AppSettings(_ "EmerytalnaPracownika")) RentowaPracownika = _ CSng(ConfigurationSettings.AppSettings( _ "RentowaPracownika")) ChorobowaPracownika = _ CSng(ConfigurationSettings.AppSettings( _ "ChorobowaPracownika")) SkladkaZdrowia1 = _ CSng(ConfigurationSettings.AppSettings( _ "SkladkaZdrowia1")) SkladkaZdrowia2 = _ CSng(ConfigurationSettings.AppSettings( _ "SkladkaZdrowia2")) EnerytalnaFirmy = _ CSng(ConfigurationSettings.AppSettings( _ "EnerytalnaFirmy")) RentowaFirmy = _ CSng(ConfigurationSettings.AppSettings( _ "RentowaFirmy")) WypoczynkowaFirmy = _ CSng(ConfigurationSettings.AppSettings( _ "WypoczynkowaFirmy")) FunduszPracowniczy = _ CSng(ConfigurationSettings.AppSettings( _ "FunduszPracowniczy")) FirmyGSP = _ CSng(ConfigurationSettings.AppSettings( _ "FirmyGSP")) bsqlok = True Catch ex As Exception MsgBox("Mam problem z odczytaniem danych z app.config", _ MsgBoxStyle.Critical, conmsgerr) End Try ' ustawienie tytułu okna aplikacji Me.Text = strtytul ' procedura poniższa ma charakter pomocniczy, jej zadaniem jest ' zbadanie, czy zmienna txtkomunikat zawiera jakiś tekst, jeżeli ' tak, to zawartość tej zmiennej zostanie pokazana jako komunikat ' krytyczny, a formularz frm nie zostanie pokazany Private Sub PokazForm(ByRef frm As Form, ByVal txtkomunikat As _ String, Optional ByVal txttytulokna As String = "") If txtkomunikat.length > 0 Then MsgBox(txtKomunikat, MsgBoxStyle.Critical, conmsgerr) Else If txttytulokna.length > 0 Then

27 27 frm.text = txttytulokna frm.mdiparent = Me frm.show() ' przykład procedury uruchamiającej formularz rejestracji nowego ' studenta Private Sub mnunowystudent_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles mnunowystudent.click Dim frm As New frmnowystudent ' tworzymy nowy formularz ' deklarujemy nowy obiekt w oparciu o interfejs INowyStudent Dim w As INowyStudent ' tworzymy ten obiekt w oparciu o klasę CStudent w = New CStudent ' możemy wywołać metodę udostępnioną przez interfejs w.otwarcie(strbaza, frm) ' za pomocą PokazForm próbujemy pokazać formularz PokazForm(frm, w.komunikat) ' dalsze procedury uruchamiające formularze aplikacji End Class 3.3. Plik konfiguracyjny aplikacji W zasadzie każda aplikacja ma pewien zestaw informacji konfiguracyjnych, które powinny być pobrane z dysku w momencie jej uruchomienia. Można je przechowywać w plikach testowych z rozszerzeniem *.ini, można także w plikach znacznie bardziej uporządkowanych. W przypadku aplikacji tworzonych w środowisku.net można skorzystać ze specjalnego pliku typu Application Configuration File. Plik ten dodajemy do naszego rozwiązania tak jak inne obiekty, czyli wybierając go z okna szablonów. Standardowa jego nazwa to app.config, a informacje konfiguracyjne zapisywane są w standardzie dokumentów XML. Między znacznikami <appsettings> i </appsettings> dodawane są kolejne wartości zgodnie ze schematem <add key= NazwaKlucza value= Wartość klucza />. Poniżej fragment okna tego pliku z trzema wartościami opisującymi tytuł okna aplikacji, łańcuch połączenia do bazy danych SQL oraz ścieżkę do folderu, gdzie będą umieszczane pliki raportów czy innych dokumentów generowanych w naszej aplikacji. Kolejnych dziesięć kluczy opisuje wartości składek wykorzystywanych w obliczniach sladników płac.

28 28 W kodzie procedury wykonywanej w momencie startu naszej aplikacji możemy odczytać wartości zmiennych konfiguracyjnych instrukcjami jak niżej. zmienna = ConfigurationSettings.AppSettings("NazwaKlucza") W momencie tworzenia pliku wykonywalnego aplikacji plik app.config zapisywany jest w folderze bin\debug pod nazwą NazwaAplikacji.exe.config. Zawartość tego pliku może być zmodyfikowany w miarę potrzeby nawet przy pomocy takiego programu jak Notatnik. Poniżej widok tego pliku właśnie w Notatniku, w którym zmiana wartości kluczy jest banalna (ale trzeba pamiętać o tym, że konsekwencją dokonanych zmian może być problem z funkcjonowaniem aplikacji).

29 4. Własne formanty w VB.NET 29 Środowisko programistyczne Visual Studio dostarcza bardzo bogaty zestaw formantów (kontrolek), które można wykorzystywać we własnych projektach. W praktyce okazuje się, że w wielu przypadkach dobrze byłoby, abyśmy mogli dysponować własną, unikalną kontrolką, która lepiej będzie pasować do naszego rozwiązania niż standardowe kontrolki. Potrzeba dysponowania własną kontrolką wynika w wielu sytuacjach także z tego powodu, że w przypadku jej braku musielibyśmy użyć kilka kontrolek standardowych, co ani nie jest wygodne, ani eleganckie. Rozwiązaniem będzie zaprojektowanie własnych kontrolek, po ich wyposażeniu w odpowiedni kod będziemy mogli wykorzystywać je w tych wszystkich projektach, w których okaże się to bardziej efektywne niż wykorzystywanie standardowych formantów. W kolejnych kilku podrozdziałach przedstawimy sposób zaprojektowania formantów przeznaczonych do wprowadzania numerów rachunków bankowych, adresu mailowego i jeszcze kilku innych. Procedury wbudowane w te formanty będą odpowiadać nie tylko za zachowanie się tych formantów w trakcie projektowania, lecz także za walidację wprowadzanych informacji Formant numeru rachunku bankowego Projekt formantu NrRachunkuB ankowego Prace nad utworzeniem własnego formantu pozwalającego nie tylko na łatwiejsze wprowadzanie 26-cio cyfrowego numeru rachunku bankowego, lecz także na sprawdzenie jego poprawności zaczynamy od utworzenia nowego projektu w środowisku Visual Studio.

30 30 Po wywołaniu polecenia New Project z menu File w oknie Templates wskazujemy ikonę Windows Control Library, a w polu tekstowym Name wpisujemy nazwę tworzonego formantu. Klik przycisku OK tworzy nowy projekt. Po przejściu do okna kodu zmieniamy nazwę klasy tworzonego formantu z domyślnej UserControl1 na docelową, czyli w naszym przypadku będzie to NrRachunkuBankowego. Musimy także zmienić nazwę pliku klasy w oknie Solution Explorer. Wprowadzone zmiany pokazane są poniżej. Poza zmianami nazwy klasy formantu w sekcji deklaracji modułu klasy zaimportowano przestrzeń nazw System.ComponentModel, a w kodzie klasy wpisano instrukcję dziedziczenia po klasie System.Windows.Forms.UserControl. Kończymy ten etap prac przez zapisanie tworzonego projektu w wybranym miejscu na dysku. Zaczynamy od wywołania polecenia SaveAll z menu File, a następnie wskazujemy miejsce zapisania naszego projektu.

31 31 Po zapisaniu projektu możemy kontynuować prace nad zaprojektowaniem formantu do wprowadzania 26-cio cyfrowego numeru rachunku bankowego. Numer rachunku bankowego to ciąg znaków składający się z dwóch cyfr i dalej z 6 grup po cztery cyfry w każdej. Wykorzystamy pola tekstowe do wpisania kolejnych grup cyft tworzących pełny numer, kolejno będą to pola tekstowe o nazwach odpowiednio txtpierwszedwie, txtcztery1, txtcztery2 itd., aż do txtcztery6. Wysokość utworzonego formantu jest ustawiona na standardowe 20 pixeli, a szerokości pól tekstowych są tak dobrane, aby pomieściły 2 lub 4 cyfry: w pierwszym przypadku jest to 20 pixeli, w pozostałych 32 pixele. Iststne jest jeszcze ustawienie lokalizacji poszczególnych pól, w tym przypadku pierwszy z nich ustawiony jest w punkcie 0,0 (czyli 0 pixeli od lewej krawędzi formantu (formularza) i 0 pixeli od jego górnej krawędzi. Pozostałe pola tekstowe mają tak zmienioną odległość od lewej krawędzi, aby kolejne zaczynało się w tym miejscu, gdzie kończy się poprzednie. Przykładowo, pole txtcztery2 ustawione jest na pozycji 32, 0 (32 pixele od lewej krawędzi = 20 pixeli szerokość pierwszego pola i 32 pixele szerokości pola txtcztery1). Na prawo od ostatniego pola tekstowego pozostawiono pusty fragment formantu, będziemy w nim wyświetlać symbol wystąpienia błędu podczas walidacji poprawności wprowadzonego numeru.

32 32 Po zaprojektowaniu formantu musimy utworzyć procedury jego obsługi. Po przejściu do okna kodu klasy uzupełniamy wstępne instrukcje o poniższe deklaracje i procedury. Imports System.ComponentModel ' kod klasy tworzonego formantu Public Class NrRachunkuBankowego ' instrukcja dziedziczenia po klasie bazowej UserControl Inherits System.Windows.Forms.UserControl ' definicja typu wyliczanego, jest on konieczny do ' utworzenia właściwości Input Type, z jej pomocą użytkownik ' będzie mógł włączyć/wyłączyć walidację znaków w grupach Enum selection Tak = True Nie = False End Enum ' deklaracja stałych niezbędnych do przerysowania składowych ' formantu w przypadku zmiany jego rozmiaru, jest to stosunek ' szerokości pól tekstowych do szerokości całego formantu Private Const DwieCyfry As Single = Private Const CzteryCyfry As Single = ' deklaracja zmiennych prywatnych klasy formnatu ' zmienna mwalidacja przechowuje wybór użytkownika co do ' walidacji znaków w grupach, jej typ to selection ' zmienna mczynumerpoprawny będzie zawierała True, jeżeli tak Private mwalidacjagrup As selection Private mczynumerpoprawny As Boolean ' przesłaniamy metodę OnFontChanged z klasy bazowej, jej zadaniem ' będzie wywołanie naszej procedury odpowiedzialnej za sposób ' przeskalowania rozmiarów formantu przy zmianie czcionki Protected Overrides Sub OnFontChanged(ByVal e As _ System.EventArgs) MyBase.OnFontChanged(e) ZmienPolaTekstowe() ' tworzymy własną procedurę obsługującą zmianę rozmiaru ' formantu przez programistę w trakcie projektowania Private Sub NrRachunkuBankowego_Resize(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Resize ZmienPolaTekstowe() ' procedura ZmienPolaTekstowe będzie odpowiedzialna za skalowanie ' formantu Private Sub ZmienPolaTekstowe() Dim szer As Integer = Me.ClientRectangle.Width Dim wys As Integer = Me.ClientRectangle.Height

33 33 Dim TextBox2, TextBox4 As Integer If wys < 20 Then Me.Height = 20 If szer < 240 Then Me.Width = 240 ' skalujemy względnie szerokości pól tekstowych TextBox2 = szer * DwieCyfry TextBox4 = szer * CzteryCyfry ' modyfikujemy granice każdego z pól tekstowych Me.txtPierwszeDwie.SetBounds(0, 0, TextBox2, 0) Me.txtCztery1.SetBounds(0 + TextBox2, 0, TextBox4, 0) Me.txtCztery2.SetBounds(0 + TextBox2 + TextBox4, 0, _ TextBox4, 0) Me.txtCztery3.SetBounds(0 + TextBox2 + TextBox4 * 2, 0, _ TextBox4, 0) Me.txtCztery4.SetBounds(0 + TextBox2 + TextBox4 * 3, 0, _ TextBox4, 0) Me.txtCztery5.SetBounds(0 + TextBox2 + TextBox4 * 4, 0, _ TextBox4, 0) Me.txtCztery6.SetBounds(0 + TextBox2 + TextBox4 * 5, 0, _ TextBox4, 0) ' definiujemy właściwość InputType, z jej opisaniem i zaliczeniem ' do kategorii zachowanie <Description("Określa, czy ma być robiona walidacja grup"), _ Category("Behavior")> _ Property InputType() As selection Get Return mwalidacjagrup End Get Set(ByVal value As selection) mwalidacjagrup = value End Set End Property ' definiujemy właściwość CzyNumerPoprawny, zwrotnie otrzymamy ' True lub False, zależenie od wartości zwróconej przez prywatną ' funkcję SprawdzNumer, która zbada, czy kompletny numer ' rachunku jest poprawny ReadOnly Property CzyNumerPoprawny() As Boolean Get Return sprawdznumer(dajnumer) End Get End Property ' właściwość DajNumer zwraca kompletny numer rachunku bankowego ' poprzez połączenie znaków wprowadzonych w poszczególnych polach

34 34 ReadOnly Property DajNumer() As String Get Return Me.txtPierwszeDwie.Text & " " & _ Me.txtCztery1.Text & " " & Me.txtCztery2.Text & _ Me.txtCztery3.Text & " " & Me.txtCztery4.Text & " " & _ Me.txtCztery5.Text & " " & Me.txtCztery6.Text End Get End Property ' tworzymy teraz serię prywatnych procedur odpowiedzialnych ' za przeniesienie fokusu do kolejnego pola po wprowadzeniu ' potrzebnej liczby znaków do danego pola (2 do pierwszego, 'do pozostałych 4) Private Sub txtpierwszedwie_textchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles _ txtpierwszedwie.textchanged If Me.txtPierwszeDwie.Text.Length = 2 Then Me.txtCztery1.Focus() Private Sub txtcztery1_textchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles txtcztery1.textchanged If Me.txtCztery1.Text.Length = 4 Then Me.txtCztery2.Focus() Private Sub txtcztery2_textchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles txtcztery2.textchanged If Me.txtCztery2.Text.Length = 4 Then Me.txtCztery3.Focus() Private Sub txtcztery3_textchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles txtcztery3.textchanged If Me.txtCztery3.Text.Length = 4 Then Me.txtCztery4.Focus() Private Sub txtcztery4_textchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles txtcztery4.textchanged If Me.txtCztery4.Text.Length = 4 Then Me.txtCztery5.Focus()

35 35 Private Sub txtcztery5_textchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles txtcztery5.textchanged If Me.txtCztery5.Text.Length = 4 Then Me.txtCztery6.Focus() ' w przypadku pola txtcztery6 procedura badająca, czy już ' wprowadzono 4 znaki jest znacznie rozbudowana, zawiera bowiem ' nie tylko instrukcje sprawdzające, czy znaki są cyframi, lecz ' także kod sprawdzający, czy cały numer jest poprawny Private Sub txtcztery6_textchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles txtcztery6.textchanged If Me.txtCztery6.Text.Length = 4 Then If mwalidacjagrup = selection.tak Then If Not Me.txtCztery6.Text.Length = 4 Or _ Not IsNumeric(Me.txtCztery6.Text) Then Me.ErrorProvider1.SetError(Me.txtCztery6, _ "Proszę wprowadzić cztery cyfry w siódmej grupie!") Beep() Me.txtCztery6.Focus() Else Me.ErrorProvider1.SetError(Me.txtCztery6, "") If Not CzyNumerPoprawny() Then Me.ErrorProvider1.SetError(Me.txtCztery6, _ "Podany numer nie jest numerem konta bankowego!") Beep() Me.txtPierwszeDwie.Focus() Else Me.ErrorProvider1.SetError(Me.txtCztery6, "") ' tworzymy teraz serię procedur sprawdzających, czy znaki ' wprowadzone w polach tekstowych są cyframi. Nie ma procedury ' dla pola txtcztery6, ponieważ jest to uwazględnione w ' procedurze txtcztery6_textchanched Private Sub txtpierwszedwie_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtpierwszedwie.validating If mwalidacjagrup = selection.nie Then Exit Sub If Not Me.txtPierwszeDwie.Text.Length = 2 Or Not _ IsNumeric(Me.txtPierwszeDwie.Text) Then Me.ErrorProvider1.SetError(Me.txtPierwszeDwie, _ "Proszę wprowadzić dwie cyfry w pierwszej grupie!") Beep()

36 36 Me.txtPierwszeDwie.Focus() Else Me.ErrorProvider1.SetError(Me.txtPierwszeDwie, "") Private Sub txtcztery1_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtcztery1.validating If mwalidacjagrup = selection.nie Then Exit Sub If Not Me.txtCztery1.Text.Length = 4 Or Not _ IsNumeric(Me.txtCztery1.Text) Then Me.ErrorProvider1.SetError(Me.txtCztery1, _ "Proszę wprowadzić cztery cyfry w drugiej grupie!") Beep() Me.txtCztery1.Focus() Else Me.ErrorProvider1.SetError(Me.txtCztery1, "") Private Sub txtcztery2_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtcztery2.validating If mwalidacjagrup = selection.nie Then Exit Sub If Not Me.txtCztery2.Text.Length = 4 Or Not _ IsNumeric(Me.txtCztery2.Text) Then Me.ErrorProvider1.SetError(Me.txtCztery2, _ "Proszę wprowadzić cztery cyfry w trzeciej grupie!") Beep() Me.txtCztery2.Focus() Else Me.ErrorProvider1.SetError(Me.txtCztery2, "") Private Sub txtcztery3_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtcztery3.validating If mwalidacjagrup = selection.nie Then Exit Sub If Not Me.txtCztery3.Text.Length = 4 Or Not _ IsNumeric(Me.txtCztery3.Text) Then Me.ErrorProvider1.SetError(Me.txtCztery3, _ "Proszę wprowadzić cztery cyfry w czwartej grupie!") Beep() Me.txtCztery3.Focus() Else Me.ErrorProvider1.SetError(Me.txtCztery3, "")

37 37 Private Sub txtcztery4_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtcztery4.validating If mwalidacjagrup = selection.nie Then Exit Sub If Not Me.txtCztery4.Text.Length = 4 Or Not _ IsNumeric(Me.txtCztery4.Text) Then Me.ErrorProvider1.SetError(Me.txtCztery4, _ "Proszę wprowadzić cztery cyfry w piątej grupie!") Beep() Me.txtCztery4.Focus() Else Me.ErrorProvider1.SetError(Me.txtCztery4, "") Private Sub txtcztery5_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtcztery5.validating If mwalidacjagrup = selection.nie Then Exit Sub If Not Me.txtCztery5.Text.Length = 4 Or Not _ IsNumeric(Me.txtCztery5.Text) Then Me.ErrorProvider1.SetError(Me.txtCztery5, _ "Proszę wprowadzić cztery cyfry w szóstej grupie!") Beep() Me.txtCztery5.Focus() Else Me.ErrorProvider1.SetError(Me.txtCztery5, "") ' prywatna funkcja SprawdzNumer bada, czy kompletny numer ' rachunku bankowego spełnia reguły poprawności NRB. Badanie ' wykonywane jest wg reguły opublikowanej w sieci 1 Private Function SprawdzNumer(ByVal nrb As String) As Boolean Dim t As String = Trim(nrB), i As Integer, xp As Long, _ z() As String z = Split(t, " ") t = "" For i = 0 To UBound(z) t &= z(i) Next If Not t.length = 26 Then Return False Else Dim w() As Integer = New Integer(29) {1, 10, 3, 30, 9, 90, _ 27, 76, 81, 34, 49, 5, 50, 15, 53, 45, 62, 38, 89, 17, _ 1

38 38 73, 51, 25, 56, 75, 71, 31, 19, 93, 57} t &= "2521" t = t.substring(2, t.length - 2) & t.substring(0, 2) For i = 1 To 30 xp += w(i - 1) * CInt(t.Substring(t.Length - i, 1)) Next If xp Mod 97 = 1 Then Return True Else Return False End Function ' publiczna metoda SkasujError pozwoli użytkownikowi skasować ' ikonę błędu wyświetloną na prawo od pola txtcztery6 formantu Public Sub SkasujError() Me.ErrorProvider1.SetError(Me.txtCztery6, "") End Class Dodanie formantu do przybornika Po zaprojektowaniu formantu i utworzeniu potrzebnego kodu kompilujemy projekt, po kompilacji będziemy mogli dodać w pasku narzędziowym Toolbox nową zakładkę, a następnie umieścić w niej utworzony formant. Z menu kontekstowego wywołanego prawym przyciskiem myszy w obszarze Toolbox wywołujemy polecenie Add Tab, co skutkuje dodaniem nowej zakładki, chwilowo bez żadnej nazwy. W polu nazwy utworzonej zakładki wpisujemy jej nazwę, w moim przypadku była to nazwa Moje kontrolki. Musimy teraz dodać utworzony formant do tej zakładki, wystarczy w tym celu ustawić wskaźnik myszy na jej nazwie i z menu kontekstowego wywołać polecenie Choose Item. W otwartym oknie dialogowym o nazwie Choose Toolbox Item w zakładce.net FrameWork Component powinniśmy odszukać i zaznaczyć potrzebny formant, oczywiście wtedy, gdy znajduje się na liście dostępnych formantów. W naszym przypadku nie jest to oczywiście możliwe, dlatego musimy skorzystać z przycisku Browse, aby wskazać lokalizację pliku *.dll, który został utworzony w momencie kompilacji projektu.

39 39 Potrzebny plik standardowo umieszczany jest w podfolderze Bin\Debug w folderze naszego projeku. Po jego wskazaniu w oknie Browse i akceptacji plik dll jest umieszany w liście komponentów.net Framework, tak jak to pokazano niżej. Po akceptacji przycisku OK utworzony formant zostaje dodany do zakładki naszych kontrolek w pasku Toolbox.

40 Testowanie utworzonego formantu Dla przetestowania utworzonego formantu numeru rachunku bankowego dodamy do projektu tego formantu nowy projekt. Z menu File wywołujemy polecenie Add i dalej New Project, co skutkuje otwarciem okna z szablonami projektów. Wybieramy szablon Windows Application i tworzymy nowy projekt. W tym momencie w naszym rozwiązaniu mamy dwa projekty, jeden z nich musimy wskazać jako projekt startowy (jeżeli tego nie zrobimy, to debuger nie wie, który z nich uruchomić). Wskazujemy myszą projekt aplikacji windowsowej i z menu kontekstowego wywołujemy polecenie Set as StartUp Project. Aplikacja windowsowa została utworzona z jednym, pustym formularzem. Po przejściu do okna projektu tego formularza umieszczamy w nim naszą kontrolkę, czyli NrRachunkuBankowego. Zestaw formantów został uzupełniony o pole tekstowe o nazwie txtnumer oraz przycisk polecenie o nazwie cmdtest. Jego klik ma spowodować, że do pola tekstowego zostanie zapisany kompletny numer rachunku bankowego. Formanty te zostały jeszcze uzupełnione o stosowne etykiety opisujące ich przeznaczenie. W trakcie projektowania formularza można określić, czy formant NrRachunkuBankowego ma przeprowadzać walidację grup cyfr czy też nie. W pokazanej obok sytuacji w oknie właściwości tego formantu w kategorii Behavior znajdziemy właściwość InputType z domyślnie ustawioną wartością Nie. Wybranie opcji Tak spowoduje, że taka walidacja będzie przeprowadzana. Właściwość ta może być także zmieniona w kodzie formularza, tak też będzie to zrobione w naszym przykładzie.

41 41 Przechodząc do kodu tego formularza utworzymy dwie procedury zdarzeniowe, pierwsza z nich będzie uruchamiana w momencie załadowania formularza, a jej zadaniem będzie uaktywnienie opcji walidacji poszczególnych grup cyfr w formancie numeru bankowego. Zadaniem drugiej z nich będzie wyświetlenie w polu tekstowym kompletnego numeru rachunku bankowego. Public Class Form1 Private Sub Form1_Load(ByVal sender As Object, ByVal e As _ System.EventArgs) Handles Me.Load ' korzystając z właściwości InputType włączamy obsługę grup cyfr Me.NrRachunkuBankowego1.InputType = _ NrRachunkuBamkowego.NrRachunkuBankowego.selection.Tak Private Sub cmdtest_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles cmdtest.click ' badanie, czy numer jest poprawny? If Me.NrRachunkuBankowego1.CzyNumerPoprawny Then Me.txtNumer.Text = Me.NrRachunkuBankowego1.DajNumer MsgBox("poprawny") Else ' skasowanie ikony błędu Me.NrRachunkuBankowego1.SkasujError() MsgBox("numer nie jest poprawny") ' ustawienie fokusu w formancie Me.NrRachunkuBankowego1.Focus() End Class Poniżej widok formularza po uruchomieniu, został wprowadzony przypadkowy numer rachunku bankowego, po wprowadzeniu ostanich czterech cyfr procedura walidacyjna formantu sygnalizuje stan błędu spowodowany niepoprawnym numerem. Klik przycisku polecenia spowoduje skasowanie ikony błędu i umieszczenie kursora w dwucyfrowym polu tekstowym formantu NrRachunkuBankowego w celu skorygowania całego numeru. Po wprowadzeniu poprawnego numeru konta bankowego procedury walidacyjne nie zgłaszają żadnego błędu, który mógłby być spowodowany z jednej strony tym, że któryś ze

42 42 znaków nie reprezentuje cyfry lub że wprowadzony numer nie jest zgodny ze standardem NRB. Taką sytuację mamy pokazaną poniżej. Klik przycisku Test formantu odczytuje z formantu kompletny numer rachunku i wyświetla go w polu tekstowym txtnumer. Dodatkowo wyświetlany jest komunikat potwierdzajacy zgodność wprowadzonego numeru ze standardem NRB. Poniżej pokazane są dwie sytuacje, w których procedury walidacyjne formantu zgłosiły stan błędu. Pierwszy z nich spowodowany jest tym, że w pierwszym polu formantu wprowadzono jeden a nie dwa znaki, stąd zgłoszenie błędu. Drugi błąd spowodowany jest tym, że wprawdzie wprowadzono wymaganą liczbę znaków, ale nie wszystkie z nich są cyframi.

43 4.2. Formant adresu mailowego 43 Praktycznie każda baza danych musi w obecnych czasach gromadzić adresy mailowe, stąd istotne jest posiadanie dedykowanego formantu do jego wprowadzania. Jak wiemy adres mailowy składa się z dwóch tekstów rozdzielonych jego schemat można zapisać jako Zarówno w przypadku loginu jak i domeny obowiązują pewne ograniczenia. Do najważniejszych z nich można zaliczyć zasadę, że do ich wypisania możemy użyć wyłącznie znaków alfabetu angielskiego, cyfr oraz symbolu kropki. W wyrazie określającym domenę musi wystąpić co najmniej jedna kropka Projekt formantu Podobnie jak w poprzednim rozdziale tworzymy nowy projekt typu Windows Control Library nadając mu nazwę np. AdresMailowy. Korzystając z okna Project Solution zmieniamy nazwę pliku formantu z domyślnej UserControl1.vb na AdresMailowy.vb. W kodzie klasy formantu dopisujemy instrukcję importu przestrzeni nazw System.ComponentModel, zmieniamy nazwę klasy na AdresMailowy oraz wstawiamy instrukcję dziedziczenia klasy System.Windows.Forms.UserControl. Po tych zmianach zapisujemy tworzony projekt w odpowiednim (wg naszego uznania) miejscu na dysku. Kolejny etap to skomponowanie formantu z trzech pól tekstowych o nazwach odpowiednio txtlogin, txtmalpa i txtdomena. Te trzy pola tekstowe ustawiamy tak, jak na pokazanym niżej zrzucie ekranowym.

44 44 Podobnie jak w przypadku formantu NrRachunkuBankowy ustawiamy te trzy pola tekstowe w lokalizacjach (odpowiednio): 0, 0 dla txtlogin z rozmiarem 92, 20; 92, 0 dla txtmalpa z rozmiarem 17, 20; 109, 0 dla txtdomena z rozmiarem 131, 20. W polu txtlogin tekst został wyrównany do prawej strony, w txtmalpa wyśrodkowany, a w txtdomena wyrównany do lewej. W polu txtmalpa wpisano a pole zostało ustawione jako niedostępne. Na prawo od pola txtdomena pozostawiono fragment formularza na wyświetlenie symbolu błędu przy walidacji wprowadzonego adresu Kod formantu AdresMailowy W kodzie tego formularza musimy utworzyć kilka procedur i właściwości wykorzystywanych do obsługi zdarzeń związanych z tym formantem. Imports System.ComponentModel ' kod klasy tworzonego formantu Public Class AdresMailowy Inherits System.Windows.Forms.UserControl ' deklaracja zmiennych prywatnych klasy Private madresmailowy As String Private mwalidacja As selection ' deklaracja stałych na potzreby skalowania formantu Private Const Login As Single = Private Const Malpa As Single = Private Const Domena As Single = ' deklaracja typu wyliczanego Enum Selection Tak = 0 ' indeksowanie od tej wartości Nie End Enum ' definicje właściwości zwracającej kompletny adres mailowy ReadOnly Property AdresMailowy() As String Get Return Me.txtLogin.Text & & Me.txtDomena.Text End Get End Property ' procedura walidująca treść loginu Private Sub txtlogin_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtlogin.validating

45 45 If mwalidacja = selection.nie Then Exit Sub ' funkcja CzyDobreZnaki bada, czy znaki są poprawne If Not CzyDobreZnaki(LCase(Me.txtLogin.Text)) Then Me.ErrorProvider1.SetError(Me.txtLogin, _ "Login zawiera niedopuszczalne znaki!") Beep() Me.txtLogin.Focus() Else Me.ErrorProvider1.SetError(Me.txtLogin, "") ' procedura walidująca treść domeny Private Sub txtdomena_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtdomena.validating If mwalidacja = selection.nie Then Exit Sub If Not CzyDobreZnaki(LCase(Me.txtDomena.Text)) Then Me.ErrorProvider1.SetError(Me.txtDomena, _ "Domena zawiera niedopuszczalne znaki!") Beep() Me.txtDomena.Focus() Else Me.ErrorProvider1.SetError(Me.txtDomena, "") ' funkcja sprawdzająca kod znaków Private Function CzyDobreZnaki(ByVal t As String) As Boolean Dim i As Integer, k As Integer If t.length = 0 Then CzyDobreZnaki = False Exit Function For i = 0 To t.length - 1 k = Asc(t.Substring(i, 1)) If k = 46 Or (k > 47 And k < 58) Or _ (k > 96 And k < 123) Then ' nic nie rób Else CzyDobreZnaki = False Exit Function Next CzyDobreZnaki = True End Function ' definicja właściwości pozwalającej użytkownikowi na ' zdecydowanie, czy walidacja składników adresu ma być wykonana

46 46 <Description("Określa, czy ma być robiona walidacja loginu " & _ "i domeny"), Category("Behavior")> _ Property InputType() As selection Get Return mwalidacja End Get Set(ByVal value As selection) mwalidacja = value End Set End Property ' przesłaniamy metodę klasy bazowej w celu wywołania naszej ' procedury o nazwie ZmienPolaTekstowe. Protected Overrides Sub OnFontChanged(ByVal e As _ System.EventArgs) MyBase.OnFontChanged(e) ZmienPolaTekstowe() ' tworzymy procedurę obsługującą zdarzenie zmiany rozmiaru ' formantu Private Sub AdresMailowy_Resize(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Resize ZmienPolaTekstowe() ' procedura ZmienPolaTekstowe odpowiada za przeskalowanie ' składników formantu w momencie zmiany jego rozmiaru lub ' zmianę fontu wykorzystywanego w polach tekstowych Private Sub ZmienPolaTekstowe() Dim szer As Integer = Me.ClientRectangle.Width Dim wys As Integer = Me.ClientRectangle.Height Dim txtlogin, txtdomena, txtmalpa As Integer If wys < 20 Then Me.Height = 20 If szer < 275 Then Me.Width = 275 txtlogin = szer * Login txtdomena = szer * Domena txtmalpa = szer * Malpa Me.txtLogin.SetBounds(0, 0, txtlogin, 0) Me.txtMalpa.SetBounds(0 + txtlogin, 0, txtmalpa, 0) Me.txtDomena.SetBounds(0 + txtlogin + txtmalpa, 0, _ txtdomena, 0) End Class

47 Testowanie formantu i dodanie do Toolboxa Poniżej widok po uruchomieniu debugera, mamy wyświetlone specjalne okno z zaprojektowanym przez nas formantem i oknem jego właściwości. Właściwość WalidacjaAdresu ustawiona jest na Tak, stąd zgłoszony błąd po wpisaniu w części adresu odpowiadającemu loginowi tekstu janusz gorczynski, błąd jest efektem spacji. Podobnie sprawdzana jest poprawność adresu domenowego. Jeżeli zachowanie formantu jest zgodne z zaplanowanym przez nas, to możemy formant dodać do paska narzędziowego Toolbox, postępując dokładnie tak samo, jak w przypadku formantu NrRachunkuBankowego (wystarczy dodać formant do istniejącej już grupy Moje kontrolki).

48 Formant przełącznika ToggleNUD W środowisku VB.NET firma Microsoft zgubiła bardzo przydatny formant przełącznika typu Toggle (znany z VBA). W standardowej postaci pozwalał na przełączanie się między dwoma stanami (wartościami przypisywanymi do zmiennej). W naszym projekcie będziemy wykorzystywać formant typu NumericUpDown do ustawienia zmiennej numerycznej na określonej wartości poprzez klik górnego czy dolnego przewijaka. Zmiana wartości odbywa się z pewnym, zdefiniowanym skokiem. Wydaje się za celowe modyfikowanie tej wielkości w tych przypadkach, gdy zakres regulacji jest stosunkowo duży (po to, by szybciej osiągnąć zamierzoną wartość). Idealnym rozwiązaniem byłby formant typu Toggle, którego klik zmieniałby parametr skoku cyklicznie z wartości minimalnej na maksymalną i odwrotnie. Ponieważ w standardowym zestawie formantów takowego nie ma, to musimy go sobie sami zaprojektować. Ponieważ będziemy go wykorzystywać do zmiany skoku (właściwość Increament) formantu NumericUpDown, to nazwiemy go ToggleNUD Projekt formantu ToggleNUD Postępując analogicznie jak w dwóch wcześniejszych projektach formantów tworzymy nowy projekt typu Windows Control Library, dokonujemy koniecznych zmian w nazwie klasy i nazwie pliku UserControl.vb (zmieniając ją na ToggleNUD.vb). Projekt naszego formantu jest bardzo skromny, bowiem jest to jeden przycisk o nazwie cmdtoggle. Przycisk ten umieszczono w lewym górnym narożniku formularza, a jego rozmiar ustawiono na 98 pikseli szerokości i 35 pikseli wysokości. Takie same rozmiary nadano także formularzowi naszego formantu.

49 Kod formantu ToggleNUD 49 W kodzie formantu umieszczamy procedury obsługujące funkcjonowanie tego formantu. Imports System.ComponentModel ' kod klasy formantu Public Class ToggleNUD Inherits System.Windows.Forms.UserControl ' deklaracja zmiennych prywatnych Private mminimum As Integer Private mmaksimum As Integer Private maktualnyskok As Integer Private mopisminimum As String Private mopismaksimum As String ` ' dekalracja zdarzenia zwracającego aktualną wartość skoku Public Event DajSkok(ByVal Skok As Integer) ' metoda klasy opisująca przycisk formantu Public Sub OpisStart() maktualnyskok = mminimum Me.cmdToggle.Text = "Zmień skok " & vbcrlf & "z " & _ maktualnyskok.tostring & " na " & mmaksimum.tostring ' kod właściwości zwracającej AktualnySkok ReadOnly Property AktualnySkok() As Integer Get Return maktualnyskok End Get End Property ' kod właściwości pozwalający na ustalenie lub zwrócenie ' minimalnej wartości skoku <Description("Podaj minimalną wartość skoku pokrętła"), _ Category("Behavior")> _ Property MinimumSkok() As Integer Get Return mminimum End Get Set(ByVal value As Integer) mminimum = value maktualnyskok = mminimum mopisminimum = "Zmień skok " & vbcrlf & "z " & _ maktualnyskok.tostring & " na " & mminimum.tostring End Set End Property ' kod właściwości pozwalający na ustalenie lub zwrócenie

50 50 ' maksymalnej wartości skoku <Description("Podaj maksymalną wartość skoku pokrętła"), _ Category("Behavior")> _ Property MaksimumSkok() As Integer Get Return mmaksimum End Get Set(ByVal value As Integer) mmaksimum = value mopismaksimum = "Zmień skok " & vbcrlf & "z " & _ maktualnyskok.tostring & " na " & mmaksimum.tostring End Set End Property ' procedura obsługująca zdarzenie klik przycisku formantu ' jednym z jej zadań jest wygenerowanie zdarzenia Private Sub cmdtoogle_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles cmdtoggle.click If maktualnyskok = mminimum Then maktualnyskok = mmaksimum Me.cmdToggle.Text = "Zmień skok " & vbcrlf & "z " & _ maktualnyskok.tostring & " na " & mminimum.tostring Else maktualnyskok = mminimum Me.cmdToggle.Text = "Zmień skok " & vbcrlf & "z " & _ maktualnyskok.tostring & " na " & mmaksimum.tostring RaiseEvent DajSkok(mAktualnySkok) ' nadpisujemy metodę z klasy bazowej, jest to konieczne, ' ponieważ chcemy wywołać własną procedurę klasy ZmienRozmiar Protected Overrides Sub OnFontChanged(ByVal e As _ System.EventArgs) MyBase.OnFontChanged(e) ZmienRozmiar() ' procedura obsługująca zdarzenie Zmiana rozmiaru także wywołuje ' własną procedurę klasy ZmienRozmiar Private Sub ToggleNUD_Resize(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Resize ZmienRozmiar() ' procedura zmieniająca rozmiar formantu Private Sub ZmienRozmiar() Dim szer As Integer = Me.ClientRectangle.Width Dim wys As Integer = Me.ClientRectangle.Height If wys < 35 Then

51 51 Me.Height = 35 If szer < 98 Then Me.Width = 98 Me.cmdToggle.SetBounds(0, 0, szer, wys) End Class Testowanie formantu i dodanie do przybornika Dla przetestowania formantu ToggleNUD dodamy do naszego rozwiązania kolejny projekt, tym razem będzie to Windows Application. Dodany projekt ustawiamy jako ten, od którego nastąpi uruchomienie rozwiązania (składającego się z projektu formantu i projektu aplikacji windowsowej). W analogiczny sposób jak w przypadku wcześniejszych formantów dodajemy utworzony formant do zakładki Moje kontrolki, a następnie umieszczamy kontrolkę ToggleNUD w formularzu aplikacji windowsowej. Dodajemy jeszcze etykietę, będziemy w niej wyświetlać aktualną wartość skoku po każdym kliknięciu naszego formantu. Gotowy formularz pokazany jest niżej. Na etapie projektowania, korzystając z okna właściwości, ustawiamy minimalną i maksymalną wartość skoku. W tym przykładzie wartość minimalna została ustawiona na 1, a wartość maksymalna na 10. Obie wartości można oczywiście ustawić programowo w kodzie procedury obsługującej zdarzenie załadowania formularza, stosujemy wtedy proste przypsanie: Me.ToggleNUD1.MinimumSkok = 1 Me.ToggleNUD1.MaksimumSkok = 10

52 52 W kodzie formularza wpisujemy dwie procedury i deklarację zmiennej z klasy ToggleNUD z użyciem słowa kluczowego WithEvents. Public Class Form1 ' deklaracja obiektu z klasy ToogleNUD z wykorzystaniem słowa ' kluczowego WithEvents, co pozwoli na przechwytywane zdarzeńia ' generowanego w tej klasie, a zwracajacego aktulaną wartość ' skoku. W poniższej deklaracji pierwsza nazwa ToggleNUD oznacza ' przestrzeń nazw, druga nazwę klasy Dim WithEvents u As ToggleNUD.ToggleNUD ' procedura odpowiedzialna za przechwycenie zdarzenia Private Sub ToggleNUD1_DajSkok(ByVal Skok As Integer) _ Handles ToggleNUD1.DajSkok Me.Label1.Text = "Skok ustawiony na " & Skok.ToString ' procedura uruchamiana w momencie załadowania formularza ' jej zadaniem jest zainicjowanie formantu ToggleNUD i etykiety Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load Me.ToggleNUD1.OpisStart() Me.Label1.Text = "Skok ustawiony na " & _ Me.ToggleNUD1.AktualnySkok.ToString End Class Poniż dwa widoki formularza testowego po uruchomieniu.

53 Formant numeru Pesel W ramach aplikacji przeznaczonej do obsługi studiów podyplomowych przewidziane są formularze ekranowe do pobierania czy edycji danych zarówno studentów jak i pracowników. Jedną z pobieranych informacji będzie numer Pesel, można go oczywiście pobrać z pomocą standardowego pola tekstowego, ale znacznie lepszym rozwiązaniem będzie zaprojektowanie dedykowanej kontrolki. Lepszym dlatego, że będziemy mogli w niej zaszyć wszystkie potrzebne sprawdziany poprawności takiego numeru Projekt formantu Pesel Postępując analogicznie jak w wcześniejszych projektach formantów tworzymy nowy projekt typu Windows Control Library, dokonujemy koniecznych zmian w nazwie klasy i nazwie pliku UserControl.vb (zmieniając ją na Pesel.vb). Projekt naszego formantu jest bardzo skromny, bowiem jest to pole tekstowe o nazwie txtpesel, dodatkowo na tacy umieszczono formant typu ErrorProvider, wykorzystamy go do wyświetlenia informacji o ewentualnym błędzie w podanym numerze ewidencyjnym. Pole to umieszczono w lewym górnym narożniku formularza, a jego rozmiar ustawiono na 72 piksele szerokości i 20 pikseli wysokości. Szerokość formularza zwiększono do 100 pikseli rezerwując miejsce na wyświetlenie ikony ewentualnego błędu Kod formantu Pesel W kodzie formularza umieszczamy procedury obsługujące funkcjonowanie tworzonej kontrolki, będą to zarówno definicje właściwości i metod oraz procedury prywatne związane z obsługą poprawności wprowadzonego numeru Pesel.

54 54 Imports System.ComponentModel Public Class Pesel Inherits System.Windows.Forms.UserControl Enum Selection Tak = 0 Nie End Enum ' deklaracja prywatnych zmiennych i stałej klasy Private Const cyfr11 As Single = 0.72 Private mweryfikujnumer As Selection Private mczynumerpoprawny As Boolean Private mdataurodzenia As String Private mkomunikat As String = "" Protected Overrides Sub OnFontChanged(ByVal e As _ System.EventArgs) MyBase.OnFontChanged(e) ZmienPolaTekstowe() <Description("Określa, czy ma być sprawdzian numeru"), _ Category("Behavior")> _ Property WeryfikacjaNumeru() As Selection Get Return mweryfikujnumer End Get Set(ByVal value As Selection) mweryfikujnumer = value End Set End Property ' procedura reagująca na wprowadzane znaki z klawiatury, ' pilnuje, aby to były cyfry i żeby to było max. 11 znaków Private Sub txtpesel_keypress(byval sender As Object, _ ByVal e As System.Windows.Forms.KeyPressEventArgs) _ Handles txtpesel.keypress If e.keychar < "0" Or e.keychar > "9" Then Beep() Me.ErrorProvider1.SetError(Me.txtPesel, _ "Nr PESEL może zawierać wyłącznie cyfry!") e.handled = True Else Me.ErrorProvider1.SetError(Me.txtPesel, "") If Me.txtPesel.Text.Length = 11 Then Beep() e.handled = True ' procedura walidacyjna, korzysta z funkcji spradznumer

55 55 Private Sub txtpesel_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtpesel.validating If Not sprawdznumer(me.txtpesel.text) Then Beep() Me.ErrorProvider1.SetError(Me.txtPesel, mkomunikat) Else Me.ErrorProvider1.SetError(Me.txtPesel, "") ' prywatna funkcja sprawdznumer odpowiada za sprawdzenie, czy ' wprowadzony do pola tekstowego ciąg znaków jest poprawny. ' Jeżeli nie, to przygotowywany jest stosowny komunikat. Private Function sprawdznumer(byval t As String) As Boolean Dim x, i As Integer, _ w() As Integer = {1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1}, _ ts, tm As String If mweryfikujnumer = Selection.Nie Then Return True Else mkomunikat = "" If t.length <> 11 Then mkomunikat = _ "Numer Pesel musi zawierać dokładnie 11 cyfr!" Return False Else ' sprawdzamy składowe numeru ' jakie cyfry miesiąca? x = CInt(t.Substring(2, 2)) ' jakie stulecie? Select Case x Case Is > 80 ts = "18" & t.substring(0, 2) tm = Format(x - 80, "00") Case Is > 60 ts = "22" & t.substring(0, 2) tm = Format(x - 60, "00") Case Is > 40 ts = "21" & t.substring(0, 2) tm = Format(x - 40, "00") Case Is > 20 ts = "20" & t.substring(0, 2) tm = Format(x - 20, "00") Case Is > 0 ts = "19" & t.substring(0, 2) tm = Format(x, "00") Case Else

56 56 mkomunikat = _ "Źle określony numer miesiąca " & _ " (symbol stulecia)!" Return False End Select If t.substring(4, 5) > "00" AndAlso _ t.substring(4, 5) > "31" Then ' ustalenie daty urodzenia mdataurodzenia = _ ts & "-" & tm & "-" & t.substring(4, 5) Else mkomunikat = "Źle określony numer dnia!" Return False ' sprawdzenie poprawności całego numeru For i = 0 To 9 x += CInt(Me.txtPesel.Text.Substring(i, 1)) * w(i) Next If 10 - (x Mod 10) = _ CInt(Me.txtPesel.Text.Substring(10, 1)) Then Return True Else mkomunikat = "Podany numer Pesel nie jest poprawny!" Return False End Function ' procedura aktualizująca rozmiar formantu Private Sub ZmienPolaTekstowe() Dim szer As Integer = Me.ClientRectangle.Width Dim wys As Integer = Me.ClientRectangle.Height Dim TextBox11 As Integer If wys < 20 Then Me.Height = 20 If szer < 100 Then Me.Width = 100 TextBox11 = szer * cyfr11 Me.txtPesel.SetBounds(0, 0, TextBox11, 0) ' implementacja właściwości ReadOnly Property CzyNumerPoprawny() As Boolean Get Return sprawdznumer(me.txtpesel.text) End Get

57 57 End Property ReadOnly Property DajPesel() As String Get Return Me.txtPesel.Text End Get End Property ReadOnly Property DataUrodzenia() As String Get Return mdataurodzenia End Get End Property End Class Testowanie formantu Pesel Poniżej widok po uruchomieniu debugera, mamy wyświetlone specjalne okno z zaprojektowanym przez nas formantem i oknem jego właściwości. Został zgłoszony błąd spowodowany naciśnięciem klawisza nie będącego cyfrą.

58 58 Właściwość WeryfikacjaNumeru ustawiona jest na Tak, stąd zgłoszony błąd po wpisaniu ciągu cyfr, które nie reprezentują poprawnego numeru Pesel. Po sprawdzeniu poprawności funkcjonowania formantu kompilujemy projekt (z menu Build wybieramy Build Pesel) i formant jest gotowy do użycia wystarczy dodać go do przybornika.

59 59 5. Edycje studiów podyplomowych Studia podyplomowe realizowane w naszej Uczelni trwają od 2 do 3 semestrów, a uruchamianie są w ramach określonej terminowo i zakresowo edycji. Pojęcie to jest szczególnie adekwatne w przypadku studiów realizowanych z dofinansowaniem PARP 2, które uruchamiane są w następstwie ogłoszonego konkursu na prowadzenie tego typu studiów. Warunki konkursu determinują zarówno czas trwania, zakres tematyczny (kierunki studiów podyplomowych), liczbę słuchaczy oraz termin realizacji takich studiów. Studia podyplomowe własne, czyli bez dofinansowania PARP uruchamiane są w momencie zgłoszenia pewnej minimalnej liczby słuchaczy, są także otwarte dla znaczenie szerszego kręgu zainteresowanych 3. Niezależnie od formy prowadzenia danej edycji studiów (z dofinansowanie PARP lub bez niego) dla danej edycji studiów będziemy określać te same elementy: Nazwę edycji studiów; Liczbę semestrów i liczbę godzin ogółem; Kierunki studiów realizowane w danej edycji; Listę przedmiotów realizowanych w ramach danego kierunku; Listę wykładowców realizujących poszczególne przedmioty. Listę osób zajmujących się administracją danej edycji. Dane te będą przechowywane w tabelach bazy danych na MS SQL Server Tabele i relacje między nimi Podstawowe dane o edycjach studiów podyplomowych przechowywane są w tabeli EdycjeStudiow, pola tej tabeli i typy danych pokazane są poniżej. Infromacje o kierunkach studiów podyplomowych są przechowywane w tabeli Kierunki. 2 PARP Państwowa Agencja Rozwoju Przedsiębiorczości 3 Bez warunku, że słuchaczem może być osoba zatrudniona wyłącznie w przedsiębiorstwie, co wyklucza osoby pracujące w samorządach i administracji publicznej

60 60 Tabela EdycjeKierunki wiąze informacje z tabel EdycjeStudiow i Kierunki, jej kluczem złożonym są klucze obu wymienionych tabel. Tabela Przedmioty zawiera pełne nazwy przedmiotów oraz ich skróty (na potrzeby raportów z ankiet oceniających sposób prowadzenia zajęć. Tabela KierunkiPrzedmioty przyporządkowuje poszczególnym kierunkom studiów przedmioty, które są na nich realizowane. Tabela Pracownicy przechowuje informacje o wszystkich pracownikach zaangażowanych w realizację studiów podyplomowych, zarówno wykładowców jak i pracowników obsługi administracyjnej. Pole Rola identyfikuje danego pracownika jako wykładowcę (wartość 1), pracownika administracyjnego (wartość 2) lub wykładowcę, który także spełnia jakąś rolę administracyjną (wartość 3). Pole SkrotP (unikalne i obowiązkowe dla wykładowców) będzie wykorzystywane na etapie raportów z ankiet oceniających sposób prowadzenia zajęć.

61 61 Tabela PrzedmiotProwadzacy przyporządkowuje poszczególnym przedmiotom identyfikatory wykładowców (może być taka sytuacja, że dany przedmiot prowadzi więcej niż jeden wykładowca). W tabeli StawkiWykladowcy rejestrowane są stawki za realizację jednej godziny zajęć na danej edycji studiów (stawki te obejmują całość pracy dydaktycznej samo przeprowadzenie zajęć, przygotowanie materiałów dydaktycznych w wersji cyfrowej, przygotowanie testów weryfikujących wiedzę, dostępność dla słuchaczy). Tabela EdycjaAdministracja przechowuje identyfikatory osób zaangażowanych w administracyjną obsługę danej edycji studiów oraz identyfikator roli spełnianej przez danego pracownika. Tabela RoleAdministracyjne zawiera opisy ról administracyjnych, a tabela StawkiAdministracji przechowuje informacje o miesięcznych kosztach zatrudnienia tych pracowników i wymiarze czasu pracy.

62 62 Wzajemne relacje między wymienionymi wyżej tabelami pokazane są niżej.

63 Procedury i funkcje przechowywane Dostęp do tabel bazy danych będzie realizowany poprzez utworzone na serwerze SQL procedury przechowywane wspomagane w kilku przypadkach funkcjami skalarnymi, także utworzonymi na serwerze. Kolejno przedstawimy te procedury i funkcje wraz z krótką informacją co ich roli. Procedury będą pogrupowane wg interfejsów klasy CEdycjaKierunekPrzedmiot Wykorzystane w IEdycjeStudiow Procedura pczymoznadopisacedycje zwraca zero wtedy, gdy nazwa dodawanej edycji studiów jest unikalna. Będziemy z tej procedury korzystać w momencie dodawania nowej edycji. create procedure int out as from dbo.edycjestudiow where Procedura pzapiszedycje dodaje do tabeli EdycjeStudiow nowy record. Podobnie jak poprzednią procedurę będziemy ją wykorzystywać w momencie dodawania nowej edycji. create procedure int as insert into dbo.edycjestudiow (NazwaEdycji, DataStart, DataKoniec, StatusE, Procedura pedycjedomodyfikacji zwraca wszystkie, posortowane wg daty rozpoczęcia, rekordy z tabeli EdycieStudiow. Zwrócony rekordset będzie wykorzystany jako źródło danych formantu typu DataGridView. create procedure int as select * from dbo.edycjestudiow order by DataStart Procedura pcombostatusedycji zwraca identyfikatory i opisy możliwych statutów edycji studiów. Dane zwrócone przez tę procedurę wykorzystamy jako źródło danych kolumny typu ComboBox, którą dodamy do gridu wyświetlającego edycje studiów w trybie ich edycji.

64 64 create procedure int as select * from dbo.statusedycji order by opis Procedura pcomboforma dostarcza identyfikatory i możliwe formy dofinansowania edycji studiów. Podobnie jak wcześniejsza procedura dane zwrócone przez tę procedurę będą źródłem danych pola typu ComboBox w gridzie wyświetlających dane edycji studiów w trybie edycji. create procedure int as select * from dbo.comboforma order by opisf Procedura pupdateedycjastudiow odpowiada za aktualizację wskazanego rekordu w tabeli EdycieStudiow. create procedure int as update dbo.edycjestudiow set where Wykorzystane w IKierunkiStudiow Pokazana niżej procedura bada, czy można dodać określony rekord do tabeli Kierunki. CREATE procedure int out as from Kierunki where or Procedura pwstawnowykierunek wstawia nowy rekord do tabeli Kierunki. CREATE procedure int as insert into dbo.kierunki (Kierunek, SkrotK, LiczbaSemestrow, @godzin) Procedura pczytakiskrotdobry bada, czy podany jako argument skrót nazwy kierunku jest unikalny.

65 65 CREATE procedure int out as from dbo.kierunki where Procedura pczymoznausunackierunek bada, czy można bezpiecznie usunąć wskazany kierunek z tabeli Kierunki. create procedure int out as from dbo.edycjekierunki where begin from dbo.kierunkiprzedmioty where begin from dbo.dane where end else end else Procedura pusunkierunek usuwa wskazany rekord z tabeli Kierunki. create procedure int as delete from Kierunki where id_k Pokazana niżej procedura zwraca rekordset, który zostanie wykorzystany w formularzu dedykowanym do obsługi edycji kierunków studiów. create procedure int as select * from dbo.kierunki order by Kierunek

66 66 Porcedura paktualizujkierunek odpowiada za aktualizację wskazanego rekordu w tabeli Kierunki. create procedure int as update dbo.kierunki set where Wykorzystane w IPrzedmioty Zadaniem pokazanej niżej procedury jest sprawdzenie, czy przekazany w pierwszym argumencie skrót nazwy przedmiotu jest unikalny czy też nie. W pierwszym przypadku zwracana jest wartość zero, w drugim jest to wartość większa od zera. create procedure int out as from Przedmioty where Procedura pwstawprzedmiot odpowiada za wstawienie do tabeli Przedmioty nowego rekordu, ale tylko wtedy, gdy nazwa przedmiotu oraz jego skrót będą unikalne. Zwracany jest parametr typu Integer, jego wartość 0 jest wskaźnikiem sukcesu operacji wstawienia nowego rekordu. create procedure int out as from Przedmioty where or insert into dbo.przedmioty (Przedmiot, SkrotP) Procedura pdajprzedmioty odpowiada za zwrócenie wszystkich danych z tabeli Przedmioty posortowanych wg pola Przedmiot (czyli nazwy przedmiotu). create procedure int as select id_p, Przedmiot, SkrotP from Przedmioty order by Przedmiot

67 67 Procedura paktualizujprzedmioty odpowiada za aktualizację wskazanego rekordu w tabeli Przedmioty. create procedure nvarchar(10) as update dbo.przedmioty set where Wykorzystane w IEdycjeKierunki Porcedura pdajedycje zwraca identyfikatory i nazwy edycji studiów podyplomowych uporządkowane wg kolejności ich rejestracji. Zwracany zestaw rekordów zależy od wartości jak jest zerowy, to zwracane są wszystkie edycje, jak nie, to zwracane są edycje planowane i aktualnie realizowana. create procedure int as select id_e, NazwaEdycji from dbo.edycjestudiow where statuse=1 order by id_e else select id_e, NazwaEdycji from dbo.edycjestudiow where statuse in (1, 2) order by id_e Poniższa procedura odpowiada za wstawienie nowego rekordu do tabeli skojarzeń EdycjeKierunki. create procedure money as insert into dbo.edycjekierunki (id_e, id_k, LimitMiejsc, @koszt) Procedura ppotencjalnekierunki zwraca listę tych kierunków, które mogą być skojarzone z daną edycją studiów. create procedure int as select id_k, Kierunek from Kierunki where id_k not in

68 68 (select id_k from dbo.edycjekierunki where Order by Kierunek Pokazana niżej procedura zwraca pełną informację o skojarzeniach edycji studiów z kierunkami. create procedure int as select EdycjeStudiow.id_e, EdycjeStudiow.NazwaEdycji, Kierunki.id_k, Kierunki.Kierunek from EdycjeKierunki INNER JOIN EdycjeStudiow on EdycjeKierunki.id_e = EdycjeStudiow.id_e INNER JOIN Kierunki on EdycjeKierunki.id_k = Kierunki.id_k Order by EdycjeStudiow.NazwaEdycji, Kierunki.Kierunek Procedura pusunedycjekierunek odpowiada za usunięcie z tabeli EdycjeKierunki wskazanego rekordu. create procedure int as delete dbo.edycjekierunki where and Wykorzystane w IKierunekPrzedmioty Procedura pdajkierunki zwraca rekordset identyfikatorów i nazw kierunków studiów uporządkowane alfabetycznie wg nazw kierunków. create procedure int as select id_k, Kierunek from Kierunki order by kierunek Pokazana niżej procedura zwraca potencjalną listę przedmiotów danego kierunku. create procedure int as select id_p, Przedmiot from dbo.przedmioty where id_p not in (select id_p from dbo.kierunkiprzedmioty where order by przedmiot Zadaniem procedury pwstawkierunekprzedmiot jest wstawienie do tabeli KierunkiPrzedmioty identyfikatorów kierunku i przedmiotu.

69 69 create procedure int as insert into KierunkiPrzedmioty (id_k, id_p) Pokazana niżej procedura zwraca pełną informację o skojarzeniach kierunków studiów i przedmiotów. create procedure int as select Kierunki.id_k, Kierunki.Kierunek, Przedmioty.id_p, Przedmioty.Przedmiot from KierunkiPrzedmioty INNER JOIN Kierunki on KierunkiPrzedmioty.id_k = Kierunki.id_k INNER JOIN Przedmioty on KierunkiPrzedmioty.id_p = Przedmioty.id_p Order by Kierunki.Kierunek, Przedmioty.Przedmiot Procedura pusunkierunekprzedmiot usuwa wskazany rekord z tabeli skojarzeń KierunkiPrzedmioty. create procedure int as delete dbo.kierunkiprzedmioty where and Wykorzystane w IWykladowcyPrzedmioty Procedura pdajlisteludzi zwraca uporządkowaną alfabetycznie listę wykładowców wraz z ich stopniami naukowymi. create procedure int as select id_w, rtrim(tytul) + ' ' + Wykladowca as Ktos from dbo.pracownicy order by Wykladowca Pokazana niżej procedura zwraca listę potencjalnych przedmiotów wykładowcy. create procedure int as select distinct Przedmioty.id_p, Przedmioty.Przedmiot from Przedmioty where Przedmioty.id_p not in (select id_p from PrzedmiotProwadzacy where order by Przedmioty.Przedmiot

70 70 Zadaniem kolejnej procedury jest wstawienie nowego rekordu do tabeli skojarzeń PrzedmiotProwadzacy. create procedure int as insert into PrzedmiotProwadzacy (id_w, id_p) Pokazana niżej procedura zwraca pełną informację o skojarzeniach wykładowców i przedmiotów. create procedure int as select PrzedmiotProwadzacy.id_w, Pracownicy.Tytul + N' ' + Pracownicy.Wykladowca AS Kto, PrzedmiotProwadzacy.id_p, Przedmioty.Przedmiot from PrzedmiotProwadzacy INNER JOIN Pracownicy on PrzedmiotProwadzacy.id_w = Pracownicy.id_w INNER JOIN Przedmioty on PrzedmiotProwadzacy.id_p = Przedmioty.id_p Order by Pracownicy.Wykladowca, Przedmioty.Przedmiot Zadaniem kolejnej prezentowanej procedury jest usunięcie z tabeli skojarzeń PrzedmiotProwadzacy wskazanego rekordu. create procedure int as delete dbo.przedmiotprowadzacy where and Wykorzystane w IEdycjeLimituMiejsc Pokazana niżej procedura zwraca rekordset, który będzie wykorzystany jako źródło formantu typu DataGridView prezentującego informacje o edycjach studiów, kierunkach oraz limicie miejsc i czesnym w trybie ich edycji. create procedure int as select EdycjeKierunki.id_e, EdycjeKierunki.id_k, EdycjeStudiow.NazwaEdycji, Kierunki.Kierunek, EdycjeKierunki.LimitMiejsc, EdycjeKierunki.KosztStudenta from EdycjeKierunki INNER JOIN EdycjeStudiow on EdycjeKierunki.id_e = EdycjeStudiow.id_e INNER JOIN Kierunki on EdycjeKierunki.id_k = Kierunki.id_k where EdycjeStudiow.StatusE < 3

71 71 Kolejna procedura odpowiada za aktualizację limitu miejsc w tabeli EdycjeKierunki. create procedure int as update dbo.edycjekierunki set where and skojarzeń

72 Klasa CEdycjaKierunekPrzedmiot Klasa CEdycjaKierunekPrzedmiot będzie zawierać te wszystkie metody i właściwości, które będziemy wykorzystywać do obsługi formularzy związanych tematycznie z edycjami studiów podyplomowych, kierunkami prowadzonych studiów oraz przedmiotami realizowanymi w ramach tych kierunków. W praktyce utworzenie metod i właściwości tej klasy wymaga wcześniejszego zaprojektowania potrzebnych formularzy zawierających te formanty, do których będziemy się odwoływać w kodzie tej klasy. W sekcji deklaracji tej klasy musimy zaimportować dwie grupy przestrzeni nazw, pierwsza z nich określa dwie przestrzenie nazw niezbędne do komunikacji z serwerem MS SQL. Druga grupa zawiera dwie przestrzenie nazw, pierwsza z nich odwołuje się do przestrzeni związanej z globalizacją, a druga do przestrzeni związanej z wątkami. Obie są niezbędne do ustalenia lokalnego formatu daty krótkiej. ' import przestrzeni nazw dla potrzeb komunikacji z MS SQL Imports System.Data Imports System.Data.SqlClient ' import przestrzeni nazw dla ustawień regionalnych Imports System.Globalization ' import przestrzeni nazw dla ustalenia kraju Imports System.Threading Z uwagi na tworzenie klasy obsługującej dość dużą grupę zagadnień wykorzystamy mechanizm interfesjów do pogrupowania metod i właściwości klasy wg zadań do wykonania. Deklaracja tych interfejsów będzie występować przed kodem klasy Interfejs IEdycjaStudiow W tym interfejsie zadeklarujemy funkcje i procedury, które wykorzystamy do obsługi dwóch formularzy. Pierwszy z nich będzie odpowiadał za zarejestrowanie nowej edycji studiów, a drugi za ich modyfikację. Public Interface IEdycjaStudiow Function Komunikat() As String Function CzySukces() As String Sub ZapisEdycji(ByVal strconn As String, ByVal frm As _ frmnowaedycja) Sub ModyfikacjaDane(ByVal strconn As String, ByVal frm As _ frmmodyfikacjaedycji) Sub UpdateEdycjiStudiow(ByVal strconn As String, ByVal frm As _ frmmodyfikacjaedycji, ByRef U() As Boolean) End Interface

73 73 ' fragment kodu klasy CEdycjaKierunekPrzedmiot Public Class CEdycjaKierunekPrzedmiot ' dziedziczenie po klasie CForStorageSub Inherits CForStorageSub ' informacja o implementacji interfesju IEdycjaStudiów Implements IEdycjaStudiow ' dekalracja prywatnych zmiennych klasy Private mkomunikat As String = "" Private mczysukces As String = "" Private mtable1 As DataTable Private mtable2 As DataTable Private mtable3 As DataTable ' zmienna prywatna mformat ma zawierać krótki format daty ' w wersji regionalnej Private mformat As DateTimeFormatInfo = _ New CultureInfo(Thread.CurrentThread.CurrentCulture. _ ToString).DateTimeFormat ' deklaracja zmiennej z informacją, że będzie generowane zdarzenie Private WithEvents combocontrol As System.Windows.Forms.ComboBox ' ' dalsze instrukcje klasy End Class ' implementacja funkcji CzySukces, Komunikat i DajTabele Public Function CzySukces() As String Implements _ IEdycjaStudiow.CzySukces Return mczysukces End Function Public Function Komunikat() As String Implements _ IEdycjaStudiow.Komunikat Return mkomunikat End Function Metoda ZapisEdycji odpowiada za zapisanie nowych danych w tabeli EdycjeStudiow, przed wykonaniem zapisu wykonywany jest sprawdzian, czy takiej edycji już nie ma w tej tabeli. Jeżeli jest, to zwracany jest stosowny komunikat, jeżeli nie, wykonywany jest zapis. Public Sub ZapisEdycji(ByVal strconn As String, ByVal frm As _ frmnowaedycja) Implements IEdycjaStudiow.ZapisEdycji Dim conn As New SqlConnection(strconn), z1, z2 As Integer ' ustalenie, jaki jest status edycji studiów, korzystamy ' z funkcji UstalGrb z modułu Parp z1 = UstalGrb(frm.grbStatus) ' ustalenie formy dofinansowania z2 = UstalGrb(frm.grbForma) Try conn.open()

74 74 If MyBase.DajWartosc(conn, "dbo.pczymoznadopisacedycje", _ frm.txtedycja.text, 5, 100, _ 1, 0) > 0 Then mczysukces = "Taka edycja już jest w bazie danych!" Else ' można, dopisujemy MyBase.Wykonaj(conn, "dbo.pzapiszedycje", _ frm.txtedycja.text, 5, 0, _ frm.dtpstart.value.tostring( _ mformat.shortdatepattern), 4, 0, _ frm.dtpkoniec.value.tostring( _ mformat.shortdatepattern), 4, 0, _ z1, 1, 0, _ z2, 1, 0) Catch ex As Exception mkomunikat = _ "Problem z wykonaniem procedury przechowywanej." Finally conn.close() conn = Nothing End Try Procedura (metoda) ModyfikacjaDane jest odpowiedzialna za przygotowanie danych z tabeli EdycjeStudiow do wyświetlenia w formancie DataGridView. Problem komplikuje się, bowiem w miejsce oryginalnych kolumn chcemy umieścić albo pola kombi, albo specjalną kolumnę pozwalającą na wybór daty z kalendarza. W tym ostatnim przypadku skorzystamy z pomocniczej klasy CCalendarColumn. Public Sub ModyfikacjaDane(ByVal strconn As String, _ ByVal frm As frmmodyfikacjaedycji) Implements _ IEdycjaStudiow.ModyfikacjaDane Dim conn As New SqlConnection(strconn) ' deklaracja pomocniczych zmiennych Dim tb, op, fo As DataTable Try conn.open() ' pobieramy podstawowe dane z tabeli EdycjeStudiow tb = MyBase.DajRekordset(conn, _ "dbo.pdanemodyfikacjiedycji", _ 1, 1, 0) ' pobieramy dane na potrzeby pola kombo do wyboru statusu op = MyBase.DajRekordset(conn, _ "dbo.pcombostatusedycji", 1, 1, 0) ' pobieramy dane na potrzeby pola kombo do wyboru formy ' dofinansowania fo = MyBase.DajRekordset(conn, "dbo.pcomboforma", _ 1, 1, 0)

75 ' zdefiniowanie nazw kolumn w obietach op, tb i fo ' w tb jest oryginalna kolumna o nazwie statuse ' będziemy ją chcieli zastąpić kolumną z kombobox, ale ' zanim to zrobimu uzgadniamy nazwy obu kolumn op.columns(0).columnname = "statuse" op.columns(1).columnname = "opis" tb.columns(4).columnname = "statuse" ' analogiczne działania podejmujemy w stosunku do kolumny ' o nazwie forma w tabeli tb tb.columns(5).columnname = "forma" fo.columns(0).columnname = "forma" fo.columns(1).columnname = "opisf" ' definiujemy właściwości gridu With frm.dgvedycje.datasource = tb.defaultview.columns(0).visible = False.Columns(1).Width = 235.Columns(2).Width = 120.Columns(3).Width = 120 ' ukrywamy oryginalne kolumny statuse i forma.columns(4).visible = False.Columns(5).Visible = False ' modyfikujemy nagłówki kolumn.columns(1).headertext = "Nazwa edycji studiów".columns(2).headertext = "Data rozpoczęcia".columns(3).headertext = "Data zakończenia" End With ' tworzymy nową kolumnę typu DataGridComboBoxColumn Dim cbostatuse As New DataGridViewComboBoxColumn() ' definiujemy nagłówek cbostatuse.headertext = "Status edycji" ' określamy właściwości tej kolumny (tak, aby wyświetlała ' dane z oryginalnej kolumny statuse With cbostatuse.datapropertyname = "statuse".datasource = op.displaymember = "opis".valuemember = "statuse" End With frm.dgvedycje.columns.add(cbostatuse) ' tworzymy analogiczną kolumnę dla formy Dim cboforma As New DataGridViewComboBoxColumn() cboforma.headertext = "Dofinansowanie" With cboforma.datapropertyname = "forma".datasource = fo.displaymember = "opisf".valuemember = "forma" End With 75

76 76 frm.dgvedycje.columns.add(cboforma) ' utworzenie nowej instancji kolumny kalenarza Dim cols As New CCalendarColumn ' nadanie jej nazwy - takiej samej jak kolumna daty ' rozpoczęcia edycji w datatabele cols.datapropertyname = "DataStart" ' nadanie nazwy kolumny do wyświetlenia cols.headertext = "Data rozpoczęcia" ' ustalenie likalizacji kolumny 'DataStart' w gridzie Dim locs As Integer = _ frm.dgvedycje.columns.indexof( _ frm.dgvedycje.columns("datastart")) ' usunięcie oryginalnej kolumny frm.dgvedycje.columns.removeat(locs) ' dodanie na jej miejsce i z jej nazwą kolumny kalendarza frm.dgvedycje.columns.insert(locs, cols) ' podobne opercje dla kolumny 'DataKoniec' Dim colk As New CCalendarColumn colk.datapropertyname = "DataKoniec" colk.headertext = "Data zakończenia" Dim lock As Integer = _ frm.dgvedycje.columns.indexof( _ frm.dgvedycje.columns("datakoniec")) frm.dgvedycje.columns.removeat(lock) frm.dgvedycje.columns.insert(lock, colk) Catch ex As Exception mkomunikat = _ "Problem z wykonaniem procedury przechowywanej." Finally conn.close() conn = Nothing End Try Procedura (metoda) UpdateEdycjiStudiow jest odpowiedzialna za aktulizację danych w tabeli EdycjeStudiow. Public Sub UpdateEdycjiStudiow(ByVal strconn As String, _ ByVal frm As frmmodyfikacjaedycji, ByRef U() As Boolean) _ Implements IEdycjaStudiow.UpdateEdycjiStudiow Dim conn As New SqlConnection(strconn), i As Integer Try conn.open() With frm.dgvedycje For i = 0 To UBound(U) If U(i) Then ' aktualizujemu MyBase.Wykonaj(conn, "dbo.pupdateedycjestudiow", _ 1, 0, _

77 77 5, 100, _ 4, 0, _ 4, 0, _ 1, 0, _ 1, 0) Next End With Catch ex As Exception mkomunikat = _ "Problem z wykonaniem procedury przechowywanej." Finally conn.close() conn = Nothing End Try Interfejs IKierunkiStudiow Interfejs IKierunkiStudiow ma za zadanie udostępnić te metody i właściwości klasy CEdycjaKierunekPrzedmiot, które są dedykowane do obsługi zdarzeń związanych z zarejestrowaniem nowego kierunku studiów czy z edycją istniejących kierunków studiów. Public Interface IKierunkiStudiow Function Komunikat() As String Function CzySukces() As String Sub WeryfikacjaSkrotu(ByVal strconn As String, _ ByVal skrot As String) Sub ZapiszKierunek(ByVal strconn As String, _ ByVal frm As frmnowykierunek) Sub DaneDoAktualizacji(ByVal strconn As String, _ ByVal frm As frmkierunkiaktualizacja) Sub ZapiszAktualizacje(ByVal strconn As String, _ ByVal dgv As DataGridView, ByRef u() As Boolean) Sub CzyMoznaUsunacKierunek(ByVal strconn As String, _ ByVal idk As Integer) Sub UsunKierunek(ByVal strconn As String, _ ByVal idk As Integer) End Interface W definicji interfejsu wymienione są funkcje Komunikat oraz CzySukces, jak pamiętamy, dokładnie takie same funkcje zostały utworzone i zaimplementowane w interfejsie IEdycjaStudiow. Oczywiście nie ma możliwości utworzenia ponownych implementacji tych samych funkcji w klasie CEdycjaKierunekPrzedmiot, nie ma także takiej potrzeby, po prostu zmodyfikujemy implementację obu funkcji tak, aby była wspólną dla obu interfejsów.

78 78 W kodzie klasy CEdycjaKierunekPrzedmiot umieszczamy informację o implementacji dodatkowego interfejsu oraz implementacje jego metod i funkcji. Public Class CEdycjaKierunekPrzedmiot Inherits CForStorageSub Implements IEdycjaStudiow Implements IKierunekStudiow Private mkomunikat As String = "" W istniejącej implememntacji funkcji Komunikat dodajemy odwołanie do interfejsu IKierunkiStudiow. Public Function Komunikat() As String Implements _ IEdycjaStudiow.Komunikat, IKierunkiStudiow.Komunikat Return mkomunikat End Function Analogicznie postępujemy w przypadku istniejącej implementacji funkcji CzySukces. Public Function CzySukces() As String Implements _ IEdycjaStudiow.CzySukces, IKierunkiStudiow.CzySukces Return mczysukces End Function Implementujemy procedurę WeryfikacjaSkrotu, jej zadaniem będzie ustalenie, czy skrót nazwy kierunku jest unikalny. Public Sub WeryfikacjaSkrotu(ByVal strconn As String, _ ByVal skrot As String) _ Implements IKierunkiStudiow.WeryfikacjaSkrotu ' deklarujemy i tworzymy obiekt SqlConnection Dim conn As New SqlConnection(strconn) ' będziemy wykonywac operacje na bazie danych, zawieramy je w ' bloku Try... End Try dla obsługi ewentualnych błędów Try ' otwieramy połączenie z bazą danych conn.open() ' badamy, czy procedura SQL zwraca wynik większy od zera ' jeżeli tak, to skrót nie jest unikalny, tworzymy komunikat If MyBase.DajWartosc(conn, "dbo.pczytakiskrotdobry", _ skrot, 5, 10, _ 1, 0) > 0 Then mczysukces = "Taki skrót już jest w tabeli Kierunki" ' jeżeli warunek nie był spełniony, to skrót jest unikalny ' pusty ciąg znaków w zmiennej mczyjest będzie ' potwierdzeniem, nic nie musimy robić, bo zmienna ta jest ' inicjowana pustym ciągiem znaków w momencie tworzenia ' instancji klasy

79 79 Catch ex As Exception ' mamy problem z komunikacją z MS SQL mkomunikat = "Błąd dostępu do bazy danych" Finally ' sprzątamy po sobie zamykając obiekt conn conn.close() ' i usuwając go z RAM conn = Nothing End Try Metoda ZapiszKierunek odpowiada za zapisanie do bazy danych informacji opisujących nowy kierunek studiów. Public Sub ZapiszKierunek(ByVal strconn As String, _ ByVal frm As frmnowykierunek) _ Implements IKierunkiStudiow.ZapiszKierunek Dim conn As New SqlConnection(strconn) Try conn.open() ' badamy, czy nazwa i skrót są unikalne? ' jeżeli nie, to stosowny komunkikat, jeżeli tak ' to zapisujemy dane If MyBase.DajWartosc(conn, "dbo.pczymoznadodackierunek", _ frm.txtnazwa.text, 5, 200, _ frm.txtskrot.text, 5, 10, _ "czytaknie", 1, 0) Then mczysukces = _ "Nie mozna dopisać rekordu, taki kierunek " & _ "lub skrót już są w bazie" Else ' można dopisać MyBase.Wykonaj(conn, "dbo.pwstawnowykierunek", _ frm.txtnazwa.text, 5, 200, _ frm.txtskrot.text, 5, 10, _ frm.nudsemestry.value, 1, 0, _ frm.nudgodziny.value, 1, 0) Catch ex As Exception mkomunikat = _ "Błąd dostępu do bazy danych lub wykonania procedury" Finally conn.close() conn = Nothing End Try Metoda DaneDoAktualizacji odpowiada za pobranie wszystkich danych z tabeli Kierunki i ich przypisanie jako źródło danych do formantu typu DataGridView.

80 80 Dodatkowo procedura definiuje szereg właściwości tego formantu (ukrywa pierwszą kolumnę, określa szerokości pozostałych, zmienia sposób wyrównania tekstu w dwóch ostatnich kolumnach, definiuje opisy kolumn). Public Sub DaneDoAktualizacji(ByVal strconn As String, _ ByVal frm As frmkierunkiaktualizacja) _ Implements IKierunkiStudiow.DaneDoAktualizacji Dim conn As New SqlConnection(strconn), i As Integer Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "pdajdanekierunkowdoedycji", _ 1, 1, 0) With frm.dgvkierunki.datasource = mtable1.columns(0).visible = False.Columns(1).Width = 350 ' nazwa.columns(2).width = 70 ' skrot.columns(3).width = 70 'liczba semestrow.columns(4).width = 70 ' liczba godzin ' definicja nagłówków kolummn.columns(1).headertext = "Nazwa kierunku studiów".columns(2).headertext = "Skrót".Columns(3).HeaderText = "Semestrów".Columns(4).HeaderText = "Godzin" ' zmiana wyrównania dwóch ostatnich kolumn For i = 3 To 4.Columns(i).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter Next End With Catch ex As Exception mkomunikat = "Błąd dostępu do bazy danych" Finally conn.close() conn = Nothing End Try Metoda ZapiszAktualizacje odpowiada za zaktualizowanie danych w tabeli Kierunki. Aktualizacja danego rekordu wykonywana jest wtedy, gdy w zmiennej tablicowej na pozycji tego rekordu jest wartość True. Public Sub ZapiszAktualizacje(ByVal strconn As String, _ ByVal dgv As DataGridView, ByRef u() As Boolean) _ Implements IKierunkiStudiow.ZapiszAktualizacje Dim conn As New SqlConnection(strconn), i As Integer Try conn.open()

81 81 For i = 0 To dgv.rows.count - 1 If u(i) Then ' aktualizujemy MyBase.Wykonaj(conn, "dbo.paktualizujkierunek", _ dgv.rows(i).cells(0).value, 1, 0, _ dgv.rows(i).cells(1).value, 5, 200, _ dgv.rows(i).cells(2).value, 5, 10, _ dgv.rows(i).cells(3).value, 1, 0, _ dgv.rows(i).cells(4).value, 1, 0) Next Catch ex As Exception mkomunikat = "Błąd dostępu do bazy danych" Finally conn.close() conn = Nothing End Try Metoda CzyMoznaUusnacKierunek będzie wykorzystywana w trakcie edycji kierunków studiów, jej zadaniem jest ustalenie, czy kierunek, który chcemy usunąć nie występuje w tabelach powiązanych (EdycjeKierunki, KierunkiPrzedmioty i Dane). Jeżeli tak, to procedura zasygnalizuje niemożność usunięcia danego kierunku studiów. Public Sub CzyMoznaUusnacKierunek(ByVal strconn As String, _ ByVal idk As Integer) _ Implements IKierunkiStudiow.CzyMoznaUsunacKierunek Dim conn As New SqlConnection(strconn), i As Integer Try conn.open() i = MyBase.DajWartosc(conn, "dbo.pczymoznausunackierunek", _ idk, 1, 0, _ 1, 1) Catch ex As Exception mkomunikat = "Błąd dostępu do bazy danych" Finally conn.close() conn = Nothing End Try ' zbudowanie komunikatu co do możności usunięcia kierunku Select Case i Case 1 mczysukces = "Nie można usunąć zaznaczonego wiersza," & _ " identyfikator kierunku jest w tabeli EdycjeKierunki" Case 2 mczysukces = "Nie można usunąć zaznaczonego wiersza," & _ " identyfikator kierunku jest w tabeli " & _ "KierunkiPrzedmioty"

82 82 Case 3 mczysukces = "Nie można usunąć zaznaczonego wiersza," & _ " identyfikator kierunku jest w tabeli Dane" End Select Metoda UsunKierunek będzie wykorzystywana do fizycznego usunięcia rekordu wskazanego kierunku studiów z tabeli Kierunki. Public Sub UsunKierunek(ByVal strconn As String, _ ByVal idk As Integer) _ Implements IKierunkiStudiow.UsunKierunek Dim conn As New SqlConnection(strconn) Try conn.open() MyBase.Wykonaj(conn, "dbo.pusunkierunek", _ idk, 1, 0) Catch ex As Exception mkomunikat = "Błąd dostępu do bazy danych" Finally conn.close() conn = Nothing End Try Interfejs IPrzedmioty Poniżej prezentujemy interfejs IPrzedmioty oraz implementację jego metod i właściwości. Interfejs ten będzie wykorzystywany do obsługi zdarzeń związanych z rejestracją nowego przedmiotu jak i edycją wcześniej wprowadzonych nazw. Metoda DaneEdycjiPrzedmiotow będzie otrzymywać, jako jeden z argumentów, formularz o nazwie frmedycjaprzedmiotu, którego projekt będzie przedstawiony w dalszej części tej pracy. Public Interface IPrzedmioty Function Komunikat() As String Function CzySukces() As String Sub CzySkrotUnikalny(ByVal strconn As String, _ ByVal skrot As String) Sub ZapiszPrzedmiot(ByVal strconn As String, ByVal nazwa As _ String, ByVal skrot As String) Sub DaneEdycjiPrzedmiotow(ByVal strconn As String, _ ByVal frm As frmedycjaprzedmiotu) Sub AktualizujPrzedmioty(ByVal strconn As String, _ ByVal dgv As DataGridView, ByRef x() As Boolean) End Interface

83 83 W definicji interfejsu wymienione są funkcje Komunikat oraz CzySukces, jak pamiętamy, dokładnie takie same funkcje zostały utworzone i zaimplementowane w kilku wcześniej przedstawionych interfejsach, wystarczy zmodyfikować ich implementacje tak, aby dotyczyła i tego interfejsu. W kodzie klasy CEdycjaKierunekPrzedmiot umieszczamy informację o implementacji interfejsu IPrzedmioty oraz implementacje jego metod i funkcji. Public Class CEdycjaKierunekPrzedmiot Inherits CForStorageSub Implements IEdycjaStudiow Implements IKierunekStudiow Implements IPrzedmioty Private mkomunikat As String = "" W istniejącej implememntacji funkcji Komunikat dodajemy odwołanie do interfejsu IPrzedmioty. Public Function Komunikat() As String Implements _ IEdycjaStudiow.Komunikat, IKierunkiStudiow.Komunikat, _ IPrzedmioty.Komunikat Return mkomunikat End Function Analogicznie postępujemy w przypadku istniejącej implementacji funkcji CzySukces. Public Function CzySukces() As String Implements _ IEdycjaStudiow.CzySukces, IKierunkiStudiow.CzySukces, _ IPrzedmioty.CzySukces Return mczysukces End Function Metoda (publiczna procedura) CzySkrotUnikalny odpowiada za ustalenie, czy zaproponowany przez użytkownika skrót nazwy przedmiotu jest unikalny. Public Sub CzySkrotUnikalny(ByVal strconn As String, _ ByVal skrot As String) Implements _ IPrzedmioty.CzySkrotUnikalny Dim conn As New SqlConnection(strconn) ' będziemy wykonywac operacje na bazie danych, zawieramy je w ' bloku Try... End Try dla obsługi ewentualnych błedów Try conn.open() ' badamy, czy procedura SQL zwraca wynik większy od zera ' jeżeli tak, to skrót nie jest unikalny, tworzymy komunikat If MyBase.DajWartosc(conn, _ "dbo.pczyskrotprzedmiotuunikalny", _ skrot, 5, 10, _ 1, 0) > 0 Then

84 84 mczysukces = "Taki skrót już jest w tabeli Przedmioty" ' jeżeli warunek nie był spełniony, to skrót jest unikalny ' pusty ciąg znaków w zmiennej mczyjest będzie ' potwierdzeniem, nic nie musimy robić, bo zmienna ta jest ' inicjowana pustym ciągiem znaków w momencie tworzenia ' instancji klasy Catch ex As Exception ' mamy problem z komunikacją z MS SQL mkomunikat = "Błąd dostępu do bazy danych" Finally conn.close() conn = Nothing End Try Metoda ZapiszPrzedmiot odpowiada za zapisanie wprowadzonej nazwy przedmiotu i jego skrótu w tabeli Przedmioty. Procedura przechowywana realizująca to zadanie przed dokonaniem zapisu wykona sprawdzenie, czy zarówno nazwa przedmiotu jak i skrót nazwy są unikalne. Public Sub ZapiszPrzedmiot(ByVal strconn As String, _ ByVal nazwa As String, ByVal skrot As String) _ Implements IPrzedmioty.ZapiszPrzedmiot Dim conn As New SqlConnection(strconn) Try conn.open() ' badamy, czy nazwa i skrót są unikalne? Jeżeli nie, to ' stosowny komunkikat, jeżeli tak to zapisujemy dane If MyBase.DajWartosc(conn, "dbo.pwstawprzedmiot", _ nazwa, 5, 250, _ skrot, 5, 10, _ "czytak", 1, 0) > 0 Then mczysukces = "Nie mozna dopisać rekordu, taki " & _ "przedmiot lub jego skrót już są w tabeli Przedmioty" Catch ex As Exception mkomunikat = _ "Błąd dostępu do bazy danych lub wykonania procedury" Finally conn.close() conn = Nothing End Try Metoda DaneEdycjiPrzedmiotow jest odpowiedzialna za pobranie z tabeli Przedmioty wszystkich danych i przypisania ich jako źródło danych formantu dgvprzedmioty umieszczonego w formularzu frmedycjaprzedmiotow.

85 85 Public Sub DaneEdycjiPrzedmiotow(ByVal strconn As String, _ ByVal frm As frmedycjaprzedmiotu) _ Implements IPrzedmioty.DaneEdycjiPrzedmiotow Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, "dbo.pdajprzedmioty", _ 0, 1, 0) With frm.dgvprzedmioty.datasource = mtable1.columns(0).visible = False.Columns(1).Width = 420.Columns(2).Width = 100.Columns(1).HeaderText = "Nazwa przedmiotu".columns(2).headertext = "Skrót nazwy" End With Catch ex As Exception mkomunikat = "Błąd pobrania listy przedmiotów" Finally conn.close() conn = Nothing End Try Metoda AktualizujPrzedmioty otrzymuje jako argumenty formant dgvprzedmioty typu DataGridView oraz zmienną tablicową typu logicznego, której wartości ustawione na True sygnalizują konieczność aktualizacji danego rekordu w tabeli Przedmioty. Public Sub AktualizujPrzedmioty(ByVal strconn As String, _ ByVal dgv As DataGridView, ByRef x() As Boolean) _ Implements IPrzedmioty.AktualizujPrzedmioty Dim conn As New SqlConnection(strconn), i As Integer Try conn.open() With dgv For i = 0 To.Rows.Count - 1 If x(i) Then MyBase.Wykonaj(conn, "dbo.paktualizujprzedmioty", _ 1, 0, _ 5, 250, _ 5, 10) Next End With Catch ex As Exception mkomunikat = "Błąd aktualizacji przedmiotów" Finally conn.close()

86 86 conn = Nothing End Try Interfejs IEdycjeKierunki Interfejs IEdycjeKieruki ma za zadanie udostępnić te metody i właściwości klasy CEdycjaKierunekPrzedmiot, które są dedykowane do obsługi zdarzeń związanych ze skojarzeniem edycji studiów z kierunkami przewidzianymi do realizacji w ramach tych edycji, a także z usunięciem niepotrzebnych skojarzeń. W deklaracji interfejsu zapowiedziane są dwie właściwości (są one wspólne dla pozostałych interfejsów) oraz pięć metod, pierwsza z nich będzie odpowiadać za przygotowanie danych dla formularza frmedycjakierunki, druga za dostarczenie listy potencjalnych kierunków po zmianie edycji studiów, a trzecia za wstawienie nowych danych do tabeli EdycjeKierunki. Dwie ostatnie metody będą wykorzystywane przy usuwaniu niepotrzebnych skojarzeń, zarówno edycji studiów i kierunków, kierunków i przedmiotów jak i wykładowców i przedmiotów. Public Interface ISkojarzeniaEdycjeKierunki Function Komunikat() As String Function DajTabele() As DataTable Sub PrzygotujDane(ByVal strconn As String, _ ByVal frm As frmedycjakierunki) Sub ZmianaEdycji(ByVal strconn As String, ByVal ide As Integer) Sub ZapiszSkojarzenia(ByVal strconn As String, _ ByVal frm As frmedycjakierunki) Sub UsunDane(ByVal strconn As String, ByVal frm As _ frmusunskojarzenia) Sub UsunSkojarzenia(ByVal strconn As String, ByVal dgv As _ DataGridView, ByVal ktore As String) End Interface W kodzie modułu klasy CEdycjaKierunkiPrzedmioty została dodana instrukcja wskazująca na implementację interfejsu ISkojarzeniaEdycjeKierunki. Public Class CEdycjaKierunekPrzedmiot Inherits CForStorageSub Implements IEdycjaStudiow Implements IKierunkiStudiow Implements IEdycjeKierunki Private mkomunikat As String = "" Private mczysukces As String = "" ' dalsze instrukcje modułu klasy End Class

87 87 W kodzie implementującym właściwość (funkcję) Komunikat dodano instrukcję wskazującą na jej implementację przez interfejs ISkojarzeniaEdycjeKierunki. Public Function Komunikat() As String Implements _ IEdycjaStudiow.Komunikat, IKierunkiStudiow.Komunikat, _ ISkojarzeniaEdycjeKierunki.Komunikat Return mkomunikat End Function Funkcja (właściwość) DajTabele odpowiada za udostępnienie zmiennej prywatnej klasy mtable1. Public Function DajTabele() As DataTable Implements _ IEdycjeKierunki.DajTabele Return mtable1 End Function Metoda PrzygotujDane odpowiada za pobranie z bazy danych listy zarejestrowanych edycji studiów i przypisanie ich jako źródło danych do pola kombo cboedycje instancji formularza frmedycjakierunki. Public Sub PrzygotujDane(ByVal strconn As String, _ ByVal frm As frmedycjakierunki) Implements _ IEdycjeKierunki.PrzygotujDane Dim conn As New SqlConnection(strconn) Try conn.open() 'przygotowanie danych dla pola combo cboedycje mtable1 = MyBase.DajRekordset(conn, "dbo.pdajedycje", _ 1, 1, 0) UstawComboBox(frm.cboEdycje, mtable1, "NazwaEdycji", "id_e") Catch ex As Exception mkomunikat = "Błąd pobrania listy edycji studiów" Finally conn.close() conn = Nothing End Try Metoda ZmianaEdycji jest odpowiedzialna za dostarczenie potencjalnej listy kierunków po zmianie edycji studiów. Pobrana z bazy danych lista kierunków zapisywana jest w prywatnej zmiennej klasy mtable1, a udostępniana jest spoza klasy przez funkcję (właściwość) DajTabele. Public Sub ZmianaEdycji(ByVal strconn As String, ByVal ide As _ Integer) Implements IEdycjeKierunki.ZmianaEdycji Dim conn As New SqlConnection(strconn) Try conn.open()

88 88 mtable1 = MyBase.DajRekordset(conn, _ "dbo.ppotencjalnekierunki", ide, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy kierunków studiów" Finally conn.close() conn = Nothing End Try Metoda ZapiszSkojarzenia odpowiada za wstawienie nowych rekordów do tabeli EdycjeKierunki. Metoda wykonuje swoją pracę przeglądając kolekcję zaznaczonych pozycji w liście lstkierunki. Public Sub ZapiszSkojarzenia(ByVal strconn As String, _ ByVal frm As frmedycjakierunki) _ Implements ISkojarzeniaEdycjeKierunki.ZapiszSkojarzenia Dim conn As New SqlConnection(strconn) Try conn.open() Dim i, j As Integer, t As String = "" With frm.lstkierunki For i = 0 To.SelectedItems.Count 1 MyBase.Wykonaj(conn, "dbo.pwstawedycjekierunek", _ frm.cboedycje.selectedvalue, 1, 0, _ DirectCast(.SelectedItems(i), _ DataRowView)(0), 1, 0, _ 25, 1, 0) Next End With Catch ex As Exception mkomunikat = " Błąd zapisu skojarzeń edycji i kierunków" Finally conn.close() conn = Nothing End Try Metoda UsunDane została tak zaprojektowana, aby mogła dostarczyć dane, które wykorzystamy przy usuwaniu niepotrzebnych skojarzeń edycji studiów i kierunków, kierunków i przedmiotów oraz wykładowców i przedmiotów. W pokazanym niżej kodzie metoda ta obsługuje (chwilowo) tylko interfejs IEdycjeKierunki, przy omawianiu dalszych interfejsów dodamy obsługę tej samej metody zdefiniowanej w tych interfejsach. ` Public Sub UsunDane(ByVal strconn As String, ByVal frm As _ frmusunskojarzenia) Implements IEdycjeKierunki.UsunDane Dim conn As New SqlConnection(strconn), sp As String = "" ' analizowana jest zawartość pola tekstowego txtktory w celu ' ustalenia, która procedura przechowywana ma być wykonana.

89 89 Select Case frm.txtktory.text Case "1" sp = "dbo.plistaedycjekierunki" Case "2" sp = "dbo.plistakierunkiprzedmioty" Case "3" sp = "dbo.plistawykladowcyprzedmioty" End Select Try conn.open() mtable1 = MyBase.DajRekordset(conn, sp, 1, 1, 0) With frm.dgvco.datasource = mtable1 ' zerowa i trzecia kolumna to identyfikatory, ukrywamy je.columns(0).visible = False.Columns(2).Visible = False ' szerokości 1 i 3 kolumny dostosowujemy do sytuacji Select Case frm.txtktory.text Case "1".Columns(1).Width = 150.Columns(3).Width = 330 Case "2".Columns(1).Width = 200.Columns(3).Width = 280 Case "3".Columns(1).Width = 150.Columns(3).Width = 330 End Select End With ' deklarujemy nową kolumnę typu DataGridViewCheckBoxColumn Dim col As New DataGridViewCheckBoxColumn ' nadajemy jej jakąś nazwę col.datapropertyname = "usun" ' określamy tytuł kolumny col.headertext = "Zaznacz usunięcie" ' definiujemy zwracane wartości (zaznaczone, nie) col.truevalue = True col.falsevalue = False ' wstawiamy tę kolumnę przed kolumną o indeksie zero frm.dgvco.columns.insert(0, col) ' ustawiamy jej szerokość frm.dgvco.columns(0).width = 120 Catch ex As Exception mkomunikat = "Błąd pobrania danych o skojarzeniach" Finally conn.close() conn = Nothing End Try

90 90 Metoda UsunSkojarzenia została tak zaprojektowana, aby mogła obsługiwać usuwanie niepotrzebnych skojarzeń zarówno w przypadku edycji studiów i kierunków, kierunków i przedmiotów jak i wykładowców i przedmiotów. W tym celu procedury przechowywane uruchamiane w tej metodzie mają dokładnie taki sam zestaw argumentów. W pokazanym niżej kodzie metoda ta obsługuje (chwilowo) tylko interfejs IEdycjeKierunki, przy omawianiu dalszych interfejsów dodamy obsługę tej samej metody zdefiniowanej w tych interfejsach. Public Sub UsunSkojarzenia(ByVal strconn As String, _ ByVal dgv As DataGridView, ByVal ktore As String) _ Implements IEdycjeKierunki.UsunSkojarzenia Dim conn As New SqlConnection(strconn), i As Integer Dim sp As String = "" ' ustalamy nazwę procedury przechowywanej do wykonania Select Case ktore Case "1" sp = "dbo.pusunedycjekierunek" Case "2" sp = "dbo.pusunkierunekprzedmiot" Case "3" sp = "dbo.pusunwykladowceprzedmiot" End Select Try conn.open() With dgv For i = 0 To.Rows.Count - 1 If CBool(.Rows(i).Cells(0).Value) = True Then ' usuwamy wskazany rekord przekazując do ' procedury identyfikatory z ukrytych kolumn MyBase.Wykonaj(conn, sp, _ 1, 0, _ 1, 0) Next End With Catch ex As Exception mkomunikat = "Błąd usunięcia skojarzeń" Finally conn.close() conn = Nothing End Try

91 Interfejs IEdycjaLimituMiejsc Interfejs IEdycjaLimituMiejsc ma za zadanie udostępnić te metody i właściwości klasy CEdycjaKierunekPrzedmiot, które są dedykowane do obsługi zdarzeń związanych z edycją liczby miejsc i wysokości czesnego przewidzianych na danym kierunku realizowanym w danej edycji studiów. W deklaracji interfejsu zapowiedziane są dwie właściwości (są one wspólne dla pozostałych interfejsów) oraz dwie metody, pierwsza z nich będzie odpowiadać za przygotowanie danych dla formularza frmedycjalimitumiejsc, a druga za aktualizację liczby miejsc w tabeli EdycjeKierunki. Public Interface IEdycjaLimituMiejsc Function Komunikat() As String Function CzySukces() As String Sub PrzygotujDaneDlaMiejsc(ByVal strconn As String, _ ByVal frm As frmedycjalimitumiejsc) Sub AktualizujSkojarzenia(ByVal strconn As String, _ ByVal dgv As DataGridView, ByRef x() As Boolean) End Interface W kodzie modułu klasy CEdycjaKierunkiPrzedmioty została dodana instrukcja wskazująca na implementację interfejsu IEdycjaLimituMiejsc. Public Class CEdycjaKierunekPrzedmiot Inherits CForStorageSub Implements IEdycjaStudiow Implements IKierunkiStudiow Implements ISkojarzeniaEdycjeKierunki Implements IEdycjaLimituMiejsc Private mkomunikat As String = "" Private mczysukces As String = "" ' dalsze instrukcje modułu klasy End Class W kodzie implementującym właściwość (funkcję) Komunikat dodano instrukcję wskazującą na jej implementację przez interfejs ISkojarzeniaEdycjeKierunki. Public Function Komunikat() As String Implements _ IEdycjaStudiow.Komunikat, IKierunkiStudiow.Komunikat, _ ISkojarzeniaEdycjeKierunki.Komunikat, _ IEdycjaLimituMiejsc.Komunikat Return mkomunikat End Function Analogicznie uzupełniono implementację funkcji CzySukces. Public Function CzySukces() As String Implements _ IEdycjaStudiow.CzySukces, IKierunkiStudiow.CzySukces, _

92 92 IEdycjaLimituMiejsc.CzySukces Return mczysukces End Function Procedura PrzygotujDaneDlaMiejsc ma za zadanie pobrać dane do wyświetlenia w gridzie formularza i odpowiednio przygotować kolumny tego gridu do obsługi edycji limitu miejsc i wysokości czesnego. Potrzebne dane pobierane są za pomocą procedury przechowywanej dbo.pdaneedycjilimitumiejsc, pierwsze dwie kolumny zwróconych danych odpowiadają polom id_e (identyfikator edycji studiów) oraz id_k (identyfikator kierunku studiów), dane te będą nam potrzebne dla wskazania rekordu do aktualizacji w tabeli EdycjeKierunki, ale nie powinniśmy ich pokazywać użytkownikowi, stąd ustawienie właściwości Visible pierwszych dwóch kolumn gridu na False. Kolejne dwie kolumny zwróconych danych zawierają nazwę edycji studiów oraz nazwę kierunku studiów, dane te oczywiście pokazujemy użytkownikowi, ale nie możemy pozwolić na ich edycję, stąd ustawienie właściwości ReadOnly dla kolumny drugiej i trzeciej gridu na True. Public Sub PrzygotujDaneDlaMiejsc(ByVal strconn As String, _ ByVal frm As frmedycjalimitumiejsc) _ Implements IEdycjaLimituMiejsc.PrzygotujDaneDlaMiejsc Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdaneedycjilimitumiejsc", _ 1, 1, 0) With frm.dgvmiejsca.datasource = mtable1.columns(0).visible = False.Columns(1).Visible = False.Columns(2).Width = 200 ' nazwa edycji.columns(3).width = 400 ' nazwa kierunki.columns(4).width = 100 'limit miejsc ' określenie nagłówków kolumn.columns(2).headertext = "Edycja studiów".columns(3).headertext = "Kierunek studiów".columns(4).headertext = "Miejsc" ' zdefiniowanie 2 i 3 kolumny jako ReadOnly.Columns(2).ReadOnly = True.Columns(3).ReadOnly = True ' zdefiniowanie sposobu wyrównania 4 kolumny.columns(4).defaultcellstyle.alignment = _ DataGridViewContentAlignment.MiddleCenter End With Catch ex As Exception

93 93 mkomunikat = "Błąd dostępu do bazy danych" Finally conn.close() conn = Nothing End Try Proceedura AktualizujSkojarzenia odpowiada za zaktualizowanie limitu miejsc w tych rekordach tabeli EdycjeKierunki, które wskazane są wartością True w zmiennej tablicowej x przekazanej do tej procedury. Potrzebne dane pobierane są z gridu przekazanego do tej procedury, a sama aktualizacja wykonywana za pośrednictwem procedury przechowywanej dbo.paktualizujedycjekierunkimiejsca. Public Sub AktualizujSkojarzenia(ByVal strconn As String, _ ByVal dgv As DataGridView, ByRef x() As Boolean) _ Implements IEdycjaLimituMiejsc.AktualizujSkojarzenia Dim conn As New SqlConnection(strconn), i As Integer Try conn.open() For i = 0 To dgv.rows.count - 1 If x(i) Then ' aktualizujemy MyBase.Wykonaj(conn, _ "dbo.paktualizujedycjekierunkimiejsca", _ dgv.rows(i).cells(0).value, 1, 0, _ dgv.rows(i).cells(1).value, 1, 0, _ dgv.rows(i).cells(4).value, 1, 0) Next Catch ex As Exception mkomunikat = "Błąd dostępu do bazy danych" Finally conn.close() conn = Nothing End Try

94 Interfejs IKierunkiPrzedmioty Interfejs IKierunkiPrzedmioty zaprojektowano na potrzeby obsługi zdarzeń związanych z kojarzeniem kierunków studiów z przedmiotami, które mają być na nich realizowane. Kod deklaracji interfejsu pokazany jest niżej, dwie z jego metod otrzymają jako argument formularz frmkierunkiprzedmioty, którego projekt będzie przedstawiony w dalszej części tej książki. Metoda UsunDane otrzymuje jako jeden z argumentów formularz frmusunskojarzenia, jego projekt także będzie przedstawiony w dalszej części, a będzie on wykorzystywany do usuwania niepotrzebnych skojarzeń. Public Interface IKierunkiPrzedmioty Function Komunikat() As String Function DajTabele() As DataTable Sub DaneKierunekPrzedmioty(ByVal strconn As String, _ ByVal frm As frmkierunkiprzedmioty) Sub ZmianaKierunku(ByVal strconn As String, ByVal idk As Integer) Sub ZapiszKierunekPrzedmioty(ByVal strconn As String, _ ByVal frm As frmkierunkiprzedmioty) Sub UsunDane(ByVal strconn As String, ByVal frm As _ frmusunskojarzenia) Sub UsunSkojarzenia(ByVal strconn As String, ByVal dgv As _ DataGridView, ByVal ktore As String) End Interface W kodzie klasy CEdycjeKierunkiPrzedmioty mamy zapowiedź implementacji tego interfejsu. Public Class CEdycjaKierunekPrzedmiot Inherits CForStorageSub Implements IKierunkiPrzedmioty Implements IEdycjaStudiow ' dalsze instrukcje klasy End Class Funkcja Komunikat występowała już we wcześniejszych interfejsach, wystarczy w jej implementacji dodać obsługę także jej wystąpienia w tym interfejsie. Public Function Komunikat() As String Implements _ IEdycjaStudiow.Komunikat, IKierunkiStudiow.Komunikat, _ ISkojarzeniaEdycjeKierunki.Komunikat, _ IEdycjaLimituMiejsc.Komunikat, IPrzedmioty.Komunikat, _ IKierunkiPrzedmioty.Komunikat, _ Return mkomunikat End Function Funkcja DajTabele występowała już wcześniej, wystarczy w jej implementacji dodać dodać także jej wystąpienie w tym interfejsie.

95 95 Public Function DajTabele() As DataTable Implements _ IEdycjeKierunki.DajTabele,IKierunkiPrzedmioty.DajTabele Return mtable1 End Function Metoda DaneKierunekPrzedmioty jest odpowiedzialna za dostarczenie danych do pola kombo o nazwie cbokierunki umieszczonego w formularzu przekazanym jako argument tej metody, w którym użytkownik będzie mógł wybrać kierunek studiów. Public Sub DaneKierunekPrzedmioty(ByVal strconn As String, _ ByVal frm As frmkierunkiprzedmioty) _ Implements IKierunkiPrzedmioty.DaneKierunekPrzedmioty Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, "pdajkierunki", _ 1, 1, 0) UstawComboBox(frm.cboKierunki, mtable1, "Kierunek", "id_k") Catch ex As Exception mkomunikat = "Błąd dostępu do bazy danych" Finally conn.close() conn = Nothing End Try Metoda ZmianaKierunku jest odpowiedzialna za dostarczenie potencjalnej listy przedmiotów po zmianie kierunku studiów. Uurchamiana w tej metodzie procedura przechowywana dostarcza listę tych przedmiotów, które z wybranym kierunkiem studiów jeszcze nie zostały skojarzone. Public Sub ZmianaKierunku(ByVal strconn As String, ByVal idk As _ Integer) Implements IKierunkiPrzedmioty.ZmianaKierunku Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.ppotencjalneprzedmiotykierunku", "idk", idk, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy przedmiotów" Finally conn.close() conn = Nothing End Try Metoda ZapiszKierunekPrzedmioty odpowiada za zapisanie w tabeli KierunkiPrzedmioty rekordów dla wszystkich wybranych skojarzeń.

96 96 Public Sub ZapiszKierunekPrzedmioty(ByVal strconn As String, _ ByVal frm As frmkierunkiprzedmioty) Implements _ IKierunkiPrzedmioty.ZapiszKierunekPrzedmioty Dim conn As New SqlConnection(strconn), i As Integer, _ idk As Integer = frm.cbokierunki.selectedvalue conn.open() Try With frm.chlprzedmioty ' deklaracja obiektu do przejęcia identyfikatora ' przedmiotu Dim lst As System.Data.DataRowView For i = 0 To.CheckedIndices.Count - 1 ' zaznaczny wiersz jest przypisywany do lst lst =.CheckedItems(i) MyBase.Wykonaj(conn, "pwstawkierunekprzedmiot", _ idk, 1, 0, _ lst.item(0), 1, 0) Next do nowej rejestracji.datasource = Nothing End With Catch ex As Exception mkomunikat = "Błąd zapisu kierunku i przedmiotu" Finally conn.close() conn = Nothing End Try Metody UsunDane i UsunSkojarzenia już mamy zaimplementowane, wystarczy dodać informację o obsłudze tych metod w interfejsie IKierunkiPrzedmioty. Public Sub UsunDane(ByVal strconn As String, ByVal frm As _ frmusunskojarzenia) Implements IEdycjeKierunki.UsunDane, IKierunkiPrzedmioty.UsunDane '... kod metody... Public Sub UsunSkojarzenia(ByVal strconn As String, _ ByVal dgv As DataGridView, ByVal ktore As String) _ Implements IEdycjeKierunki.UsunSkojarzenia, IKierunkiPrzedmioty.UsunSkojarzenia '... kod metody...

97 Interfejs IWykladowcyPrzedmioty Interfejs IWykladowcyPrzedmioty zaprojektowano na potrzeby obsługi zdarzeń związanych z kojarzeniem wykładowców z przedmiotami, które mogą prowadzić w ramach realizacji studiów podyplomowych. Kod deklaracji interfejsu pokazany jest niżej, dwie z jego metod otrzymają jako argument formularz frmwykladowcyprzedmioty, którego projekt będzie przedstawiony później. Public Interface IWykladowcyPrzedmioty Function Komunikat() As String Function DajTabele() As DataTable Sub DaneWykladowcyPrzedmioty(ByVal strconn As String, _ ByVal frm As frmwykladowcyprzedmioty) Sub ZmianaWykladowcy(ByVal strconn As String, _ ByVal idw As Integer) Sub ZapiszWykladowcyPrzedmioty(ByVal strconn As String, _ ByVal frm As frmwykladowcyprzedmioty) Sub UsunDane(ByVal strconn As String, ByVal frm As _ frmusunskojarzenia) Sub UsunSkojarzenia(ByVal strconn As String, ByVal dgv As _ DataGridView, ByVal ktore As String) End Interface W kodzie klasy CEdycjeKierunkiPrzedmioty mamy zapowiedź implementacji tego interfejsu. Public Class CEdycjaKierunekPrzedmiot Inherits CForStorageSub Implements IWykladowcyPrzedmioty Implements IEdycjaStudiow ' dalsze instrukcje klasy End Class Funkcja Komunikat występowała już we wcześniejszych interfejsach, wystarczy w jej implementacji dodać obsługę także jej wystąpienia w tym interfejsie. Public Function Komunikat() As String Implements _ IEdycjaStudiow.Komunikat, IKierunkiStudiow.Komunikat, _ IEdycjeKierunki.Komunikat, _ IEdycjaLimituMiejsc.Komunikat, IPrzedmioty.Komunikat, _ IKierunkiPrzedmioty.Komunikat, _ IWykladowcyPrzedmioty.Komunikat Return mkomunikat End Function W implementacji funkcji DajTabele dodajemy informację o obsłudze tej funkcji w interfejsie IWykladowcyPrzedmioty.

98 98 Public Function DajTabele() As DataTable Implements _ IEdycjeKierunki.DajTabele,IKierunkiPrzedmioty.DajTabele, _ IWykladowcyPrzedmioty.DajTabele Return mtable1 End Function Metoda DaneWykladowcyPrzedmioty jest odpowiedzialna za dostarczenie danych do pola kombo o nazwie cboprzedmioty umieszczonego w formularzu przekazanym jako argument tej metody, w którym użytkownik będzie mógł wybrać wykładowcę. Public Sub DaneWykladowcyPrzedmioty(ByVal strconn As String, _ ByVal frm As frmwykladowcyprzedmioty) _ Implements IWykladowcyPrzedmioty.DaneWykladowcyPrzedmioty Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, "dbo.pdajlisteludzi", _ 1, 1, 0) UstawComboBox(frm.cboPracownik, mtable1, "ktos", "id_w") Catch ex As Exception mkomunikat = "Błąd pobrania listy wykładowców" Finally conn.close() conn = Nothing End Try Metoda ZmianaWykladowcy odpowiada za pobranie z bazy danych listy potencjalnych przedmiotów dla wykładowcy, którego identyfikator zostaje przekazany do tej metody. Procedura przechowywana uruchamiana w tej metodzie zwraca listę tych przedmiotów, które temu wykładowcy jeszcze nie zostały przypisane. Dzięki temu unikamy takiej sytuacji, w której moglibyśmy przypisać pracownikowi wielokrotnie ten sam przedmiot. Tak naprawdę moglibyśmy tylko podjąć taką próbę, ale przy próbie zapisu do bazy danych wystąpiłby błąd wynikający z faktu, że taki zestaw identyfikatorów wykładowcy i przedmiotu już jest w tabeli ProwadzacyPrzedmioty. Public Sub ZmianaWykladowcy(ByVal strconn As String, _ ByVal idw As Integer) Implements _ IWykladowcyPrzedmioty.ZmianaWykladowcy Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.ppotencjalneprzedmiotywykladowcy", _ idw, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy przedmiotów"

99 99 Finally conn.close() conn = Nothing End Try Metoda ZapiszWykladowcyPrzedmioty odpowiada za przejrzenie listy zaznaczanej chlprzedmioty umieszczonej w formularzu będącym argumentem tej metody. Przegląda jest kolekcja zaznaczonych pozycji, dla każdej z nich i dla identyfikatora wykładowcy wykonywana jest procedura przechowywana odpowiedzialna za wstawienie nowego rekordu do tabeli ProwadzacyPrzedmioty. Warto zwrócić uwagę na sposób odczytania identyfikatora przedmiotu z wykorzystaniem obiektu typu System.Data.DataRowView. Public Sub ZapiszWykladowcyPrzedmioty(ByVal strconn As String, _ ByVal frm As frmwykladowcyprzedmioty) _ Implements IWykladowcyPrzedmioty.ZapiszWykladowcyPrzedmioty Dim conn As New SqlConnection(strconn), i As Integer, _ idw As Integer = frm.cbopracownik.selectedvalue() Try conn.open() ' deklaracja obiektu do przejęcia identyfikatora przedmiotu Dim lst As System.Data.DataRowView With frm.chlprzedmioty For i = 0 To.CheckedIndices.Count 1 ' zaznaczny wiersz jest przypisywany do lst lst =.CheckedItems(i) ' identyfikator przedmiotu jest na 0 pozycji w lst MyBase.Wykonaj(conn, "dbo.pwstawprzedmiotprowadzacy", _ idw, 1, 0, _ lst.item(0), 1, 0) Next ' przygotowanie do nowej rejestracji.datasource = Nothing End With Catch ex As Exception mkomunikat = "Błąd zapisu do bazy danych" Finally conn.close() conn = Nothing End Try Metody UsunDane i UsunSkojarzenia już mamy zaimplementowane, wystarczy dodać informację o obsłudze tych metod w interfejsie IWykladowcyPrzedmioty.

100 100 Public Sub UsunDane(ByVal strconn As String, ByVal frm As _ frmusunskojarzenia) Implements IedycjeKierunki.UsunDane, IKierunkiPrzedmioty.UsunDane, _ IWykladowcyPrzedmioty.UsunDane '... kod metody... Public Sub UsunSkojarzenia(ByVal strconn As String, _ ByVal dgv As DataGridView, ByVal ktore As String) _ Implements IEdycjeKierunki.UsunSkojarzenia, IKierunkiPrzedmioty.UsunSkojarzenia, _ IWykladowcyPrzedmioty.UsunSkojarzenia, _ '... kod metody...

101 Obsługa edycji studiów Rejestracja nowej edycji Formularz frmnowaedycja zastał zaprojektowany na potrzeby zarejestrowania w bazie danych nowej edycji studiów podyplomowych. Umieszczono w nim następujące formanty: txtedyckja pole tekstowe przeznaczone do pobrania od użytkownika nazwy nowej edycji studiów; dtpstart i dtpkoniec formanty typu DateTimePicker przeznaczone do wskazania daty rozpoczęcia i zakończenia edycji studiów; grupa opcji grbstatus z trzema przyciskami typu RadioButton pozwalającymi na wybranie jednego z możliwych statutów edycji, przyciski te nazwano odpowiednio (ostatnie znaki nazwy opisują wartość danego przycisku (na potrzeby funkcji UstalGrb): rdbplanowany1, rdbrealizowana2 i rdbzakonczona3; grupa opcji grbforma z dwoma przyciskami typu RadioButton o nazwach rdbparp1 i rdbwlasne2 dla określenia, czy edycja jest realizowana we współpracy z PARP; btnzapisz przycisk polecenia (Button), jego klik uruchomi procedurę odpowiedzialną za wykonanie ostatecznej walidacji wprowadzonych danych i ich zapis do tabeli EdycjeStudfiow; etykiety opisujące wymienione wyżej formanty. niżej. Sposób umieszczenia tych formantów na powierzchni formularza pokazany jest Dodatkowo, na tzw tacy umieszczono formant o nazwie ErrorProvider1 (typu ErrorProvider) dla zabezpieczenie procesu walidacji wprowadzonych danych.

102 102 W kodzie klasy formularza frmnowaedycja umieszczono te procedury, które zapewniają jego poprawne funkcjonowanie, są to procedury odpowiedzialne za zainicjowanie formularza, walidację wybranych formantów i zapis wprowadzonych danych w bazie. Pokazany niżej kod zawiera niezbędne wyjaśnienia w formie komentarzy. Public Class frmnowaedycja ' deklaracja zmiennej pomocniczej klasy Dim f As Boolean ' Zadaniem procedury obsługującej zdarzenie załadowania ' formularza jest zainicjowanie dat wyświetlanych w formantach ' dtpstart i dtpkoniec oraz zaznaczenie przycisków radiowych w ' obu grupach przycisków Private Sub frmnowaedycja_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load Me.dtpStart.Value = Now().ToString Me.dtpKoniec.Value = Now().AddYears(1).ToString ZaznaczRdb(Me.rdbPlanowana1) ZaznaczRdb(Me.rdbParp1) ' Procedura walidacji formantu dtpstart, pilnuje, aby data ' rozpoczęcia realizacji edycji była wcześniejsza minimum o rok ' od daty jej zakończenia Priodvate Sub dtpstart_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles dtpstart.validating If Me.dtpStart.Value.AddYears(1) > Me.dtpKoniec.Value Then Beep() Me.ErrorProvider1.SetError(Me.dtpStart, _ "Data rozpoczęcia musi być o minimum rok " & _ "wcześniejsza od daty zakończenia!") Else Me.ErrorProvider1.SetError(Me.dtpStart, "") ' Procedura walidacji formantu dtpkoniec, pilnuje, aby data ' zakończenia realizacji edycji była późniejsza minimum o rok ' od daty jej rozpoczęcia Private Sub dtpkoniec_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles dtpkoniec.validating If Me.dtpStart.Value.AddYears(1) > Me.dtpKoniec.Value Then Beep() Me.ErrorProvider1.SetError(Me.dtpKoniec, _ "Data zakończenia musi być o minimum rok późniejsza " & _ "od daty rozpoczęcia!") Else Me.ErrorProvider1.SetError(Me.dtpKoniec, "")

103 103 ' Procedura walidacji formantu txtedycja pilnuje, aby wprowadzony ' ciąg znaków miał od 10 do 100 znaków Private Sub txtedycja_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtedycja.validating f = CzyTextBoxDobry(Me.txtEdycja, Me.ErrorProvider1, _ "Nazwa edycji studiów musi być podana (od 10 do " & ) "100 znaków)", 10, 200, True) ' Procedura odpowiedzialna za ostateczną walidację danych ' i ich zapis do bazy. Zapis realizowany jest poprzez instancję ' klasy CEdycjaKierunekPrzedmiot zadeklarowaną z wykorzystaniem ' interfejsu IEdycjaStudiow i wywołaniem metody ZapisEdycji Private Sub cmdzapisz_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnzapisz.click If CzyTextBoxDobry(Me.txtEdycja, Me.ErrorProvider1, _ "Nazwa edycji studiów musi być podana (od 10 do 100 " & _ "znaków)", 10, 200, True) Then Exit Sub If Me.dtpStart.Value.AddYears(1) > Me.dtpKoniec.Value Then Beep() Me.ErrorProvider1.SetError(Me.dtpStart, _ "Data rozpoczęcia musi być minimum o rok " & _ "wcześniejsza od daty zakończenia") Exit Sub If Me.dtpStart.Value >= Me.dtpKoniec.Value.AddYears(-1) Then Beep() Me.ErrorProvider1.SetError(Me.dtpKoniec, _ "Data zakończenia musi być minimum o rok " & _ "późniejsza od daty rozpoczęcia") Exit Sub ' zapisujemy Dim w As IEdycjaStudiow w = New CEdycjaKierunekPrzedmiot w.zapisedycji(strbaza, Me) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' przygotowujemy formularz do nowej rejestracji Me.txtEdycja.Text = "" Me.dtpStart.Value = Now().ToString Me.dtpKoniec.Value = Now().AddYears(1).ToString ZaznaczRdb(Me.rdbPlanowana1)

104 104 ZaznaczRdb(Me.rdbParp1) End Class Poniżej widok tego formularza w trakcie rejestracji nowej edycji studiów. Wprowadzana jest data rozpoczęcia jej realizacji. Wszystkie dane są już podane, klik przycisku Zapisz spowoduje ich dopisanie do bazy danych. W efekcie w tabeli EdycjeStudiow został dopisany nowy rekord.

105 Modyfikacja istniejących edycji Formularz frmmodyfikacjaedycji jest stosunkowo prosty, zawiera bowiem tylko dwa formanty. Pierwszy z nich to formant typu DataGridView, którego nazwa została zmieniona na dgvedycje. Drugim formantem jest przycisk polecenia (Button) o nazwie btnaktualizuj, jego klik ma uruchomić procedurę aktualizującą rekordy w tabeli EdycjeStudiow. Projekt tego formularza pokazany jest poniżej, formant dgvedycje został umieszczony w lewym górnym narożniku formularza i tak poszerzony, aby pomieścił wszystkie przewidziane do pokazania kolumny. Z kolei jego wysokość została tak dobrana, aby w dolnej części formularza można było umieścić przycisk btnaktualizuj. W kodzie klasy formularza, w jego sekcji deklaracji zadeklarowano zmienną tablicową x() typu logicznego, jej wartości ustawione na True będą wskaźnikiem, że dany wiersz gridu został zmodyfikowany. Zmienna ilew będzie przechowywać liczbę wierszy gridu. Public Class frmmodyfikacjaedycji ' deklaracja pomocniczych zmiennych modułu formularza Dim x() As Boolean, ilew As Integer ' zadaniem procedury uruchamianej w momencie otwierania ' formularza jest zainicjowanie tablicy x(), wcześniej musi ' być określony jej wymiar za pomocą polecenie Redim Private Sub frmmodyfikacjaedycji_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load Dim i As Integer ilew = Me.dgvEdycje.Rows.Count ReDim x(ilew - 1) For i = 0 To ilew - 1 x(i) = False Next

106 106 ' procedura obsługująca walidację komórek gridu Private Sub DataGridView1_CellValidating( _ ByVal sender As Object, ByVal e As System.Windows.Forms. _ DataGridViewCellValidatingEventArgs) _ Handles dgvedycje.cellvalidating ' uzależniamy działanie od indeksu kolumny Select Case e.columnindex Case 1 ' nazwa If e.formattedvalue.tostring.length < 10 Then Me.dgvEdycje.Rows(e.RowIndex).ErrorText = _ "Nazwa edycji musi mieć minimum 10 znaków!" e.cancel = True ' sprawdzamy, czy nazwa jest unikalna? Dim i As Integer For i = 0 To Me.dgvEdycje.Rows.Count - 1 If i <> e.rowindex And e.formattedvalue = _ Me.dgvEdycje.Rows(i).Cells(e.ColumnIndex).Value _ Then Me.dgvEdycje.Rows(e.RowIndex).ErrorText = _ "Nazwa edycji musi być unikalna!" e.cancel = True Next Case 2 ' data start If Not IsDate(e.FormattedValue) Then Me.dgvEdycje.Rows(e.RowIndex).ErrorText = _ "Wprowadzony ciąg znaków jako data rozpoczęcia " & _ "nie jest datą!" e.cancel = True ' data, pytanie czy dobra Dim d1, d2 As Date d1 = CDate(e.FormattedValue) d2 = CDate(Me.dgvEdycje.Rows(e.RowIndex).Cells(3).Value) ' badamy, czy różnica między datami jest minimum rok If d1.addyears(1) > d2 Then Me.dgvEdycje.Rows(e.RowIndex).ErrorText = _ "Data rozpoczęcia musi być minimum o rok " & _ "wcześniejsza od daty zakończenia!" e.cancel = True Case 3 ' data koniec If Not IsDate(e.FormattedValue) Then Me.dgvEdycje.Rows(e.RowIndex).ErrorText = _ "Wprowadzony ciąg znaków jako data zakończenia " & _ "nie jest datą!" e.cancel = True

107 107 Dim d1, d2 As Date d1 = CDate(Me.dgvEdycje.Rows(e.RowIndex).Cells(2).Value) d2 = CDate(e.FormattedValue) If d1.addyears(1) > d2 Then Me.dgvEdycje.Rows(e.RowIndex).ErrorText = _ "Data zakończenia musi być minimum o rok " & _ "późniejsza od daty rozpoczęcia!" e.cancel = True Case 6, 7 ' modyfikacja statutu lub formy dofinansowania If Not x(e.rowindex) Then x(e.rowindex) = True End Select ' procedura usuwająca ewentualny stan błędu, innym jej zadaniem ' jest badanie, czy znacznik aktualizacji wiersza jest ustawiony Private Sub DataGridView1_CellEndEdit(ByVal sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvedycje.cellendedit Me.dgvEdycje.Rows(e.RowIndex).ErrorText = String.Empty If Not x(e.rowindex) Then x(e.rowindex) = True ' procedura realizuje zadanie aktualizacji danych w tabeli ' EdycjeStudiow, robi to poprzez utworzenie instancji z klasy ' CEdycjaKierunekPrzedmiot. Obiekt jest deklarowny interfejsem ' IEdycjaStudiow, co pozwala na dostęp do dedykowanych metod Private Sub btnaktualizuj_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnaktualizuj.click Dim w As IEdycjaStudiow w = New CEdycjaKierunekPrzedmiot w.updateedycjistudiow(strbaza, Me, x) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Aktualizacja zakończona sukcesem", _ MsgBoxStyle.Information, conmsgerr) Me.Close() End Class Poniżej widok formularza frmmodyfikacjaedycji, w formancie dgvedycje pokazane są wybrane kolumny tabeli EdycjeStudiow (pola id_e, statuse oraz forma zostały ukryte). W miejsce dwóch ostatnich pól w gridzie zostały wyświetlone kolumny typu ComboBox, co zwalnia użytkownika od pamiętania, jaka liczba identyfikuje dany status czy formę dofinansowania. Warto także zauważyć, że takie rozwiązanie w zasadzie eliminuje możliwość popełnienia błędu (w tym sensie, że użytkownik nie ma możliwości wprowadzenia takiej liczby, która niczego nie identyfikuje).

108 108 W ostanim wierszu została skorygowana data zakończenia edycji, w kolumnie opisującej wiersze pojawił się symbol edycji danych. Klik przycisku Aktualizuj spowoduje zmodyfikowanie odpowiedniego rekordu w tabeli EdycjeStudiow. Pomyślne zakończenie edycji potwierdzane jest stosownym komunikatem, po jego akceptacji formularz zostanie zamknięty.

109 5.5. Obsługa kierunku studiów Rejestracja nowego kierunku studiów 109 Formularz frmnowykierunek pozwala na pobranie od użytkownika danych nowego kierunku studiów. Na powierzchni formularza umieszczono formanty: niżej. txtnazwa pole tekstowe do wpisania nazwy kierunku studiów; txtskrot pole tekstowe do wprowadzenia skrótu nazwy kierunku; btnskrot przycisk polecenia, jego klik ma uruchomić procedurę weryfikującą unikalność skrótu nazwy kierunku studiów; nudseemstry numeryczne pokrętło (NumericUpDown) przeznaczone do określenia liczby semestrów; nudgodziny numeryczne pokrętło do ustalenia ogólnej liczby godzin; ToggleNUD1 własna kontrolka typu przełącznik pozwalająca na zmianę właściwości Increment formantu nudgodziny; btnzapisz przycisk polecenia uruchamiający proces walidacji i zapisu danych w bazie; etykiety (Label) opisujące wymienione wyżej formanty. Sposób rozmieszczenia tych formantów na powierzchni formularza pokazany jest Pole tekstowe txtnazwa ma ustawioną właściwość Multiline na True, co pozwoliło tak zmienić wysokość tego formantu, aby zmieścić dwa wiersze nazwy kierunku studiów.

110 110 Przełącznik ToggleNUD1 ma domyślną właściwość Text pozostawioną jako Button1, w procedurze uruchamianej w momencie otwarcia tego formularza właściwość ta zostanie zmieniona na opis zmiany skoku. W module formularza frmnowykierunek utworzono te wszystkie procedury i funkcje, które są niezbędne do zapewnienia jego poprawnej pracy. Kod zaczyna się importem przestrzeni nazw ToggleNUD, w której utworzyliśmy klasę przełącznika o tej samej nazwie. Imports ToggleNUD Public Class frmnowykierunek ' zmienna f będzie wykorzystywano w walidacji, będzie ' także pełnić rolę pewnej zmiennej wskaźnikowej Dim f As Boolean = False ' zadaniem procedury uruchamianej w momencie otwierania tego ' formularza jest zainicjowanie jego formantów Private Sub frmnowykierunek_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load f = True ' ustawienie minimalnej i maksymalnej liczby godzin Me.nudGodziny.Minimum = 160 Me.nudSemestry.Maximum = 320 ' ustawienie minimalnej i maksymalnej wartości przełącznika Me.ToggleNUD1.MinimumSkok = 1 Me.ToggleNUD1.MaksimumSkok = 20 Me.nudGodziny.Increment = Me.ToggleNUD1.MinimumSkok ' wywołanie metody z klasy ToggleNUD modyfikującej opis ' przełącznika Me.ToggleNUD1.OpisStart() ' zadaniem procedury obsługującej zdarzenie Click przycisku ' btnskrot jest sprawdzenie, czy skrót ma odpowiednią liczbę ' znaków i czy jest unikalny Private Sub btnskrot_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnskrot.click ' zaczynamy od sprawdzenia, czy długość tekstu jest ' odpowiednia If Me.txtSkrot.Text.Length < 3 Or _ Me.txtSkrot.Text.Length > 10 Then MsgBox("Skrót nie może zawierać mniej niż 3 znaki ani " & _ "więcej niż 10 znaków", _ MsgBoxStyle.Critical, conmsgerr) ' ustawiamy kursor w polu txtskrot i wychodzimy z procedury Me.txtSkrot.Focus() Exit Sub ' teraz musimy sprawdzić, czy skrót jest unikalny w tabeli

111 111 ' korzystamy z klasy cedycjakierunekprzedmiot i interfejsu ' IKierunekStudiow Dim w As IKierunkiStudiow w = New CEdycjaKierunekPrzedmiot ' wywołujemy metodę WeryfikacjaSkrotu w.weryfikacjaskrotu(strbaza, Me.txtSkrot.Text) If w.komunikat.length > 0 Then ' były problemy z bazą danych, nie jest wykonana procedura MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else If w.czysukces.length > 0 Then ' skrót nie jest unikalny, komunikat na ekran MsgBox(w.CzySukces, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Skrót '" & Me.txtSkrot.Text & _ "' jest unikalny", MsgBoxStyle.Information, conmsgok) ' procedura walidacyjna pola tekstowego txtnazwa Private Sub txtnazwa_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtnazwa.validating f = CzyTextBoxDobry(Me.txtNazwa, Me.ErrorProvider1, _ "Nazwa kierunku musi być podana (od 10 do 200 znaków)", _ 10, 200, True) ' procedura walidacyjna pola tekstowego txtskrot Private Sub txtskrot_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtskrot.validating f = CzyTextBoxDobry(Me.txtSkrot, Me.ErrorProvider1, _ "Skrót nazwy musi zawierać od 3 do 10 znaków", 3, 10, True) ' pomocnicza funkcja PonownaWalidacja będzie odpowiadać za ' weryfikację istotnych danych Private Function PonownaWalidacja() As Boolean ' jeżeli funkcja zwróci prawdę, to nie możemy wykonać zapisu ' do bazy danych ' sprawdzamy oba pole tekstowe, czyli txtnazwa i txtskrot If CzyTextBoxDobry(Me.txtNazwa, Me.ErrorProvider1, _ "Nazwa kierunku musi być podana (od 10 do 200 znaków)", _ 10, 200, True) Then Return True If CzyTextBoxDobry(Me.txtSkrot, Me.ErrorProvider1, _ "Skrót nazwy musi zawierać od 3 do 10 znaków", 3, 10, _

112 112 True) Then Return True ' pola tekstowe ok ' sprawdzamy, czy jest warunek, że ogólna liczba godzin >= ' semestrów * 80 If Me.nudGodziny.Value < Me.nudSemestry.Value * 80 Then ' jakiś komunikat o błędzie Me.ErrorProvider1.SetError(Me.nudGodziny, _ "Zbyt mała liczba godzin") Beep() Me.nudGodziny.Focus() Return True Else Me.ErrorProvider1.SetError(Me.nudGodziny, "") Return False End Function ' procedura obsługi zdarzenia Click przycisku btnzapisz, jej ' zadaniem jest ponowna weryfikacja wprowadzonych danych ' i ich zapis do bazy danych Private Sub btnzapisz_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnzapisz.click ' musimy ponownie wymusić walidacje istotnych kontrolek If PonownaWalidacja() Then Exit Sub ' zapis do bazy danych, skorzystamy z klasy ' CEdycjaKierunekPrzedmiot i interfejsu IKierunkiStudiow Dim w As IKierunkiStudiow w = New CEdycjaKierunekPrzedmiot ' wywołujemy metodę ZapiszKierunek w.zapiszkierunek(strbaza, Me) If w.czysukces.length > 0 Then ' zapis nie jest możliwy, bo albo nazwa kierunku albo skrot ' nie są unikalne MsgBox(w.CzySukces, MsgBoxStyle.Critical, conmsgerr) Else ' można było wywołać procedurę zapisującą ale czy zapis ' był udany? Jeżeli tak, to funkcja CzyZapisPoprawny ' zawiera pusty ciąg znaków If w.komunikat.length > 0 Then ' niestety nie MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' zapis się powiódł, można przygootwać formularz do nowej ' rejestacji Me.txtNazwa.Text = "" Me.txtSkrot.Text = ""

113 113 ' procedura obsługująca zdarzenie zmiany skoku przełacznika ' formantu ToggleNUD1 Private Sub ToggleNUD1_DajSkok(ByVal Skok As Integer) _ Handles ToggleNUD1.DajSkok Me.nudGodziny.Increment = Skok End Class Ponizej widok instancji formularza frmnowykierunek w trakcie rejestrowania danych nowego kierunku studiów. Po wprowadzeniu skrótu nazwy kierunku poprzez klik przycisku Sprawdź skrót wywołano procedurę sprawdzającą jego unikalność. Wyświetlony komunikat potwierdza spełnienie tego warunku. Wszystkie dane nowego kierunku studiów są już wprowadzone do formantów formularza, klik przycisku Zapisz do bazy spowoduje uruchomienie procedury realizującej końcową walidację tych danych, a po stwierdzeniu ich poprawności zapis danych do bazy.

114 114 Po zapisaniu danych formularz jest przygotowywany do rejestracji kolejnego kierunku studiów Aktualizacja istniejących kierunków Formularz frmkierunkiaktualizacja został zaprojektowany w celu umożliwwienia edycji danych dotychczas zarejestrowanych kierunków studiów, włącznie z możliwością ich usuwania (ale tylko wtedy, gdy nie występują w tabelach powiązanych). Na powierzchni formularza umieszczono dwa formanty: dgvkierunki formant typu DataGridView do wyświetlenia danych z tabeli Kierunki; btnaktualizuj przycisk polecenia odpowiedzialny za uruchomienie procedury aktualizującej. Poniżej widok projektu tego formularza, formant dgvkierunki jest zaznaczony, w oknie jego właściwości wskazany jest właściwość AllowUserToAddRows ustawiona na False, chodziło o to, aby uniemożliwić dodawanie nowego kierunku studiów. Z kolei właściwość AllowUserToDeleteRows ustawiona jest na domyślną wartość True, co pozwoli nam na podjęcie próby skasowania wiersza po jego wcześniejszym zaznaczeniu za pomocą klawisza Delete. W kodzie modułu formularza frmkerunkiaktualizacja utworzono szereg procedur i funkcji, większość z nich dotyczy walidacji komórek gridu lub usunięcia zaznaczonego wiersza. Public Class frmkierunkiaktualizacja ' deklaracja potrzebnych zmiennych, zmienna tablicowa x() ' będzie wykorzystywana jako zmienna wskaźnikowa do określenia ' czy dany wiersz gridu został zmodyfikowany

115 115 Dim x() As Boolean, i As Integer ' procedura obsługująca zdarzenie Load formularza, jej zadaniem ' jest inicjalizacja zmiennej tablicowej x() Private Sub frmkierunkiaktualizacja_load(byval sender As _ Object, ByVal e As System.EventArgs) Handles Me.Load ReDim x(me.dgvkierunki.rows.count - 1) For i = 0 To Me.dgvKierunki.Rows.Count - 1 x(i) = False Next ' procedura obslugująca walidację komórek gridu, numer indeksu ' kolumny bieżącej komórki wykorzystywany jest do zróźnicowania ' jej działania. Private Sub dgvkierunki_cellvalidating(byval sender As Object, _ ByVal e As System.Windows.Forms. _ DataGridViewCellValidatingEventArgs) _ Handles dgvkierunki.cellvalidating With Me.dgvKierunki Select Case e.columnindex Case 1 ' nazwa kierunku If e.formattedvalue.tostring.length < 10 Then Beep().Rows(e.RowIndex).ErrorText = _ "Nazwa kierunku studiów musi mieć minimum " & _ "10 znaków!" e.cancel = True Exit Sub If e.formattedvalue.tostring.length > 200 Then Beep().Rows(e.RowIndex).ErrorText = "Nazwa kierunku " & _ "studiów musi mieć co najwyżej 200 znaków!" e.cancel = True Exit Sub For i = 0 To.Rows.Count - 1 If i <> e.rowindex And e.formattedvalue = _ Trim(.Rows(i).Cells(1).Value) Then Beep().Rows(e.RowIndex).ErrorText = "Nazwa " & _ "kierunku studiów musi być unikalna!" & _ " Zobacz wiersz " & i.tostring e.cancel = True Exit Sub Next Case 2 ' skrót kierunku If e.formattedvalue.tostring.length < 3 Then

116 116 Beep().Rows(e.RowIndex).ErrorText = "Skrót nazwy " & _ "kierunku studiów musi mieć minimum 3 znaki!" e.cancel = True Exit Sub If e.formattedvalue.tostring.length > 10 Then Beep().Rows(e.RowIndex).ErrorText = "Skrót nazwy " & _ "kierunku studiów musi mieć co najwyżej 10 " & _ "znaków!" e.cancel = True Exit Sub For i = 0 To.Rows.Count - 1 If i <> e.rowindex And e.formattedvalue = _ Trim(.Rows(i).Cells(2).Value) Then Beep().Rows(e.RowIndex).ErrorText = "Skrót nazwy " & _ "kierunku studiów musi być unikalny!" & _ " Zobacz wiersz " & i.tostring e.cancel = True Exit Sub Next Case 3 ' liczba semestrów If Not IsNumeric(e.FormattedValue) Then Beep().Rows(e.RowIndex).ErrorText = "Wprowadzony " & _ "ciąg znaków nie jest liczbą semestrów!" e.cancel = True Exit Sub If CInt(e.FormattedValue) < 2 Or _ CInt(e.FormattedValue) > 4 Then Beep().Rows(e.RowIndex).ErrorText = "Poprawna liczba " & _ "semestrów to 2, 3 lub 4!" e.cancel = True Exit Sub Case 4 ' liczba godzin If Not IsNumeric(e.FormattedValue) Then Beep().Rows(e.RowIndex).ErrorText = "Wprowadzony " & _ "ciąg znaków nie jest liczbą godzin!" e.cancel = True Exit Sub

117 117 If CInt(e.FormattedValue) < _.Rows(e.RowIndex).Cells(3).Value * 80 Then Beep().Rows(e.RowIndex).ErrorText = "Liczba godzin " & _ nie może być mniejsza niż " & _ (.Rows(e.RowIndex).Cells(3).Value * _ 80).ToString & "!" e.cancel = True Exit Sub If CInt(e.FormattedValue) > _.Rows(e.RowIndex).Cells(3).Value * 120 Then Beep().Rows(e.RowIndex).ErrorText = "Liczba godzin " & _ "nie może być większa niż " & _ (.Rows(e.RowIndex).Cells(3).Value * _ 120).ToString & "!" e.cancel = True Exit Sub End Select End With ' zadaniem pokazanej niżej procedury jest ewentualne usunięcie ' ikony błędu i jego komunikatu. Innym zadaniem jest zmiana ' wartości zmiennej tablicowej x() na pozycji odpowiadającej ' bieżącemu wierszowi będzie to informacja o aktualizacji Private Sub dgvkierunki_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvkierunki.cellendedit Me.dgvKierunki.Rows(e.RowIndex).ErrorText = String.Empty If Not x(e.rowindex) Then x(e.rowindex) = True ' zadaniem pokazanej niżej procedury jest obsługa usunięcia ' zaznaczonego wiersza. Najpierw prowadzone jest badanie, czy ' kierunek studiów, który chcemy usunąć występuje jedynie ' w tabeli Kierunki, a nie w tabelach powiązanych np. w tabeli ' EdycjeKierunki. W sytuacji, gdy występuje w tabelach ' powiązancyh, to procedura zgłasza stosowny komunikat i kończy ' swoją pracę. Jeżeli wiersz gridu może być usunięty, to ' procedura upewnia się, czy naprawdę chcemy usunąć dany wiersz Private Sub dgvkierunki_userdeletingrow(byval sender As Object, _ ByVal e As System.Windows.Forms. _ DataGridViewRowCancelEventArgs) _ Handles dgvkierunki.userdeletingrow ' wywołanie procedury sprawdzającej, czy można usunąć wskazany ' kierunek, korzystamy z interfejsu IKierunkiStudiow w klasie ' CEdycjeKierunekPrzedmiot

118 118 Dim w As IKierunkiStudiow w = New CEdycjaKierunekPrzedmiot w.czymoznausunackierunek(strbaza, e.row.cells(0).value) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, "Usunąć wiersz?") e.cancel = True Else If w.czysukces.length > 0 Then MsgBox(w.CzySukces, MsgBoxStyle.Critical, _ "Usunać wiersz?") e.cancel = True Else Dim response As DialogResult = _ MessageBox.Show("Czy jesteś pewien, że chcesz " & _ "skasować ten wiersz?", _ "Usunać wiersz?", MessageBoxButtons.YesNo, _ MessageBoxIcon.Question, _ MessageBoxDefaultButton.Button2) If (response = DialogResult.No) Then e.cancel = True Else ' wywołanie procedury usuwającej Dim z As IKierunkiStudiow z = New CEdycjaKierunekPrzedmiot z.usunkierunek(strbaza, e.row.cells(0).value) If z.komunikat.length > 0 Then MsgBox("Broblem z wykonaniem procedury " & _ "przechowywanej, usunięcie niemożliwe", _ MsgBoxStyle.Critical, "Usunąć wiersz?") e.cancel = True End Class Na kilku zrzutach ekranowych pokażemy teraz jak funkcjonuje omawiany formularz. Zaczniemy od pokazania formularza w trakcie edycji liczby godzin dla jednego z kierunku studiów (Informatyka stosowana), dla którego wcześniej nie była podana liczba godzin zajęć. Po wpisaniu do kolumny gridu oznaczonej jako Godzin np. liczby 5 i przy próbie opuszczenia tej komórki zgłaszany jest błąd i wyświetlany stosowny komunikat, czym jest spowodowany (komunikat jest widoczny po wskazaniu myszą symbolu błędu). Sytuacja taka pokazana jest poniżej, z uwagi na postać procedury walidacyjnej jedyna możliwość opuszczenia tej komórki gridu może mieć wtedy, gdy wpiszemy

119 119 odpowiednią liczbę godzin (w tym wypadku klawisz Esc nie pomaga, ponieważ wpisuje do tej komórki pusty ciąg znaków, a procedura na to nie pozwala). Po wpisaniu liczby np. 192 możemy już przejść do innego wiersza gridu, jednocześnie usuwany jest symbol błędu. Poniżej widzimy taką sytuację, liczba godzin dla kierunku Informatyka stosowana jest już zmieniona, mamy także zaznaczony wiersz kierunku, który będziemy chcieli usunąć. Naciśnięcie klawisza Del (Delete) spowoduje uruchomienie procedury odpowiedzialnej za obsługę zdarzenia związanego z próbą usunięcia wiersza gridu. Po sprawdzeniu, czy zaznaczony kierunek nie występuje w tabelach powiązanych (EdycjeKierunki, KierunkiPrzedmioty czy Dane) procedura wyświetla komunikat z prośbą o potwierdzenie zamiaru usunięcia tego wiersza.

120 120 Klik przycisku Tak spowoduje usunięcie wskazanego kierunku studiów z tabeli Kierunki. W pokazanej niżej sytuacji widzimy, że kierunek O wykorzystaniu metod matematycznych w został usunięty. Mamy zamiar usunąć kierunek Projektowanie aplikacji bazodanowych w środowisku MS Windows, zobaczymy, czy będziemy mogli to zrobić. Naciśnięcie kalwisza Del (Delete) skutkuje wyświetleniem pokazanego niżej komunikatu, z którego wynika, że nie możemy usunąć zaznaczonego w gridzie wiersza, co spowodowane jest tym, że identyfikator tego kierunku występuje w tabelach powiązanych. Dla jasności oczywiście że mimo tego ten kierunek może być usunięty (tzw. usuwanie kaskadowe, ale wymaga ono znacznie więcej uwagi ze strony użytkownika).

121 Edycja limitu miejsc i kosztu studiów Formularz frmedycjalimitumiejsc został zaprojektowany w celu umożliwwienia edycji limitu miejsc i wysokości czesnego na danym kierunku studiów realizowanym w odpowiedniej edycji studiów. Dodatkowo można edytować koszt studiów dla studenta. Na powierzchni formularza umieszczono dwa formanty: dgvmiejsca formant typu DataGridView, wyświetlimy w nim nazwę edycji studiów, nazwę kierunku studiów oraz liczbę miejsc i wysokość czesnego; btnaktualizuj przycisk polecenia odpowiedzialny za zaktualizowanie w tabeli EdycjeKierunki zmodyfikowanych danych. Rozmiar gridu dgvmiejsca (i tym samym formularza) został tak dobrany, aby pozwolił na wyświetlenie potencjalnie długich nazw kierunków studiów. W kodzie modułu tego formularza utworzono procedury niezbędne dla jego obsługi, w tym dla walidacji liczby miejsc. Public Class frmedycjalimitumiejsc ' deklaracja potrzebnych zmiennych Dim x() As Boolean, i As Integer ' zadaniem procedury Load jest przedefiniowanie wymiaru zmiennej ' tablicowej x oraz jej inicjalizacja ' zmienna publiczna flaga (zadeklarowana w pliku Parp.vb) ' otrzymuje wartość False Private Sub frmedycjalimitumiejsc_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ReDim x(me.dgvmiejsca.rows.count - 1) For i = 0 To Me.dgvMiejsca.Rows.Count - 1 x(i) = False Next flaga = True

122 122 ' poniżej kod procedury obsługującej zdarzenie walidacji ' komórek gridu. Korzystając ze zmiennej e walidacja robiona ' jest wyłącznie dla kolumny 4 (limitu miejsc). Badanie dotyczy ' stwierdzenia, czy zmodyfikowana komórka zawiera liczbę, jeżeli ' tak, to czy jest to liczba z odpowiedniego zakresu. Private Sub dgvmiejsca_cellvalidating(byval sender As Object, _ ByVal e As System.Windows.Forms. _ DataGridViewCellValidatingEventArgs) _ Handles dgvmiejsca.cellvalidating ' jeżeli flaga nie jest True to wyjdź z procedury If Not flaga Then Exit Sub With Me.dgvMiejsca If e.columnindex = 4 Then If Not IsNumeric(e.FormattedValue) Then Beep().Rows(e.RowIndex).ErrorText = _ "Wprowadzony ciąg znaków nie jest liczbą!" e.cancel = True Exit Sub ElseIf CInt(e.FormattedValue) < 20 Then Beep().Rows(e.RowIndex).ErrorText = _ "Liczba miejsc nie może być mniejsza niż 20!" e.cancel = True Exit Sub ElseIf CInt(e.FormattedValue) > 30 Then Beep().Rows(e.RowIndex).ErrorText = _ "Liczba godzin nie może być większa niż 30!" e.cancel = True Exit Sub End With ' poniższa procedura likwiduje ewentualny komunikat o błędzie, ' dodatkowo zaznacza numer wiersza jako zaktualizowany Private Sub dgvmiejsca_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvmiejsca.cellendedit Me.dgvMiejsca.Rows(e.RowIndex).ErrorText = String.Empty If Not x(e.rowindex) Then x(e.rowindex) = True ' procedura zdarzenia Click przycisku btnaktualizuj odpowiada ' za aktualizację limitu miejsc w tabeli EdycjeKierunki, robi to ' poprzez utworzenie instancji klasy CEdycjaKierunekPrzedmiot.

123 123 ' Instancja deklarowana jest interfejsem IEdycjaLimituMiejsc Private Sub btnaktualizuj_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnaktualizuj.click Dim w As IEdycjaLimituMiejsc w = New CEdycjaKierunekPrzedmiot w.aktualizujskojarzenia(strbaza, Me.dgvMiejsca, x) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else Me.Close() End Class Poniżej widok okna tworzonej przez nas aplikacji, polecenie Edycja limitu miejsc w menu Edycje i kierunki studiów, przedmioty za chwilę zostanie kliknięte, co uruchomi instancję formularza frmedycjalimitumiejsc. Poniżej widok tego formularza, naszym zamiarem jest zmiana liczby miejsc na kierunku Analityk finansowy realizowanym w ramach edycji Edycja2011_12. Dotyczasowa wartość może być zmieniona, oczywiście musimy wpisać poprawną wartość (liczbę z zakresu 20 do 30).

124 124 Wpisanie liczby spoza tego zakresu powoduje, przy próbie zmiany wiersza, wyświetlenie ikony błędu ze stosownym komunikatem. Przycisk Esc w takiej sytuacji przywraca poprzednią wartość, można oczywiście wpisać od razu poprawną liczbę. Dla zademonstrowania działania tego formularza możemy zmienić limit miejsc w dwóch ostatnich wierszach na odpowiednio 30 dla Projektowania aplikacji bazodanowych oraz 21 dla Kierunek wprowadzony dla potrzeb testu. Klik przycisku Aktualizuj powoduje modyfikację odpowiednich danych w tabeli EdycjeKierunki, a następnie formularz ekranowy zostaje zamknięty. Ponowne wywołanie tego samego polecenia (Edycja limitu miejsc) pokazuje, że dokonane zmiany zostały rzeczywiście zapisane w bazie danych. W analogiczny sposób można zmienić także koszt studenta, porównując dwa pokazane wyżej zrzuty ekranowe widzimy, że dla dwóch ostatnich wierszy zmodyfikowano nie tylko limit miejsc, ale także koszt studenta.

125 Obsługa przedmiotów Rejestracja nowego przedmiotu Formularz frmnowyprzedmiot został zaprojektowany w celu umożliwwienia rejestracji w bazie danych nazw nowych przedmiotów i skrótów tych nazw. Na powierzchni formularza umieszczono: txtnazwa pole tekstowe przeznaczone do wprowadzenia nazwy nowego przedmiotu, jego właściwość Multiline została ustawiona na True, co pozwoliło na zwiększenie jego wysokości tak, aby można było pomieścić dopuszczalne 250 znaków; txtskrot pole tekstowe przeznaczone do wprowadzenia skrotu nazwy przedmiotu (od 3 do 10 znaków); btnsprawdz przycisk polecenia uruchamiający procedurę weryfikującą unikalność skrótu nazwy przedmiotu; btnzapisz przycisk polecenia uruchamiający procedurę zapisującą wprowadzone dane do tabeli Przedmioty; i kilka etykiet opisujących te formanty oraz ErrorProvider1 umieszczony na tacy. W kodzie formularza frmnowyprzedmiot utworzono kilka procedur związanych głównie z walidacją wprowadzonych danych, sprawdzającą unikalność skrótu nazwy jak i zapisującą wprowadzone dane do bazy danych. Public Class frmnowyprzedmiot ' zmienna f będzie wykorzystywano w walidacji, będzie ' także pełnić rolę pewnej zmiennej wskaźnikowej Dim f As Boolean = False ' procedury walidacyjne wykorzystują funkcję z modułu Parp.vb

126 126 Private Sub txtnazwa_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtnazwa.validating f = CzyTextBoxDobry(Me.txtNazwa, Me.ErrorProvider1, _ "Nazwa przedmiotu musi być podana (od 10 do 250 znaków)", _ 10, 250, True) ' Private Sub txtskrot_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles txtskrot.validating f = CzyTextBoxDobry(Me.txtSkrot, Me.ErrorProvider1, _ "Skrót nazwy przedmiotu musi być podany (od 3 do 10 " & _ "znaków)", 3, 10, True) ' procedura sprawdzająca unikalność skrótu nazwy najpierw ' sprawdza, czy tekst ten jest poprawny pod względem długości, ' jeżeli tak, to sprawdzana jest unikalność poprzez utworzenie ' instancji klasy IPrzedmioty Private Sub btnsprawdz_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnsprawdz.click If CzyTextBoxDobry(Me.txtSkrot, Me.ErrorProvider1, _ "Skrót nazwy przedmiotu musi być podany (od 3 do 10 " & _ "znaków)", 3, 10, True) Then Exit Sub Dim w As IPrzedmioty w = New CEdycjaKierunekPrzedmiot w.czyskrotunikalny(strbaza, Me.txtSkrot.Text) If w.komunikat.length = 0 Then If w.czysukces.length > 0 Then MsgBox(w.CzySukces, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Skrót jest unikalny", _ MsgBoxStyle.Information, _ "Weryfikacja unikalności skrótu nazwy przedmiotu") Else MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Private Sub btnzapisz_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnzapisz.click If PonownaWalidacja() Then Exit Sub ' zapis do bazy danych, skorzystamy z klasy ' CEdycjaKierunekPrzedmiot Dim w As IPrzedmioty w = New CEdycjaKierunekPrzedmiot w.zapiszprzedmiot(strbaza, Me.txtNazwa.Text, _ Me.txtSkrot.Text)

127 127 If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else If w.czysukces.length = 0 Then Me.txtNazwa.Text = Nothing Me.txtSkrot.Text = Nothing Else MsgBox(w.CzySukces, MsgBoxStyle.Critical, conmsgerr) Private Function PonownaWalidacja() As Boolean ' jeżeli funkcja zwróci prawdę, to nie możemy wykonać zapisu ' do bazy danych sprawdzamy oba pole tekstowe, czyli txtnazwa ' i txtskrot If CzyTextBoxDobry(Me.txtNazwa, Me.ErrorProvider1, _ "Nazwa przedmiotu musi być podana (od 10 do 250 znaków)", _ 10, 200, True) Then Return True If CzyTextBoxDobry(Me.txtSkrot, Me.ErrorProvider1, _ "Skrót nazwy musi zawierać od 3 do 10 znaków", 3, _ 10, True) Then Return True Return False End Function End Class

128 Edycja przedmiotów Formularz frmedycjaprzedmiotu zaprojektowano dla potrzeb edycji (aktualizacji) nazw i ich skrótów. W formularzu umieszczono formant typu DataGridView o nazwie dgvprzedmioty i przycisk polecenia btnaktualizuj. Instancja tego formularza tworzona jest odpowiednim poleceniem w menu aplikacji, którego klik uruchamia pokazaną niżej procedurę zdarzeniową. Private Sub mnuedycjaprzedmiotow _Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuedycjaprzedmiotow.click Dim frm As New frmedycjaprzedmiotu Dim w As IPrzedmioty w = New CEdycjaKierunekPrzedmiot w.daneedycjiprzedmiotow(strbaza, frm) PokazForm(frm, w.komunikat) W module klasy tego formularza musimy utworzyć szereg procedur obsługujących zdarzenia, jakie mogą zajść przy użytkowaniu tego formularza.

129 129 Public Class frmedycjaprzedmiotu ' deklaracja potrzebnych zmiennych Dim x() As Boolean, i As Integer ' zadaniem procedury wykonywanej w momencie załadowania ' formularza jest przedefiniowanie wymiaru zmiennej x oraz ' jej inicjalizacja wartościami False Private Sub frmedycjaprzedmiotu_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ReDim x(me.dgvprzedmioty.rows.count - 1) For i = 0 To Me.dgvPrzedmioty.Rows.Count - 1 x(i) = False Next flaga = True ' poniższa procedura uruchamiana jest w momencie rozpoczynania ' edycji komórki gridu, a jej zadaniem jest oczyszczenie ' zawartości tej komórki z początkowych i końcowych spacji Private Sub dgvprzedmioty_cellbeginedit(byval sender As Object, _ ByVal e As System.Windows.Forms. _ DataGridViewCellCancelEventArgs) Handles _ dgvprzedmioty.cellbeginedit Me.dgvPrzedmioty.Rows(e.RowIndex).Cells( _ e.columnindex).value = Trim(Me.dgvPrzedmioty.Rows( _ e.rowindex).cells(e.columnindex).value) ' poniższa procedura uruchamiana jest w momenice kończenia ' edycji komórki gridu, a jej zadaniem jest skasowanie ' ewentualnego komunikatu o błędzie oraz sprawdzeniem czy do ' zmiennej tablicowej x na odpowiedniej pozycji jest wpisana ' jest wartość True, jeżeli nie, to jest wpisywana Private Sub dgvprzedmioty_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvprzedmioty.cellendedit Me.dgvPrzedmioty.Rows(e.RowIndex).ErrorText = String.Empty If Not x(e.rowindex) Then x(e.rowindex) = True ' poniższa procedura reaguje na podwójny klik w kolumnie 1 (tu ' są nazwy przedmiotów), a jej zadaniem jest pokazanie specjalnie ' zaprojektowanego formularza w trybie okna dialogowego. 4 Private Sub dgvprzedmioty_celldoubleclick(byval sender As _ Object, ByVal e As System.Windows.Forms. _ DataGridViewCellEventArgs) Handles _ dgvprzedmioty.celldoubleclick 4 Więcej na temat projektowania własnych formularzy dialogowych jest w rozdziale 6.7.3

130 130 If e.columnindex = 1 Then Dim pg As New frmedytujtextbox pg.tytul = "Edycja nazwy przedmiotu" pg.temat = Me.dgvPrzedmioty.Rows( _ e.rowindex).cells(e.columnindex).value.tostring If pg.showdialog = Windows.Forms.DialogResult.OK Then Me.dgvPrzedmioty.Rows( _ e.rowindex).cells(e.columnindex).value = pg.temat ' poniższa procedura obsługuje proces walidacji komórki gridu. ' Jej działanie uzależnione jest od edytowanej kolumny, poza ' sprawdzeniem długości tekstu sprawdzana jest także jego ' unikalność w kolumnie Private Sub dgvprzedmioty_cellvalidating(byval sender As _ Object, ByVal e As System.Windows.Forms. _ DataGridViewCellValidatingEventArgs) Handles _ dgvprzedmioty.cellvalidating If Not flaga Then Exit Sub With Me.dgvPrzedmioty Select Case e.columnindex Case 1 ' nazwa przedmiotu If e.formattedvalue.tostring.length < 10 Then Beep().Rows(e.RowIndex).ErrorText = _ "Nazwa przedmiotu musi mieć minimum 10 znaków!" e.cancel = True Exit Sub If e.formattedvalue.tostring.length > 250 Then Beep().Rows(e.RowIndex).ErrorText = _ "Nazwa przedmiotu musi mieć co najwyżej " & _ "250 znaków!" e.cancel = True Exit Sub For i = 0 To.Rows.Count - 1 If i <> e.rowindex And e.formattedvalue = _ Trim(.Rows(i).Cells(1).Value) Then Beep().Rows(e.RowIndex).ErrorText = _ "Nazwa przedmiotu studiów musi być " & _ "unikalna! Zobacz wiersz " & _ (i + 1).ToString e.cancel = True Exit Sub

131 131 Next Case 2 'skrot If e.formattedvalue.tostring.length < 3 Then Beep().Rows(e.RowIndex).ErrorText = _ "Skrót nazwy przedmiotu musi mieć minimum 3 znaki!" e.cancel = True Exit Sub If e.formattedvalue.tostring.length > 10 Then Beep().Rows(e.RowIndex).ErrorText = _ "Skrót nazwy przedmiotu musi mieć co " & _ "najwyżej 10 znaków!" e.cancel = True Exit Sub For i = 0 To.Rows.Count - 1 If i <> e.rowindex And e.formattedvalue = _ Trim(.Rows(i).Cells(2).Value) Then Beep().Rows(e.RowIndex).ErrorText = _ "Sktót nazwy przedmiotu musi być unikalny! " & _ "Zobacz wiersz " & (i + 1).ToString e.cancel = True Exit Sub Next End Select End With ' poniższa procedura uruchamia proces aktualizacji Private Sub btnaktualizuj_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnaktualizuj.click Dim w As IPrzedmioty w = New CEdycjaKierunekPrzedmiot w.aktualizujprzedmioty(strbaza, Me.dgvPrzedmioty, x) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Dane przedmiotów zostały zaktualizowane", _ MsgBoxStyle.Information, "Aktualizacja nazw przedmiotów") Me.Close() End Class

132 132 Poniżej widok instancji formularza frmedycjaprzedmiotu, naszym zamiarem była edycja nazwy przedmiotu Style zarządzania, rozwijanie kreatywności, analiza ról w zespole, z uwagi na konieczność dopisania jeszcze dłuższego fragmentu wykonany został podwójny klik na tej komórce gridu. Efektem jest otwarcie instancji formularza frmedytujtextbox w trybie okna dialogowego. Edycja w tym formularzu jest zawsze wygodniejsza, a po jej zakończeniu poprawiony tekst jest wstawiany w miejscu, z którego ten formularz był wywołany. W przypadku wprowadzenia nazwy przedmiotu czy też skrótu nazwy przedmiotu o liczbie znaków innej niż to przewidziano w procedurze walidacyjnej zgłaszany jest stosowny komunikat o wystąpieniu stanu błędu. Sytuacja taka pokazana jest na kolejnym zrzucie ekranowym, komunikat został spowodowany zbyt dużą liczbą znaków w skrócie nazwy przedmiotu.

133 133 Po wprowadzeniu wszystkich koniecznych poprawek klik przycisku Aktualizuj uruchamia procedurę, która odpowiada za zaktualizowanie odpowiednich rekordów w tabeli Przedmioty. Zakończenie aktualizacji sygnalizowane jest pokazanym niżej komunikatem. Klik przycisku OK zamyka instancję formularza frmedycjaprzedmiotu.

134 Skojarzenia Skojarzenie edycji i kierunków studiów Formularz frmedycjakierunki został zaprojektowany w celu powiązania edycji studiów z kierunkami przewidzianymi do zrealizowania w ramach danej edycji. Na powierzchni formularza umieszczono: cboedycja pole kombo przeznaczone do wyświetlenia listy zaplanowanych edycji studiów; lstkierunki pole listy wyświetlające listę dostępnych kierunków studiów; btnzapisz przycisk polecenia uruchamiający procedurę zapisu identyfikatorów edycji i kierunków w tabeli EdycjeKierunki; oraz dwie etykiety opisujące pole kombo i pole listy. Formant lstkierunki ma ustawioną właściwość SelectionMode na wartość MultiSelect, co pozwoli użytkownikowi na wyselekcjonowanie wielu kierunków poprzez prosty klik na wybranym kierunku (a klik na wcześniej zaznaczonym kierunku zdejmuje zaznaczenie). Kod tego formularza jest wyjątkowo krótki, zawiera bowiem jedynie dwie procedury, pierwsza z nich będzie obsługiwać zdarzenie wyboru edycji w polu kombo cboedycje, a druga zdarzenie kliku przycisku btnzapisz. Zadaniem procedury cboedycje_selectedvaluechanged jest dostarczenie do listy lstkierunki potencjalnej listy kierunków studiów, będzie to zrobione poprzez utworzenie instancji klasy CEdycjeKierunkPrzedmiot.

135 135 Public Class frmedycjakierunki Private Sub cboedycje_selectedvaluechanged(byval sender _ As Object, ByVal e As System.EventArgs) _ Handles cboedycje.selectedvaluechanged If Not flaga Then Exit Sub ' instancja klasy jest deklarowana przy pomocy interfejsu ' IEdycjeKierunki, co ograniczy dostęp do metod i właściwości ' tego tylko interfejsu (a nie całej klasy) Dim w As IEdycjeKierunki w = New CEdycjaKierunekPrzedmiot ' wywołanie metody w.zmianaedycji(strbaza, Me.cboEdycje.SelectedValue) ' badanie, czy dane zostały pobrane z bazy SQL If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' tak, przypisujemy nowe źródło danych do lstkierunki With Me.lstKierunki.DataSource = w.dajtabele.displaymember = "Kierunek".ValueMember = "id_k".selectedvalue = -1 End With Private Sub btnzapisz_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnzapisz.click Dim w As ISkojarzeniaEdycjeKierunki w = New CEdycjaKierunekPrzedmiot w.zapiszskojarzenia(strbaza, Me) ' badanie, czy operacja zapisu zakończyła się sukcesem If w.komunikat.length > 0 Then ' nie, wystąpił błąd w dostępie do bazy danych MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' przygotowanie do nowego kojarzenia Me.cboEdycje.SelectedValue = -1 ' usunięcie zaznaczeń z listy kierunków Me.lstKierunki.DataSource = Nothing End Class Poniżej widok menu naszej aplikacji z rozwiniętą pozycją Edycje i kierunki studiów, przedmioty oraz wskazaniem polecenia Skojarzenia/Edycji studiów i kierunków.

136 136 Klik tego polecenia otwiera formularz pozwalajacy na wybór edycji studiów, a następnie na przypisanie do wybranej edycji kierunków studiów. W pokazanej niżej sytuacji wybrano edycję lat 2011_2012, co skutkuje wyświetleniem w liście lstkierunki tych kierunków, które potencjalnie mogą być realizowane w wybranej edycji. Poniżej pokazany jest widok tego samego formularza po zaznaczeniu trzech kierunków studiów przewidzianych do realizacji w wybranej edycji.

137 137 Klik przycisku Zapisz spowoduje wstawienie identyfikatorów edycji studiów oraz identyfikatorów kierunków studiów do tabeli EdycjeKierunki. Domyślnie wstawiona będzie liczba miejsc na każdym kierunku na poziomie 25 słuchaczy oraz domyślna wysokość czesnego. Na zakończenie operacji wstawienia nowych skojarzeń formularz przygotowywany jest do dalszych skojarzeń Skojarzenie kierunku studiów i przedmiotów Do obsługi skojarzeń kierunku studiów i przedmiotów zaprojektowano formularz o nazwie frmkierunkiprzedmioty, którego projekt pokazany jest niżej. Na powierzchni formularza umieszczono następujące formanty: cbokierunki pole kombi pozwalające na wybór kierunku studiów; chlprzedmioty lista zaznaczana, w niej wyświetlimy potencjalne przedmioty; lstwybraneprzedmioty zwykła lista, będą do niej przenoszone nazwy przedmiotów wskazane w formancie chlprzedmioty; btnzapisz przycisk polecenia uruchamiający procedurę odpowiedzialną za zapisanie skojarzeń w bazie danych; formant ErrorProvider1 i kilka etykiet opisujących niektóre z formantów. Instancja formularza frmkierunkiprzedmioty wyświetlana jest po wykonaniu kliku na odpowiedniej pozycji w menu aplikacji.

138 138 Pokazana wyżej pozycja menu otrzymała nazwę mnukierunkiprzedmioty, a kod procedury obsługującej klik tego polecenia pokazany jest niżej. Private Sub mnukierunkiprzedmioty_click(byval sender As _ System.Object, ByVal e As System.EventArgs) _ Handles mnukierunkiprzedmioty.click Dim frm As New frmkierunkiprzedmioty flaga = False Dim w As IKierunkiPrzedmioty w = New CEdycjaKierunekPrzedmiot w.danekierunekprzedmioty(strbaza, frm) ' pytanie, czy dane zostały pobrane i można pokazać formularz? If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else frm.mdiparent = Me frm.show() Formularz może już być prezentowany użytkownikowi, ale dla zapewnienia mu pelnej funkcjonalności musimy utworzyć jeszcze szereg procedur w module tego formularza. Procedury te będą obsługiwać zdarzenia związane z wyborem kierunku studiów, zaznaczeniem lub usunięciem zaznaczenia w liście chlprzedmioty jak i procedury obsługującej zapisanie skojarzeń w bazie danych. Poniżej kod tych procedur wraz z wyjaśniającymi komentarzami. Public Class frmkierunkiprzedmioty ' zadaniem procedury zdarzenia Load formularza jest przypisanie ' zmiennej globalnej flaga wartości True, co pozwoli na obsługę ' zdarzenia SelectedValueChange pola kombo cbokierunki ' w momencie przygotowywania formularza do pokazania zmienna ' ta miała przypisaną wartość False po to, aby wspomniane ' zdarzenie nie było obsługiwane w momencie definiowania ' właściwości tego formantu

139 139 Private Sub frmkierunkiprzedmioty_load(byval sender As Object, _ ByVal e As EventArgs) Handles Me.Load flaga = True ' zadaniem procedury obsługującej zdarzenie SelectedValueChanged ' jest modyfikacja etykiety opisującej listy zaznaczaną oraz ' dostarczenie danych do wyświetlenia w chlprzedmioty Private Sub cbokierunki_selectedvaluechanged(byval sender As _ Object, ByVal e As EventArgs) Handles _ cbokierunki.selectedvaluechanged If Not flaga Then Exit Sub ' tworzymy etykietę formantu chlprzedmioty Me.Label3.Text = _ "Lista wybranych przedmiotów dla kierunku: " & _ Me.cboKierunki.SelectedItem(1).ToString ' ustawienie flaga na False, aby wyłączyć obsługę zdarzenia ' ItemCheck formantu chlprzedmioty w trakcie definiowania ' jego źródła danych flaga = False ' dostarczamy dane do chlprzedmioty Dim w As IKierunkiPrzedmioty w = New CEdycjaKierunekPrzedmiot w.zmianakierunku(strbaza, Me.cboKierunki.SelectedValue) ' instancja klasy CEdycjaKierunkiPrzedmioty utworzona, ' sprawdzamy, czy dane zostały pobrane If w.komunikat.length > 0 Then ' nie, komunikat na ekran MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' tak, definiujemy właściwośi chlprzedmioty With Me.chlPrzedmioty.DataSource = w.dajtabele.displaymember = "Przedmiot".ValueMember = "id_p" End With ' ustawienie flaga na True, będzie obsługa ItemCheck flaga = True ' zadaniem procedury zdarzenia ItemCheck formantu chlprzedmioty ' jest zbadanie, czy miało miejsce zaznaczenie pozycji listy, ' czy jej odznaczenie. W pierwszym przypadku do formantu ' lstwybraneprzedmioty dodajemy zaznaczony przedmiot, a w drugim ' usuwamy ten przedmiot z tej zwykłej listy. Private Sub chlprzedmioty_itemcheck(byval sender As Object, _ ByVal e As ItemCheckEventArgs) Handles _ chlprzedmioty.itemcheck ' deklaracja obiektu typu System.Data.DataRowView dla

140 140 ' ustalenia nazwy zaznaczonego przedmiotu Dim chklst As System.Data.DataRowView ' do obiektu chklst przypisujemy cały wiersz listy chklst = Me.chlPrzedmioty.SelectedItem If e.newvalue = CheckState.Checked Then ' było zaznaczenie, dodajemy Me.lstWybranePrzedmioty.Items.Add( _ chklst.item(1).tostring) Me.lstWybranePrzeedmioty.Sorted = True Else ' zdjęto zaznaczenie, usuwamy Me.lstWybranePrzedmioty.Items.Remove( _ chklst.item(1).tostring) ' procedura obsługuje validację listy lstwybraneprzedmioty, ' nie wybrano żadnego przedmiotu, to następuje wyjście ' z procedury Private Sub cmdzapisz_click(byval sender As Object, ByVal e As _ EventArgs) Handles cmdzapisz.click If flistawyboruisinvalid(me.lstwybraneprzedmioty, _ "Musisz wybrać jakieś przedmioty!", _ Me.ErrorProvider1) Then Exit Sub Dim w As IKierunkiPrzedmioty w = New CEdycjaKierunekPrzedmiot w.zapiszkierunekprzedmioty(strbaza, Me) If w.komunikat.length = 0 Then ' przygotowanie formularza do wyboru przedmiotów dla ' kolejnego kierunku flaga = False Me.cboKierunki.SelectedValue = -1 Me.lstWybranePrzeedmioty.Items.Clear() Else MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) End Class Poniżej widok instancji formularza frmkierunkiprzedmioty w trakcie wskazywania przedmiotów przewidzianych do realizacji w ramach wybranego kierunku studiów.

141 141 Klik przycisku Zapisz uruchomi procedurę zapisującą trzy rekordy do tabeli KierunkiPrzedmioty. W rozdziale poświęconym usuwaniu wcześniej wprowadzonych skojarzeń pokażemy, jak można usunąć niepotrzebne skojarzenia (wprowadzone np. dla potrzeb testowych, jak w tym przypadku).

142 Skojarzenie wykładowcy i przedmiotów Do obsługi skojarzeń kierunku studiów i przedmiotów zaprojektowano formularz o nazwie frmwykładowcyprzedmioty, którego projekt pokazany jest niżej. Na powierzchni formularza umieszczono następujące formanty: cbopracownik pole kombi pozwalające na wybór wykładowcy; chlprzedmioty lista zaznaczana, w niej wyświetlimy potencjalne przedmioty; lstwybraneprzedmioty zwykła lista, będą do niej przenoszone nazwy przedmiotów wskazane w formancie chlprzedmioty; btnzapisz przycisk polecenia uruchamiający procedurę odpowiedzialną za zapisanie skojarzeń w bazie danych; formant ErrorProvider1 i kilka etykiet opisujących niektóre z formantów. Instancja formularza frmwykladowcyprzedmioty wyświetlana jest po wykonaniu kliku na odpowiedniej pozycji w menu aplikacji. Poniżej pokazany jest fragment formularza głównego naszej aplikacji, czyli formularza frmmdistudia, wskazana znacznikiem myszy pozycja menu otrzymała nazwę mnuwykladowcyprzedmioty.

143 143 Klik tego polecenia uruchamia pokazaną niżej procedurę, jej zadaniem jest przygotowanie instancji formularza frmwykladowcyprzedmioty do pokazania użytkownikowi. Private Sub mnuwykladowcowprzedmiotow_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuwykladowcowprzedmiotow.click flaga = False Dim frm As New frmwykladowcyprzedmioty Dim w As IWykladowcyPrzedmioty w = New CEdycjaKierunekPrzedmiot w.danewykladowcyprzedmioty(strbaza, frm) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else frm.mdiparent = Me frm.show() Formularz może już być prezentowany użytkownikowi, ale dla zapewnienia mu pełnej funkcjonalności musimy utworzyć jeszcze szereg procedur w module tego formularza. Procedury te będą obsługiwać zdarzenia związane z wyborem wykładowcy, zaznaczeniem lub usunięciem zaznaczenia w liście chlprzedmioty jak i procedury obsługującej zapisanie skojarzeń w bazie danych. Poniżej kod tych procedur, tym razem bez rozbudowanych komentarzy, ponieważ prezentowany kod jest bardzo podobny do kodu formularza frmkierunkiprzedmioty. Public Class frmwykladowcyprzedmioty Private Sub frmwykladowcyprzedmioty_load( _ ByVal sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load flaga = True

144 144 Private Sub cbopracownik_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbopracownik.selectedvaluechanged If Not flaga Then Exit Sub Me.Label2.Text = _ "Lista potencjalnychprzedmiotów dla wykładowcy: " & _ Me.cboPracownik.SelectedItem(1).ToString Dim w As IWykladowcyPrzedmioty w = New CEdycjaKierunekPrzedmiot w.zmianawykladowcy(strbaza, Me.cboPracownik.SelectedValue) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else flaga = False With Me.chlPrzedmioty.DataSource = w.dajtabele.displaymember = "Przedmiot".ValueMember = "id_p" End With flaga = True Me.lstWybranePrzeedmioty.Items.Clear() Private Sub chlprzedmioty_itemcheck(byval sender As Object, _ ByVal e As ItemCheckEventArgs) Handles _ chlprzedmioty.itemcheck Dim chklst As System.Data.DataRowView chklst = Me.chlPrzedmioty.SelectedItem If e.newvalue = CheckState.Checked Then Me.lstWybranePrzeedmioty.Items.Add( _ chklst.item(1).tostring) Me.lstWybranePrzeedmioty.Sorted = True Else Me.lstWybranePrzeedmioty.Items.Remove( _ chklst.item(1).tostring) Private Sub btnzapisz_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnzapisz.click If flistawyboruisinvalid(me.lstwybraneprzeedmioty, _ "Musisz wybrać jakieś przedmioty!", _ Me.ErrorProvider1) Then Exit Sub flaga = False Dim w As IWykladowcyPrzedmioty w = New CEdycjaKierunekPrzedmiot w.zapiszwykladowcyprzedmioty(strbaza, Me) If w.komunikat.length = 0 Then

145 145 ' przygotowanie formularza do wyboru przedmiotów dla ' kolejnego wykładowcy Me.cboPracownik.SelectedValue = -1 Me.lstWybranePrzedmioty.Items.Clear() flaga = True Else MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) End Class Poniżej widok instancji formularza frmwykladowcyprzedmioty w trakcie wskazywania przedmiotów przewidzianych do realizacji przez wybranego wykładowcę. Klik przycisku Zapisz uruchamia procedurę dopisującą do bazy danych trzy rekordy (do tabeli PracownicyPrzedmioty).

146 Usunięcie skojarzeń Przy przedstawianiu interfejsu IEdycjeKierunki sygnalizowaliśmy, że metody UsunDane i UsunSkojarzenia oraz formularz frmusunskojarzenia zostały tak zaprojektowane, aby było możliwe ich wykorzystanie do usuwania możliwych skojarzeń przewidzianych w tej aplikacji, czyli edycji studiów i kierunków, kierunków i przedmiotów oraz wykładowców i przedmiotów. Podstawą tego rozwiązania był formularz frmusunskojarzenia, którego projekt pokazany jest niżej. Na powierzchni formularza umieszczono, jak to jest zresztą pokazane w oknie Document Outline wyświetlonym na tle formularza, trzy formanty: dgvco formant typu DataGridView, będziemy w jego kolumnach prezentować dane jednego z trzech typów skojarzeń; btnaktualizuj przycisk polecenia uruchamiający procedurę aktualizującą; txtktory pole tekstowe przechowujące informację symbolicznie opisującą jedno z trzech możliwych skojarzeń. Pole to ma ustawioną właściwość Visible na False, ponieważ tekst do tego pola jest wpisywany przez procedurę obsługującą odpowiednie polecenie w menu, a tekst ten jest wykorzystany w metodzie UsunSkojarzenia. W module klasy tego formularza utworzono jedną procedurę obsługującą zdarzenie Click przycisku btnaktualizuj. Public Class frmusunskojarzenia Private Sub btnaktualizuj_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnaktualizuj.click Dim t As String = ""

147 147 Select Case Me.txtKtory.Text Case "1" Dim w As IEdycjeKierunki w = New CEdycjaKierunekPrzedmiot w.usunskojarzenia(strbaza, Me.dgvCo, Me.txtKtory.Text) t = w.komunikat Case "2" Dim w As IKierunkiPrzedmioty w = New CEdycjaKierunekPrzedmiot w.usunskojarzenia(strbaza, Me.dgvCo, Me.txtKtory.Text) t = w.komunikat Case "3" Dim w As IWykladowcyPrzedmioty w = New CEdycjaKierunekPrzedmiot w.usunskojarzenia(strbaza, Me.dgvCo, Me.txtKtory.Text) t = w.komunikat End Select If t.length > 0 Then MsgBox(t, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Aktualizacja zakończona pomyślnie", _ MsgBoxStyle.Information, _ "Usuwanie niepotrzebnych skojarzeń") Me.Close() End Class Edycji studiów i kierunków Klik polecenia Usuń skojarzenia/edycji studiów i kierunków uruchami procedurę tworzącą instancję formularza frmusunskojarzenia w wersji przewidzianej do usunięcia niepotrzebnego skojarzenia takich dwóch elementów. niżej. Kod tej procedury (utworzonej w formularzu głównym aplikacji) pokazany jest

148 148 Private Sub mnuusubedycjekierunki_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles mnuusunedycjekierunki.click ' utworzenie nowej instancji formularza Dim frm As New frmusunskojarzenia ' wstawienie identyfikatora do pola txtktory frm.txtktory.text = "1" ' wstawienie identyfikatora musiało być przed utworzeniem ' instancji klasy CEdycjaKierunkiPrzedmioty, ponieważ ' metoda UsunDane korzysta z tego identyfikatora Dim w As IKierunkiPrzedmioty w = New CEdycjaKierunekPrzedmiot w.usundane(strbaza, frm) ' badanie, czy przygotowanie danych przebiegło pozytywnie If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' tak, tworzymy tytuł instancji formularza frm.text = _ "Usuwanie niepotrzebnego skojarzenia edycji i kierunku" frm.mdiparent = Me frm.show() Poniżej widok tego formularza, skojarzenie ostatnie jest zaznaczone jako te, które ma być usunięte. Klik przycisku Aktualizuj zakończy formalnie to działanie, z tabeli EdycjeKierunki zostanie usunięty rekord odpowiadający zaznaczeniu w pokazanym wyżej formularzu, co skutkuje pokazanym niżej komunikatem.

149 149 Klik przycisku OK w oknie komunikatu zamyka zarówno komunikat jak i formularz usuwania skojarzeń Kierunków studiów i przedmiotów Klik polecenia Usuń skojarzenia/kierunków i przedmiotów uruchami procedurę tworzącą instancję formularza frmusunskojarzenia w wersji przewidzianej do usunięcia niepotrzebnego skojarzenia takich dwóch elementów. niżej. Kod tej procedury (utworzonej w formularzu głównym aplikacji) pokazany jest Private Sub mnuusunkierunkiprzedmioty_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuusunkierunkiprzedmioty.click Dim frm As New frmusunskojarzenia frm.txtktory.text = "2" Dim w As IKierunkiPrzedmioty w = New CEdycjaKierunekPrzedmiot w.usundane(strbaza, frm)

150 150 If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else frm.text = _ "Usuwanie niepotrzebnego skojarzenia kierunku i przedmiotu" frm.mdiparent = Me frm.show() Poniżej widok instancji formularza frmusunskojarzenia w trakcie usuwania niepotrzebnych skojarzeń kierunków studiów i przedmiotów. Dla kierunku Analityk finansowy mamy zaznaczonych kilka przedmiotów do usunięcia skojarzeń. Klik przycisku Aktualizuj usuwa zaznaczone skojarzenia, poniżej ten sam formularz otwarty ponowie po usunięciu tych skojarzeń. Jak widzimy dla kierunku Analityk finansowy już nie mamy przypisanych takich przedmiotów jak Controling logistyki czy e-logistyka.

151 Wykładowców i przedmiotów 151 Klik polecenia Usuń skojarzenia/wykładowców i przedmiotów uruchomi procedurę tworzącą instancję formularza frmusunskojarzenia w wersji przewidzianej do usunięcia niepotrzebnego skojarzenia takich dwóch elementów. niżej. Kod tej procedury (utworzonej w formularzu głównym aplikacji) pokazany jest Private Sub mnuusunwykladowcowprzedmiotow_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuusunwykladowcowprzedmiotow.click Dim frm As New frmusunskojarzenia frm.txtktory.text = "3" Dim w As IWykladowcyPrzedmioty w = New CEdycjaKierunekPrzedmiot w.usundane(strbaza, frm) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else frm.text = "Usuwanie niepotrzebnego skojarzenia " & _ "wykładowcy i przedmiotu" frm.mdiparent = Me frm.show() Poniżej widok instancji formularza frmusunskojarzenia w trakcie usuwania niepotrzebnych skojarzeń wykładowców i przedmiotów. Dla przykładowo wybranego wykładowcy (dr Szurkowski Rajmund) zaznaczono do usnięcia trzy skojarzenia.

152 152 Klik przycisku Anuluj uruchomi procedurę zdarzeniową, która usunie z tabeli PracownicyPrzedmioty rekordy odpowiadające tym skojarzeniom. Podobnie jak w poprzednich przypadkach fakt dokonania zmian w tej tabeli potwierdzany jest specjalnym komunikatem.

153 6. Realizacja zajęć 153 W tym rozdziale zajmiemy się obsługą realizacji zajęć dydaktycznych, a punktem wyjścia będzie zarejestrowanie w tabeli Terminy terminów realizacji poszczególnych zjazdów w ramach danej edycji studiów. W kolejnym kroku stworzymy możliwość rejestrakcji planów zajęć w tabeli PlanyZajec. Mając dane z tych dwóch tabel oraz korzystając z informacji zapisanych w takich tabelach jak Kierunki, Przedmioty, Prowadzacy i kilku jeszcze innych będziemy w stanie wygenerować potrzebne raporty. Na potrzeby obsługi zdarzeń związanych z bieżącą realizacją zajęć dydaktycznych zbudujemy klasę CRealizacja oraz szereg formularzy i raportów Tabele bazy danych Na potrzeby obsługi realizacji zajęć zaplanowano w bazie danych szereg tabel i procedur przechowywanych. Tabele, których projekty pokażemy niżej współpracują z tabelami, które przedstawiliśmy w rozdziale poświęconym edycjom studiów, kierunkom i przedmiotom. W pewnym sensie tabele Terminy i PlanZajec mają dla bieżącej realizacji studiów znaczenie zasadnicze, bowiem informacje w nich zawarte będziemy wykorzystywać w bardzo wielu zadaniach, które trzeba wykonywać w trakcje zajęć. Tabela Terminy będzie przechowywać terminy wszystkich zjazdów szkoleniowych przewidzianych do realizacji w ramach danej edycji studiów podyplomowych. Tabela Godziny przechowuje pomocnicze informacje precyzujące godziny realizowanych zajęć w układzie dobowym oraz ich wymiar. Z uwagi na to, że być może rodzaj informacji przechowywanych w tej tabeli nie jest do końca jasny wyjątkowo pokazujemy niżej jej zawartość. W kolumnie godzina mamy

154 154 podany dokładny czas realizacji danych zajęć, kolumna kolejność ma charakter techniczny i określa kolejność sortowania zgromadzonych danych, a ostatnia podaje wymiar godzin. Tabela PlanyZajec spełnia w naszym projekcie bardzo ważną rolę, w niej gromadzone są informacje o szczegółach planowanych zajęć. W kolumnie idt mamy identyfikator terminu zajęć (z tabeli Terminy), w idk identyfikator wykładowcy (z tabeli Pracownicy), w idp identyfikator przedmiotu (z tabeli Przedmioty), w idg identyfikator z tabeli Godziny. Pole Temat będzie przechowywać planowany temat zajęć, a pole DataR datę rozliczenia finansowego tych zajęć. Brak wpisu w tym polu będzie także sygnałem, że dane zajęcia nie zostały jeszcze rozliczone. Tabela ObecnosciNew gromadzone będą informacje o udziale słuchaczy studiów podyplomowych w poszczególnych zajęciach. Pierwsze dwa pola tej tabeli (identyfikator terminu i słuchacza) tworzą klucz złożony tej tabeli. Pole Godzin przechowuje fizyczny wymiar godzin zajęć dydaktycznych, w których dany słuchacz uczestniczył.

155 155 Tabela WynikiTestuC będzie przechowywać wyniki testów przedmiotowych (cząstkowych) realizowanych w określonym terminie (pole idt), przez danego wykładowcę (pole idw) i z określonego przedmiotu (idp). Pole idt wskazuje pośrednio na edycję studiów, semestr i zjazd szkoleniowy, a identyfikator studenta (ids) także na kierunek studiów. Tabela TestySemestralne będzie przechowywać wyniki wstępnego i końcowego testu semestralnego. Pole jakitest będzie identyfikować rodzaj testu (1 to test początkowy, 2 to test końcowy). Tabela WplatyStudentow będzie przechowywać informacje o wpłaconym udziale własnym studentów. Rejestrowany jest identyfikator studenta i identyfikator edycji studiów, wpłacona kwota i data wpłaty oraz data rejestracji w bazie danych. Poniżej pokazany jest schemat relacji między wymienionymi wyżej tabelami oraz wybranymi, pozostałymi tabelami bazy danych.

156 156

157 6.2. Procedury przechowywane Wykorzystywane w IRejestracjaTerminow Procedura pdajedycje była już przedstawiona wcześniej. 157 Procedura pzapisztermin odpowiada za wstawienie nowego rekordu do tabeli Terminy, ale operacja ta będzie miała miejsce tylko wtedy, jeżeli takiego rekordu już nie ma w tej tabeli. Procedura ustala liczbę rekordów dla podanej edycji studiów, semestru i zjazdu i na tej podstawie podejmuje decyzję o wstawieniu nowego rekordu. Zwracany jest wynik tego badania, jak zerowy, to nowe rekordy zostały dodane. Nowe, bo procedura wstawia dwa rekordy, drugi ma datę realizacji zwiększoną o jeden dzień. create procedure int out as from dbo.terminy where and and begin insert into dbo.terminy (ide, semestr, zjazd, @termin) insert into dbo.terminy (ide, semestr, zjazd, end Procedura pdajterminysobot zwraca rekordset na potrzeby edycji terminów. Z tabeli Terminy zwracane są tylko te rekordy, które dotyczą sobót. W warunku Where wykorzystano funkcję SQL o nazwie DatePart z kwalifikatorem dw (weekday). create procedure int as select * from dbo.terminy where DATEPART(dw, termin)=7 Procedura paktualizujtermin odpowiada za aktualizację dwóch rekordów w tabeli Terminy wskazanych identyfikorem edycji i wartościami semestru i zjazdu. create procedure smalldatetime as update dbo.terminy set where update dbo.terminy set where

158 Wykorzystywane w IRejestracjaPlanow Procedura pdajterminydoplanu odpowiada za przygotowanie odpowiednio spreparowanego rekordsetu, który w pierwszej kolumnie zwróci identyfikator terminu, a w drugiej jego skondensowany opis. create procedure int as select Terminy.idt, EdycjeStudiow.NazwaEdycji + '; ' + case when Terminy.semestr=1 then 'Semestr 1' when Terminy.semestr=2 then 'Semestr 2' End + '; ' + case when Terminy.zjazd=1 then 'Zjazd 1' when Terminy.zjazd=2 then 'Zjazd 2' when Terminy.zjazd=3 then 'Zjazd 3' when Terminy.zjazd=4 then 'Zjazd 4' when Terminy.zjazd=5 then 'Zjazd 5' else 'Zjazd 6' end + '; ' + case when datepart(dw,terminy.termin)=7 then 'Sobota' else 'Niedziela' end as Kiedy from EdycjeStudiow INNER JOIN Terminy ON EdycjeStudiow.id_e = Terminy.ide where EdycjeStudiow.StatusE =1 order by Terminy.idt Procedura pdajkierunkiwgedycji odpowiada za przygotowanie listy kierunków realizowanych w ramach edycji studiów odpowiadającej wybranemu terminowi zajęć. create procedure int as int select Kierunki.id_k, Kierunki.Kierunek from EdycjeKierunki INNER JOIN Kierunki ON EdycjeKierunki.id_k = Kierunki.id_k where EdycjeKierunki.id_e in (select ide from dbo.terminy where order by Kierunki.Kierunek Procedura pdajpracownikowkierunku odpowiada za przygotowanie listy wykładowców przewidzianych do realizacji zajęć na wybranym kierunku studiów. create procedure int

159 159 as select distinct Pracownicy.id_w, Pracownicy.Tytul + ' ' + Pracownicy.Wykladowca as kto, Pracownicy.Wykladowca from Pracownicy INNER JOIN PrzedmiotProwadzacy ON Pracownicy.id_w = PrzedmiotProwadzacy.id_w INNER JOIN KierunkiPrzedmioty ON PrzedmiotProwadzacy.id_p = KierunkiPrzedmioty.id_p where KierunkiPrzedmioty.id_k order by Pracownicy.Wykladowca Procedura pdajprzedmiotywykladowcy odpowiada za przygotowanie listy przedmiotów przewidzianych do realizacji przez wybranego wykładowcę. create procedure int as select Przedmioty.id_p, Przedmioty.Przedmiot from PrzedmiotProwadzacy INNER JOIN Przedmioty ON PrzedmiotProwadzacy.id_p = Przedmioty.id_p where PrzedmiotProwadzacy.id_w order by Przedmiot Procedura pwstawplanzajec odpowiada za wstawienie nowego rekordu do tabeli PlanZajec. create procedure nvarchar(500) as insert into dbo.planzajec (idt, idk, idw, idp, idg, @temat) Procedura pdajterminyedycji dostarcza danych, które wykorzystamy w trakcie edycji planów zajęć. create procedure int as select PlanZajec.id, PlanZajec.idt, PlanZajec.idk, 'Sem.'+cast(Terminy.semestr as varchar(1))+' Z'+ cast(terminy.zjazd as varchar(1))+' ' +convert(varchar(10),terminy.termin,103) as Kiedy, Kierunki.SkrotK, PlanZajec.idw, PlanZajec.idp, PlanZajec.idg, PlanZajec.Temat from PlanZajec INNER JOIN Terminy ON PlanZajec.idt = Terminy.idt INNER JOIN EdycjeStudiow ON Terminy.ide = EdycjeStudiow.id_e INNER JOIN Kierunki ON PlanZajec.idk = Kierunki.id_k where EdycjeStudiow.StatusE IN (1, 2)

160 160 Procedura pdajlisteludzi zwraca uporządkowaną alfabetycznie listę wykładówców wraz z ich tytułami czy stopniami naukowymi create procedure int as select id_w, rtrim(tytul) + ' ' + Wykladowca as Ktos from dbo.pracownicy order by Wykladowca Procedura pdajlisteprzedmiotow była już pokazana wcześniej/ Procedura pdajgodzinyplanu odpowiednio spreparowaną listę godzin dydaktycznych. create procedure int as select idg, case when ilegodzin=2 then '2 godziny' when ilegodzin=4 then '4 godziny' when IleGodzin=8 then '8 godzin' end + ' - ' + godzina as kiedy from dbo.godziny order by kolejnosc Procedura CzyDobryWykladowca sprawdza, czy wykładowca o podanym identyfikatorze został przewidziany do prowadzenia zajęć na wskazanym kierunku studiów. create procedure int out as from KierunkiPrzedmioty INNER JOIN PrzedmiotProwadzacy ON KierunkiPrzedmioty.id_p = PrzedmiotProwadzacy.id_p where KierunkiPrzedmioty.id_k AND PrzedmiotProwadzacy.id_w Procedura CzyDobryPrzedmiot wykonuje dwa sprawdziany, w pierwszym sprawdza, czy przedmiot wskazany jego identyfikatorem jest prowadzony przez danego wykładowcę. Jeżeli tak, to realizowany jest kolejny krok, w którym procedura bada, czy ten przedmiot jest wykładany na danym kierunku. create procedure int out as

161 161 from PrzedmiotProwadzacy where id_w and -- sprawdzamy, czy ten przedmiot jest na kierunku idk from KierunkiPrzedmioty where and Pokazana niżej procedura odpowiada za aktualizację rekordu w tabeli PlanZajec. create procedure nvarchar(500) as update PlanZajec set where Wykorzystywane w IObecnosci Lista aktywnych kierunków studiów (realizowanych w ramach bieżącej edycji studiów podyplomowych) zwraca jest za pośrednictwem poniższej procedury. create procedure int as select Kierunki.id_k, Kierunki.Kierunek, EdycjeStudiow.StatusE from EdycjeKierunki INNER JOIN Kierunki ON EdycjeKierunki.id_k = Kierunki.id_k INNER JOIN EdycjeStudiow ON EdycjeKierunki.id_e = EdycjeStudiow.id_e where EdycjeStudiow.StatusE = 2 order by Kierunki.Kierunek Lista studentów wykorzystywana w trakcie rejestracji ich obecności na zjazdach szkoleniowych zwracana jest przez pokazaną niżej procedurę. create procedure int as select ids, Nazwisko+' ' + Imie as Kto from Studenci where Studenci.idk order by Nazwisko, imie Obecności na zajęciach szkoleniowych rejestrowane są za pośrednictwem poniższej procedury, ale tylko wtedy, gdy takiego rekordu jeszcze nie ma w tabeli ObecnosciNew. create procedure int out as from dbo.obecnoscinew

162 162 where and insert into dbo.obecnoscinew (idt, ids, Lista kierunków studiów wykorzystywana w trakcie rejestrowania obecności na zajęciach szkoleniowych zwracana jest przez poniższą procedurę. create procedure int as from dbo.edycjestudiow where StatusE=2 select distinct Kierunki.id_k, Kierunki.Kierunek from ObecnosciNew INNER JOIN Terminy ON ObecnosciNew.idt = Terminy.idt INNER JOIN EdycjeKierunki ON Terminy.ide = EdycjeKierunki.id_e INNER JOIN Kierunki ON EdycjeKierunki.id_k = Kierunki.id_k where Terminy.ide order by Kierunki.Kierunek Procedura pdajgodzinyobecnosci pozornie wygląda na dość skomplikowaną, a jej zadaniem jest zwrócenie listy studentów z identyfikatorem zjazdu szkoleniowego i dnia szkolenia na potrzeby przygotowania raportu obecności. create procedure int as int from dbo.edycjestudiow where StatusE=2 begin select Studenci.Pesel, 'Z'+cast(Terminy.zjazd as nvarchar(1)) + case when datepart(dw,terminy.termin)=7 then 'S' else 'N' end as ZjazdDzien, ObecnosciNew.Godzin from ObecnosciNew INNER JOIN Terminy ON ObecnosciNew.idt = Terminy.idt INNER JOIN Studenci ON ObecnosciNew.ids = Studenci.ids where Studenci.idk AND Terminy.ide AND Terminy.semestr order by Studenci.Pesel, Terminy.zjazd, zjazddzien desc end else

163 163 begin select Studenci.Nazwisko+' '+Studenci.Imie as Kto, 'Z'+cast(Terminy.zjazd as nvarchar(1)) + case when datepart(dw,terminy.termin)=7 then 'S' else 'N' end as ZjazdDzien, ObecnosciNew.Godzin from ObecnosciNew INNER JOIN Terminy ON ObecnosciNew.idt = Terminy.idt INNER JOIN Studenci ON ObecnosciNew.ids = Studenci.ids where Studenci.idk AND Terminy.ide AND Terminy.semestr order by Kto, Terminy.zjazd, zjazddzien desc end Procedura poniższa zwraca dla danego kierunku i semestru listę studentów, którym zarejestrowano obecności. create procedure int as int from dbo.edycjestudiow where StatusE=2 select distinct Studenci.Nazwisko+' '+Studenci.Imie as Kto, Studenci.ids from ObecnosciNew INNER JOIN Terminy ON ObecnosciNew.idt = Terminy.idt INNER JOIN Studenci ON ObecnosciNew.ids = Studenci.ids where Studenci.idk AND Terminy.ide AND Terminy.semestr order by Kto Zadaniem poniższej procedury jest zwrócenie skomponowanej informacji o numerze zjazdu i dniu tygodnia oraz identyfikatora terminu dla podanego semestru i kierunku dla tych studentów, których obecności zostały odnotowane w bazie danych create procedure int as int from dbo.edycjestudiow where StatusE=2 select distinct 'Z'+cast(Terminy.zjazd as nvarchar(1)) + case when datepart(dw,terminy.termin)=7 then 'S' else 'N' end as ZjazdDzien, Terminy.idt

164 164 from ObecnosciNew INNER JOIN Terminy ON ObecnosciNew.idt = Terminy.idt INNER JOIN Studenci ON ObecnosciNew.ids = Studenci.ids where Studenci.idk AND Terminy.ide AND Terminy.semestr order by ZjazdDzien Procedura poniższa odpowiada za aktualizację obecności. create procedure int as update dbo.obecnoscinew set where and Wykorzystywane w ITesty Procedura plistaaktywnychkierunkow była już przedstawiona wcześniej. Procedura pdajkierunkidoaktualizacjitestow zwraca listę tych kierunków studiów, dla których istnieją zarejestrowane wyniki testów przedmiotowych. create procedure int as select distinct Kierunki.id_k, Kierunki.Kierunek from Kierunki INNER JOIN KierunkiPrzedmioty ON Kierunki.id_k = KierunkiPrzedmioty.id_k INNER JOIN WynikiTestuC ON KierunkiPrzedmioty.id_p = WynikiTestuC.idp Order by Kierunki.Kierunek Poniższa procedura zwraca listę tych wykładowców, dla których są zarejestrowane wyniki testów przedmiotowych. create procedure int as select distinct pracownicy.id_w, Pracownicy.Tytul + N' ' + Pracownicy.Wykladowca AS Kto, Pracownicy.Wykladowca from WynikiTestuC INNER JOIN KierunkiPrzedmioty ON WynikiTestuC.idp = KierunkiPrzedmioty.id_p INNER JOIN Terminy ON WynikiTestuC.idt = Terminy.idt INNER JOIN Pracownicy ON WynikiTestuC.idw = Pracownicy.id_w where KierunkiPrzedmioty.id_k AND Terminy.semestr AND Terminy.zjazd order by Pracownicy.Wykladowca Kolejna procedura zwraca przedmioty danego pracownika wykładającego na danym kierunku studiów.

165 165 create procedure int as select Przedmioty.id_p, Przedmioty.Przedmiot from PrzedmiotProwadzacy INNER JOIN KierunkiPrzedmioty ON PrzedmiotProwadzacy.id_p = KierunkiPrzedmioty.id_p INNER JOIN Przedmioty ON KierunkiPrzedmioty.id_p = Przedmioty.id_p where PrzedmiotProwadzacy.id_w AND KierunkiPrzedmioty.id_k Order by Przedmioty.Przedmiot Poniższa procedura zwraca listę przedmiotów wskazanego wykładowcy i kierunku spośród tych, dla których zarejestrowane są wyniki testów przedmiotowych. create procedure int as select distinct Przedmioty.id_p as idp, Przedmioty.Przedmiot from PrzedmiotProwadzacy INNER JOIN Przedmioty ON PrzedmiotProwadzacy.id_p = Przedmioty.id_p INNER JOIN WynikiTestuC ON Przedmioty.id_p = WynikiTestuC.idp INNER JOIN KierunkiPrzedmioty ON Przedmioty.id_p = KierunkiPrzedmioty.id_p INNER JOIN Terminy ON WynikiTestuC.idt = Terminy.idt where WynikiTestuC.idw AND KierunkiPrzedmioty.id_k AND Terminy.semestr AND Terminy.zjazd Order by Przedmioty.Przedmiot Procedura pobecnosciustaltermin odpowiada za zwrócenie identyfikatora terminu wskazanego semestru, zjazdu i dnia tygodnia. create procedure int out as int from dbo.edycjestudiow where StatusE=2 from dbo.terminy where and and and Wyniki testu przedmiotowego zapisywane są w bazie danych za pomocą poniższej procedury.

166 166 create procedure int out as from dbo.wynikitestuc where and and and insert into dbo.wynikitestuc (ids, idt, idw, idp, Aktualizacja wyników testów przedmiotowych realizowana jest poniższą procedurą. create procedure decimal(5,4) as update dbo.wynikitestuc set where Procedura pdajraporttestup odpowiada za przygotowanie danych, które będą wykorzystane do przygotowania raportu z wyników testów przedmiotowych. create procedure int as select Studenci.Nazwisko + N' ' + Studenci.Imie AS kto, 'Z'+cast(Terminy.zjazd as nvarchar(1)) as Zjazd, AVG(WynikiTestuC.punkty) AS AvgPunkty from WynikiTestuC INNER JOIN Terminy ON WynikiTestuC.idt = Terminy.idt INNER JOIN Studenci ON WynikiTestuC.ids = Studenci.ids where Studenci.idk AND Terminy.semestr AND Terminy.ide group by Studenci.Nazwisko + N' ' + Studenci.Imie, Terminy.zjazd order by kto Kolejna procedura przygotowuje dane testów przedmiotowych do ich edycji. create procedure int as select WynikiTestuC.idtc, Studenci.Nazwisko + N' ' + Studenci.Imie AS Kto, WynikiTestuC.punkty from Studenci INNER JOIN WynikiTestuC ON Studenci.ids = WynikiTestuC.ids where WynikiTestuC.idt AND WynikiTestuC.idw AND WynikiTestuC.idp order by Kto

167 Wykorzystywane w ISzkolenia 167 Procedura pszkoleniatermin odpowiada za zwrócenie identyfikatora i terminu wskazanego semestrem i zjazdem. create procedure int as int from dbo.edycjestudiow where StatusE=2 select idt, Termin from Terminy where and and Procedura pkierunkiszkolenia zwraca informacje o aktualnych kierunkach szkoleń, limicie miejsc i skrócie nazwy kierunku. create procedure int as select Kierunki.id_k, Kierunki.Kierunek, EdycjeKierunki.LimitMiejsc, Kierunki.SkrotK from EdycjeKierunki INNER JOIN Kierunki ON EdycjeKierunki.id_k = Kierunki.id_k INNER JOIN EdycjeStudiow ON EdycjeKierunki.id_e = EdycjeStudiow.id_e where EdycjeStudiow.StatusE = 2 order by Kierunki.Kierunek Pokazana niżej procedura zwraca listę tematów z ich detalami, które zostały zaplanowane do zrealizowania w ramach danego kierunku studiów i zjazdu szkoleniowego. create procedure int as select Terminy.termin, PlanZajec.Temat, Godziny.godzina, Godziny.IleGodzin from PlanZajec INNER JOIN Godziny ON PlanZajec.idg = Godziny.idg INNER JOIN Terminy ON PlanZajec.idt = Terminy.idt where PlanZajec.idt AND PlanZajec.idk order by Terminy.termin

168 Wykorzystywane w IDaneAnkiet Procedura plistaaktywnychkierunkow była już prezentowana. Procedura pdajpracownikowkierunku także była już prezentowana. Zadaniem pokazanej niżej procedury jest zwrócenie listy przedmiotów prowadzonych na danym kierunku przez danego wykładowcę. create procedure int as select Przedmioty.id_p, Przedmioty.Przedmiot from PrzedmiotProwadzacy INNER JOIN KierunkiPrzedmioty ON PrzedmiotProwadzacy.id_p = KierunkiPrzedmioty.id_p INNER JOIN Przedmioty ON KierunkiPrzedmioty.id_p = Przedmioty.id_p where PrzedmiotProwadzacy.id_w AND KierunkiPrzedmioty.id_k Order by Przedmioty.Przedmiot Wyniki ankiet wstawiane są do tabeli Dane za pośrednictwem poniższej procedury. create procedure nvarchar(500) as int from dbo.edycjestudiow where StatusE=2 insert into Dane (id_e, Semestr, Zjazd, id_k, id_p, id_w, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, @id_w,

169 Klasa CRealizacja Jak wspomnieliśmy wczesniej utworzymy klasę o nazwie CRealizacja, zawrzemy w niej te metody i właściwości, które będziemy wykorzystywać dla potrzeb obsługi zdarzeń związanych z realizacją zajęć. W klasie tej utworzymy szereg interfejsów, ich rolą będzie przyporządkowanie metod i właściwości do określonych zadań Interfejs IRejestracjaTerminow Poniżej fragment kodu tej klasy z procedurami wykorzystywanymi do rejestracji terminów zajęć i ich edycji. Imports System.Data Imports System.Data.SqlClient Imports System.IO ' deklaracja interfejsu wykorzystywanego do obsługi terminów ' zajęć i ich edycji Public Interface IRejestracjaTerminow Function Komunikat() As String Sub OtwarcieTerminow(ByVal strconn As String, _ ByVal frm As frmterminy) Sub ZapiszTermin(ByVal strconn As String, ByVal ide As Integer, _ ByVal semestr As Integer, ByVal zjazd As Integer, _ ByVal termin As Date) Sub EdycjaTerminow(ByVal strconn As String, ByVal frm As _ frmedycjaterminow) Sub AktualizujTerminy(ByVal strconn As String, ByVal dgv As _ DataGridView, ByRef x() As Boolean) End Interface ' kod klasy Public Class CRealizacja Inherits CForStorageSub ' dziedziczymy po tej klasie Implements IRejestracjaTematow ' ewentualnie informacja o implementacji innych interfejsów... ' dekalracja zmiennych prywatnych klasy Private mkomunikat As String = "" Private mstrconn As String Private mtable1 As DataTable Private mtable2 As DataTable Private mtable3 As DataTable ' implementacja właściwości i metod Public Function Komunikat() As String Implements _ IRejestracjaTerminow.Komunikat Return mkomunikat End Function

170 170 ' implementacja funkcji DajTabela (obsługuje wiele interfejsów) Public Function DajTabele() As DataTable Implements _ IRozliczenieWykladowcow.DajTabele, _ IRejestracjaPlanow.DajTabele, _ IWzorceAnkiet.DajTabele, _ IObecnosci.DajTabele Return mtable1 End Function Metoda OtwarcieTerminow otrzymuje jako jeden z argumentów instancję formularza frmterminy, projekt tego formularza będzie pokazany trochę później. Public Sub OtwarcieTerminow(ByVal strconn As String, _ ByVal frm As frmterminy) Implements _ IRejestracjaTerminow.OtwarcieTerminow Dim conn As New SqlConnection(strConn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, "dbo.pdajedycje", _ "idp", 1, 1, 0) UstawComboBox(frm.cboEdycja, mtable1, "NazwaEdycji", "id_e") ' zaznaczenie semestru 1 i zjazdu 1 ZaznaczRdb(frm.rdbSemestr1) ZaznaczRdb(frm.rdbZjazd1) Catch ex As Exception mkomunikat = "Błąd pobrania edycji studiów z bazy SQL" Finally conn.close() conn = Nothing End Try ' procedura zapisu terminu zajęć Public Sub ZapiszTermin(ByVal strconn As String, ByVal ide As _ Integer, ByVal semestr As Integer, _ ByVal zjazd As Integer, ByVal termin As Date) _ Implements IRejestracjaTerminow.ZapiszTermin Dim conn As New SqlConnection(strConn), i As Integer Try conn.open() ' procedura SQL bada, czy taki termin już nie jest w bazie, ' jeżeli tak, to zapis nie jest wykonywany, a procedura ' zwraca liczbę większą niż jeden jako sygnał tego faktu, ' co pozwoli na przygotowanie stosownego komunikatu. If MyBase.DajWartosc(conn, "dbo.pzapisztermin", _ ide, 1, 0, _ semestr, 1, 0, _ zjazd, 1, 0, _ termin.toshortdatestring, 4, 0, _ 1, 0) > 0 Then

171 171 mkomunikat = "Taki termin juz jest w tabeli Terminy" Catch ex As Exception mkomunikat = "Błąd zapisu terminu do bazy SQL" Finally conn.close()' zamykamy połączenie conn = Nothing' usuwamy obiekt conn z pamięci RAM End Try Metoda EdycjaTerminow jest odpowiedzialna za przygotowanie danych z tabeli Terminy do ich edycji w formancie typu DataGridView umieszonym w formularzu frmedycjaterminow. Public Sub EdycjaTerminow(ByVal strconn As String, ByVal frm As _ frmedycjaterminow) Implements _ IRejestracjaTerminow.EdycjaTerminow Dim conn As New SqlConnection(strConn), ed As DataTable Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajterminysobot", _ 1, 1, 0) ' pobranie danych dla pola kombo, wyświetlimy w nim ' edycje studiów zamiast ich identyfikatorów ed = MyBase.DajRekordset(conn, "dbo.pdajedycje", _ "idp", 1, 1, 0) ed.columns(0).columnname = "id_e" ed.columns(1).columnname = "ide" ' zdefiniowanie właściwości gridu With frm.dgvterminy.datasource = mtable1.columns(0).visible = False.Columns(1).Visible = False.Columns(2).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter.Columns(2).HeaderText = "Semestr".Columns(2).HeaderCell.Style.Alignment = _ DataGridViewContentAlignment.MiddleCenter.Columns(3).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter.Columns(3).HeaderText = "Zjazd".Columns(3).HeaderCell.Style.Alignment = _ DataGridViewContentAlignment.MiddleCenter.AllowUserToAddRows = False.AllowUserToDeleteRows = False End With ' deklarujemy i tworzymy nową kolumnę z combobox Dim cboedycja As New DataGridViewComboBoxColumn()

172 172 UstawComboBoxColumn(cboEdycja, ed, "ide", "ide", "id_e", _ "Nazwa edycji", 200) ' wstawiamy tę kolumnę na pozycji 1 w gridzie frm.dgvterminy.columns.insert(1, cboedycja) ' tworzymy instację klasy CCalendarColumn Dim col As New CCalendarColumn ' wskazanie na oryginalną kolumnę w gridzie col.datapropertyname = "termin" col.headertext = "Sobota zjazdu" ' ustalamy lokalizację tej oryginalnej kolumny w gridzie Dim loc As Integer = frm.dgvterminy.columns.indexof( _ frm.dgvterminy.columns("termin")) ' usuwamy tę oryginalną kolumnę frm.dgvterminy.columns.removeat(loc) ' i wstawiamy na jej miejsce kolumnę z kalendarzem frm.dgvterminy.columns.insert(loc, col) Catch ex As Exception mkomunikat = "Błąd pobrania terminów z bazy SQL" Finally conn.close() conn = Nothing End Try Metoda AktualizujTerminy jest odpowiedzialna za aktualizację danych w tabeli Terminy, modyfikowane są dwa sąsiednie rekordy w tej tabeli wskazane wartością True w zmiennej tablicowej x() na danej pozycji. W pętli przeglądane są wszystkie wiersze gridu i w przypadku, gdy dane były zaktualizowane to jest uruchamiana procedura aktualizująca. Dla przypomnienia, w gridzie były tylko rekordy z tabeli Terminy odpowiadające sobotom zjazdów szkoleniowych. Public Sub AktualizujTerminy(ByVal strconn As String, _ ByVal dgv As DataGridView, ByRef x() As Boolean) _ Implements IRejestracjaTerminow.AktualizujTerminy Dim conn As New SqlConnection(strConn), i As Integer Try conn.open() For i = 0 To dgv.rows.count - 1 If x(i) Then ' aktualizujemy dwa sąsiednie wiersze, dwa dlatego, ' że sobota była w gridzie, ale niedziela nie! MyBase.Wykonaj(conn, "dbo.paktualizujtermin", _ dgv.rows(i).cells(0).value, 1, 0, _ dgv.rows(i).cells(1).value, 1, 0, _ dgv.rows(i).cells(2).value, 1, 0, _ dgv.rows(i).cells(3).value, 1, 0, _ CDate(dgv.Rows(i).Cells(4). _ Value).ToShortDateString, 4, 0)

173 173 Next Catch ex As Exception mkomunikat = "Błąd aktualizacji teminów zajęć w bazie SQL" Finally conn.close() conn = Nothing End Try End Class Interfejs IRejestracjaPlanow Poniżej fragment kodu klasy CRealizacja z procedurami i funkcjami wykorzystywanymi do rejestracji planów zajęć i ich edycji. ' deklaracja interfejsu wykorzystywanego do obsługi planów ' zajęć i ich edycji Public Interface IRejestracjaPlanow Function Komunikat() As String Function DajTabele() As DataTable Sub OtwarciePlanow(ByVal strconn As String, ByVal frm As _ frmplanyzajec) Sub PlanyPrewadzacy(ByVal strconn As String, ByVal idk As _ Integer) Sub PlanyPrzedmioty(ByVal strconn As String, ByVal idw As _ Integer, ByVal idk As Integer) Sub PlanyZapisz(ByVal strconn As String, ByVal frm As _ frmplanyzajec) ' edycja planow Sub EdytujPlany(ByVal strconn As String, ByVal frm As _ frmedycjaplanow) Sub CzyDobryWykladowca(ByVal strconn As String, ByVal idk As _ Integer, ByVal idw As Integer) Sub CzyDobryPrzedmiot(ByVal strconn As String, ByVal idk As _ Integer, ByVal idw As Integer, ByVal idp As Integer) Sub ZapiszAktualizacje(ByVal strconn As String, ByVal dgv As _ DataGridView, ByRef u() As Boolean End Interface W kodzie klasy wstawiamy wiersz informujący o implementacji tego interfejsu. Public Class CRealizacja Inherits CForStorageSub ' dziedziczymy po tej klasie Implements IRejestracjaTematow Implements IRejestracjaPlanow ' ewentualnie informacja o implementacji innych interfejsów

174 174 Kolejny krok to implementacja właściwości i metod omawianego interfejsu. Funkcja (właściwość) Komunikat już była zaimplementowana wcześniej (w tej klasie), a więc wystarczy dodać jedynie jej obsługę także w tym interfejsie. Public Function Komunikat() As String Implements _ IRejestracjaTerminow.Komunikat, IRejestracjaPlanow.Komunikat Return mkomunikat End Function Funkcja DajTabele musi być zaimplementowana (jeszcze nie ma jej implementacji w tej klasie), wpisujemy więc poniższe instrukcje. Public Function DajTabele() As DataTable Implements _ IRejestracjaPlanow.DajTabele Return mtable1 End Function Metoda OtwarciePlanow jest odpowiedzialna za przygotowanie instancji formularza frmplanyzajec do pokazania użytkownikowi. W ramach tych przygotowań z bazy danych pobierane są dwa zestawy danych, które będą zaprezentowane w polach kombi cbotermin i cbogodzina tego formularza. Public Sub OtwarciePlanow(ByVal strconn As String, ByVal frm As _ frmplanyzajec) Implements IRejestracjaPlanow.OtwarciePlanow Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajterminydoplanu", _ 1, 1, 0) ' ustawienie właściowści pola kombi cbotermin UstawComboBox(frm.cboTermin, mtable1, "Kiedy", "idt") mtable2 = MyBase.DajRekordset(conn, _ "dbo.pdajgodzinyplanu", _ 1, 1, 0) ' ustawienie właściowści pola kombi cbogodzina UstawComboBox(frm.cboGodzina, mtable2, "kiedy", "idg") Catch ex As Exception mkomunikat = "Błąd pobrania danych z bazy SQL" Finally conn.close() conn = Nothing End Try Metoda PlanyZmianaTerminu jest odpowiedzialna za pobranie z bazy danych nowego rekordsetu opisującego przewidziane do realizacji w wybranym terminie kierunki studiów. Dane te zostaną wykorzystane w kodzie formularza frmplanyzajec do

175 175 zaktualizowania źródła danych pola kombi cbokierunki, a będą przekazane przez właściwość DajTabele. Public Sub PlanyZmianaTerminu(ByVal strconn As String, _ ByVal idt As Integer) Implements _ IRejestracjaPlanow.PlanyZmianaTerminu Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajkierunkiwgedycji", _ idt, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy kierunków z bazy SQL" Finally conn.close() conn = Nothing End Try Dwie pokazane niżej metody odpowiedzialne są za przygotowanie nowych źródeł danych dla pól kombo cbopracownik i cboprzedmiot w instancji formularza frmplanyzajec. Public Sub PlanyProwadzacy(ByVal strconn As String, _ ByVal idk As Integer) Implements _ IRejestracjaPlanow.PlanyPrewadzacy Dim conn As New SqlConnection(strConn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajpracownikowkierunku", _ idk, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy pracowników z bazy SQL" Finally conn.close() conn = Nothing End Try Public Sub PlanyPrzedmioty(ByVal strconn As String, _ ByVal idw As Integer, ByVal idk As Integer) Implements _ IRejestracjaPlanow.PlanyPrzedmioty Dim conn As New SqlConnection(strConn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo. pprzedmiotywgkierunkuwykladowcy ", _

176 176 idk, 1, 0) idw, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy przedmiotów z bazy SQL" Finally conn.close() conn = Nothing End Try Metoda PlanyZapisz jest odpowiedzialna za wstawienie do tabeli PlanyZajec nowego rekordu. Public Sub PlanyZapisz(ByVal strconn As String, ByVal frm As _ frmplanyzajec) Implements IRejestracjaPlanow.PlanyZapisz Dim conn As New SqlConnection(strconn) Try conn.open() With frm MyBase.Wykonaj(conn, "dbo.pwstawplanzajec", _ 1, 0, _ 1, 0, _ 1, 0, _ 1, 0, _ 1, 0, _ 5, 500) End With Catch ex As Exception mkomunikat = "Błąd zapisu planu zajęć do bazy SQL" Finally conn.close() conn = Nothing End Try Metoda EdytujPlany jest odpowiedzialna za przygotowanie źródła danych dla formantu dgvplany (typu DataGridView) instancji formularza frmedycjaplanow. Problem jest o tyle skomplikowany, że chcemy stworzyć sobie możliwość edycji danych z tabeli PlanyZajec w zakresie zmiany wykładowcy, realizowanego przedmiotu i godziny realizacji oraz tematu zajęć. Poniżej fragment surowych danych z tej tabeli dla ilustracji problemu.

177 177 Naszym zamiarem jest stworzenie sobie takiej sytuacji, aby edycji można było poddać kolumny idw, idp, idg i Temat, oczywiście dla danego terminu zajęć i kierunku. Pewnym ułatwieniem jest przygotowanie procedury przechowywanej o nazwie pdajterminyedycja, która opisuje nam termin zajęć z podaniem semestru i zjazdu, a kierunek studiów identyfikuje dodatkowo jego skrótem. Wyświetlenie pokazanych wyżej danych w gridzie nie daje nam żadnej możliwości edycji takich danych w zakresie zmiany wykładowcy, przedmiotu czy godziny zajęć. Zadaniem pokazanej niżej metody jest ułatwienie tego zadania poprzez dodanie do formantu dgvplany trzech nowych kolumn typu DataGridViewComboBoxColumn, które wykorzystamy do przetłumaczenia identyfikatorów na ich zrozumiały opis. Public Sub EdytujPlany(ByVal strconn As String, ByVal frm As _ frmedycjaplanow) Implements IRejestracjaPlanow.EdytujPlany Dim conn As New SqlConnection(strconn), tw, tp, tg As _ DataTable Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajterminyedycja", _ "id", 1, 1, 0) ' budujemy źródła danych dla kombo opisującego wykładowcę tw = MyBase.DajRekordset(conn, "dbo.pdajlisteludzi", _ 1, 1, 0) ' instancja formularza ma niewidoczny grid o nazwie ' dgvpracownik, tworzymy jego źródło danych wskazując obiekt ' tw (wykorzystamy te dane dla ustalenia identyfikatora ' wykładowcy na podstawie jego opisu With frm.dgvpracownik.datasource = tw.allowusertoaddrows = False End With ' budujemy źródła danych dla kombo opisującego przedmiot tp = MyBase.DajRekordset(conn, "dbo.pdajlisteprzedmiotow", _ 0, 1, 0) ' instancja formularza ma niewidoczny grid o nazwie ' dgvprzedmiot, tworzymy jego źródło danych wskazując obiekt ' tp (wykorzystamy te dane dla ustalenia identyfikatora ' przedmiotu na podstawie jego nazwy With frm.dgvprzedmiot.datasource = tp.allowusertoaddrows = True

178 178 End With ' budujemy źródła danych dla kombo opisującego godziny tg = MyBase.DajRekordset(conn, "dbo.pdajgodzinyplanu", _ 1, 1, 0) ' definiujemy właściwości dgvplany With frm.dgvplany.datasource = mtable1.columns(0).visible = False 'id.columns(1).visible = False 'idt.columns(2).visible = False 'idk.columns(3).readonly = True ' bez możliwości edycji.columns(4).readonly = True ' bez możliwości edycji.columns(3).width = 120.Columns(4).Width = 60.Columns(5).Visible = False 'idw.columns(6).visible = False 'idp.columns(7).visible = False 'idg.columns(8).width = 500 ' zamrażamy pierwsze 5 kolumn (przed skrolingiem).columns(0).frozen = True.Columns(1).Frozen = True.Columns(2).Frozen = True.Columns(3).Frozen = True.Columns(4).Frozen = True ' blokujemy dodawanie i usuwanie wierszy.allowusertoaddrows = False.AllowUserToDeleteRows = False End With ' dodajemy nowe kolumny do gridu Dim cbowykladowca As New DataGridViewComboBoxColumn() ' ustawiamy właścości nowej kolumny, przekazujemy kolejno ' nazwę kolumny, jej źródło danych, nazwę kolumny, której ' wartości mają być tłumaczone w kombo, nazwę kolumny w ' w źródle danych, która ma być wykorzystana jako ' DisplayValue,nazwę kolumny w źródle która spełni ' rolę ValueMember oraz nazwę kolumny w gridzie ' ostatni parametr to szerokość tej kolumny UstawComboBoxColumn(cboWykladowca, tw, "idw", "Ktos", _ "id_w", "Wykładowca", 170) ' wstawiamy tę nową kolumnę do gridu na pozycji tej kolumny, ' której wartości ma tłumaczyć frm.dgvplany.columns.insert(5, cbowykladowca) ' to samo dla przedmiotów Dim cboprzedmiot As New DataGridViewComboBoxColumn() UstawComboBoxColumn(cboPrzedmiot, tp, "idp", "Przedmiot", _ "id_p", "Przedmiot", 170) frm.dgvplany.columns.insert(6, cboprzedmiot) ' to samo dla godzin Dim cbogodzina As New DataGridViewComboBoxColumn()

179 179 UstawComboBoxColumn(cboGodzina, tg, "idg", "Kiedy", _ "idg","godzina", 170) frm.dgvplany.columns.insert(7, cbogodzina) Catch ex As Exception mkomunikat = "Błąd pobrania danych o terminach" Finally conn.close() conn = Nothing End Try Pokazana wyżej metoda EdytujPlany tworzy źródła danych dla dodatkowych kolumn typu DataGridViewComboBoxColumn bez brania pod uwagę faktu, że dla konkretnego wiersza gridu te dane mogą być nie do przyjęcia przykładowo do istniejącego kierunku studiów dobieramy wykładowcę z ogólnej listy, a nie z listy ograniczonej do tego kierunku. Podobny problem dotyczy przedmiotów. Pokazana niżej metoda CzyDobryWykladowca jest sprawdzianem, czy wybór wykładowcy (dla danego kierunku) jest poprawny, będziemy z niej korzystać w formularzu frmedycjaplanow w procedurze walidacyjnej komórek gridu. Public Sub CzyDobryWykladowca(ByVal strconn As String, _ ByVal idk As Integer, ByVal idw As Integer) Implements IRejestracjaPlanow.CzyDobryWykladowca Dim conn As New SqlConnection(strconn) Try conn.open() If MyBase.DajWartosc(conn, "dbo.pczydobrywykladowca", _ idk, 1, 0, _ idw, 1, 0, _ 1, 0) = 0 Then mkomunikat = "nie" Catch ex As Exception mkomunikat = "Błąd sprawdzenia wykładowcy" Finally conn.close() conn = Nothing End Try Metoda CzyDobryPrzedmiot spełnia taką samą rolę w odniesieniu do przedmiotu, tym razem zakres sprawdzianu jest jeszcze większy, bowiem sprawdzane jest, czy dany przedmiot może być prowadzony przez wybranego wykładowcę, jeżeli tak, to dodatkowo wykonywany jest sprawdzian, czy przedmiot ten jest realizowany na wybranym kierunku.

180 180 Public Sub CzyDobryPrzedmiot(ByVal strconn As String, _ ByVal idk As Integer, ByVal idw As Integer, _ ByVal idp As Integer) Implements _ IRejestracjaPlanow.CzyDobryPrzedmiot Dim conn As New SqlConnection(strconn) Try conn.open() If MyBase.DajWartosc(conn, "dbo.pczydobryprzedmiot", _ idk, 1, 0, idw, 1, 0, _ idp, 1, 0, 1, 0) = 0 Then mkomunikat = "nie" Catch ex As Exception mkomunikat = "Błąd sprawdzenia przedmiotu" Finally conn.close() conn = Nothing End Try Metoda ZapiszAktualizacje odpowiedzialna jest za zapisanie wszystkich zmian w tabeli PlanyZajec. Public Sub ZapiszAktualizacje(ByVal strconn As String, _ ByVal dgv As DataGridView, ByRef u() As Boolean) _ Implements IRejestracjaPlanow.ZapiszAktualizacje Dim conn As New SqlConnection(strconn), i As Integer Try conn.open() With dgv For i = 0 To dgv.rows.count - 1 If u(i) Then' zapisujemy MyBase.Wykonaj(conn, "dbo.pzapiszaktualizacjeplanow", _ 1, 0, _ 1, 0, _ 1, 0, _ 1, 0, _ 5, 500) Next End With Catch ex As Exception mkomunikat = "Błąd aktualiazacji planów zajęc" Finally conn.close() conn = Nothing End Try

181 Interfejs IObecnosci 181 Interfejs IObecnosci deklaruje te właściwości i metody, które będziemy wykorzystywać w trakcie rejestrowania obecności na zajęciach i raportowania. Public Interface IObecnosci Function Komunikat() As String Function DajTabele() As DataTable Function DajTabele2() As DataTable Sub DaneRejestracjiObecnosci(ByVal strconn As String, ByVal frm _ As frmrejestrobecnosci) Sub RejestracjaZmianaKierunku(ByVal strconn As String, _ ByVal idk As Integer) Sub ObecnosciZapisz(ByVal strconn As String, ByVal frm As _ frmrejestrobecnosci) Sub EdycjaObecnosci(ByVal strconn As String, ByVal frm As _ frmedycjaobecnosci) Sub PokazDaneEdycjiObecnosci(ByVal strconn As String, _ ByVal idk As Integer, ByVal semestr As Integer) Sub ZapiszAktualizacjeObecnosci(ByVal strconn As String, _ ByVal frm As frmedycjaobecnosci, ByRef u(,) As Boolean) End Interface Metoda, której kod pokazany jest niżej jest odpowiedzialna za przygotowanie instancji formularza frmrejestrobecnosci do pokazania użytkownikowi. W ramach tego działania pobierana jest z bazy danych lista aktywnych kierunków studiów (w tym sensie, że są to kierunki realizowane w bieżącej edycji studiów), ustawiane właściwości pola kombo wyświetlającego te kierunki oraz wstępnie zaznaczane są przyciski radiowe semestru, zjazdu i dnia szkoleniowego. Public Sub DaneRejestracjiObecnosci(ByVal strconn As String, _ ByVal frm As frmrejestrobecnosci) Implements _ IObecnosci.DaneRejestracjiObecnosci Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.plistaaktywnychkierunkow", 1, 1, 0) UstawComboBox(frm.cboKierunek, mtable1, "Kierunek", "id_k") ZaznaczRdb(frm.rdbSemestr1) ZaznaczRdb(frm.rdbZjazd1) ZaznaczRdb(frm.rdbSobota7) Catch ex As Exception mkomunikat = "Błąd pobrania listy kierunków" Finally conn.close() conn = Nothing End Try

182 182 Metoda RejestracjaZmianaKierunku jest odpowiedzialna za dostarczenie listy studentów tego kierunku. Public Sub RejestracjaZmianaKierunku(ByVal strconn As String, ByVal idk As Integer) Implements _ IObecnosci.RejestracjaZmianaKierunku Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pstudencidoobecnosci", idk, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy studentów" Finally conn.close() conn = Nothing End Try Metoda ObecnosciZapisz odpowiada za zapisanie obecności studentów (wyrażonej liczbą godzin uczestnictwa w zajęciach danego dnia szkoleniowego). Przed wykonaniem zapisu procedura bada, czy takiego wpisu już nie ma w bazie. Public Sub ObecnosciZapisz(ByVal strconn As String, _ ByVal frm As frmrejestrobecnosci) Implements _ IObecnosci.ObecnosciZapisz Dim conn As New SqlConnection(strconn), i, j As Integer Try conn.open() Dim semestr As Integer = UstalGrb(frm.grbSemestr) Dim zjazd As Integer = UstalGrb(frm.grbZjazd) Dim dzien As Integer = UstalGrb(frm.grbDzien) Dim idt As Integer = MyBase.DajWartosc(conn, _ "dbo.pobecnosciustaltermin", _ semestr, 1, 0, zjazd, 1, 0, _ dzien, 1, 0, 1, 0) For i = 0 To frm.dgvobecnosci.rows.count - 1 j = MyBase.DajWartosc(conn, "dbo.pwstawobecnoscinew", _ idt, 1, 0, _ frm.dgvobecnosci.rows(i).cells(0).value, _ 1, 0, _ frm.dgvobecnosci.rows(i).cells(2). _ Value, 1, 0, 1, 0) If j > 0 Then mkomunikat &= "Obecność dla studenta " & _ frm.dgvobecnosci.rows(i).cells(1).value & _ " już jest w bazie" & vbcrlf Next

183 183 Catch ex As Exception mkomunikat = "Błąd zapisu obecności" Finally conn.close() conn = Nothing End Try Zadaniem metody EdycjaObecnosci jest przygotowanie instancji formularza frmedycjaobecnosci do pokazania go użytkownikowi. Public Sub EdycjaObecnosci(ByVal strconn As String, _ ByVal frm As frmedycjaobecnosci) Implements _ IObecnosci.EdycjaObecnosci Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pkierunkidoobecnosci", _ 1, 1, 0) UstawComboBox(frm.cboKierunki, mtable1, "Kierunek", _ "id_k") ZaznaczRdb(frm.rdbSemestr1) Catch ex As Exception mkomunikat = "Błąd pobrania informacji o kierunkach" Finally conn.close() conn = Nothing End Try Metoda PokazDaneEdycjiObecnosci przygotowuje godziny obecnosci do ich edycji. Public Sub PokazDaneEdycjiObecnosci(ByVal strconn As String, _ ByVal idk As Integer, ByVal semestr As Integer) _ Implements IObecnosci.PokazDaneEdycjiObecnosci Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajgodzinyobecnosci", _ semestr, 1, 0, _ idk, 1, 0, _ 2, 1, 0) Dim tb As New DataTable tb = ZbudujTabele(mTable1, "Nazwisko i imię") Dim loc As Integer = tb.columns.indexof(tb.columns("razem")) tb.columns.removeat(loc) mtable1 = tb

184 184 Catch ex As Exception mkomunikat = "Błąd pobrania informacji o godzinach obecności" Finally conn.close() conn = Nothing End Try Metoda ZapiszAktualizacjeObecnosci odpowiada za zaktualizowanie wskazanego rekordu. Public Sub ZapiszAktualizacjeObecnosci(ByVal strconn As String, _ ByVal frm As frmedycjaobecnosci, _ ByRef u(,) As Boolean) Implements _ IObecnosci.ZapiszAktualizacjeObecnosci Dim conn As New SqlConnection(strconn), _ i, j, ids, idt As Integer Dim tw, tk As DataTable Try conn.open() ' pobranie pomocniczych informacji z bazy danych na ' potrzeby ustalenia ids studenta tw = MyBase.DajRekordset(conn, "dbo.pdajstudentowids", _ UstalGrb(frm.grbSemestr), 1, 0, _ frm.cbokierunki.selectedvalue, 1, 0) ' pobranie pomocniczych informacji z bazy danych na ' potrzeby ustalenia idt terminu tk = MyBase.DajRekordset(conn, "dbo.pdajzjazddzienidt", _ UstalGrb(frm.grbSemestr), 1, 0, _ frm.cbokierunki.selectedvalue, 1, 0) With frm.dgvobecnosci For i = 0 To.Rows.Count - 1 For j = 1 To.Columns.Count - 1 If u(i, j) Then 'pytanie, jaki student i jakie idt?? ids = UstalId(.Rows(i).Cells(0).Value, tw) idt = UstalId(.Columns(j).HeaderText, tk) MyBase.Wykonaj(conn, _ "dbo.paktualizujobecnosci", _ ids, 1, 0, _ idt, 1, 0, _ 1, 0) Next Next End With Catch ex As Exception mkomunikat = "Błąd aktgualizacji obecności" Finally conn.close()

185 185 conn = Nothing End Try Interfejsc ITesty Interfejs ITesty deklaruje właściwości i metody wykorzystywane do rejestrowania i edytowania wyników testów. Public Interface ITesty Function Komunikat() As String Function DajTabele() As DataTable Function DajTabele2() As DataTable Sub PrzygotujRejestrTestow(ByVal strconn As String, _ ByVal frm As frmrejestrtestowcz) Sub TestyZmianaKierunku(ByVal strconn As String, _ ByVal semestr As Integer, ByVal zjazd As Integer, _ ByVal idk As Integer, ByVal ktory As String) Sub TestyZmianaWykladowcy(ByVal strconn As String, _ ByVal semestr As Integer, ByVal zjazd As Integer, _ ByVal idk As Integer, ByVal idw As Integer, _ ByVal ktory As String) Sub TestyZapisz(ByVal strconn As String, _ ByVal frm As frmrejestrtestowp) Sub DaneTestuDoAktualizacji(ByVal strconn As String, _ ByVal frm As frmrejestrtestowp) ' testy semestralne Sub PrzygotujTestySemestralne(ByVal strconn As String, _ ByVal frm As frmrejestrtestus) Sub TestySemestralneZmianaKierunku(ByVal strconn As String, _ ByVal semestr As Integer, ByVal idk As Integer, _ ByVal pomoc As String, ByVal ktory As String) Sub TestySemestralneZapiszAktualizuj(ByVal strconn As String, _ ByVal frm As frmrejestrtestus, ByRef u() As Boolean) End Interface Wszystkie trzy właściwości (funkcje) zadeklarowane w tym interfejsie były już zaimplementowane, wystarczy dodać w tych implementacjach obsługę także tego interfejsu. Metoda PrzygotujRejestrTestow jest odpowiedzialna za przygotowanie danych do rejestracji wyników testu lub do edycji istniejących wyników. Public Sub PrzygotujRejestrTestow(ByVal strconn As String, _ ByVal frm As frmrejestrtestowcz) Implements _ ITesty.PrzygotujRejestrTestow Dim conn As New SqlConnection(strconn) Try conn.open()

186 186 If frm.txtpomoc.text = "R" Then mtable1 = MyBase.DajRekordset(conn, _ "dbo.plistaaktywnychkierunkow", _ 1, 1, 0) Else mtable1 = MyBase.DajRekordset(conn, _ "dbo.pkierunkitestowp", _ 1, 1, 0, _ 1, 1, 0) UstawComboBox(frm.cboKierunek, mtable1, "Kierunek", "id_k") ZaznaczRdb(frm.rdbSemestr1) ZaznaczRdb(frm.rdbZjazd1) ZaznaczRdb(frm.rdbSobota7) Catch ex As Exception mkomunikat = "Błąd pobrania listy aktywnych kierunków" Finally conn.close() conn = Nothing End Try Metoda TestyZmianaKierunku jest odpowiedzialna za dostarczenie aktualnej listy studentow danego kierunku. Public Sub TestyZmianaKierunku(ByVal strconn As String, _ ByVal semestr As Integer, ByVal idk As Integer, _ ByVal ktory As String) Implements _ ITesty.TestyZmianaKierunku Dim conn As New SqlConnection(strconn) Try conn.open() If ktory = "R" Then mtable1 = MyBase.DajRekordset(conn, _ "dbo.pstudencidoobecnosci", idk, 1, 0) mtable2 = MyBase.DajRekordset(conn, _ "dbo.ppracownicykierunku", idk, 1, 0) Else mtable2 = MyBase.DajRekordset(conn, _ "dbo.pdajpracownikowdoaktualizacjitestow", _ semestr, 1, 0, _ zjazd, 1, 0, _ idk, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy studentów i pracownikow" Finally conn.close() conn = Nothing

187 187 End Try Metoda TestyZapisz realizuje fizyczne zapis wyników testu, przed wstawieniem nowego rekordu wykonywany jest sprawdzian, czy taki rekord już nie istnieje. Jeżeli tak, to komponowany jest komunikat zwrotny wyjaśniający odmowę zapisu. Public Sub TestyZapisz(ByVal strconn As String, ByVal frm As _ frmrejestrtestowcz) Implements ITesty.TestyZapisz Dim conn As New SqlConnection(strconn), i, j As Integer Try conn.open() Dim semestr As Integer = UstalGrb(frm.grbSemestr) Dim zjazd As Integer = UstalGrb(frm.grbZjazd) Dim dzien As Integer = UstalGrb(frm.grbDzien) Dim idt As Integer = MyBase.DajWartosc(conn, _ "dbo.pobecnosciustaltermin", _ semestr, 1, 0, _ zjazd, 1, 0, _ dzien, 1, 0, _ 1, 0) With frm.dgvpunkty If frm.txtpomoc.text = "R" Then For i = 0 To.Rows.Count - 1 j = MyBase.DajWartosc(conn, "dbo.pzapisztestp", _ 1, 0, _ idt, 1, 0, _ frm.cbopracownik.selectedvalue, 1, 0, _ frm.cboprzedmiot.selectedvalue, 1, 0, _ 7, 0, _ 1, 0) If j > 0 Then mkomunikat &= "Test dla " & _.Rows(i).Cells(1).Value & _ " jest w bazie" & vbcrlf Next Else For i = 0 To frm.dgvpunkty.rows.count - 1 If u(i) Then MyBase.Wykonaj(conn, "dbo.paktualizujtestyp", _ 1, 0, _ 7, 0) Next End With Catch ex As Exception mkomunikat = "Błąd zapisu testu"

188 188 Finally conn.close() conn = Nothing End Try Metoda TestyZmianaWykladowcy dostarcza aktualną listę przedmiotów do rejestracji wyników testu lub do edycji jego wyników Public Sub TestyZmianaWykladowcy(ByVal strconn As String, _ ByVal semestr As Integer, ByVal zjazd As Integer, _ ByVal idw As Integer, ByVal ktory As String, ByVal idk As _ Integer) Implements ITesty.TestyZmianaWykladowcy Dim conn As New SqlConnection(strconn), sp As String = "" Try conn.open() If ktory = "R" Then mtable1 = MyBase.DajRekordset(conn, _ "dbo.pprzedmiotywgkierunkuwykladowcy", _ idk, 1, 0, _ idw, 1, 0) Else mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajprzedmiotydoaktualizacjitestow", _ semestr, 1, 0, _ zjazd, 1, 0, _ idk, 1, 0, _ idw, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy studentów" Finally conn.close() conn = Nothing End Try Poniższa metoda odpowiada za dostarczenie danych niezbędnych do aktualizacji wyników testów przedmiotowych. Public Sub DaneTestuDoAktualizacji(ByVal strconn As String, _ ByVal frm As frmrejestrtestowcz) Implements _ ITesty.DaneTestuDoAktualizacji Dim conn As New SqlConnection(strconn) Try conn.open() Dim semestr As Integer = UstalGrb(frm.grbSemestr) Dim zjazd As Integer = UstalGrb(frm.grbZjazd) Dim dzien As Integer = UstalGrb(frm.grbDzien) Dim idt As Integer = MyBase.DajWartosc(conn, _

189 189 "dbo.pobecnosciustaltermin", _ semestr, 1, 0, _ zjazd, 1, 0, _ dzien, 1, 0, _ 1, 0) mtable1 = MyBase.DajRekordset(conn, _ "dbo.ptestyprzeddoaktualizacji", _ idt, 1, 0, _ frm.cbopracownik.selectedvalue, 1, 0, _ frm.cboprzedmiot.selectedvalue, 1, 0) Catch ex As Exception mkomunikat = "Błąd przygotowaniu raportu testu C" Finally conn.close() conn = Nothing End Try Metoda PrzygotujTestySemestralne odpowiada za dostarczenie danych niezbędnych do wyświetlenia formularza przeznaczonego do rejestracji wyników testów semestralnych. Public Sub PrzygotujTestySemestralne(ByVal strconn As String, _ ByVal frm As frmrejestrtestus) Implements _ ITesty.PrzygotujTestySemestralne Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.plistaaktywnychkierunkow", _ 1, 1, 0) UstawComboBox(frm.cboKierunek, mtable1, "Kierunek", "id_k") ZaznaczRdb(frm.rdbSemestr1) Catch ex As Exception mkomunikat = "Błąd pobrania listy aktywnych kierunków" Finally conn.close() conn = Nothing End Try Poniższa metoda będzie wywoływana w momeńcie zmiany kierunku studiów w trakcie rejestracji lub edycji wyników testów semestralnych. Public Sub TestySemestralneZmianaKierunku(ByVal strconn As _ String, ByVal semestr As Integer, ByVal idk As Integer, _ ByVal pomoc As String, ByVal ktory As String) Implements _ ITesty.TestySemestralneZmianaKierunku Dim conn As New SqlConnection(strconn) Try

190 190 conn.open() If pomoc = "R" Then mtable1 = MyBase.DajRekordset(conn, _ "dbo.pstudencidoobecnosci", _ idk, 1, 0) Else mtable1 = MyBase.DajRekordset(conn, _ "dbo.ptestsemestralnydoedycji", _ semestr, 1, 0, _ idk, 1, 0, _ IIf(ktory = "P", 1, 2), 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy studentów i pracownikow" Finally conn.close() conn = Nothing End Try Zapis lub aktualizacja wyników testów semestralnych wykonywana jest za pomocą poniższej procedury. Public Sub TestySemestralneZapiszAktualizuj(ByVal strconn As _ String, ByVal frm As frmrejestrtestus, ByRef u() As _ Boolean) Implements ITesty.TestySemestralneZapiszAktualizuj Dim conn As New SqlConnection(strconn), i, j As Integer Try conn.open() Dim semestr As Integer = UstalGrb(frm.grbSemestr) With frm.dgvpunkty If frm.txtpomoc.text = "R" Then For i = 0 To.Rows.Count - 1 j = MyBase.DajWartosc(conn, _ "dbo.pwstawtestsemestralny", _ 1, 0, _ semestr, 1, 0, _ IIf(frm.txtKtory.Text="P", 1, 2), 1, 0, _ 7, 0, _ 1, 0) If j > 0 Then mkomunikat &= "Test dla " & _.Rows(i).Cells(1).Value & _ " jest w bazie" & vbcrlf Next Else For i = 0 To.Rows.Count - 1 If u(i) Then

191 191 MyBase.Wykonaj(conn, _ "dbo.paktualizujtestsemestralny", _ 1, 0, _ 7, 0) Next Catch ex As Exception mkomunikat = _ "Błąd zapisu testu semestralnego lub jego aktualizacji" Finally conn.close() conn = Nothing End Try Interfejs ISzkolenia W trakcie realizacji zajeć szkoleniowych konieczne jest wysyłanie do jednostki współfinansującej planu szkoleń nadchodzącego zjazdu. Dla każdego z prowadzonych kierunków musi być przesłana informacja w postaci dokumentu MS Word i to w ściśle określonym przez tę jednostkę formacie. Zadanie to będzie realizowane (między innymi) za pośrednictwem właściwości i metod zapowiedzianych w pokazanym niżej interfejsie. Public Interface ISzkolenia Function Komunikat() As String Function DajTabele() As DataTable Function DajTabele2() As DataTable Sub PrzygotujTerminyKierunki(ByVal strconn As String, ByVal _ semestr As Integer, ByVal zjazd As Integer) Sub PrzygotujTematy(ByVal strconn As String, ByVal idt As _ Integer, ByVal idk As Integer) End Interface Wiadomo, że w kodzie klasy CRealizacja musi się pojawić instrukcja zapowiadającą implementację właściwości i metod interfejsu (Imlements ISzkolenia) oraz sama implementacja. W przypadku właściwości tego interfejsu wystarczy dodać jego obsługę do już istniejących implementacji, z kolei metody musimy napisać na nowo. Metoda PrzygotujTerminyKierunki odpowiada za pobranie z bazy danych dwóch rekordsetów, pierwszy z nich zwraca terminy szkoleń dla wybranego semestru i zjazdu, a drugi listę kierunków realizowanych w ramach bieżącej edycji studiów. Rekordsety te będą dostępne poprzez właściwości DajTabele i DajTabele2. Public Sub PrzygotujTerminyKierunki(ByVal strconn As String, _ ByVal semestr As Integer, ByVal zjazd As Integer) _ Implements ISzkolenia.PrzygotujTerminyKierunki

192 192 Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pszkoleniatermin", _ semestr, 1, 0, _ zjazd, 1, 0) mtable2 = MyBase.DajRekordset(conn, _ "dbo.pkierunkiszkolenia", _ 2, 1, 0) Catch ex As Exception mkomunikat = _ "Błąd przygotowaniu terminów i kierunków szkoleń" Finally conn.close() conn = Nothing End Try Zadaniem metody PrzygotujTematy jest pobranie z bazy danych dokładnego planu zajęć przewidzianych do realizacji na danym kierunku i w danym terminie. Zwrócone dane będą wykorzystane do zbudowania dokumentu MS Word. Public Sub PrzygotujTematy(ByVal strconn As String, _ ByVal idt As Integer, ByVal idk As Integer) _ Implements ISzkolenia.PrzygotujTematy Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.ptematyszkolendlakierunku", _ idt, 1, 0, _ idk, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania listy tematów" Finally conn.close() conn = Nothing End Try

193 Interfejs IDaneAnkiet W tym interfejsie zebrano te właściwości i metody, które będą wykorzystane przy rejestracji wyników ankiet przedmiotowych. Public Interface IDaneAnkiet Function Komunikat() As String Function DajTabele() As DataTable Sub PrzygotujDaneAnkiet(ByVal strconn As String, ByVal frm As _ frmankieta) Sub DaneAnkietZmianaKierunku(ByVal strconn As String, ByVal idk _ As Integer) Sub DaneAnkietZmianaWykladowcy(ByVal strconn As String, _ ByVal idw As Integer, ByVal idk As Integer) Sub ZapiszDaneAnkiety(ByVal strconn As String, ByRef z() As _ Integer, ByRef u() As Integer, ByVal txtuwaga As String) End Interface Metoda PrzygotujDaneAnkiet odpowiada za pobranie z bazy danych listy aktywnych kierunków studiów i wykorzystanie ich do inicjalizacji formularza przekazanego jako argument tej metody. Public Sub PrzygotujDaneAnkiet(ByVal strconn As String, _ ByVal frm As frmankieta) Implements _ IDaneAnkiet.PrzygotujDaneAnkiet Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.plistaaktywnychkierunkow", _ 1, 1, 0) UstawComboBox(frm.cboKierunek, mtable1, "Kierunek", "id_k") ZaznaczRdb(frm.rdbPierwszy1) ZaznaczRdb(frm.rdbZjazd1) Catch ex As Exception mkomunikat = "Błąd przygotowaniu listy kierunków do ankiet" Finally conn.close() conn = Nothing End Try Metoda DaneAnkietZmianaKierunku odpowiada za pobranie z bazy danych aktualnej listy wykładowców danego kierunku. Public Sub DaneAnkietZmianaKierunku(ByVal strconn As String, _ ByVal idk As Integer) Implements _ IDaneAnkiet.DaneAnkietZmianaKierunku Dim conn As New SqlConnection(strconn)

194 194 Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.ppracownicykierunku", _ idk, 1, 0) Catch ex As Exception mkomunikat = _ "Błąd przygotowaniu listy pracowników do ankiet" Finally conn.close() conn = Nothing End Try Metoda DaneAnkietZmianaWykladowcy odpowiada za zaktualizowanie listy przedmiotów dla danego wykładowcy i kierunku studiów. Public Sub DaneAnkietZmianaWykladowcy(ByVal strconn As String, _ ByVal idw As Integer, ByVal idk As Integer) Implements _ IDaneAnkiet.DaneAnkietZmianaWykladowcy Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pprzedmiotywgkierunkuwykladowcy", _ idk, 1, 0, _ idw, 1, 0) Catch ex As Exception mkomunikat = _ "Błąd przygotowaniu listy przedmiotów do ankiet" Finally conn.close() conn = Nothing End Try Metoda ZapiszDaneAnkiety odpowiada za wstawienie do tabeli Dane nowego rekordu. Public Sub ZapiszDaneAnkiety(ByVal strconn As String, ByRef z() _ As Integer, ByRef u() As Integer, ByVal txtuwaga As _ String) Implements IDaneAnkiet.ZapiszDaneAnkiety Dim conn As New SqlConnection(strconn) Try conn.open() MyBase.Wykonaj(conn, "dbo.pwstawdaneankiet", _ z(1), 1, 0, _ z(2), 1, 0, _ z(3), 1, 0, _ z(4), 1, 0, _

195 z(5), 1, 0, _ IIf(u(1) = -1, DBNull.Value, u(1)), 1, 0, _ IIf(u(2) = -1, DBNull.Value, u(2)), 1, 0, _ IIf(u(3) = -1, DBNull.Value, u(3)), 1, 0, _ IIf(u(4) = -1, DBNull.Value, u(4)), 1, 0, _ IIf(u(5) = -1, DBNull.Value, u(5)), 1, 0, _ IIf(u(6) = -1, DBNull.Value, u(6)), 1, 0, _ IIf(u(7) = -1, DBNull.Value, u(7)), 1, 0, _ IIf(u(8) = -1, DBNull.Value, u(8)), 1, 0, _ IIf(u(9) = -1, DBNull.Value, u(9)), 1, 0, _ IIf(u(10) = -1, DBNull.Value, u(10)), 1, 0, _ IIf(txtUwaga.Length = 0, DBNull.Value, _ txtuwaga), 5, 500) Catch ex As Exception mkomunikat = "Błąd zapisu danych ankiety" Finally conn.close() conn = Nothing End Try 195

196 Rejestracja terminów zajęć Projekt formularza frmterminy Formularz frmterminy został tak zaprojektowany, aby w łatwy sposób można było zarejestrować w tabeli Terminy informacje o tym, kiedy będą realizowane zajęcia dla wskazanej edycji studiów, semestru i zjazdu. Na powierzchni formularza umieszczono takie formanty jak: cboedycja pole kombi pozwalające na wybór edycji studiów; grbsemestry ramka zawierająca dwa przyciski radiowe o nazwach odpowiednio rdbpierwszy1 i rdbdrugi2 i tekstach jak wyżej, będziemy mogli wybrać semestr zajęć; grbzjazdy ramka zawierająca sześć przycisków radiowych o nazwach odpowiednio rdbzjazd1 do rdbzjazd6 i tekstach opisujących te przyciski jak wyżej, będziemy mogli wybrać zjazd szkoleniowy; mockalendarz formant typu MonthCalendar, pozwoli nam na wskazanie terminu realizacji danego zjazdu; btnzapisz przycisk polecenia uruchamiający procedury związane z zarejestrowaniem terminu; oraz etykiety opisujące część z wymienionych formantów. Zestaw formantów uzupełnia jeszcze kontrolka typu ErrorProvider, która jak pamiętamy jest umieszczana nie w formurzu, ale na tzw. tacy, wykorzystamy ją przy walidacji poprawności danych.

197 197 Dla formantu mockalendarz zmieniono jego właściwość MaxSelectionCount z domyślnej 7 na 1, chodzi o to, aby użytkownik mógł zaznaczyć jedynie pojedynczy dzień, a nie zakres dni. Dodatkowo, w klasie tego formularza napiszemy procedurę pilnującą, aby użytkownik mógł zaznaczyć jedynie sobotę jako początek zjazdu Modyfikacja menu aplikacji Musimy teraz uzupełnić menu naszej aplikacji dodając odpowiednią pozycję, a następnie piszemy procedurę obsługującą klik tego polecenia. Poniżej fragment formularza frmmdiankieta z menu aplikacji, widoczna jest pozycja Realizacja zajęć i dalej Plan zajęć z poleceniem Rejestracja terminów zajęć. Pozycja ta otrzymała nazwę mnurejestracjaterminow, a procedura obsługująca zdarzenie Click pokazana jest poniżej. Private Sub mnuprzygootwanieterminarza_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnurejestracjaterminow.click ' ustawienie wartości zmiennej globalnej flaga na False ' co zapobiegnie przetwarzaniu zdarzenie SelectedValueChanched ' pola kombi cboeducja w momencie definiowania jego własności flaga = False ' utworzenie instancji formularza Dim frm As New frmterminy ' dekalracja obiektu w oparciu o interfejs Dim w As IRejestracjaTerminow ' utworzenie nowej instancji klasy CRealizacja w = New CRealizacja w.otwarcieterminow(strbaza, frm) ' wywołanie metody klasy ' badanie, czy dane z bazy zostały pobrane If w.komunikat.length > 0 Then ' nie, komunikat na ekran MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' zostały pobrane, można pokazać formularz frm.mdiparent = Me frm.show()

198 Kod formularza frmterminy W klasie formularza frmterminy musimy teraz napisać poniższe procedury, obsługują one zdarzenie załadowania formularza, walidację wybranych formantów oraz zdarzenie Click przycisku btnzapisz. Public Class frmterminy Dim semestr, zjazd As Integer, dzien As Date, f As Boolean ' procedura ueuchamiana przy załadowaniu formularza Private Sub frmterminy_load(byval sender As Object, ByVal e As _ System.EventArgs) Handles Me.Load flaga = True ' procedura sprawdzająca wybranie edycji studiów Private Sub cboedycja_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles cboedycja.validating f = CzyDobreCombo(Me.cboEdycja, _ "Proszę wybrać edycję studiów!", Me.ErrorProvider1, True) ' procedura sprawdzająca czy wybrano sobotę Private Sub mockalendarz_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles mockalendarz.validating If Me.mocKalendarz.SelectionRange.Start.DayOfWeek <> _ DayOfWeek.Saturday Then Me.ErrorProvider1.SetError(Me.mocKalendarz, _ "Zaznaczonym dniem musi być sobota!") Beep() Me.mocKalendarz.Focus() Else Me.ErrorProvider1.SetError(Me.mocKalendarz, "") ' procedura zdarzenia Click przycisku btnzapisz zaczyna swoją ' pracę od sprawdzenia, czy została wybrana edycja studiów. ' Drugim sparwdzianem jest badanie, czy zaznaczona została sobota Private Sub btnzapisz_click(byval sender As Object, ByVal e As _ System.EventArgs) Handles btnzapisz.click If CzyDobreCombo(Me.cboEdycja, _ "Proszę wybrać edycję studiów!", _ Me.ErrorProvider1, True) Then Exit Sub dzien = Me.mocKalendarz.SelectionRange.Start If dzien.dayofweek <> DayOfWeek.Saturday Then

199 199 Me.ErrorProvider1.SetError(Me.mocKalendarz, _ "Zaznaczonym dniem musi być sobota!") Beep() Me.mocKalendarz.Focus() Exit Sub Else Me.ErrorProvider1.SetError(Me.mocKalendarz, "") ' zapisujemy Dim w As IRejestracjaTerminow w = New CRealizacja w.zapisztermin(strbaza, Me.cboEdycja.SelectedValue, _ UstalGrb(Me.grbSemestr), UstalGrb(Me.grbZjazd), dzien) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Termin zapisany", MsgBoxStyle.Information, _ "Rejestracja terminów zajęć") End Class Poniżej widok instancji formularza frmterminy w trakcie rejestracji terminu pierwszych zajęć ostatniej z zaplanowanych edycji studiów podyplomowych. Za chwilę będzie kliknięty przycisk polecenia Zapisz, co spowoduje dodanie do tabeli Terminy nowego rekordu. Pomyślne dopisanie nowego rekordu potwierdzane jest specjalnym komunikatem, a po jego zamknięciu możemy rejestrować dalsze terminy.

200 200 Poniżej fragment danych tabeli Terminy, widoczne są dwa ostatnie rekordy, to one właśnie zostały przed chwilą dopisane.

201 Edycja terminów zajęć Formularz frmedycjaterminow pozwala na edycję wszystkich czterech pól opisujących termin zajęć poprzez wyświetlenie odpowiednio przygotowanych danych w formancie typu DataGridView. Na powierzchni formularza umieszczono dwa formanty: dgvterminy grid wyświetlający informacje o terminach zajęć; btnaktualizuj przycisk polecenia uruchamiający procedurę aktualizującą. Instancja tego formularza tworzona jest poprzez klik odpowiedniego polecenia w menu aplikacji. Klik tego polecenia uruchamia pokazaną niżej procedurę, która tworzy instancję formularza frmedycjarerminow, a następnie tworzy instancję klasy CRealiazacja wykorzystując interfejs IRejestracjaTerminow i jego metodę EdycjaTerminow. Private Sub mnuedycjaterminu_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuedycjaterminu.click Dim frm As New frmedycjaterminow Dim w As IRejestracjaTerminow

202 202 w = New CRealizacja w.edycjaterminow(strbaza, frm) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else frm.mdiparent = Me frm.show() W kodzie klasy formularza frmedycjaterminow musimy jeszcze napisać kilka procedur odpowiedzialnych za funkcjonowanie tego formularza. Public Class frmedycjaterminow Dim x() As Boolean, ilew As Integer ' przygotowanie formularza do pracy Private Sub frmedycjaterminow_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load Dim i As Integer ilew = Me.dgvTerminy.Rows.Count ReDim x(ilew - 1) For i = 0 To ilew - 1 x(i) = False Next ' obsługa zakończenia edycji komórki gridu Private Sub dgvterminy_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvterminy.cellendedit ' skasowanie ewentualnego komunikatu o błędzie Me.dgvTerminy.Rows(e.RowIndex).ErrorText = String.Empty ' zmiana wartości w zmiennej x jako sygnał edycji wiersza If Not x(e.rowindex) Then x(e.rowindex) = True ' obsługa walidacji komórek gridu Private Sub dgvterminy_cellvalidating(byval sender As Object, _ ByVal e As _ System.Windows.Forms.DataGridViewCellValidatingEventArgs) _ Handles dgvterminy.cellvalidating ' uzależniamy działanie od kolumny danej komórki Select Case e.columnindex Case 2 ' semestr If e.formattedvalue < 1 Then Me.dgvTerminy.Rows(e.RowIndex).ErrorText = _ "Numer semestru nie może być mniejszy od 1!" e.cancel = True Beep()

203 203 ElseIf e.formattedvalue > 2 Then Me.dgvTerminy.Rows(e.RowIndex).ErrorText = _ "Numer semestru nie może być większy od 2!" e.cancel = True Beep() Case 3 ' zjazd If CInt(e.FormattedValue) < 1 Then Me.dgvTerminy.Rows(e.RowIndex).ErrorText = _ "Numer zjazdu nie może być mniejszy od 1!" e.cancel = True Beep() ElseIf CInt(e.FormattedValue) > 6 Then Me.dgvTerminy.Rows(e.RowIndex).ErrorText = _ "Numer zjazdu nie może być większy od 6!" e.cancel = True Beep() Case 4 ' data Dim dzien As Date dzien = e.formattedvalue If dzien.dayofweek <> DayOfWeek.Saturday Then Me.dgvTerminy.Rows(e.RowIndex).ErrorText = _ "Proszę wskazać sobotę!!" e.cancel = True Beep() End Select ' obsługa aktualizacji gridu Private Sub btnaktualizuj_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnaktualizuj.click Dim w As IRejestracjaTerminow w = New CRealizacja w.aktualizujterminy(strbaza, Me.dgvTerminy, x) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Aktualizacja terminów zakończona pomyślnie!", _ MsgBoxStyle.Information, "Aktualizacja terminów zajęć") Me.Close() End Class Poniżej widok instancji tego formularza w trakcie edycji jednego z terminów. Klik komórki terminu powoduje wyświetlenie formantu kalendarza prezentującego dotychczasową datę, możemy teraz w łatwy sposób wskazać inną.

204 204 Wskazanie innej daty niż soboty powoduje, przy próbie zmiany rekordu, wyświetlenie komunikatu o błędzie. Sytuacja taka pokazana jest poniżej. Musimy albo wskazać sobotę, albo przyciskiem Esc powrócić do poprzedniej daty. Analogicznie sprawdzane są wartości modyfikowane w kolumnie Semestr czy Zjazd, będziemy mogli przejść do kolejnego wiersza gridu dopiero po wprowadzeniu akceptowalnych (przez procedurę walidacyjną) wartości. Klik przycisku Aktualizuj kończy proces aktualizacji terminów zajęć.

205 Rejestracja planów zajęć Projekt formularza frmplanyzajec Formularz frmplanyzajec został tak zaprojektowany, aby w łatwy sposób można było zarejestrować w tabeli PlanyZajec informacje o zajęciach, które zostały zaplanowane w wybranym terminie. Na powierzchni formularza umieszczono następujące formanty: cbotermin pole kombi pozwalające na wybór terminu zajęć dla planowanych edycji studiów podyplomowych; cbokierunek pole kombi umożliwiające wybór kierunku studiów; cbopracownik pole kombi pozwalające na wybór wykładowcy spośród wykładowców kierunku studiów wybranego w poprzednim kombo; cboprzedmiot pole kombi umożliwiające wybór przedmiotu spośród przedmiotów przewidzianych na danym kierunku studiów; cbogodzina pole kombi pozwalające na wybór godziny realizacji wybranego przedmiotu i liczby godzin dydaktycznych; txttemat pole tekstowe pozwalające na wprowadzenie tematu zajęć; btnzapisz przycisku polecenia uruchamiającego procedurę zapisu wprowadzonych danych w bazie SQL; ErrorProvider1 kontrolki obsługi błędu (umieszczonej na tacy), będziemy ją wykorzystywać w procesie walidacji wprowadzonych danych oraz etykiet opisujących niektóre z wymienionych formantów.

206 206 Dla pola tekstowego txttemat ustawiono jego właściwość Multiline na True, co pozwoliło na zwiększenie wysokości tego formantu tak, aby można było pomieścic do 500 znaków opisu tematu zajęć Modyfikacja menu aplikacji Musimy teraz uzupełnić menu naszej aplikacji dodając odpowiednią pozycję, a następnie pisząc procedurę obsługującą klik tego polecenia. Poniżej fragment okna naszej aplikacji z rozwiniętym menu otwierającym instancję formularza frmplanyzajec. Kod procedury obsługującej klik wskazanego (myszą) polecenia menu pokazany jest niżej (z klasy formularza frmmdistudia). Private Sub mnurejestracjatematow_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnurejestracjatematow.click Dim frm As New frmplanyzajec Dim w As IRejestracjaPlanow w = New CRealizacja w.otwarcieplanow(strbaza, frm) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else frm.mdiparent = Me frm.show()

207 Kod formularza frmplanyzajec W klasie formularza musimy utworzyć teraz szereg procedur obsługujących zdarzenia związane z jego funkcjonowaniem. Część tych procedur będzie obsługiwać zdarzenia SelectedValueChanged kilku pól kombo modyfikując źródła danych innych pól kombi. W procedurze zdarzenia Click przycisku btnzapisz zawrzemy instrukcje walidujące pola kombo jak i pole tekstowe txttemat. Public Class frmplanyzajec ' procedura reaguje na zmianę w polu cbotermin, a jej zadaniem ' jest aktualizacja źródła danych pola kombo cbokierunek Private Sub cbotermin_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbotermin.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IRejestracjaPlanow w = New CRealizacja w.planyzmianaterminu(strbaza, Me.cboTermin.SelectedValue) UstawComboBox(Me.cboKierunek, w.dajtabele, "Kierunek", _ "id_k", w.komunikat) ' procedura reaguje na zmianę w polu cbokierunek, a jej zadaniem ' jest aktualizacja źródła danych pola kombo cbopracownik Private Sub cbokierunek_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbokierunek.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IRejestracjaPlanow w = New CRealizacja w.planyprewadzacy(strbaza, Me.cboKierunek.SelectedValue) UstawComboBox(Me.cboPracownik, w.dajtabele, "kto", "id_w", _ w.komunikat) ' procedura reaguje na zmianę w polu cbopracownik, a jej zadaniem ' jest aktualizacja źródła danych pola kombo cboprzedmiot Private Sub cbopracownik_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbopracownik.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IRejestracjaPlanow w = New CRealizacja w.planyprzedmioty(strbaza, Me.cboPracownik.SelectedValue) UstawComboBox(Me.cboPrzedmiot, w.dajtabele, "Przedmiot", _ "id_p", w.komunikat)

208 208 ' procedura reaguje na klik przycisku btnzapisz, a jej zadaniem ' jest walidacja pól kombo i pola tekstowego, a przy pozytywnej ' walidacji tworzona jest instancja klasy CRealizacja wykonująca ' zapis wprowadzonych danych do tabeli PlanyZajec Private Sub btnzapisz_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnzapisz.click If CzyDobreCombo(Me.cboTermin, _ "Proszę wybrać termin zajęć!", Me.ErrorProvider1, _ True) Then Exit Sub If CzyDobreCombo(Me.cboKierunek, _ "Proszę wybrać kierunek studiów!", Me.ErrorProvider1, _ True) Then Exit Sub If CzyDobreCombo(Me.cboPracownik, _ "Proszę wybrać wykładowcę!", Me.ErrorProvider1, _ True) Then Exit Sub If CzyDobreCombo(Me.cboPrzedmiot, _ "Proszę wybrać przedmiot!", Me.ErrorProvider1, _ True) Then Exit Sub If CzyDobreCombo(Me.cboGodzina, _ "Proszę wybrać godzinę zajęć!", Me.ErrorProvider1, _ True) Then Exit Sub If CzyTextBoxDobry(Me.txtTemat, Me.ErrorProvider1, _ "Proszę wprowadzić temat zajęć!", 5, 500, _ True) Then Exit Sub ' można zapisywać Dim w As IRejestracjaPlanow w = New CRealizacja w.planyzapisz(strbaza, Me) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Temat zarejestrowany w bazie", _ MsgBoxStyle.Information, "Rejestracja planów zajęć") Me.txtTemat.Text = Nothing End Class

209 209 Klik przycisku Zapisz spowoduje zapisanie wprowadzonych danych w tabeli PlanyZajec pomimo tego, że ewidentnie temat zajęć nie jest w pełni skomponowany. Niestety, w praktyce walidacja pól tekstowych jest dość mocno ograniczona i tak naprawdę wszystko zależy od uwagi użytkownika. Pomyślne zapisanie danych sygnalizowane jest pokazanym niżej komunikatem, a klik jego przycisku OK spowoduje wyczyszczenie pola tekstowego Temat zajęć.

210 Edycja planów zajęć Formularz frmedycjaplanow Formularz frmedycjaplanow został tak zaprojektowany, aby była możliwa edycja wybranych kolumn danych pochodzących z tabeli PlanyZajec. Poniżej projekt tego formularza w pewnym zniekształceniu co do rzeczywistych rozmiarów (zmienionych na potrzeby jego pokazania w tej pracy). Na powierzchni formularza umieszczono trzy formanty typu DataGridView i jeden przycisk polecenia: dgvplany to w tym formancie będą wyświetlane dane do edycji; dgvpracownik pomocniczy grid, jego przeznaczeniem jest przechowanie do dalszego wykorzystania danych wykorzystanych jako DataSource pomocniczego pola kombo pozwalającego na wybór wykładowcy. Dane te będą umieszczone w tym gridzie w momencie tworzenia instancji formularza; dgvprzedmiot także pomocniczy grid, jego zadaniem jest przechoowanie danych wykorzystanych jako DataSource pomocniczego pola kombo pozwalającego na wybór przedmiotu; btnaktualizuj przycisk polecenia uruchamiający aktualizację planów zajęć. Formanty dgvpracownik oraz dgvprzedmiot mają ustawioną właściwość Visible na False, co wynika z ich pomocniczego charakteru. Instancja tego formularza uruchamiana jest poprzez klik odpowiedniego polecenia w menu aplikacji, co skutkuje wykonaniem poniższej procedury (z klasy formularza frmmdistudia).

211 211 Private Sub mnuedycjatematow_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuedycjatematow.click Dim frm As New frmedycjaplanow Dim w As IRejestracjaPlanow w = New CRealizacja w.edytujplany(strbaza, frm) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else frm.mdiparent = Me frm.show() Kod formularza frmedycjaplanow W kodzie formularza musimy utworzyć szereg procedur obsługujących zdarzenia związane z tym formularzem. Public Class frmedycjaplanow Dim x() As Boolean ' jedynym zadaniem tej procedury jest przygotowanie zmiennej ' tablicowej x do wykorzystania Private Sub frmedycjaplanow_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load Dim i, ilew As Integer ilew = Me.dgvPlany.Rows.Count For i = 0 To Me.dgvPlany.Rows.Count - 1 x(i) = False Next ' procedura ta będzie wykonywana w momencie zakończenia edycji ' komórki gridu, a jej zadaniem jest usunięcie ewentualnego ' komunikatu o błędzie i aktualizacja odpowiedniej pozycji w x() Private Sub dgvplany_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvplany.cellendedit Me.dgvPlany.Rows(e.RowIndex).ErrorText = String.Empty If Not x(e.rowindex) Then x(e.rowindex) = True ' procedura ta będzie uruchamiana w momencie, gdy użytkownik ' będzie opuszczał komórkę gridu po edycji jej zawartości Private Sub dgvplany_cellvalidating(byval sender As Object, _ ByVal e As System.Windows.Forms. _ DataGridViewCellValidatingEventArgs) Handles _ dgvplany.cellvalidating Dim t As String, i, j As Integer

212 212 t = e.formattedvalue.tostring Select Case e.columnindex Case 5 ' wykładowca ' ustalamy indeks tej pozycji For i = 0 To Me.dgvPracownik.Rows.Count - 1 If t = Me.dgvPracownik.Rows(i). _ Cells(1).Value.ToString Then j = Me.dgvPracownik.Rows(i).Cells(0).Value Exit For Next ' sprawdzamy, czy dany prawcownik wyklada na kierunku idk ' (kolumna 2) Dim w As IRejestracjaPlanow w = New CRealizacja w.czydobrywykladowca(strbaza, Me.dgvPlany.Rows( _ e.rowindex).cells(2).value, j) If w.komunikat.length = 3 Then Me.dgvPlany.Rows(e.RowIndex).ErrorText = _ "Pracownik " & t & _ " nie może prowadzić zajęć na tym kierunku" e.cancel = True Beep() ElseIf w.komunikat.length > 3 Then e.cancel = True MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Exit Sub Case 6 ' czy dobry przedmiot With Me.dgvPrzedmiot For i = 0 To.Rows.Count - 1 If t =.Rows(i).Cells(1).Value.ToString Then j =.Rows(i).Cells(0).Value Exit For Next End With ' sprawdzamy, czy ten prawcownik może prowadzic ten ' przedmiot Dim w As IRejestracjaPlanow w = New CRealizacja w.czydobryprzedmiot(strbaza, Me.dgvPlany.Rows( _ e.rowindex).cells(2).value, _ Me.dgvPlany.Rows(e.RowIndex).Cells(5).Value, j) If w.komunikat.length = 3 Then Me.dgvPlany.Rows(e.RowIndex).ErrorText = _ "Wybrany przedmiot nie może być prowadzony" e.cancel = True Beep()

213 213 ElseIf w.komunikat.length > 3 Then e.cancel = True MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Exit Sub Case 8 ' temat If t.length < 10 Or t.length > 500 Then Me.dgvPlany.Rows(e.RowIndex).ErrorText = _ "Temat musi być tekstem od 10 do 500 znaków" e.cancel = True Beep() End Select Private Sub btnaktualizuj_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnaktualizuj.click Dim w As IRejestracjaPlanow w = New CRealizacja w.zapiszaktualizacje(strbaza, Me.dgvPlany, x) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Pomyślnie zaktualizowano plany zajęć", _ MsgBoxStyle.Information, "Aktualizacja planów") Me.Close() End Class Poniżej widok instancji formularza frmedycjaplanow, dla pierwszego z rekordów chcemy zmienić wykładowcę (w konsekwenci pewnie i przedmiot oraz temat zajęć).

214 214 W kolumnie Wykładowca mamy już otwarte pole kombi z wykazem (niestety) wszystkich wykładowców, może więc zdarzyć się taka sytuacja, że wybierzemy takiego pracownika, który nie został przewidziany do prowadzenia zajęć na kierunku identyfikowanym skrótem ZPL. Jeżeli wybierzemy przykładowo pracowika Góral Konrad, to przy próbie opuszczenia tej komórki gridu zostanie zgłoszony komunikat o błędzie. Zaistniały błąd możemy skasować albo wracając do poprzedniej wartości tego pola poprzez naciśnięcie klawisza Esc, albo wybierając takiego pracownika, który ma zaplanowane zajęcia na tym kierunku.

215 215 W analogiczny sposób możemy zaktualizować przedmiot czy godzinę realizacji zajęć (wybierając odpowiednią pozycję z pola kombo). Zupełnie inaczej wygląda problem aktualizacji tematu zajęć, a cała trudność wynika z niemożności widzenia całego, dotychczasowego tekstu. Rozwiązaniem może być wykorzystanie specjalnego formularza, który wyświetlimy w trybie okna dialogowego. Projekt takiego formularza pokazany jest niżej Formularz edycji pola tekstowego typu Dialog Wszyscy znamy taki formularz systemowy jak InputBox, który pozwala w łatwy sposób przejąć informację wprowadzoną od użytkownika. W tym rozdziale zajmiemy się zaprojektowaniem tego typu formularza, który będziemy chcieli wywołać z jakiegoś innego formularza, a następnie wykorzystać informacje wprowadzone przez użytkownika. Naszym zadaniem jest przygotowanie formularza, który pozwoli na edycję zawartości pola tekstowego. Projekt takiego formularza pokazany jest niżej. Na powierzchni formularza umieszczono trzy formanty: txtedytowanepole pole tekstowe z ustawioną właściwością Multiline na True i rozmiarami 530 na 80 pikseli; btnok przycisk akceptacji dokonanych zmian; btnanuluj przycisk rezygnacji z dokonywania zmian. W oknie właściwości tego formularza przypisujemy dla właściwości AcceptButton przycisk btnok, a dla właściwości CancelButton przycisk btnanuluj. Selekcjonujemy przycisk btnok i w oknie jego właściwości dla pozycji DialogResult przpisujemy wartość OK. Selekcjonujemy przycisk btnanuluj i jego właściwości DialogResult przypisujemy wartość Cancel. Możemy jeszcze zablokować możliwość zmiany rozmiarów naszego formularza poprzez ustawienie dla właściwości MinimizeBox i MaximizeBox wartości False, a dla właściwości FormBorderStyle wybieramy wartość FixedDialog. Tytuł naszego formularza jest nieistotny, będziemy go bowiem dynamicznie zmieniać.

216 216 Kolejny krok to utworzenie w kodzie tego formularza potrzebnych procedur i właściwości, ich zadaniem będzie ustawienie tytułu formularza, wstawienie do pola tekstowego wyjściowego tekstu oraz zwrócenie tekstu po zakończeniu edycji. Kod tych procedur pokazany jest niżej. Public Class frmedytujtextbox ' ustawienie tytułu formularza Public WriteOnly Property Tytul() As String Set(ByVal value As String) Me.Text = value End Set End Property ' pobranie wstępnego tekstu i jego zwrócenie Public Property Temat() As String Get Return Me.txtEdytowanePole.Text End Get Set(ByVal value As String) Me.txtEdytowanePole.Text = value End Set End Property ' obsługa kliku przycisku btnok Private Sub btnok_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnok.click Me.Close() ' obsługa kliku przycisku btnanuluj Private Sub btnanuluj_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnanuluj.click Me.Close() End Class Wykorzystanie formularza frmedytujtextbox Pokażemy teraz jak można wykorzystać utworzony formularz do edycji tematów zajęć, będzie to wymagać dopisania w kodzie formularza frmedycjaplanow procedury obsługi zdarzenia CellDoubleClick. Kod tej procedury pokazany jest niżej, procedura będzie wykonywana wtedy, gdy ten podwójny klik będzie wykonany w komórce kolumny o indeksie osiem (tam są wyświetlane tematy zajęć). Private Sub dgvplany_celldoubleclick(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvplany.celldoubleclick If e.columnindex = 8 Then Dim w As New frmedytujtextbox

217 217 w.tytul = "Edycja teamtu zajęć" w.temat = Me.dgvPlany.Rows(e.RowIndex).Cells( _ e.columnindex).value.tostring ' pokazanie formularza w trybie okna dialogowego ' z badaniem, czy użytkownik nacisnął przycisk akceptacji If w.showdialog = Windows.Forms.DialogResult.OK Then ' tak, przejmujemy poprawiony tekst i wpisujemy go ' do tej komorki gridu, z której wykonany był podwójny ' klik Me.dgvPlany.Rows(e.RowIndex).Cells( _ e.columnindex).value = w.temat Poniżej widok instancji formularza frmedycjaplanow w trakcie edycji tematu zajęć w ostatnim rekordzie, po podwójnym kliku w tej komórce gridu została otwarta instancja formularza frmedytujtextbox z dotychczasowym tematem, który będziemy chcieli uzupełnić czy poprawić. Po kliku przycisku OK nastąpi powrót do formularza edycji planów z jednoczesnym wstawieniem poprawionego tematu do tej komórki gridu, w której nastąpił podwójny klik.

218 Rejestracja obecności Projekt formularza frmrejestrobecnosci Formualarz frmrejestrobecnosci zastał zaprojektowany pod potrzeby rejestracji obecności słuchaczy studiów podyplomowych na poszczególnych zjazdach. Projekt tego formularza pokazany jest niżej. Na powierzchni formularza umieszczono następujące formanty: cbokierunek pole kombi pozwalające na wybór kierunku studiów w ramach bieżącej edycji studiów podyplomowych; grbsemestr grupę opcji z dwoma przyciskami radiowymi o nazwach rdbsemestr1 i rdbsemestr2 pozwalająch na wybór semestru zajęć; grbzjazd grupę opcji z sześcioma przyciskami radiowymi o nazwach odpowiednio od rdbzjazd1 do rdbzjazd6 pozwalający na wskazanie zjazdu szkoleniowego;

219 219 grbdzien grupę opcji z dwoma przyciskami radiowymi o nazwach odpowiednio rdbsobota7 i rdbniedziela1 pozwalającymi na wskazanie dnia tygodnia; dgvobecnosci formant typu DataGridView, w nim będą wyświetlane dane studentów wybranego kierunku i będzie ustawiona wyjściowa liczba godzin, w których powinni uczestniczyć (w naszym przypadku będzie to osiem godzin); btnzapisz przycisk polecenia uruchamiający procedurę zapisu obecności w bazie danych oraz etykiety opisujące niektóre z tych formantów. Instancja tego formularza tworzona jest po kliku odpowiedniego polecenia w menu aplikacji, co skutkuje wykonaniem pokazanej niżej procedury. Private Sub mnurejestarcjaobecnosci_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnurejestarcjaobecnosci.click Dim frm As New frmrejestrobecnosci Dim w As IObecnosci w = New CRealizacja w.danerejestracjiobecnosci(strbaza, frm) PokazForm(frm, w.komunikat) Kod formularza frmrejestrobecnosci W module klasy tego formularza utworzono kilka procedur obsługujących zdarzenia związane z funkcjonowaniem tego formularza. Public Class frmrejestrobecnosci ' procedura obsługująca zdarzenie zmiany kierunku studiów, jej ' zadaniem jest dostarczenie aktualnej listy studentów do gridu ' dgvobecnosci oraz dołożenie dodatkowej kolumny tekstowej z ' z domyślną liczbą godzin Private Sub cbokierunek_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbokierunek.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IObecnosci w = New CRealizacja w.rejestracjazmianakierunku(strbaza, _ Me.cboKierunek.SelectedValue) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else flaga = False ' wyłączamy obsługę walidacji

220 220 With Me.dgvObecnosci.DataSource = w.dajtabele.columns(0).visible = False.Columns(1).Width = 200.Columns(1).ReadOnly = True Dim col As New DataGridViewColumn Dim cell As New DataGridViewTextBoxCell col.datapropertyname = "Godziny" col.headertext = "liczba godzin" col.celltemplate = cell.columns.add(col) Dim i As Integer For i = 0 To.Rows.Count - 1.Rows(i).Cells(2).Value = 8 Next.Columns(2).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter.AllowUserToAddRows = False.AllowUserToDeleteRows = False End With flaga = True ' procedura obsługująca zdarzenie zakończenia wprowadzania ' informacji do gridu Private Sub dgvobecnosci_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvobecnosci.cellendedit Me.dgvObecnosci.Rows(e.RowIndex).ErrorText = String.Empty ' procedura obsługująca zdarzenie walidacji zawartości danej ' komórki gridu, pilnuje, aby informacja o licznbie godzin ' była poprawnie podana Private Sub dgvobecnosci_cellvalidating(byval sender As Object, _ ByVal e As System.Windows.Forms. _ DataGridViewCellValidatingEventArgs) Handles _ dgvobecnosci.cellvalidating If Not flaga Then Exit Sub With Me.dgvObecnosci If e.columnindex = 2 Then If Not IsNumeric(e.FormattedValue) Then Beep().Rows(e.RowIndex).ErrorText = _ "Wprowadzony ciąg znaków nie jest liczbą!" e.cancel = True Exit Sub ElseIf CInt(e.FormattedValue) < 0 Then Beep()

221 221.Rows(e.RowIndex).ErrorText = _ "Liczba godzin nie może być mniejsza niż 0!" e.cancel = True Exit Sub ElseIf CInt(e.FormattedValue) > 8 Then Beep().Rows(e.RowIndex).ErrorText = _ "Liczba godzin nie może być większa niż 8!" e.cancel = True Exit Sub End With ' procedura obsługująca zdarzenie kliku przycisku Zapisz ' uruchamia zapis wprowadzonych danych do bazy, przygotowuje ' formularz do ponownej rejestracji Private Sub btnzapisz_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnzapisz.click Dim w As IObecnosci w = New CRealizacja w.obecnoscizapisz(strbaza, Me) If w.komunikat.length > 30 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Obecności zarejestrowane", _ MsgBoxStyle.Information, "Rejestracja obecności") flaga = False Me.cboKierunek.SelectedValue = -1 flaga = True ' usunięcie dodanej kolumny grudu Me.dgvObecnosci.Columns.RemoveAt(2) Me.dgvObecnosci.DataSource = Nothing End Class Poniżej widok instancji tego formularza w trakcie rejestracji liczby godzin dla słuchaczy wybranego kierunku studiów. Wybrany jest odpowiedni semestr, zjazd i dzień, a w gridzie wyświetlona jest imienna lista studentów i domyślna liczba godzin, w jakich powinni uczestniczyć.

222 222 Klik przycisku Zapisz zapisuje wprowadzone informacje w tabeli Obecnosci, a po ich zapisanu wyświetlany jest stosowny komunikat. W tym przypadku, gdy chcielibyśmy zarejestrować informacje o obecnościach już wcześniej zapisanych w bazie danych, procedura obsługująca klik przycisku Zapisz zwraca obszerny komunikat wyjaśniający przyczynę odmowy.

223 223

224 Edycja obecności Projekt formularza frmedycjaobecnosci Formularz frmedycjaobecnosci został przygotowany do edytowania obecności słuchaczy na zjazdach szkoleniowych. Formantem, w którym będziemy przeprowadzać edycję godzin jest kontrolka typu DataGridView, w której w kolejnych kolumnach będą wyświetlane liczby godzin zarejestrowane dla dnia zjazdu szkoleniowego (soboty lub niedzieli). Dane, które będziemy edytować zależą od semestru oraz kierunku studiów. Na powierzchni formularza umieszczono formanty: grbsemestr grupa opcji z dwoma przyciskami radiowymi o nazwach odpowiednio rdbsemestr1 i rdbsemestr2; cbokierunki pole kombi wyświetlające listę aktualnych (w ramach danej edycji studiów) kierunków; dgvobecnosci grid wyświetlający zestawienie krzyżowe godzin obecności zarejestrowanych dla poszczególnych studentów; btnaktualizuj przycisk polecenia uruchamiający proces aktualizacji; ErrorProvider1 formant obsługi błędów walidacji (umieszczony na tacy) oraz etykiety opisujące niektóre formanty. Instancja tego formularza tworzona jest poprzez klik odpowiedniego polecenia w menu aplikacji, co skutkuje wykonaniem pokazanej niżej procedury.

225 225 Private Sub EdycjaToolStripMenuItem_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuedycjaobecnosci.click Dim frm As New frmedycjaobecnosci Dim w As IObecnosci w = New CRealizacja w.edycjaobecnosci(strbaza, frm) PokazForm(frm, w.komunikat) Kod formularza frmedycjaobecnosci W klasie formularza musimy utworzyć szereg procedur obsługujących zdarzenia związane z jego funkcjonowaniem. Public Class frmedycjaobecnosci ' dekalrujemy zmienną tablicową dwuwymiarową o niekoreślonych ' w tym momencie wymarach Dim x(,) As Boolean ' procedura obsługująca zakończenie edycji komórki gridu Private Sub dgvobecnosci_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvobecnosci.cellendedit Me.dgvObecnosci.Rows(e.RowIndex).ErrorText = String.Empty If Not x(e.rowindex, e.columnindex) Then _ x(e.rowindex, e.columnindex) = True ' procedura obsługująca waliację komórki gridu Private Sub dgvobecnosci_cellvalidating(byval sender As Object, _ ByVal e As System.Windows.Forms. _ DataGridViewCellValidatingEventArgs) Handles _ dgvobecnosci.cellvalidating If e.columnindex > 0 Then If CInt(e.FormattedValue) < 0 Or _ CInt(e.FormattedValue) > 8 Then Me.dgvObecnosci.Rows(e.RowIndex).ErrorText = _ "liczba godzin w komórce " & _ Me.dgvObecnosci.Columns(e.ColumnIndex).HeaderText & _ " jest zła" e.cancel = True Beep() ' procedura obsługująca zmianę w polu cbokierunki, jej efektem ' musi być pobranie nowych danych z bazy i ich przypisanie do ' gridu dgvobecnosci. Takie samo zadanie powinno być wykonane ' przy zmianie semestru, dlatego zaprojektowano pomocniczą

226 226 ' procedurę Pomoc, która jest wywoływana w tej procedurze Private Sub cbokierunki_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbokierunki.selectedvaluechanged Pomoc() ' pomocnicza procedura Pomoc Private Sub Pomoc() If Not flaga Then Exit Sub If CzyDobreCombo(Me.cboKierunki, _ "Proszę wybrać kierunek studiów", Me.ErrorProvider1, _ True) Then Exit Sub Dim w As IObecnosci, i As Integer w = New CRealizacja w.pokazdaneedycjiobecnosci(strbaza, _ Me.cboKierunki.SelectedValue, UstalGrb(Me.grbSemestr)) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Me.dgvObecnosci.DataSource = Nothing Else With Me.dgvObecnosci.DataSource = w.dajtabele.columns(0).width = 150.Columns(0).ReadOnly = True.Columns(0).Frozen = True For i = 1 To.Columns.Count - 1.Columns(i).Width = 50.Columns(i).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter Next.AllowUserToAddRows = False.AllowUserToDeleteRows = False End With Dim ilew, ilek, j As Integer ilew = Me.dgvObecnosci.Rows.Count ilek = Me.dgvObecnosci.Columns.Count ReDim x(ilew - 1, ilek - 1) For i = 0 To ilew - 1 For j = 0 To ilek - 1 x(i, j) = False Next Next ' procedura obsługuje zmianę semestru, aktualizuje dane ' w gridzie

227 227 Private Sub rdbsemestr1_checkedchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles _ rdbsemestr1.checkedchanged Pomoc() ' procedura obsługuje aktualizację danych Private Sub btnzapisz_click(byval sender As Object, ByVal e As _ System.EventArgs) Handles btnzapisz.click Dim w As IObecnosci w = New CRealizacja w.zapiszaktualizacjeobecnosci(strbaza, Me, x) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Aktualizacja godzn obecności zakończona", _ MsgBoxStyle.Information, "Aktualizacja obecności") Me.Close() End Class Poniżej widok instancji tego formularza w trakcie edycji godzin obecności dla wybranego kierunku i semestru. W zaznaczonej komórce gridu jest w tej chwili liczba 0, a powinno być (powiedzmy) 6 godzin, jednak osoba dokonująca korekty popełniła błąd i wpisała 9. Przy próbie zmiany komórki zostaje zgłoszony błąd.

228 228 Po skorygowaniu błędu i kliku przycisku Aktualizuj dane zostają zaktualizowane, co potwierdza pokazany niżej komunikat. W przypadku, gdy dla wybranego semestru i kierunku nie ma zarejestrowanych godzin obecności, to zgłaszany jest stosowny komunikat.

229 Rejestracja testów przedmiotowych Warunki realizacji studiów podyplomowych z dofinansowaniem ze środków EFS zakładają przeprowadzenie na każdym zjeździe sprawdzianu przedmiotowego z materiału, który był prezentowany na poprzednim zjeździe. Wyniki tych sprawdzianów będą gromadzone w tabeli WynikiTestowC, będziemy to robić za pomocą pokaznego niżej formularza ekranowego Projekt formularza frmrejestrtestowp Projekt formularza przeznaczonego do rejestracji wyników testów przedmiotowych (cząstkowych) pokazany jest niżej. Został on tak zaprojektowany, aby nógł być także wykorzystywany do edycji wyników tych testów, stąd stosunkowo dość znacze jego skomplikowanie (w tym kodu).

230 230 Na powierzchni formularza umieszczono formanty: grbsemestr grupę opcji z dwoma przyciskami radiowymi o nazwach rdbsemestr1 i rdbseemstr2, będziemy w niej wybierać semestr zajęć; grbzjazd grupę opcji z sześcioma przyciskami radiowymi o nazwach odpowiednio od rdbzjazd1 do rdbzjazd6, będziemy w niej wybierać zjazd szkoleniowy; grpdzdzien grupę opcji z dwoma przyciskami radiowymi o nazwach rdbsobota7 i rdbniedziela1, będziemy w nim wybierać dzień realizacji zajęć; cbokierunek pole kombi pozwalające na wybór aktywnego kierunku studiów (realizowanego w ramach bieżącej edycji); cbopracownik pole kombi pozwalające na wybór wykładowcy (spośród tych, którym zaplanowano zajęcia na wybranym kierunku studiów); cboprzedmiot pole kombi pozwalające na wybór przedmiotu (spośród tych, które zostały przypisane do kierunku studiów i wybranego wykładowcy); dgvpunkty formant typu DataGridView, w nim będziemy wyświetlać listę studentów i wprowadzać (czy edytować) liczbę uzyskanych punktów (procentowo); txtdomyslnepkt pole tekstowe określające domyślną (dominującą) liczbę punktów, jaka może być przypisana studentowi; txtpomoc pomocnicze pole tekstowe, niewidoczne dla użytkownika, będzie zawierać tekst R dla rejestracji punktów lub A dla aktualizacji; btnzapisz przycisk polecenia uruchamiający procedurę zapisu lub aktualizacji danych; ErrorProvider1 formant obsługujący proces walidacji oraz etykiety oipisujące niektóre z tych formantów (w tym lblpunkty opisująca pole tekstowe domyślnej liczby punktów). Instancja tego formularza jest tworzona i pokzywana użytkownikowi po wybraniu w menu aplikacji odpowiedniego polecenia.

231 231 Klik tego polecenia uruchamia pokazaną niżej procedurę (zapisaną w formularzu frmmdistudia). Utworzona w tej procedurze instancja klasy CRealizacja poprzez metodę PrzygotujRejestTestow przygotowuje instancję formularza do pokazania użytkownikowi. Private Sub mnurejestracjatestowprzedmiotowych_click(byval _ sender As System.Object, ByVal e As System.EventArgs) _ Handles mnurejestracjatestowprzedmiotowych.click Dim frm As New frmrejestrtestowp ' określenie trybu pracy formularza frm.txtpomoc.text = "R" Dim w As ITesty w = New CRealizacja w.przygotujrejestrtestow(strbaza, frm) PokazForm(frm, w.komunikat) Kod formularza frmrejestrtestowp W klasie formularza musimy przygotować szereg procedur obsługujących zdarzenia związane z jego funkcjonowaniem, jej kod wraz z niezbędnymi komentarzami pokazany jest niżej. Public Class frmrejestrtestowp ' deklaracja pomocniczych zmiennych klasy ' zmienna f będzie określać, czy w gridzie trzeba dodać kolumnę ' punktów Dim f As Boolean = False, semestr, zjazd As Integer, _ z As Boolean ' procedura incjalizuje formularz zależnie od pola txtpomoc Private Sub frmrejestrtestowcz_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load If Me.txtPomoc.Text = "R" Then Me.Text = "Formularz rejestracji testu przedmiotowego" Me.btnZapisz.Text = "Zapisz" Me.txtDomyslnePkt.Text = "75" Me.txtDomyslnePkt.Visible = True Me.lblPunkty.Visible = True Else Me.Text = "Formularz aktualizacji testu przedmiotowego" Me.btnZapisz.Text = "Aktualizuj" Me.txtDomyslnePkt.Visible = False Me.lblPunkty.Visible = False semestr = UstalGrb(Me.grbSemestr) zjazd = UstalGrb(Me.grbZjazd) ' procedura obsługuje zmianę kierunku, dostarcza aktualne

232 232 ' źródło danych dla cbopracownik oraz gridu dgvpunkty Private Sub cbokierunek_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbokierunek.selectedvaluechanged If Not flaga Then Exit Sub Dim w As ITesty w = New CRealizacja w.testyzmianakierunku(strbaza, Me.cboKierunek.SelectedValue, _ Me.txtPomoc.Text) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else If Me.txtPomoc.Text = "R" Then ' przypisanie źródła danych do zmiennej tb Dim tb As DataTable = w.dajtabele ' dodanie nowej kolumny do tb tb.columns.add(new DataColumn("Punkty", _ GetType(Decimal))) ' sprawdzenie, co jest w txtdomyslnepkt Dim xp As Decimal, i As Integer, t As String = _ Me.txtDomyslnePkt.Text If t.length > 1 AndAlso t.indexof("%") > 0 Then t = t.substring(0, t.length - 1) If t.length > 0 AndAlso IsNumeric(t) Then xp = CDec(t) / 100 Else xp = 0 ' do komórek tej nowej kolumny wpisujemy xp For i = 0 To tb.rows.count - 1 tb.rows(i).item("punkty") = xp Next ' zdefiniowanie właściwości gridu With Me.dgvPunkty flaga = False.DataSource = w.dajtabele.columns(0).visible = False.Columns(1).Width = 200.Columns(1).ReadOnly = True.Columns(2).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter.AllowUserToAddRows = False.AllowUserToDeleteRows = False.Columns(2).DefaultCellStyle.Format = "##0.0%" flaga = True End With UstawComboBox(Me.cboPracownik, w.dajtabele2, "Kto", "id_w")

233 233 ' procedura obsługuje zmianę pracownika, dostarcza aktualne ' źródło danych dla cboprzedmiot Private Sub cbopracownik_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbopracownik.selectedvaluechanged If Not flaga Then Exit Sub Dim w As ITesty, t As String w = New CRealizacja w.testyzmianawykladowcy(strbaza, _ Me.cboPracownik.SelectedValue, Me.txtPomoc.Text, _ Me.cboKierunek.SelectedValue) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else If Me.txtPomoc.Text = "R" Then t = "id_p" Else t = "idp" UstawComboBox(Me.cboPrzedmiot, w.dajtabele, "Przedmiot", t) ' procedura sprawdza, czy wybrano kierunek studiów Private Sub cbokierunek_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) Handles _ cbokierunek.validating z = CzyDobreCombo(Me.cboKierunek, _ "Proszę wybrać kierunek studiów", Me.ErrorProvider1, True) ' procedura sprawdza, czy wybrano wykładowcę Private Sub cbopracownik_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) Handles _ cbopracownik.validating z = CzyDobreCombo(Me.cboPracownik, _ "Proszę wybrać wykładowcę", Me.ErrorProvider1, True) ' procedura sprawdza, czy wybrano przedmiot Private Sub cboprzedmiot_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) Handles _ cboprzedmiot.validating z = CzyDobreCombo(Me.cboPrzedmiot, _ "Proszę wybrać przedmiot", Me.ErrorProvider1, True)

234 234 ' procedura poniższa będzie wykonywana wtedy, gdy będziemy ' aktualizować wyniki testów, wywołuje pomocniczą procedurę ' Pomoc Private Sub cboprzedmiot_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cboprzedmiot.selectedvaluechanged Pomoc() ' procedura Pomoc jest odpowiedzialna za sprawdzenie, czy dla ' wybranych ustawień istnieją w bazie danych wyniki testu, jeżeli ' tak, to je pobiera i dostarcza do dgvpunkty, jeżeli nie, to ' zgłaszany jest stosowny komunikat, a formant dgvpunkty jest ' czyszczony z danych Private Sub Pomoc() If Not flaga Then Exit Sub If Me.txtPomoc.Text = "R" Then Exit Sub If Me.cboKierunek.SelectedValue = Nothing Or _ Me.cboPracownik.SelectedValue = Nothing Or _ Me.cboPrzedmiot.SelectedValue = Nothing Then Exit Sub Dim w As ITesty w = New CRealizacja w.danetestudoaktualizacji(strbaza, Me) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else If w.dajtabele.rows.count = 0 Then MsgBox("Brak testu do edycji", MsgBoxStyle.Information, _ "Aktualizacja testow") Me.dgvPunkty.DataSource = Nothing Else With Me.dgvPunkty.DataSource = w.dajtabele.columns(0).visible = False.Columns(1).Width = 150.Columns(1).HeaderText = "Nazwisko i imię".columns(2).headertext = "Punkty w %".Columns(2).DefaultCellStyle.Format = "##0.0%".Columns(2).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter.Columns(2).Width = 100 End With ' procedura poniższa będzie wykonywana wtedy, gdy zmienimy ' semestr lub zjazd pracując w trybie aktualizacji, wywołuje ' procedurę Pomoc

235 235 Private Sub rdbsemestr1_checkedchanged(byval sender As Object, _ ByVal e As System.EventArgs) _ Handles rdbsemestr1.checkedchanged, _ rdbzjazd1.checkedchanged, rdbzjazd2.checkedchanged, _ rdbzjazd3.checkedchanged, rdbzjazd4.checkedchanged, _ rdbzjazd5.checkedchanged If semestr <> UstalGrb(Me.grbSemestr) Or zjazd <> _ UstalGrb(Me.grbZjazd) Then semestr = UstalGrb(Me.grbSemestr) zjazd = UstalGrb(Me.grbZjazd) Pomoc() ' procedura poniższa będzie wykonywana wtedy, gdy skończymy ' edycję komórki gridu. Wprowadzona wartość punktów jest dzielona ' przez 100 w celu przejścia na procenty Private Sub dgvpunkty_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvpunkty.cellendedit With Me.dgvPunkty.Rows(e.RowIndex).ErrorText = String.Empty.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = _.Rows(e.RowIndex).Cells(e.ColumnIndex).Value / 100 End With ' procedura obsługuje walidację komórki gridu w celu sprawdzenia ' czy wprowadzona informacja (liczba punktów) jest poprawna Private Sub dgvpunkty_cellvalidating(byval sender As Object, _ ByVal e As System.Windows.Forms. _ DataGridViewCellValidatingEventArgs) Handles _ dgvpunkty.cellvalidating If Not flaga Then Exit Sub Dim t As String = e.formattedvalue ' usuwammy symbol % (jeżeli jest) If t.length > 1 AndAlso t.indexof("%") > 0 Then t = t.substring(0, t.length - 1) If e.columnindex = 2 Then If t = Nothing Then Me.dgvPunkty.Rows(e.RowIndex).ErrorText = _ "Proszę wprowadzić liczbę punktów" e.cancel = True Beep() ElseIf Not IsNumeric(t) Then Me.dgvPunkty.Rows(e.RowIndex).ErrorText = _ "Wprowadzone punkty nie są liczbą!" e.cancel = True Beep()

236 236 ElseIf CSng(t) < 0 Then Me.dgvPunkty.Rows(e.RowIndex).ErrorText = _ "Liczba punktów nie może być mniejsza od zera!" e.cancel = True Beep() ElseIf CSng(t) > 100 Then Me.dgvPunkty.Rows(e.RowIndex).ErrorText = _ "Liczba punktów nie może być większa od stu!" e.cancel = True Beep() ' procedura obsługuje zapis lub aktualizację wprowadzonych ' danych, wcześniej robiona jest dodatkowa walidacja Private Sub btnzapisz_click(byval sender As Object, ByVal e As _ System.EventArgs) Handles btnzapisz.click Dim kom As String = _ "Rejestracja wyników testów przedmiotowych" ' dodatkowe sprawdziany wyborów w polach kombo If CzyDobreCombo(Me.cboKierunek, _ "Proszę wybrać kierunek studiów", Me.ErrorProvider1, _ False) Then Exit Sub If CzyDobreCombo(Me.cboPracownik, _ "Proszę wybrać wykładowcę", _ Me.ErrorProvider1, False) Then Exit Sub If CzyDobreCombo(Me.cboPrzedmiot, _ "Proszę wybrać przedmiot", _ Me.ErrorProvider1, False) Then Exit Sub ' sprawdzamy, czy w gridzie są dane? If Me.dgvPunkty.Rows.Count = 0 Then ' nie ma, komunikat na ekran MsgBox("Brak danych do zapisania w bazie", _ MsgBoxStyle.Information, kom) Exit Sub Else ' sprawdzamy, czy są wystawione punkty Dim i As Integer z = True With Me.dgvPunkty For i = 0 To.Rows.Count - 1 If.Rows(i).Cells(2).Value = Nothing Then z = False Exit For Next End With If Not z Then

237 MsgBox("W wierszu " & (i + 1).ToString & _ " nie ma wpisanej liczby punktów, proszę poprawić!", _ MsgBoxStyle.Critical, kom) Exit Sub Dim w As ITesty w = New CRealizacja w.testyzapisz(strbaza, Me) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Wyniki testu zapisane w bazie", _ MsgBoxStyle.Information, kom) End Class 237

238 Rejestracja wyników testu przedmiotowego Poniżej widok instancji formularza frmrejestrtestowp w trakcie rejestracji wyników testu dla wybranego semestru, kierunku, wykładowcy i przedmiotu. Domyślnie w momencie wyboru kierunku studiów w kolumnie Punkty (w %) wstawiona zostało 75%, bo taka wartość jest wpisana w polu tesktowym Domyślna liczba punktów. W pokazanym momencie dla studenta Dentko Łukasz wprowadzana jest wartość 34,8, po zmianie komórki gridu zostanie zmieniony jej sposób wyświetlenia na 34,8%. Po wprowadzeniu wszystkich wyników (jeżeli ktoś nie pisał testu, to dostaje 0 punktów) klik przycisku Zapisz uruchamia procedurę zapisu wrowadzonych danych w bazie SQL.

239 239 Procedury walidacyjne zaimplementowane w formularzu frmrejestrtestowp dbają o to, aby nie można było zarejestrować niepoprawnych lub nie wprowadzonych wyników testu. Poniżej przykład takiej sytuacji. Zapis będzie możliwy tylko wtedy, gdy wprowadzimy dopuszczalne liczby punktów (od 0 do 100), w każdym innym przypadku spotkamy się ze stosownym komunikatem i oczekiwaniem na poprawienie błędu.

240 Edycja wyników testu przedmiotowego Formularz frmrejestrtestowp może także pracować w trybie edycji zarejestrowanych w bazie wyników testów przedmiotowych. Poniżej pokazana jest instancja tego formularza w trakcie edycji wyników testu z przedmiotu Logistyka w zarządzaniu zrealizowanym w semestrze 1 na zjeździe 1 przez wybranego wykładowcę.

241 Rejestracja testów semestralnych Projekt formularza frmrejestrtestus Formularz frmrejestrtestus został tak zaprojektowany, aby można go było wykorzystać zarówno do rejestracji jak i edycji wyników testów semestralnych. Na powierzchni formularza umieszczono następujące formanty: grbsemestr grupę opcji z dwoma przyciskami radiowymi o nazwach odpowiednio rdbsemestr1 i rdbsemestr2, będziemy je wykorzystywać do wskazania semestru zajęć; cbokierunek pole kombi przeznaczone do wskazania kierunku studiów; dgvpunkty formant typu DataGridView, w nim będziemy wyświetlać dane studentów i wprowadzać czy edytować wyniki testów; btnzapisz przycisk polecenia zapisujący czy aktualizujący wprowadzone dane;

242 242 txtdomyslnepkt pole tekstowe pozwalające na określenie domyślnej liczby punktów; txtktory ukryte pole tekstowe, będziemy je wykorzystywać do przechowania wskaźnika rodzaju testu semestralnego; txtpomoc ukryte pole tekstowe, będziemy je wykorzystywać do przechowania wskaźnika trybu pracy formularza (rejestracja czy edycja); ErrorProvider1 formant wykorzystywany do obsługi walidacji oraz etykiety opisujące niektóre z wymienionych formantów. Instancja formularza uruchamiana jest poprzez klik jednego z czterech poleceń w menu aplikacji. Klik jednego z tych poleceń uruchamia odpowiednią procedurę zdarzeniową spośród pokazanych niżej (utworzoną w module formularza frmmdistudia). Decyzja o pokazaniu instancji formularza czy nie podejmowana jest przez procedurę PokazForm, do niej też przekazywany jest tytuł okna formularza). Private Sub mnurejesttestup_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnurejesttestup.click Dim frm As New frmrejestrtestus frm.txtpomoc.text = "R" frm.txtktory.text = "P" Dim w As ITesty w = New CRealizacja w.przygotujtestysemestralne(strbaza, frm) PokazForm(frm, w.komunikat, _ "Rejestracja wstępnych wyników testu semestralnego") Private Sub mnurejestrtestuk_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnurejestrtestuk.click

243 243 Dim frm As New frmrejestrtestus frm.txtpomoc.text = "R" frm.txtktory.text = "K" Dim w As ITesty w = New CRealizacja w.przygotujtestysemestralne(strbaza, frm) PokazForm(frm, w.komunikat, _ "Rejestracja końcowych wyników testu semestralnego") Private Sub mnuaktualizacjatestup_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuaktualizacjatestup.click Dim frm As New frmrejestrtestus frm.txtpomoc.text = "A" frm.txtktory.text = "P" Dim w As ITesty w = New CRealizacja w.przygotujtestysemestralne(strbaza, frm) PokazForm(frm, w.komunikat, _ "Edycja wstępnych wyników testu semestralnego") Private Sub mnuaktualizacjatestuk_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuaktualizacjatestuk.click Dim frm As New frmrejestrtestus frm.txtpomoc.text = "A" frm.txtktory.text = "K" Dim w As ITesty w = New CRealizacja w.przygotujtestysemestralne(strbaza, frm) PokazForm(frm, w.komunikat, _ "Edycja końcowych wyników testu semestralnego")

244 Kod formularza frmrejestrtestus W klasie formularza utworzono kilka procedur obsługujących zdarzenia związane z funkcjonowaniem tego formularza. Ponież kod tych procedur wraz z niezbędnymi komentarzami. Public Class frmrejestrtestus ' zmienna x będzie określać wiersz gridu, w którym zaktualizowano ' komórkę z punkatami Dim z As Boolean, x() As Boolean ' procedura w zalezności od zadeklarowanego trybu pracy ' formularza ustawia właściwości kilku formantów Private Sub frmrejestrtestus_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load If Me.txtPomoc.Text = "R" Then Me.btnZapisz.Text = "Zapisz" Me.txtDomyslnePkt.Text = "0,75" Me.txtDomyslnePkt.Visible = True Me.lblPunkty.Visible = True ReDim x(2) Else Me.btnZapisz.Text = "Aktualizuj" Me.txtDomyslnePkt.Visible = False Me.lblPunkty.Visible = False ' procedura reagująca na zmianę kierunku studiów, jej zadaniem ' jest dostarczenie nowych danych do gridu Private Sub cbokierunek_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbokierunek.selectedvaluechanged If Not flaga Then Exit Sub ' badanie, czy jest domyślna liczba punktów i tryb rejestracji If Me.txtDomyslnePkt.Text = Nothing AndAlso _ Me.txtPomoc.Text = "R" Then ' nie ma, zapytanie użytkownika, czy tak ma być If MsgBox("Czy chcesz ustawić domyślą liczbę punktów?", _ MsgBoxStyle.YesNo, "Pytanie o domyślne punkty") = _ MsgBoxResult.Yes Then Exit Sub Dim w As ITesty, i As Integer w = New CRealizacja w.testysemestralnezmianakierunku(strbaza, _ UstalGrb(Me.grbSemestr), Me.cboKierunek.SelectedValue, _ Me.txtPomoc.Text, Me.txtKtory.Text)

245 245 If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else If Me.txtPomoc.Text = "R" Then ' przypisujemy rekordset z danymi do pomocniczej zmiennej Dim tb As DataTable = w.dajtabele ' do zmiennej tb dodajemy nową tabelę na punkty tb.columns.add(new DataColumn("Punkty", _ GetType(Decimal))) ' sprawdzenie, co jest w txtdomyslnepkt Dim xp As Decimal, t As String = Me.txtDomyslnePkt.Text If t.length > 1 AndAlso t.indexof("%") > 0 Then t = t.substring(0, t.length - 1) If t.length > 0 AndAlso IsNumeric(t) Then xp = CDec(t) / 100 Else xp = 0 For i = 0 To tb.rows.count - 1 tb.rows(i).item("punkty") = xp Next Else ' tryb edycji, ustalamy liczbę wierszy (studentów) Dim p As Integer = w.dajtabele.rows.count - 1 ' zmieniamy rozmiar zmiennej x i inicjujemy jej wartości ReDim x(p) For i = 0 To p x(i) = False Next ' przypisanie źródła danych do gridu i ustawienie jego ' właściwości With Me.dgvPunkty flaga = False.DataSource = w.dajtabele.columns(0).visible = False.Columns(1).Width = 200.Columns(1).ReadOnly = True.Columns(2).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter.AllowUserToAddRows = False.AllowUserToDeleteRows = False.Columns(2).DefaultCellStyle.Format = "##0.0%" flaga = True End With

246 246 ' procedura obsługująca zakończneie edycji komórki gridu, w tym ' zapisanie wprowadzonej liczby punktów jako procentów, a w ' trybie edycji ustawienie wartosci True na odpowiedniej pozycji ' w zmiennej tablicowej x Private Sub dgvpunkty_cellendedit(byval sender As Object, _ ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _ Handles dgvpunkty.cellendedit With Me.dgvPunkty.Rows(e.RowIndex).ErrorText = String.Empty.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = _.Rows(e.RowIndex).Cells(e.ColumnIndex).Value / 100 If Me.txtPomoc.Text = "A" Then If Not x(e.rowindex) Then x(e.rowindex) = True End With ' procedura obsługująca walidację komórki gridu, w tym Private Sub dgvpunkty_cellvalidating(byval sender As Object, _ ByVal e As System.Windows.Forms. _ DataGridViewCellValidatingEventArgs) Handles _ dgvpunkty.cellvalidating If Not flaga Then Exit Sub If e.columnindex = 2 Then Dim t As String = e.formattedvalue If t.length > 1 AndAlso t.indexof("%") > 0 Then t = t.substring(0, t.length - 1) If t = Nothing Then Me.dgvPunkty.Rows(e.RowIndex).ErrorText = _ "Proszę wprowadzić liczbę punktów" e.cancel = True Beep() ElseIf Not IsNumeric(t) Then Me.dgvPunkty.Rows(e.RowIndex).ErrorText = _ "Wprowadzone punkty nie są liczbą!" e.cancel = True Beep() ElseIf CSng(t) < 0 Then Me.dgvPunkty.Rows(e.RowIndex).ErrorText = _ "Liczba punktów nie może być mniejsza od zera!" e.cancel = True Beep() ElseIf CSng(t) > 100 Then Me.dgvPunkty.Rows(e.RowIndex).ErrorText = _ "Liczba punktów nie może być większa od stu!" e.cancel = True Beep()

247 247 ' procedura obsługująca końcową walidację i zapis danych Private Sub btnzapisz_click(byval sender As Object, _ ByVal e As System.EventArgs) Handles btnzapisz.click Dim kom As String = "Rejestracja wyników testów semestralnych" If CzyDobreCombo(Me.cboKierunek, _ "Proszę wybrać kierunek studiów", Me.ErrorProvider1, _ False) Then Exit Sub If Me.dgvPunkty.Rows.Count = 0 Then MsgBox("Brak danych do zapisania w bazie", _ MsgBoxStyle.Information, kom) Exit Sub Else ' sprawdzamy, czy są wystawione punkty Dim i As Integer z = True With Me.dgvPunkty For i = 0 To.Rows.Count - 1 If.Rows(i).Cells(2).Value = Nothing Then z = False Exit For Next End With If Not z Then MsgBox("W wierszu " & (i + 1).ToString & _ " nie ma wpisanej liczby punktów, proszę poprawić!", _ MsgBoxStyle.Critical, kom) Exit Sub ' zapisujemy Dim w As ITesty w = New CRealizacja w.testysemestralnezapiszaktualizuj(strbaza, Me, x) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else MsgBox("Wyniki testu zapisane w bazie", _ MsgBoxStyle.Information, kom) Me.dgvPunkty.DataSource = Nothing End Class

248 Rejestrowanie wyników testu semestralnego Poniżej widok instancji tego formularza w trakcie edycji wyników wstępnego testu semestralnego dla wybranego kierunku. Po otwarciu formularza zmieniono domyślną liczbę punktów z 75 na 55 (jako dominującą w interesującym nas teście). W przypadku wprowadzenia znaków, które nie reprezentują liczby z przedziału od 0 do 100 zostanie zgłoszony błąd i musimy go poprawić, aby przejść do kolejnej komórki gridu. Przykład takiej sytuacji pokazany jest poniżej. Powiedzmy, że usunęliśmy błąd wprowadzając np. liczbę zero (zamiast 20), co da nam okazję do pokazania edycji zapisanych wyników testu.

249 249 Próba ponownego zapisania w bazie danych wyników testu semestralnego kończy się zgłoszeniem stosownego komunikatu.

250 Aktualizowanie wyników testu semestralnego Tym razem formularz pracuje w trybie edycji wyników testu wstępnego. Po wyborze tego samego kierunku co w przykładzie rejestrowania mamy w gridzie wyniki tego testu. Myszą wskazana jest komórka z zerową liczbą punktów (przykładowa, celowa pomyłka, miało być 20 punktów), możemy teraz skorygować te punkty na właściwe. Klik przycisku Aktualizuj uruchamia procedurę zmieniającą wskazany rekord w bazie danych.

251 Zgłoszenie szkoleń Projekt formularza frmzgloszenieszkolen Formularz frmzgloszenieszkolen jest stosunkowo skromny, na jego powierzchni umieszczono dwa zestawy przycisków radiwych i przycisk polecenia. Nazwy formantów i ich przeznaczenie są następujące: grbsemestr grupa opcji z dwoma przyciskami radiowymi o nazwach odpowiednio rdbsemestr1 i rdbsemestr2, będziemy tu mogli wybrać semestr studiów; grbzjazd grupa opcji z sześcioma przyciskami radiowymi o nazwach od rdbzjazd1 do rdbzjazd6, będziemy tu wybierać zjazd szkoleniowy; btnprzygotuj przycisk polecenia uruchamiający proces przygotowania dokumentów MS Word; strstatus formant typu StatusStrip w wersji StatusLabel, będziemy tu wyświetlać komunikat aplikacji w trakcie przygotowywania zgłoszeń. Instancja tego formularza będzie tworzona po wyborze w menu aplikacji odpowiedniego polecenia (Realizacja zajęć/zgłoszenie szkoleń), co spowoduje uruchomienie pokaznej niżej procedury (z klasy formularza frmmdistudia). Private Sub mnuzgloszenieszkolen_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuzgloszenieszkolen.click Dim frm As New frmzgloszenieszkolen frm.mdiparent = Me frm.show()

252 Kod formularza frmzgloszenieszkolen Formularz frmzgloszenieszkolen wymaga jeszcze dość skomplikowanych procedur i funkcji, ich zadaniem będzie otwarcie aplikacji MS Word i przygotowanie dokumentów zgłoszenia szkoleń. Z uwagi na zamiar wykorzystywania aplikacji MS Word musi skorzystać dodać do naszego rozwiązania referencję do tej aplikacji. Poniżej pokazane jest okno dialogowe dodawania referencji, aktywna jest zakładka COM i wskazany jest komponent Microsoft Word 11.0 Object Library. Po akceptacji możemy przystąpić do tworzenia kodu. Zaczynamy od dopisania na początku kodu poleceń importu niezbędnych (dla wykorzystania MS Word) przestrzeni nazw. Imports System.Runtime.InteropServices Imports Microsoft.Office.Interop.Word Public Class frmzgloszenieszkolen ' procedura zdarzenia Load zaznacza, za pośrednictwem publicznej ' procedury z modułu PARP potrzebne przyciski radiowe, modyfikuje ' tekst w linii statusu formularza Private Sub frmzgloszenieszkolen_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ZaznaczRdb(Me.rdbSemestr1) ZaznaczRdb(Me.rdbZjazd1) Me.strStatus.Text = "Przygotowanie zgłoszeń szkoleń"

253 253 ' procedura zdarzenia Click przycisku polecenia uruchamia ' proces przygotowania zgłoszeń Private Sub btnprzygotuj_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnprzygotuj.click ' deklaracja pomocniczych zmiennych Dim dtterminy, dtkierunki, dttematy As DataTable, _ idt, i, j As Integer Dim w As ISzkolenia w = New CRealizacja w.przygotujterminykierunki(strbaza, UstalGrb(Me.grbSemestr), _ UstalGrb(Me.grbZjazd)) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' mamy już dane o termianch i kierunkach Try Me.strStatus.Text = _ "Trwa przygotowanie zgłoszeń szkoleń, czekaj..." ' otwieramy instancję MS WOrd Dim word As New Microsoft.Office.Interop.Word.Application ' deklarujemy dokument MS Word Dim doc As Microsoft.Office.Interop.Word.Document ' deklarujemy pomocnicze obiekty dokumentu Dim range As Microsoft.Office.Interop.Word.Range Dim wtable As Microsoft.Office.Interop.Word.Table ' do prywatnych zmiennych klasy przypisujemy potrzebne ' dane zwrócone przez właściwości obiektu w dtterminy = w.dajtabele dtkierunki = w.dajtabele2 ' w pętli przeglądamy kierunki studiów For i = 0 To dtkierunki.rows.count - 1 ' dla danego kierunku pobieramy listę tematow ' skorzystamy z istniejącej instacji klasy CRealizacja w.przygotujtematy(strbaza, dtterminy.rows(0).item(0), _ dtkierunki.rows(i).item(0)) ' sprawdzamy, czy wykaz tematów jest pobrany? If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' tak, przepisujemy go do zmiennej dttematy dttematy = w.dajtabele ' mamy tematy, tworzymy dokument worda wykorzystując ' szablon dokumentu z folderu wskazanego zmienną ' FolderParp doc = word.documents.add(folderparp & _ "HarmonogramNew.dot") ' szukamy zakładek i wstawiamy na ich miejsce tekst range = doc.bookmarks.item("kierunek").range range.text = dtkierunki.rows(i).item(1)

254 254 range = doc.bookmarks.item("terminp").range range.text = dtterminy.rows(0).item(1) range = doc.bookmarks.item("termink").range range.text = dtterminy.rows(1).item(1) range = doc.bookmarks.item("iles").range range.text = dtkierunki.rows(i).item(2) ' trzeba teraz wypisać tematy zajęć, wstawiamy ' tabelę o tylu wierszach (+2) ile jest tematów ' i trzech kolumnach, robimy to na końcu dokumentu wtable = doc.tables.add(doc.bookmarks.item( _ "\endofdoc").range, dttematy.rows.count + 2, 3) With wtable.range.paragraphformat.spacebefore = 3.Range.ParagraphFormat.SpaceAfter = 3.Borders.InsideLineStyle = _ Microsoft.Office.Interop.Word. _ WdLineStyle.wdLineStyleSingle.Borders.OutsideLineStyle = _ Microsoft.Office.Interop.Word. _ WdLineStyle.wdLineStyleSingle ' szerokości kolumn.columns.item(1).width = _ word.centimeterstopoints(3).columns.item(2).width = _ word.centimeterstopoints(11).columns.item(3).width = _ word.centimeterstopoints(4) ' teksty tytułu.cell(1, 1).Range.Text = _ "Data realiazacji szkolenia".cell(1, 2).Range.Text = "Przedmiot/Temat".Cell(1, 3).Range.Text = _ "Godziny realizacji szkolenia" ' tworzymy listę tematów For j = 0 To dttematy.rows.count - 1.Cell(j + 2, 1).Range.Text = _ dttematy.rows(j).item(0).cell(j + 2, 2).Range.Text = _ dttematy.rows(j).item(1).cell(j + 2, 3).Range.Text = _ dttematy.rows(j).item(2) Next ' podsumowanie.cell(dttematy.rows.count + 2, 1).Range.Text = _ "Razem godzin".cell(dttematy.rows.count + 2, 3).Range.Text = _ "16" ' bold tytułu i podsumowania.rows.item(1).range.font.bold = True

255 255.Rows.Item(dtTematy.Rows.Count + _ 2).Range.Font.Bold = True End With doc.saveas(folderparp & _ Trim(dtKierunki.Rows(i).Item(3)) & _ "_S" & UstalGrb(Me.grbSemestr).ToString & _ "Z" & UstalGrb(Me.grbZjazd).ToString & ".doc") doc.close(true) Next word.quit() MsgBox("Dokumenty zgłoszenia szkoleń przygotowane", _ MsgBoxStyle.Information, "Zgłoszenie szkoleń") Catch ex As Exception MsgBox("Mam problem z otwarciem dokumentu Worda", _ MsgBoxStyle.Critical, conmsgerr) Finally Me.strStatus.Text = "Przygotowanie zgłoszeń szkoleń" End Try End Class Poniżej widok instancji formularza frmzgloszenieszkolen, wybrany jest semestr 1 i zjazd 6, za chwilę naciśniemy przycisk Przygotuj, co uruchomi proces przygotowania dokumentów MS Word. Po zakończeniu prac procedura wyświetla sosowny komunikat. Po jego zamknięciu możemy przygotować zgłoszenia szkoleń dla kolejnego zjazdu albo po prostu zamknąć formularz.

256 256 W folderze wskazanym zmienną FolderParp znajdziemy utworzone dokumenty. A tak wygląda jeden z nich otwarty w MS Word.

257 6.13. Rejestracja wyników ankiet Formularz frmankieta 257 Projekt formularza przeznaczonego do rejestracji wyników ankiet przedmiotowych jest jednym z bardziej złożonych w naszej aplikacji. Instancja tego formularza wyświetlana jest po wyborze w menu aplikacji pokaznego niżej polecenia.

258 258 Jego klik uruchamia procedurę zdarzeniową, która tworzy instancję formularza frmankieta, a następnie instancję klasy CRealizacja deklarowaną interfejsem IDaneAnkiet, co pozwala na wywołanie metody PrzygotujDaneAnkiet. Procedura PokazForm odpowiada za ostateczne pokazanie instancji formularza (jeżeli pomyślnie pobrano potrzebne dane). Private Sub mnurejestracjaankiet_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnurejestracjaankiet.click Dim frm As New frmankieta Dim w As IDaneAnkiet w = New CRealizacja w.przygotujdaneankiet(strbaza, frm) PokazForm(frm, w.komunikat) Kod formularza frmankieta W kodzie formularza utworzono szereg procedur reagujących na zdarzenia związane z jego funkcjonowaniem. Public Class frmankieta Dim f As Boolean = False, x(10) As Integer, z(5) As Integer, _ h As Boolean ' procedura obsługuje zdarzenie podwójnego kliku formantów ' typu GroupBox wywołując procedurę ZdejmijZaznaczenie celem ' jest doprowadzene do takiej sytuacji, w której w danym ' konterzerze żaden z przycisków radikowych nie jest zaznaczony Private Sub grbpyt1_doubleclick(byval sender As Object, _ ByVal e As System.EventArgs) Handles grbpyt1.doubleclick, _ grbpyt2.doubleclick, grbpyt3.doubleclick, _ grbpyt4.doubleclick, grbpyt5.doubleclick, _ grbpyt6.doubleclick, grbpyt7.doubleclick, _ grbpyt8.doubleclick, grbpyt9.doubleclick, _ grbpyt10.doubleclick ZdejmijZaznaczenieGrb(sender) ' procedura obsługuje zdarzenie zmiany kierunku studiów, ' aktualizuje listę pracowników Private Sub cbokierunek_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbokierunek.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IDaneAnkiet w = New CRealizacja w.daneankietzmianakierunku(strbaza, _ Me.cboKierunek.SelectedValue)

259 259 UstawComboBox(Me.cboPracownik, w.dajtabele, "Kto", _ "id_w", w.komunikat) ' procedura obsługuje zdarzenie zmiany wykładowcy, aktualizuje ' listę przedmiotów zależnie od kierunku i wykładowcy Private Sub cbopracownik_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbopracownik.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IDaneAnkiet w = New CRealizacja w.daneankietzmianawykladowcy(strbaza, _ Me.cboPracownik.SelectedValue, Me.cboKierunek.SelectedValue) UstawComboBox(Me.cboPrzedmiot, w.dajtabele, "Przedmiot", _ "id_p", w.komunikat) ' procedura obsługuje zdarzenie zmiany przedmiotu, aktualizuje ' komunikat w linii stanu formularza oraz ustawia domyślnie ' zaznaczenia w pytaniach Private Sub cboprzedmiot_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cboprzedmiot.selectedvaluechanged If Not flaga Then Exit Sub Me.strAnkieta.Text = "Możesz wprowadzać wyniki ankiety" UstawDomyslnieRdb() ' procedura ustawia domyślnie zaznaczenia odpowiedzi w pytaniach ' ankiety, podane pozycje są przykładowe Private Sub UstawDomyslnieRdb() With Me ZaznaczRdb(.rdbP1_5) ZaznaczRdb(.rdbP2_5) ZaznaczRdb(.rdbP3_5) ZaznaczRdb(.rdbP4_5) ZaznaczRdb(.rdbP5_5) ZaznaczRdb(.rdbP6_5) ZaznaczRdb(.rdbP7_4) ZaznaczRdb(.rdbP8_1) ZaznaczRdb(.rdbP9_1) ZaznaczRdb(.rdbP10_1) End With ' procedura obsługuje zdarzenie zmiany zaznaczenia w którymś, ' z pytań, celem jest zmiana komunikatu w lini stanu formularza

260 260 Private Sub grbpyt_validated(byval sender As Object, ByVal e As _ System.EventArgs) Handles grbpyt1.validated, _ grbpyt2.validated, grbpyt3.validated, grbpyt4.validated, _ grbpyt5.validated, grbpyt6.validated, grbpyt7.validated, _ grbpyt8.validated, grbpyt9.validated, grbpyt10.validated If Not f Then f = True Me.strAnkieta.Text = "W trakcie wprowadzania wyników..." ' procedura obsługuje zdarzenie validacji cbokierunek Private Sub cbokierunek_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles cbokierunek.validating h = CzyDobreCombo(Me.cboKierunek, _ "Proszę wybrać kierunek!", Me.ErrorProvider1, True) ' procedura obsługuje zdarzenie validacji cbopracownik Private Sub cbopracownik_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles cbopracownik.validating h = CzyDobreCombo(Me.cboPracownik, _ "Proszę wybrać wykładowcę!", Me.ErrorProvider1, True) ' procedura obsługuje zdarzenie validacji cboprzedmiot Private Sub cboprzedmiot_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) _ Handles cboprzedmiot.validating h = CzyDobreCombo(Me.cboPrzedmiot, _ "Proszę wybrać przedmiot!", Me.ErrorProvider1, True) ' procedura obsługuje zdarzenie zapisu danych, najpierw jest ' przeprowadzana dodatkowa walidacja, później przygotowanie ' dwóch zmiennych tablicowych i skorzystanie z klasy CRealizacja Private Sub btnzapisz_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnzapisz.click If CzyDobreCombo(Me.cboKierunek, _ "Proszę wybrać kierunek!", Me.ErrorProvider1) Then Exit Sub If CzyDobreCombo(Me.cboPracownik, _ "Proszę wybrać wykładowcę!", Me.ErrorProvider1) _ Then Exit Sub If CzyDobreCombo(Me.cboPrzedmiot, _ "Proszę wybrać przedmiot!", Me.ErrorProvider1) Then Exit Sub ' wszystko OK, szykujemy zapis z(1) = UstalGrb(Me.grbSemestr) z(2) = UstalGrb(Me.grbZjazd)

261 261 z(3) = Me.cboKierunek.SelectedValue z(4) = Me.cboPracownik.SelectedValue z(5) = Me.cboPrzedmiot.SelectedValue ' teraz wartości pytań do zmiennej x x(1) = UstalGrb(Me.grbPyt1) x(2) = UstalGrb(Me.grbPyt2) x(3) = UstalGrb(Me.grbPyt3) x(4) = UstalGrb(Me.grbPyt4) x(5) = UstalGrb(Me.grbPyt5) x(6) = UstalGrb(Me.grbPyt6) x(7) = UstalGrb(Me.grbPyt7) x(8) = UstalGrb(Me.grbPyt8) x(9) = UstalGrb(Me.grbPyt9) x(10) = UstalGrb(Me.grbPyt10) ' tworzymy instancję klasy i wywołujemy odpowiednią metodę Dim w As IDaneAnkiet w = New CRealizacja w.zapiszdaneankiety(strbaza, z, x, Me.txtUwagi.Text) ' badanie, czy operacja zapisu zakończona sukcesem If w.komunikat.length > 0 Then ' nie, komunikat na ekran MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' tak, przygotowanie formularza do rejestracji wyników ' koeljnej ankiety Me.strAnkieta.Text = "Możesz wprowadzać wyniki ankiety" Me.txtUwagi.Text = Nothing f = False UstawDomyslnieRdb() End Class Na kolejnej stronie pokazany jest widok instancji formularza frmankieta w trakcie wprowadzania wyników ankiet dla wybranego wykładowcy i przedmiotu realizowanego na wybranym zjeździe i semestrze.

262 262 Klik przycisku Zapisz uruchamia wstawienie nowego rekordu do tabeli Dane, poniżej widok tego rekordu.

263 7. Raporty 263 Rozdział ten jest poświęcony przygotowaniu różnorodnych raportów przedstawiających odpowiednio uporządkowaną informację pobraną z tabel bazy danych. Do prezentacji takich zestawień będziemy stosować albo klasyczne raporty budowane w module CrystalReports, albo będziemy korzystać z formantów typu DataGridView. Obojętnie z jakiego rozwiązania skorzystamy, to zawsze punktem wyjścia do konstrukcji raportu będzie procedura przechowywana, które pobierze z tabel potrzebne dane. Poniżej kody większości z tych procedur, zostały one pogrupowane wg interfejsów, w których są wykorzystywane Procedury przechowywane Wykorzystane w IRaportyObecnosci Procedura pkierunkidoobecnosci zwraca listę tych kierunków z aktywnej edycji, dla których zostały zarejestrowane obecności studentów. create procedure int as from dbo.edycjestudiow where StatusE=2 select distinct Kierunki.id_k, Kierunki.Kierunek from ObecnosciNew INNER JOIN Terminy on ObecnosciNew.idt = Terminy.idt INNER JOIN EdycjeKierunki on Terminy.ide = EdycjeKierunki.id_e INNER JOIN Kierunki on EdycjeKierunki.id_k = Kierunki.id_k where Terminy.ide order by Kierunki.Kierunek Procedura psemestrydoraportuobecnosci odpowiada za zwrócenie tych semestrow aktywnej edycji studiów, dla których zarejestrowano obecności studentów. create procedure int as int from dbo.edycjestudiow where StatusE=2 select distinct Terminy.semestr from ObecnosciNew INNER JOIN Terminy on ObecnosciNew.idt = Terminy.idt INNER JOIN EdycjeKierunki on Terminy.ide = EdycjeKierunki.id_e where Terminy.ide AND EdycjeKierunki.id_k Procedura pdajgodzinyobecnosci zwraca listę studentów wskazanego kierunku rozpoznawanych ich nazwiskiem lub numerem Pesel wraz ze spocjalnie

264 264 skonstruowanym polem zwracającym numer zjazdu i pierwszą literę dnia szkoleniowego wraz z liczbą godzin szkoleniowych, w których uczestniczył dany student. create procedure int as int from dbo.edycjestudiow where StatusE=2 begin select Studenci.Pesel,'Z'+cast(Terminy.zjazd as nvarchar(1)) + case when datepart(dw,terminy.termin)=7 then 'S' else 'N' end as ZjazdDzien, ObecnosciNew.Godzin from ObecnosciNew INNER JOIN Terminy ON ObecnosciNew.idt = Terminy.idt INNER JOIN Studenci ON ObecnosciNew.ids = Studenci.ids where Studenci.idk AND Terminy.ide AND Terminy.semestr order by Studenci.Pesel, Terminy.zjazd, ZjazdDzien desc end else begin select Studenci.Nazwisko+' '+Studenci.Imie as Kto, 'Z'+cast(Terminy.zjazd as nvarchar(1)) + case when datepart(dw,terminy.termin)=7 then 'S' else 'N' end as ZjazdDzien, ObecnosciNew.Godzin from ObecnosciNew INNER JOIN Terminy ON ObecnosciNew.idt = Terminy.idt INNER JOIN Studenci ON ObecnosciNew.ids = Studenci.ids where Studenci.idk AND Terminy.ide AND Terminy.semestr order by Kto, Terminy.zjazd, ZjazdDzien desc end Wykorzystane w IRaportyTestow Procedura pkierunkidoobecnosci była już wcześniej prezentowana (zobacz rozdział Wykorzystane w IObecnosci). Procedura pdajraporttestup odpowiada za pobranie z bazy danych średnich testów przedmiotowych pogrupowanych wg studentów i zjazdów.

265 265 create procedure int as select Studenci.Nazwisko + N' ' + Studenci.Imie AS kto, 'Z'+cast(Terminy.zjazd as nvarchar(1)) as Zjazd, AVG(WynikiTestuC.punkty) AS AvgPunkty from WynikiTestuC INNER JOIN Terminy ON WynikiTestuC.idt = Terminy.idt INNER JOIN Studenci ON WynikiTestuC.ids = Studenci.ids where Studenci.idk AND Terminy.semestr AND Terminy.ide group by Studenci.Nazwisko + N' ' + Studenci.Imie, Terminy.zjazd order by kto Procedura poniższa odpowiada za zwrócenie listy tych kierunków studiów, dla których w bazie danych są zarejestrowane zarówno wyniki testów semestralnych wstępnych jak i końcowych, czyli te, dla których będzie można wyznaczyć przyrost wiedzy. Zestawienie robione jest dla wskazanego semestru. create procedure int as select distinct Kierunki.id_k, Kierunki.Kierunek from TestySemestralne INNER JOIN Studenci ON TestySemestralne.ids = Studenci.ids INNER JOIN Kierunki ON Studenci.idk = Kierunki.id_k where TestySemestralne.semestr AND TestySemestralne.jakiTest = 1 and Kierunki.id_k in ( select distinct Studenci.idk from TestySemestralne INNER JOIN Studenci ON TestySemestralne.ids = Studenci.ids where TestySemestralne.jakiTest = 2 and ) order by Kierunki.Kierunek Wykorzystane w IRaportyAnkiet Zadaniem procedury pdaneankietzjazdkierunek będzie zwrócenie rekordsetu zawierającego średnie z pól przechowujących odpowiedzi na poszczególne dziesieć pytań z grupowaniem po kierunku studiów i zjeździe. W zależności od wartości (klucz edycji studiów) (semestr zajęć) wykonywana jest jedna z czterech wersji zapytania. Przed wykonaniem funkcji agregatującej AVG zawartość danego pola z oceną pytania (typu Integer) jest mnożona przez wielkość 1.0 w celu wymuszenia zapisania średniej jako liczby typu Decimal. Gdyby nie to mnożenie, to funkcja AVG zwracałaby wynik jako liczbę całkowitą.

266 266 create procedure int as begin select Dane.Zjazd as Zjazd, Kierunki.SkrotK as Kierunek, AVG(Dane.P1 *1.0) AS Pyt1, avg(dane.p2*1.0) as Pyt2, avg(dane.p3*1.0) as Pyt3, avg(dane.p4*1.0) as Pyt4, avg(dane.p5*1.0) as Pyt5, avg(dane.p6*1.0) as Pyt6, avg(dane.p7*1.0) as Pyt7, avg(dane.p8*1.0) as Pyt8, avg(dane.p9*1.0) as Pyt9, avg(dane.p10*1.0) as Pyt10 from Dane INNER JOIN Kierunki ON Dane.id_k = Kierunki.id_k where group by Dane.Zjazd, Kierunki.SkrotK end else begin select Dane.Zjazd as Zjazd, Kierunki.SkrotK as Kierunek, AVG(Dane.P1 *1.0) AS Pyt1, avg(dane.p2*1.0) as Pyt2, avg(dane.p3*1.0) as Pyt3, avg(dane.p4*1.0) as Pyt4, avg(dane.p5*1.0) as Pyt5, avg(dane.p6*1.0) as Pyt6, avg(dane.p7*1.0) as Pyt7, avg(dane.p8*1.0) as Pyt8, avg(dane.p9*1.0) as Pyt9, avg(dane.p10*1.0) as Pyt10 from Dane INNER JOIN Kierunki ON Dane.id_k = Kierunki.id_k where group by Dane.Zjazd, Kierunki.SkrotK end else begin select Dane.Zjazd as Zjazd, Kierunki.SkrotK as Kierunek, AVG(Dane.P1 *1.0) AS Pyt1, avg(dane.p2*1.0) as Pyt2, avg(dane.p3*1.0) as Pyt3, avg(dane.p4*1.0) as Pyt4, avg(dane.p5*1.0) as Pyt5, avg(dane.p6*1.0) as Pyt6, avg(dane.p7*1.0) as Pyt7, avg(dane.p8*1.0) as Pyt8, avg(dane.p9*1.0) as Pyt9, avg(dane.p10*1.0) as Pyt10 from Dane INNER JOIN Kierunki ON Dane.id_k = Kierunki.id_k where and group by Dane.Zjazd, Kierunki.SkrotK end else begin select Dane.Zjazd as Zjazd, Kierunki.SkrotK as Kierunek, AVG(Dane.P1 *1.0) AS Pyt1, avg(dane.p2*1.0) as Pyt2, avg(dane.p3*1.0) as Pyt3, avg(dane.p4*1.0) as Pyt4, avg(dane.p5*1.0) as Pyt5, avg(dane.p6*1.0) as Pyt6, avg(dane.p7*1.0) as Pyt7, avg(dane.p8*1.0) as Pyt8,

267 267 avg(dane.p9*1.0) as Pyt9, avg(dane.p10*1.0) as Pyt10 from Dane INNER JOIN Kierunki ON Dane.id_k = Kierunki.id_k group by Dane.Zjazd, Kierunki.SkrotK end Z uwagi na to, że będziemy chcieli stworzyć możliwość zmiany edycji studiów podyplomowych będziemy jeszcze potrzebować danych do wyświetlenia w polu kombo, przy czym chcemy mieć możliwość umieszczenia w polu kombo pozycji (wszystkie) jako oznaczenie wszystkich możliwych edycji. Procedura przechowywana będzie musiała zwrócić tylko te edycje studiów podyplomowych, dla których są dane w tabeli Dane. Tak sformułowane zadanie realizuje pokazana niżej procedura przechowywana. Jej jest tzw. ślepym parametrem, jest potrzebny jedynie z uwagi na konstrukcję procedur w klasie CForStorageSub. create procedure int as select distinct EdycjeStudiow.id_e, EdycjeStudiow.NazwaEdycji from Dane INNER JOIN EdycjeStudiow ON Dane.id_e = EdycjeStudiow.id_e union select 0, '(wszystkie)' order by id_e Jak widzimy jest to procedura składająca (dyrektywa Union), która w pierwszym selekcie wybiera unikalne (klauzaula Distinct) identyfikatory edycji studiów i ich nazwy z tabeli EdycjeStudiow, którą wiąże z tabelą Dane poprzez pole id_e. Drugi człon tego zapytania składającego dodaje do wyników pierwszego stałe fragmenty, czyli 0 jako identyfikator edycji (wszystkich) i słowny komentarz. Całość jest sortowana rosnąco po polu id_e, dzięki czemu pozycja (wszystkie) będzie jako pierwsza w polu kombo. Procedura pdaneankietzjazdpracownicy pobierająca dane do raportu wyników ankiet wg wykładowców i zjazdów i jest praktycznie analogiczna do procedury pdaneankietzjazdkierunek. Proszę zwrócić uwagę, że pole SkrotW z tabeli Pracownicy będzie prezentowane w rekordsecie jako Kierunek, co wynika z konieczności zachowania takich samych nazw zwracanych pól, jeżeli chcemy wykorzystać ten sam szablon raportu. create procedure int as begin select Dane.Zjazd as Zjazd, Pracownicy.SkrotW as Kierunek, AVG(Dane.P1 *1.0) AS Pyt1, avg(dane.p2*1.0) as Pyt2,

268 268 avg(dane.p3*1.0) as Pyt3, avg(dane.p4*1.0) as Pyt4, avg(dane.p5*1.0) as Pyt5, avg(dane.p6*1.0) as Pyt6, avg(dane.p7*1.0) as Pyt7, avg(dane.p8*1.0) as Pyt8, avg(dane.p9*1.0) as Pyt9, avg(dane.p10*1.0) as Pyt10 from Dane INNER JOIN Pracownicy ON Dane.id_w = Pracownicy.id_w where group by Dane.Zjazd, Pracownicy.SkrotW order by Dane.Zjazd, Pracownicy.SkrotW end else begin select Dane.Zjazd as Zjazd, Pracownicy.SkrotW as Kierunek, AVG(Dane.P1 *1.0) AS Pyt1, avg(dane.p2*1.0) as Pyt2, avg(dane.p3*1.0) as Pyt3, avg(dane.p4*1.0) as Pyt4, avg(dane.p5*1.0) as Pyt5, avg(dane.p6*1.0) as Pyt6, avg(dane.p7*1.0) as Pyt7, avg(dane.p8*1.0) as Pyt8, avg(dane.p9*1.0) as Pyt9, avg(dane.p10*1.0) as Pyt10 from Dane INNER JOIN Pracownicy ON Dane.id_w = Pracownicy.id_w where group by Dane.Zjazd, Pracownicy.SkrotW order by Dane.Zjazd, Pracownicy.SkrotW end else begin select Dane.Zjazd as Zjazd, Pracownicy.SkrotW as Kierunek, AVG(Dane.P1 *1.0) AS Pyt1, avg(dane.p2*1.0) as Pyt2, avg(dane.p3*1.0) as Pyt3, avg(dane.p4*1.0) as Pyt4, avg(dane.p5*1.0) as Pyt5, avg(dane.p6*1.0) as Pyt6, avg(dane.p7*1.0) as Pyt7, avg(dane.p8*1.0) as Pyt8, avg(dane.p9*1.0) as Pyt9, avg(dane.p10*1.0) as Pyt10 from Dane INNER JOIN Pracownicy ON Dane.id_w = Pracownicy.id_w where and group by Dane.Zjazd, Pracownicy.SkrotW order by Dane.Zjazd, Pracownicy.SkrotW end else begin select Dane.Zjazd as Zjazd, Pracownicy.SkrotW as Kierunek, AVG(Dane.P1 *1.0) AS Pyt1, avg(dane.p2*1.0) as Pyt2, avg(dane.p3*1.0) as Pyt3, avg(dane.p4*1.0) as Pyt4, avg(dane.p5*1.0) as Pyt5, avg(dane.p6*1.0) as Pyt6, avg(dane.p7*1.0) as Pyt7, avg(dane.p8*1.0) as Pyt8,

269 269 avg(dane.p9*1.0) as Pyt9, avg(dane.p10*1.0) as Pyt10 from Dane INNER JOIN Pracownicy ON Dane.id_w = Pracownicy.id_w Group by Dane.Zjazd, Pracownicy.SkrotW order by Dane.Zjazd, Pracownicy.SkrotW end W bazie danych utworzono jeszcze dwie podobne procedury, pierwsza z nich o nazwie pdaneankietprzedmiotyzjazdy zwraca wyniki, które wykorzystamy do prezentacji średnich z ankiet wg przedmiotów i zjazdów, a procedura o nazwie pdaneankietprzedmiotypracownicy dostarczy danych do raportu wg wykładowców i przedmiotów.

270 Wykorzystane w IWzorceAnkiet Procedura poniższa dostarcza identyfikator aktualnej edycji studiów. create procedure int out as from dbo.edycjestudiow where StatusE=2 Procedura pustaltermin zwraca rekordset zawierający terminy realizacji zajęć określonego zjazdu, semestru i edycji studiów. create procedure int as select Termin from Terminy where and and Procedura pwykazktocokiedy zwraca dla podanych argumentów rekordset zawierający nazwę kierunku studiów, stopień naukowy i nazwisko wykładowcy, nazwę przedmiotu i termin realizacji zajęć. create procedure nvarchar(100) as select distinct Kierunki.Kierunek, Pracownicy.Tytul + ' '+ Pracownicy.Wykladowca as kto, as Termin from PlanZajec INNER JOIN Terminy ON PlanZajec.idt = Terminy.idt INNER JOIN Pracownicy ON PlanZajec.idw = Pracownicy.id_w INNER JOIN Przedmioty ON PlanZajec.idp = Przedmioty.id_p INNER JOIN Kierunki ON PlanZajec.idk = Kierunki.id_k where and and

271 Klasa CRaporty Interfejs IRaportyObecnosci W tym interfejsie zapowiedziano te właściwości i metody, które będziemy wykorzystywać w przygotowaniu raportów obecności. Public Interface IRaportObecnosci Function Komunikat() As String Function DajTabele() As DataTable Sub PrzygotujRaportObecnosci(ByVal strconn As String, _ ByVal frm As frmprzygotujraportobecnosci) Sub ZmianaKierunkuObecnosci(ByVal strconn As String, _ ByVal idk As Integer) Sub DaneRaportuObecnosci(ByVal strconn As String, ByVal frm As _ frmraportobecnosci, ByVal fr As frmprzygotujraportobecnosci) End Interface Metoda PrzygotujRaportObecnosci odpowiada za zbudowanie źródła danych dla pola kombo wyświetlającego listę kierunków, dla których może być przygotowany raport obecności. Public Sub PrzygotujRaportObecnosci(ByVal strconn As String, _ ByVal frm As frmprzygotujraportobecnosci) Implements _ IRaportObecnosci.PrzygotujRaportObecnosci Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pkierunkidoobecnosci", 1, 1, 0) UstawComboBox(frm.cboKierunki, mtable1, "Kierunek", "id_k") ZaznaczRdb(frm.rdbPesel1) ZaznaczRdb(frm.rdbS_1) Catch ex As Exception mkomunikat = "Błąd pobrania kierunków do raportu obecności" Finally conn.close() conn = Nothing End Try Metoda ZmianaKierunkuObecnosci odpowiada za uaktualnienie listy semestrów, dla których zarejestrowano obecności (dla wskazanego kierunku). Public Sub ZmianaKierunkuObecnosci(ByVal strconn As String, _ ByVal idk As Integer) Implements _ IRaportObecnosci.ZmianaKierunkuObecnosci Dim conn As New SqlConnection(strconn) Try

272 272 conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.psemestrydoraportuobecnosci", idk, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania semestrów do raportu obecności" Finally conn.close() conn = Nothing End Try Metoda DaneRaportuObecnosci odpowiada za przygotowanie zestawienia krzyżowego, w którym wiersze będą opisywać studentów, a kolumny zjazd i dzień szkoleniowy. Tak spreparowana tabela (precyzyjnie obiekt typu DataTable) zostanie przypisana jako źródło danych gridu formularza. Public Sub DaneRaportuObecnosci(ByVal strconn As String, _ ByVal frm As frmraportobecnosci, ByVal fr As _ frmprzygotujraportobecnosci) Implements _ IRaportObecnosci.DaneRaportuObecnosci Dim conn As New SqlConnection(strconn) Dim i, j As Integer, tt As String If UstalGrb(fr.grbWgCzego) = 1 Then tt = "Pesel" j = 100 Else tt = "Nazwisko i imię" j = 140 Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajgodzinyobecnosci", _ UstalGrb(fr.grbSemestr), 1, 0, _ fr.cbokierunki.selectedvalue, 1, 0, _ UstalGrb(fr.grbWgCzego), 1, 0) Dim tb As New DataTable tb = ZbudujTabele(mTable1, tt) With frm.dgvraport.datasource = tb.columns(0).width = j For i = 1 To tb.columns.count - 2.Columns(i).Width = 40.Columns(i).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter Next.Columns(tb.Columns.Count - 1).Width = 80.Columns(tb.Columns.Count - 1). _ DefaultCellStyle.Alignment = _

273 273 DataGridViewContentAlignment.MiddleCenter.AllowUserToAddRows = False.AllowUserToDeleteRows = False End With Catch ex As Exception mkomunikat = "Błąd przygotowania danych raportu" Finally conn.close() conn = Nothing End Try Interfejs IRaportyTestow W interfejsie zapowiedziane są te właściwości i metody klasy CRaporty, które będą wykorzystywane do obsługi zdarzeń związanych z raportowaniem wyników testów przedmiotowych i semestralnych. Public Interface IRaportTestow Function Komunikat() As String Function DajTabele() As DataTable Sub WstepDoRaportTestuC(ByVal strconn As String, ByVal frm As _ frmraporttestup) Sub PokazRaportTestuC(ByVal strconn As String, ByVal idk As _ Integer) Sub PrzygotujRaportTestuSemestralnego(ByVal strconn As String, _ ByVal frm As frmraporttestowsemestralnych) Sub TestSemestralnyZmianaKierunku(ByVal strconn As String, _ ByVal semestr As Integer, ByVal idk As Integer) Sub TestSemestralnyZmianaSemestru(ByVal strconn As String, _ ByVal semestr As Integer) End Interface Metoda pokazana niżej odpowiada za dostarczenie listy kierunków studiów do pola kombo cbokierunek instancji formularza frmraporttestup przed pokazaniem go użytkownikowi. Public Sub WstepDoRaportTestuC(ByVal strconn As String, _ ByVal frm As frmraporttestup) Implements _ IRaportTestow.WstepDoRaportTestuC Dim conn As New SqlConnection(strconn), i As Integer Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pkierunkidoobecnosci", 1, 1, 0) UstawComboBox(frm.cboKierunek, mtable1, "Kierunek", "id_k") Catch ex As Exception mkomunikat = "Błąd przygotowaniu raportu testu C" Finally

274 274 conn.close() conn = Nothing End Try Metoda PokazRaportTestuC przygotowuje zbiorcze dane testu przedmiotowego dla wskazanego kierunku studiów. Public Sub PokazRaportTestuC(ByVal strconn As String, ByVal idk _ As Integer) Implements IRaportTestow.PokazRaportTestuC Dim conn As New SqlConnection(strconn), i As Integer Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajraporttestup", _ 1, 1, 0, _ idk, 1, 0, _ 1, 1, 0) Catch ex As Exception mkomunikat = _ "Błąd przygotowaniu raportu testu przedmiotowego" Finally conn.close() conn = Nothing End Try Pokazana niżej metoda jest odpowiedzialna za wstępne (bo dla semestru 1) przygotowanie listy tych kierunków studiów, dla których zgromadzone dane pozwalają na przygotowanie raportu z postępu wiedzy. Public Sub PrzygotujRaportTestuSemestralnego(ByVal strconn As _ String, ByVal frm As frmraporttestowsemestralnych) _ Implements IRaportTestow.PrzygotujRaportTestuSemestralnego Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pkierunkitestysemestralneraport", 1, 1, 0) UstawComboBox(frm.cboKierunek, mtable1, "Kierunek", "id_k") ZaznaczRdb(frm.rdbSemestr1) Catch ex As Exception mkomunikat = _ "Błąd przygotowaniu raportu testów semestralnych" Finally conn.close() conn = Nothing End Try

275 275 Zmiana kierunku studiów powoduje wykonanie poniższej metody, a jej efektem jest dostarczenie nowego zestawu danych do zaprezentowania w formularzu raportu. Public Sub TestSemestralnyZmianaKierunku(ByVal strconn As _ String, ByVal semestr As Integer, ByVal idk As Integer) _ Implements IRaportTestow.TestSemestralnyZmianaKierunku Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.ptestsemestralnydoraportu", _ semestr, 1, 0, _ idk, 1, 0) Catch ex As Exception mkomunikat = _ "Błąd przygotowaniu raportu testów semestralnych" Finally conn.close() conn = Nothing End Try W przypadku zmiany semestru wykonywana jest poniższa metoda, a jej zadaniem jest dostarczenie aktualnej (dla wybranego semestru) listy tych kierunków, dla których zgromadzone dane pozwalają na przygotowanie raportu przyrostu wiedzy. Public Sub TestSemestralnyZmianaSemestru(ByVal strconn As _ String, ByVal semestr As Integer) Implements _ IRaportTestow.TestSemestralnyZmianaSemestru Dim conn As New SqlConnection(strconn) Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pkierunkitestysemestralneraport", _ semestr, 1, 0) Catch ex As Exception mkomunikat = _ "Błąd przygotowaniu raportu testów semestralnych" Finally conn.close() conn = Nothing End Try

276 Interfejs IRaportyAnkiet W interfejscie zadeklarowane są te właściwości i metody klasy CRaporty, które będziemy wykorzystywać do obsługi raportów wyników ankiet przedmiotowych. Public Interface IRaportAnkiet Function Komunikat() As String Function DajTabele() As DataTable Sub PrzygotujDaneOtwarcia(ByVal strconn As String, ByVal frm As _ frmankietaraport) Sub DanePoZmianieEdycjiSemestru(ByVal strconn As String, _ ByVal ide As Integer, ByVal semestr As Integer, _ ByVal ktory As String) End Interface Zadaniem metody PrzygotujDaneOtwarcia jest pobranie z bazy danych informacji koniecznych do pokazania instancji formularza frmankietaraport. Public Sub PrzygotujDaneOtwarcia(ByVal strconn As String, _ ByVal frm As frmankietaraport) Implements _ IRaportAnkiet.PrzygotujDaneOtwarcia Dim conn As New SqlConnection(strconn), tb As DataTable, _ sp, rapaut, rapcomm As String Dim tytul As String = "Wyniki ankiet przedmiotowych " Select Case frm.txtpomoc.text Case "KierunkiZjazdy" sp = "dbo.pdaneankietzjazdkierunek" tytul &= "wg kierunków studiów i zjazdów" rapcomm = "Średnio dla kierunku" rapaut = "Zjazdy" Case "PracownicyZjazdy" sp = "dbo.pdaneankietzjazdpracownicy" tytul &= "wg pracowników i zjazdów" rapcomm = "Średnio dla pracownika" rapaut = "Zjazdy" Case "PrzedmiotyZjazdy" sp = "dbo.pdaneankietprzedmiotyzjazdy" tytul &= "wg przedmiotów i zjazdów" rapcomm = "Średnio dla przedmiotu" rapaut = "Zjazdy" Case "PrzedmiotyPracownicy" sp = "dbo.pdaneankietprzedmiotypracownicy" tytul &= "wg pracowników i przedmiotów" rapcomm = "Średnio dla pracownika" rapaut = "Przedmioty" End Select Try conn.open() mtable1 = MyBase.DajRekordset(conn, sp, _

277 277 0, 1, 0, 0, 1, 0) ' tworzymy instancję naszego raportu Dim objraport As New crprzykladowyszablon ' przypisanie źródła danych objraport.setdatasource(mtable1) 'i tytułu objraport.summaryinfo.reporttitle = tytul objraport.summaryinfo.reportcomments = rapcomm objraport.summaryinfo.reportauthor = rapaut frm.crvankieta.reportsource = objraport frm.text = objraport.summaryinfo.reporttitle frm.rdbbrak.checked = True tb = MyBase.DajRekordset(conn, _ "dbo.pdajedycjedoraportow", 1, 1, 0) With frm.cboedycja.datasource = tb.displaymember = "NazwaEdycji".ValueMember = "id_e".selectedvalue = 0 End With Catch ex As Exception munikat = "Błąd pobrania danych" Finally conn.close() conn = Nothing End Try Metoda DanePoZmianieEdycjiSemestru dostarcza aktualne źródło danych dla raportu. Public Sub DanePoZmianieEdycjiSemestru(ByVal strconn As String, _ ByVal ide As Integer, ByVal semestr As Integer, _ ByVal ktory As String) Implements _ IRaportAnkiet.DanePoZmianieEdycjiSemestru Dim conn As New SqlConnection(strconn), sp As String Select Case ktory Case "KierunkiZjazdy" sp = "dbo.pdaneankietzjazdkierunek" Case "PracownicyZjazdy" sp = "dbo.pdaneankietzjazdpracownicy" Case "PrzedmiotyZjazdy" sp = "dbo.pdaneankietprzedmiotyzjazdy" Case "PrzedmiotyPracownicy" sp = "dbo.pdaneankietprzedmiotypracownicy" End Select Try conn.open() mtable1 = MyBase.DajRekordset(conn, sp, _

278 278 ide, 1, 0, _ semestr, 1, 0) Catch ex As Exception mkomunikat = "Błąd pobrania danych" Finally conn.close() conn = Nothing End Try Interfejs IWzorceAnkiet W tym interfejsie deklarowane są te właściwości i metoda, które będą wykorzystane przy przygotowywaniu wzorców ankiet przedmiotowych. Public Interface IWzorceAnkiet Function Komunikat() As String Function DajTabele() As DataTable Sub PrzygotujWzorceAnkiet(ByVal strconn As String, _ ByVal semestr As Integer, ByVal zjazd As Integer) End Interface Metoda PrzygotujWzorceAnkiet dostarcza z bazy danych informacje, które zostaną wykorzystane do sporządzenia wzorców ankiet w formie klasycznego raportu. Public Sub PrzygotujWzorceAnkiet(ByVal strconn As String, ByVal _ semestr As Integer, ByVal zjazd As Integer) Implements _ IWzorceAnkiet.PrzygotujWzorceAnkiet Dim conn As New SqlConnection(strconn), ide, i As Integer, _ tp As String = "", t As String Dim tb As DataTable Try conn.open() ide = MyBase.DajWartosc(conn, "dbo.pdajidaktualnejedycji", _ "idp", 1, 1, 0, 1, 0) tb = MyBase.DajRekordset(conn, "dbo.pustaltermin", _ ide, 1, 0, _ semestr, 1, 0, _ zjazd, 1, 0) For i = 0 To tb.rows.count - 1 tb.rows(i).item(0).tostring tp &= t.substring(0, t.length - 9) & " - " Next tp = tp.substring(0, tp.length - 3) tp = "Semestr " & semestr.tostring & ", zjazd " & _ zjazd.tostring & ", termin " & tp mtable1 = MyBase.DajRekordset(conn, _ "dbo.pwykazktocokiedy", _ ide, 1, 0, _ semestr, 1, 0, _

279 zjazd, 1, 0, _ tp, 5, 100) Catch ex As Exception mkomunikat = "Błąd pobrania danych do wzorców ankiet SQL" Finally conn.close() conn = Nothing End Try 279

280 Raporty obecności W przypadku raportowania obecności mamy dość poważny problem, a wynika on z faktu, że liczba kolumn takiego raportu nie jest z góry znana. Tym samym przygotowanie szablonu raportu krzyżowego z dynamicznie zmienną liczbą kolumn w standardowym module CrystalReports jest albo niemożliwe, albo bardzo skomplikowane. W prezentowanej aplikacji sugerujemy rozwiązanie tego problemu poprzez wykorzystanie do prezentacji tabeli krzyżowej gridu w miejsce klasycznego raportu Projekt formularza frmprzygotujraportobecnosci Formularz, którego projekt pokazano niżej został tak przygotowany, aby w łatwy sposób zdefiniować sposób przygotowania raportu obecności. W formularzu umieszczono formanty: cbokierunek pole kombo pozwalające na wybór kierunku studiów; grbsemestr grupę opcji z dwoma przyciskami radiowymi o nazwach rdbs_1 i rdbs_2 pozwalającymi na wybór semestru, dla którego ma być przygotowany raport obecności; grpwgczego grupa opcji z dwoma przyciskami radiowymi o nazwach rdbpesel1 i rdbnazwisko2, wybór jednego z nich determinuje sposób identyfikacji słuchaczy; btnpokaz przycisk polecenia uruchamiajacy wyświetlenie raportu; ErrorProvider1 formant wykorzystywany do walidacji danych. Istancja tego formularza uruchamiana jest po wyborze w menu aplikacji polecenia Raporty/Obecności, klik tego polecenia uruchamia pokazaną niżej procedurę zdarzeniową.

281 281 Private Sub mnuraportobecnosci_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuraportobecnosci.click Dim frm As New frmprzygotujraportobecnosci Dim w As IRaportObecnosci w = New CRaporty w.przygotujraportobecnosci(strbaza, frm) PokazForm(frm, w.komunikat) W module klasy tego formularza utworzono szereg procedur obsługujących zdarzenia związane z funkcjonowaniem formularza. Public Class frmprzygotujraportobecnosci Dim f As Boolean ' procedura reagująca na zmianę kierunku studiów, musi ustalić ' czy dla wybranego kierunku istnieją zarejestrowane obecności ' w obu semestrach, czy tylko w jednym z nich Private Sub cbokierunki_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbokierunki.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IRaportObecnosci w = New CRaporty w.zmianakierunkuobecnosci(strbaza, _ Me.cboKierunki.SelectedValue) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else With w.dajtabele If.Rows.Count = 0 Then MsgBox("Dla wybranego kierunku nie ma " & _ "zarejestrowanych obecności", _ MsgBoxStyle.Information, _ "Przygotowanie raportu obecności") Me.rdbS_1.Enabled = False Me.rdbS_2.Enabled = False ElseIf.Rows.Count = 1 Then If.Rows(0).Item(0) = 1 Then Me.rdbS_1.Enabled = True Me.rdbS_1.Checked = True Me.rdbS_2.Enabled = False Else Me.rdbS_1.Enabled = False Me.rdbS_2.Enabled = True Me.rdbS_2.Checked = True Else Me.rdbS_1.Enabled = True

282 282 Me.rdbS_2.Enabled = True End With ' procedura sprawdzająca, czy wybrano kierunek studiów Private Sub cbokierunki_validating(byval sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) Handles _ cbokierunki.validating f = CzyDobreCombo(Me.cboKierunki, _ "Proszę wybrać kierunek studiów!", Me.ErrorProvider1, True) ' procedura obsługująca pokazanie właściwego raportu, zaczyna od ' sprawdzenia, czy jest wybrany kierunek studiów Private Sub btnpokaz_click(byval sender As Object, ByVal e As _ System.EventArgs) Handles btnpokaz.click If CzyDobreCombo(Me.cboKierunki, _ "Proszę wybrać kierunek studiów!", Me.ErrorProvider1) _ Then Exit Sub ' utworzenie instancji formularza raportu Dim frm As New frmraportobecnosci Dim w As IRaportObecnosci w = New CRaporty ' wywołanie metody, która zwróci dane do gridu w.daneraportuobecnosci(strbaza, frm, Me) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' skomponowanie tytułu otwieranego formularza raportu frm.text = "Raport obecności dla kierunku " & _ Me.cboKierunki.SelectedItem(1).ToString & _ " w semestrze " & UstalGrb(Me.grbSemestr).ToString frm.mdiparent = frmmdistudia frm.show() End Class

283 Projekt formularza frmraportobecnosci Uzupełnieniem powyższego formularza jest formularz frmraportobecnosci, to w nim będzie prezentowane krzyżowe zestawienie liczby godzin dla poszczególnych słuchaczy w dniach zjazdowych. W formularzu frmraportobecnosci umieściliśmy jedynie dwa formanty: dgvobecnosci formant typu DataGridView, będziemy w nim prezentować dane pobrane z bazy danych i odpowiednio zestawione w celu otrzymania tabeli krzyżowej; ContexMenuStrip1 formant umieszczony na tacy, który wykorzystamy do utworzenia menu kontekstowego gridu. Formularz frmraportobecnosci ma w rzeczywistości znacznie większe rozmiary, zostały one tak dobrane, aby można było wyświetlić informacje o obecnościach we wszystkich dniach szkoleniowych jednego semestru (12 dni plus 2 dodatkowe kolumny, jedna na opis studentów, druga na podsumowanie liczby godzin). Instancja tego formularza uruchamiana jest przez procedurę zdarzeniową utworzoną w formularzu frmprzygotujraportobecnosci, a obsługującą klik przycisku btnpokaz. W module klasy tego formularza utworzono trzy procedury obsługujące pozycje menu kontekstowego gridu. Public Class frmraportobecnosci Private Sub mnupodgladwydruku_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnupodgladwydruku.click Dim w As TypBooleanPrintPage = _ UstawDrukGridu(Me.dgvRaport, Me.Text) If w.f Then Dim myprintpreviewdialog As PrintPreviewDialog = _ New PrintPreviewDialog myprintpreviewdialog.document = w.p

284 284 myprintpreviewdialog.showdialog() Private Sub mnugriddoexcela_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnugriddoexcela.click ZapiszGridDoExcela(Me.dgvRaport, "A1", _ Me.dgvRaport.Columns.Count) Private Sub mnugriddoschowka_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnugriddoschowka.click Clipboard.Clear() Clipboard.SetText(GridDoSchowka(Me.dgvRaport, _ Me.dgvRaport.Columns.Count)) End Class Poniżej widok gotowego raportu dla wybranego kierunku i semetru studiów.

285 Raporty testów przedmiotowych Projekt formularza frmraporttestup Raporty testów przedmiotowych będą prezentowane w odpowiednio skontruowanym formularzu o nazwie frmraporttestup, którego projekt pokazany jest poniżej. Na powierzchni formularza umieszczono formanty: grbsemestr grupę opcji z dwoma przyciskami radiowymi o nazwach odpowiednio rdbsemestr1 i rdbsemestr2; cbokierunek pole kombi pozwalające na wybór kierunku studiów; dgvpunkty formant typu DataGridView, w nim będziemy wyświetlać detale raportu; etykietę opisującą pole kombi oraz ContextMenuStrip1 - formant typu ContextMenuStrip, wykorzystamy go do utworzenia menu kontekstowego gridu. Po zaznaczeniu formantu dgvpunkty w oknie jego właściwości musimy wybrać dla właściwości ContextMenuStrip nasz formant tego typu, czyli ContexMenuStrip1. Kolejny krok to zdefiniowanie poleceń menu kontekstowego. Klik formantu ContexMenuStrip1 otwiera okno edycji, co pozwala na utworzenie wpisów menu kontekstowego, w naszym przypadku będą to dwa polecenia: Podgląd wydruku i Zapisz w MS Excel.

286 286 Wstawione w ten sposób polecenia menu kontekstowego mają swoją nazwę systemową, zawsze możemy ją zmienić na bardziej czytelną. W naszym przypadku pierwsze z nich otrzymało nazwę mnupodgladgridu, a drugie mnugriddoexcela. Instancja formularza frmraporttestup tworzona jest po wyborze pokazanego niżej polecenia w menu aplikacji. Klik tego polecenia jest równoważny z wykonaniem pokazanej niżej procedury. Private Sub mnuraporttestowprzedmiotowych_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuraporttestowprzedmiotowych.click Dim frm As New frmraporttestup Dim w As IRaportTestow w = New CRaporty w.wstepdoraporttestuc(strbaza, frm) PokazForm(frm, w.komunikat) Kod formularza frmraporttestup W module klasy tego formularza tworzymy wszystkie potrzebne procedury obsługujące zdarzenia zachodzące w tym formularzu, także procedury obsługi menu kontekstowego. Public Class frmraporttestup Private Sub cbokierunek_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbokierunek.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IRaportTestow, i As Integer w = New CRaporty w.pokazraporttestuc(strbaza, Me.cboKierunek.SelectedValue) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else If w.dajtabele.rows.count = 0 Then MsgBox("Brak danych do wyświetlenia raportu " & _ "zborczego", MsgBoxStyle.Information, _ "Raport testów przedmiotowych") Else Dim tz As New DataTable

287 287 tz = ZbudujTabele(w.DajTabele, "Nazwisko i imie", 2) With Me.dgvPunkty.DataSource = Nothing.DataSource = tz.columns(0).width = 150 For i = 1 To.Columns.Count - 1.Columns(i).DefaultCellStyle.Format = "##0.0%".Columns(i).Width = 60 Next End With 'obsługa poleceń menu kontekstowego Private Sub mnupodgladgridu_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnupodgladgridu.click Dim w As TypBooleanPrintPage = UstawDrukGridu(Me.dgvPunkty, _ "Raport testów przedmiotowych dla kierunku " & _ Me.cboKierunek.SelectedText) If w.f Then Dim myprintpreviewdialog As PrintPreviewDialog = _ New PrintPreviewDialog myprintpreviewdialog.document = w.p myprintpreviewdialog.showdialog() Private Sub mnugriddoexcela_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnugriddoexcela.click ZapiszGridDoExcela(Me.dgvPunkty, "A1", _ Me.dgvPunkty.Columns.Count) End Class Poniżej widok instancji formularza frmraporttestup wyświetlającego przykładowy raport wyników testów przedmiotowych dla jednego z kierunków studiów. W kolumnach mamy pokazane średnie liczby punktów osiągnięte przez słuchaczy w kolejnych zjazdach wybranego semestru, a ostatnia kolumna podaje średnią z danego semestru.

288 288 Klik prawym przyciskiem myszy w lewym górnym narożniku gridu pokazuje menu kontekstowe. Wybór pierwszego z tych poleceń uruchamia proces podglądu gridu.

289 289 Po wyborze drukarki procedura wyświetla jeszcze komunikat z pytaniem o centrowanie raportu na stronie. Po odpowiedzi mamy już okno podglądu raportu.

290 Raporty testów semestralnych Projekt formularza frmraporttestowsemestralnych Raporty testów przedmiotowych będą prezentowane w odpowiednio skonstruowanym formularzu, którego projekt pokazany jest poniżej. Na powierzchni formularza umieszczono formanty: grbsemestr grupę opcji z dwoma przyciskami radiowymi o nazwach odpowiednio rdbsemestr1 i rdbsemestr2; cbokierunek pole kombi pozwalające na wybór kierunku studiów; dgvpunkty formant typu DataGridView, w nim będziemy wyświetlać detale raportu; etykietę opisującą pole kombi oraz ContextMenuStrip1 - formant typu ContextMenuStrip, wykorzystamy go do utworzenia menu kontekstowego gridu. Po zaznaczeniu formantu dgvpunkty w oknie jego właściwości musimy wybrać dla właściwości ContextMenuStrip nasz formant tego typu, czyli ContexMenuStrip1.

291 291 Instancja formularza frmraporttestowsemestralnych tworzona jest po wyborze w menu aplikacji odpowiedniego polecenia. Jego klik uruchamia pokazaną niżej procedurę zdarzeniową. Private Sub mnuraporttestowsemestralnych_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuraporttestowsemestralnych.click Dim frm As New frmraporttestowsemestralnych Dim w As IRaportTestow w = New CRaporty w.przygotujraporttestusemestralnego(strbaza, frm) PokazForm(frm, w.komunikat) Kod formularza frmraporttestowsemestralnych W module formularza musimy utworzyć kilka procedur, będą one obsługiwać zdarzenia związane z funkcjonowaniem tego formularza. Public Class frmraporttestowsemestralnych 'obsługa poleceń menu kontekstowego Private Sub cbokierunek_selectedvaluechanged(byval sender As _ Object, ByVal e As System.EventArgs) Handles _ cbokierunek.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IRaportTestow, i As Integer w = New CRaporty w.testsemestralnyzmianakierunku(strbaza, _ UstalGrb(Me.grbSemestr), Me.cboKierunek.SelectedValue) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else Dim tb As New DataTable tb = ZbudujTabele(w.DajTabele, "Nazwisko i imię", 2) With Me.dgvPunkty.DataSource = tb.columns(0).width = 140.Columns(1).HeaderText = "Wstępny".Columns(2).HeaderText = "Końcowy".Columns(3).HeaderText = "Przyrost".Columns(1).HeaderCell.Style.Alignment = _

292 292 DataGridViewContentAlignment.MiddleCenter.Columns(2).HeaderCell.Style.Alignment = _ DataGridViewContentAlignment.MiddleCenter.Columns(3).HeaderCell.Style.Alignment = _ DataGridViewContentAlignment.MiddleCenter For i = 0 To.Rows.Count - 1.Rows(i).Cells(3).Value = _.Rows(i).Cells(2).Value -.Rows(i).Cells(1).Value Next For i = 1 To tb.columns.count - 1.Columns(i).Width = 100.Columns(i).DefaultCellStyle.Alignment = _ DataGridViewContentAlignment.MiddleCenter.Columns(i).DefaultCellStyle.Format = "##0.0%".Columns(i).ReadOnly = True Next.AllowUserToAddRows = False.AllowUserToDeleteRows = False End With 'obsługa poleceń menu kontekstowego, podgląd wydruku gridu Private Sub PodgladWydrukuToolStripMenuItem_Click(ByVal sender _ As System.Object, ByVal e As System.EventArgs) Handles _ PodgladWydrukuToolStripMenuItem.Click Dim w As TypBooleanPrintPage = UstawDrukGridu(Me.dgvPunkty, _ "Raport postępu na kierunku " & Me.cboKierunek.SelectedText) If w.f Then Dim myprintpreviewdialog As PrintPreviewDialog = _ New PrintPreviewDialog myprintpreviewdialog.document = w.p myprintpreviewdialog.showdialog() 'obsługa poleceń menu kontekstowego, skopiowanie gridu do Excela Private Sub SkopiujDoMSExcelToolStripMenuItem_Click(ByVal _ sender As System.Object, ByVal e As System.EventArgs) _ Handles SkopiujDoMSExcelToolStripMenuItem.Click ZapiszGridDoExcela(Me.dgvPunkty, "A1", _ Me.dgvPunkty.Columns.Count) 'obsługa zmiany semestru Private Sub rdbsemestr1_checkedchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles _ rdbsemestr1.checkedchanged If Not flaga Then Exit Sub Me.dgvPunkty.DataSource = Nothing

293 293 Dim w As IRaportTestow w = New CRaporty w.testsemestralnyzmianasemestru(strbaza, _ UstalGrb(Me.grbSemestr)) UstawComboBox(Me.cboKierunek, w.dajtabele, "Kierunek", _ "Id_k", w.komunikat) End Class Poniżej widok instancji tego formularza, pokazany jest raport testów semestralnych dla wybranego kierunku studiów w wybranym semestrze. Ostatnia kolumna pokazuje przyrost wiedzy w procentach uzyskanych punktów. Z menu kontekstowego gridu można wywołać polecenie zapisu do MS Excel. Jego kilk otwiera systemowe okno dialogowe zapisywania pliku.

294 294 W rezultacie w MS Excel mamy kompletny raport semestralny, który ewentualnie można dalej obrabiać.

295 Raporty ankiet przedmiotowych Raporty prezentujące zbiorcze wyniki ankiet przedmiotowych przygotujemy wykorzystując moduł CrystalReports do zaprojektowania raportu i jego prezentacji. Proces przygotowania raportu prezentującego określone dane będzie obejmował następujące etapy: 1. Przygotowanie procedury przechowywanej pobierającej z bazy danych potrzebne dane; 2. Przygotowanie obiektu typu DataSet zawierającego obiekt typu DataTable o kolumnach odpowiadających zwracanym polom w rekordsecie uzyskiwanym w pkt. 1. Musi być spełniony warunek co do nazw pól i typów zwracanych danych; 3. Przygotowanie obiektu typu CrystalReports, dla którego źródłem danych będzie obiekt DataTable utworzony w pkt. 2. Zaprojektujemy w ten sposób szablon raportu; 4. Przygotowanie formularza ekranowego z obiektem CrystalReportsViewer; źródłem danych dla tego formantu będzie szablon raportu utworzony w poprzednim punkcie; 5. Przygotowanie odpowiednich procedur pobierających dane z bazy danych, zdefiniowanie źródła danych dla raportu oraz zmodyfikowanie istotnych właściwości raportu (np. tytułu) Wg kierunków studiów i zjazdów Wyniki ankiet przedmiotowych gromadzone są w tabeli Dane, a ich struktura (pola) pozwalają na zbadanie dynamiki odpowiedzi na dziesięć pytań zawartych w tej ankiecie zależnie od edycji studiów podyplomowych i semestru zrealizowanych zajęć. Uzyskane średnie ocen mogą być zgrupowane wg kierunków studiów. Kolejno przedstawimy poszczególne fazy pracy nad utworzeniem odpowiedniego raportu Utworzenie DataSet i DataTable Po utworzeniu niezbędnych procedur przechowywanych przechodzimy do VisualStudio i naszego projektu, dodamy do niego nowy obiekt typu DataSet. W oknie SolutionExplorer naprowadzamy wskaźnik myszy na nazwę rozwiązania i po kliku prawym przyciskiem myszy wywołujemy polecenia Add i New item, co skutkuje otwarciem okna z zainstalowanymi wzorcami obiektów. W oknie tym zaznaczamy szablon DataSet, a następnie zmieniamy jego domyślną nazwę na jakąś inną (docelową), na potrzeby tego przykładu niech ten obiekt nosi nazwę dsprzykladowy.

296 296 Po akceptacji przycisku Add mamy otwarty, pusty obiekt typu DataSet, będziemy teraz tworzyć w nim obiekt typu DataTable. Po ustawieniu myszki w oknie obiektu dsprzykladowy wywołujemy menu kontekstowe, z którego wybieramy polecenie Add i dalej DataTable, co skutkuje utworzeniem nowego obiektu typu DataTable. Bezpośrednio po utworzeniu jest on obiektem aktywnym, co pozwala nam na zmianę jego nazwy w oknie właściwości na jakąś inną (taką, która lepiej opisuje przeznaczenie tego obiektu). W pokazanej niżej sytuacji zmieniliśmy jego nazwę na dtprzykladowa.

297 297 W kolejnych krokach dodajemy do obiektu dtprzykladowa kolumny, których nazwy zmieniamy tak, aby były zgodne z kolumnami rekorsetu zwracanego przez procedurę pdaneankietzjazdkierunek. Pierwsza kolumna została już dodana, a jej nazwa zmieniona na Zjazd, właśnie dodaliśmy kolejną kolumnę i za chwilę zmienimy jej nazwę na Kierunek. Po dodaniu wszystkich kolumn musimy jeszcze zadbać, aby typy danych przechowywanych w poszczególnych kolumnach były zgodne z typami danych rekordsetu uzyskiwanego dzięki procedurze pdaneankietzjazdkierunek. Kolejne kolumny obiektu dtprzykladowa muszą przechowywać informacje typu: Zjazd integer, Kierunek string, Pyt1 decimal,, Pyt10 decimal. W momencie dodawania nowej kolumny jej typ danych ustawiany jest na string, tym samym musimy zmienić typy danych pierwszej kolumny oraz kolumn odpowiedających poszczególnym pytaniom.

298 298 Po zaznaczeniu kolumny Zjazd otwieramy okno właściwości i odszukujemy właściwość DataType, jak wcześniej wspomnieliśmy domyślnie ustawiony jest typ tekstowy, a my musimy mieć liczbę całkowitą. Po rozwinięciu listy typów wybieramy System.Int32. Operację zmiany typu danych z System.String na System.Decimal musimy teraz przeprowadzić dla kolumn Pyt1 do Pyt10, zamiast robić to pojedynczo możemy zaznaczyć wszystkie potrzebne kolumny i dopiero otworzyć okno właściwości i zmienić typ danych. Poniżej pokazana jest taka sytuacja na moment przed zmianą typu danych dla zaznaczonych kolumn Przygotowanie szablonu raportu Mamy już obiekt typu DataTable tak zdefiniowany, aby odpowiadał liczbie i typom danych zwracanych przez procedurę przechowywaną zaprojektowaną dla potrzeb naszego

299 299 raportu (czyli raportu. pdaneankietzjazdkierunek), możemy więc zbudować szablon Zaczynamy od dodania do naszego rozwiązania nowego obiektu, tym razem będzie to obiekt typu CrystalReports, a jego nazwę zmienimy na crprzykladowyszablon. Bezpośreednio po jego dodaniu uruchamia się kreator raportów, będziemy z niego korzystać przy projektowaniu naszego szablonu.

300 300 Po przejściu dalej zostaje otwarte kolejne okno, wskażemy w nim źródło danych dla projektowanego raportu. W liście Available Data Sources rozwijamy pozycję Project Data i dalej ADO.NET DataSets i StudiaPARP.dsPrzykladowy selekcjonując obiekt dtprzykladowy (nazwa StudiaPARP to nazwa naszego projektu, w Twoim przypadku może to być inna nazwa). Poprzez klik przycisku wskazanego wskaźnikiem myszki przenosimy zaznaczone źródło danych do listy Selected Tables (poniżej widok po przeniesieniu źródła danych) i przyciskiem Dalej kontynuujemy pracę kreatora. W kolejnym oknie musimy wskazać te pola źródła danych, które mają być wykorzystane w raporcie. Zaczynamy od wyświetlenia listy pól w obiekcie dtprzykladowa

301 301 (klik na symbol krzyżyka), a następnie przyciskiem oznaczonym podwójnym znakiem większości przenosimy wszystkie pola do listy Fields to Display. Poniżej widok po przeniesieniu wszystkich pól obiektu dsprzykladowa. Klik przycisku Dalej otwiera kolejne okno kreatora, będziemy mogli w nim wskazać to pole, wg którego chcemy pogrupować informacje w raporcie.

302 302 W naszym przypadku jest to pole Kierunek, jest już zaznaczone w liście Available Fields, klik przycisku wskazanego myszką przeniesie je do listy Group By. W polu kombi pod listą Group By mamy domyślnie wybrany rosnący sposób sortowania wartości pola Kierunek, pozostawiamy go jako naturalny porządek. Klik przycisku Dalej przenosi nas do kolejnego okna dialogowego kreatora raportu.

303 303 Kolejne okno dialogowe pozwala na wybór pól i funkcji agregatujących do wiersza podumowań dla każdej z wartości pola Kierunek. Domyślnie dla pól numerycznych wybierana jest funkcja Sum (suma). W naszym przypadku dla pola Zjazd wybierzemy funkcję Count (policz), a dla pozostałych pól funkcję Avg (średnia). Sytuacja taka pokazana jest poniżej. Klik przycisku Dalej otwiera kolejne dwa okno dialogowe kreatora raportów, w pierwszym z nich można opcjonalnie wskazać sposób sortowania grup rekordów w oparciu o podsumowania.

304 304 W naszym przypadku nie będziemy wybierali żadnego sposobu uporządkowania. Podobnie nie będziemy włączali do raportu wykresu (w tym przykładzie). Kolejny klik przycisku Dalej pozwoli nam na określnie rodzaju informacji, przy których pola raportu mają być pokazywane.

305 305 Domyślnie ustawiana jest opcja przy każdej wartości, tak to pozostawiamy dla każdego z pól. Kolejny klik przycisku Dalej otwiera ostatnie już okno kreatora, możemy w nim wybrać styl raportu.

306 306 Po kliku przycisku Zakończ kreator kończy pracę wyświetlając okno projektu naszego raportu. Sytuacja taka pokazana jest poniżej. Po lewej stronie mamy otwarte okno Field Explorer, a główną część zajmuje okno projektu raportu. Projekt raportu podzielony jest na sekcje, kolejno mamy sekcję Report Header (nagłówek raportu), Page Header (nagłówek strony), GroupHeaderSection (nagłówek grupy), Details (sekcja detali), GroupFooterSection (stopka podsumowania grupy), ReportFooter (stopka raportu) i PageFooter (stopka strony). W sekcjach umieszczać będziemy pola tekstowe opisujące różne informacje, zarówno związane (jak etykiety pól) jak i niezwiązane (etykiety pomocnicze), pola tekstowe wyświetlające zawartości pól raportu czy też specjalne pola tekstowe (tytuł raportu, data wydruku, numer strony). Czeka nas teraz sporo pracy związanej ze sformatowaniem szablonu raportu, prace te będą polegać zarówno na zmianie pozycji niektórych pól tekstowych, dodaniu nowych pól czy innych obiektów (np. linii) jak i zmianie sposobu wyświetlania informacji w tych polach (np. zmiana czcionki, sposobu jej wyświetlenia, wyrównania, rozmiaru itd.). Zakres prac wynika generalnie z naszej koncepcji raportu, także z tego, jak go chcemy wykorzystywać, w tym od odpowiedzi na pytanie, czy chcemy go wykorzystać do zaprezentowania jednego, określonego raportu, czy też do zbudowania raportu w pewnym sensie dynamicznego, takiego, które niektóre z elementów mogą być programowo zmieniane. W sekcji ReportHeader (w pokazanej wyżej sytuacji sekcja ta jest nieaktywna) będziemy chcieli umieścić specjalne pole tekstowe wyświetlające tytuł raportu. Użycie tego specjalnego pola pozwoli nam na dynamiczną zmianę tytułu raportu w miarę potrzeb.

307 307 Zaczynamy od uaktywnienia sekcji nagłówka raportu, z menu kontekstowego (uruchomionego prawym przyciskiem myszy w momencie, gdy jej wskaźnik jest utawiony na sekcji nagłówka) wywołujemy polecenie Don t Suppress. Po powiększeniu wysokości tej sekcji ustawiamy w jej obszarze mysz i z menu kontekstowego wybierzemy polecenie Insert, Special Field i Report Title. Sytuacja taka pokazana jest niżej. Po wyborze polecenia Report Title do wskaźnika myszy zostaje podczepione pole tekstowe, umieszczamy je w sekcji nagłówka raportu, np. tak, jak to pokazano niżej.

308 308 Wstawione pole tekstowe musi być teraz sformatowane, a więc powiekszamy jego szerokość i wysokość (można myszką), możemy także z menu kontekstowego wywołać polecenie Format Object, w efekcie zostanie wyświetlone pokazane niżej okno dialogowe. Korzystając z zakładki Common zmieniliśmy dwie właściwości: sposób wyrównania tekstu w tym polu oraz zostało uaktywnione pole wyboru Can Grow, co pozwoli na dynamiczne powiększanie wysokości tego pola w miarę potrzeb. Korzystając z zakładki Font możemy wybrać np. Times New Roman w rozmiarze 12 pkt i pogrubiony styl do wyświetlenia tytułu raportu. Poniżej widok fragmentu okna raportu po dokonaniu tych zmian. Dodatkowo, do tej sekcji zostało przeniesione pole specjalne Print Date (z sekcji Page Header). W sekcji Page Header mamy etykiety opisujące poszczególne pola raportu, w przypadku grupowania informacji może być wygodniejsze takie rozwiązanie, gdy etykiety te przeniesiemy do sekcji GroupHeader. Przeniesienie może dotyczyć wszystkich etykiet z wyjątkiem pierwszej etykiety (pola grupującego), którą po prostu możemy usunąć. Poniżej fragment okna raportu po zaznaczeniu tych etykiet i ich przeniesieniu do sekcji GroupHeader.

309 309 Zastanowienia wymaga etykieta pola Zjazd, w przypadku gdybyśmy chcieli wykorzystać crprzykladowyszablon do wyświetlenia np. raportu prezentującego wyniki ankiet przedmiotowych wg edycji studiów podyplomowych oraz semestrów zajęć, to zamiast etykiety Zjazd powinniśmy mieć etykietę Semestr. Jedna z możliwości, to wykorzystanie do opisania tego pola jednego ze specjalnych pól raportu (takich, których zawartość będziemy mogli zmieniać w trakcie wykonywania programu). Można w tym celu wykorzystać np. pole File Autor i tak też zrobiliśmy w naszym przykładzie. Poniżej widok raportu po wprowadzeniu zmian: w miejsce etykiety pola Zjazd jest wstawione pole File Autor, zmieniona jest czcionka wszystkich pól w tej sekcji z Arial na Times New Roman, zostały usunięte krawędzie dolne tych pól, a po powiększeniu wysokości sekcji pod polami została dodana linia rozdzielająca tę sekcję od sekcji detali. Po narysowaniu linii wysokość sekcji musi być trochę zmniejszona (nie powinno być dodatkowej przerwy między linią a sekcją detali). Z sekcji Page Header usunięto etykietę pola grupującego, a całą sekcję zwinięto (poleceniem Suppres z menu kontekstowego) W sekcji Details kreator raportów umieścił pole Kierunek, jego pozostawienie w tym miejscu nie ma sensu, ponieważ dla każdego z wierszy w tej sekcji (np. dla każdego ze zjazdów) nazwa aktualnego kierunku (grupy) będzie powtarzana. Dodatkowo będzie to ta sama nazwa, która zostanie wyświetlona przez pole Group #1 Name.

310 310 Po usunięciu tego pola zmieniamy czcionkę wykorzystaną do wyświetlania danych w tej sekcji z Arial na Times New Roman. Zmianę czcionki wykonujemy po zaznaczeniu wszystkich pól w tej sekcji, korzystamy wtedy z polecenia Format Multiple Object w menu kontekstowym. W sekcji GroupFooter również musimy wprowadzić szereg zmian. Pole Group #1 Name po raz kolejny powtarzało by wartość pola grupującego, usuniemy je i w tym miejscu dodamy pole specjalne, np. Report Comments, w którym w czasie działania programu będziemy mogli modyfikować opis podsumowania grupy (np. średnio dla zjazdów czy średnio dla semestrów ). Zmienimy także sposób wyświetlania danych w tej sekcji poprzez zmianę czcionki i usunięcie krawędzi pól. Dla odzielenia tej sekcji od sekcji detali dodamy linię nad polami umieszczonymi w tej sekcji. W sekcji Report Footer zmieniamy treść pola tekstowego z Grand Total na inną, np. Średnia ogólna, a następnie formatujemy wszystkie pola w tej sekcji (zmiana czcionki na Times New Roman, usunięcie krawędzi pól). Możemy także opuścić trochę wszystkie pola robiąc miejsce na linię odzielającą tę sekcję od sekcji wcześniejszych. Poniżej widok crprzykladowyszablon po wprowadzeniu wszystkich przedstawionych wyżej zmian. Przygotowany szablon raportu można także wzbogacić o stałe elementy graficzne, umieszczając np. w sekcji nagłówka raportu jakiś obraz (np. logo firmy). W naszym przykładzie umieścimy w nagłówku raportu tzw. logotyp PARP-u uzupełniony logiem naszej Uczelni, musimy tylko pamiętać o tym, aby był on umieszczony w pliku typu JPG i zapisany w folderze [NaszaAplikacja]\Bin\Debug.

311 311 Przed jego umieszczeniem w nagłówku raportu musimy przygotować miejsce na ramkę tego obrazu, w tym celu zwiększamy wysokość tej sekcji (w pokazanym niżej przykładzie do 1915 punktów) i przesuwamy pole specjalne ReportTitle w dół tej sekcji. Jest jeszcze problem gdzie umieścić pole specjalne PrintDate, po zastanowieniu pole to przenieśliśmy do sekcji Report Footer umieszczając je jako ostatni element w tej sekcji. Po takich przygotowaniach możemy już dodać do sekcji nagłówka raportu ramkę obrazu wskazując ścieżkę do przygotowanego pliku graficznego typu JPG. Z menu kontekstowego wywołujemy polecenie Insert i dalej Picture, w efekcie otwierane jest okno dialogowe, w którym musimy wskazać folder oraz plik graficzny do osadzenia w ramce obrazu. Po wyborze pliku i jego akceptacji wskaźnik myszy zostaje zastąpiony ramką obrazu, którą musimy umieścić w wybranej lokalizacji. Po akceptacji miejsca ramka zostaje osadzona z jednoczesnym wyświetleniem obrazu. Poniżej widok szablonu raportu po umieszczeniu w sekcji nagłówka raportu logotypu PARP-u uzupełnionym logiem naszej Uczelni. W stosunku do poprzedniej wersji szablonu dokonano jeszcze dwóch zmian: pole PrintDate zostało umieszczone w sekcji stopki raportu, a z sekcji GroupFooterSection usunięto podsumowanie dla pola Zjazd (ta informacja niewiele wnosi i nie ma znaczenia merytorycznego dla raportu, ponieważ przy wybranej funkcji agregatującej podawało liczbę rekordów w sekcji Details).

312 Przygotowanie formularza prezentującego raport Dodajemy do naszego rozwiąznia kolejny obiekt, tym razem będzie to formularz ekranowy, którego nazwę zmieniamy na np. frmankietaraport. Na formularzu umieszczamy formant typu CrystalReportViewer, którego nazwę zmieniamy na crvankieta, a właściwość DisplayGroupTree na False. Efektem jest rozciągnięcie rozmiarów tego formantu tak, że wypełnia cały formularz. Na dole formularza będziemy chcieli umieścić kilka dodatkowych formantów, ale chwilowo nie możemy tego zrobić (bo nie ma miejsca). Musimy zmienić właściwość Dock formantu crvankieta z Fill na None, a następnie ręcznie rozciągnąć krawędzie tego formantu tak, aby na dole formularza pozostawić obszar 1-1,5cm wolnej przestrzeni. W tym obszarze umieszczamy pole kombi o nazwie cboedycja, ramkę GroupBox z trzema przyciskami radiowymi pozwalającymi na wybór semestru (o nazwach rdbpierwszy, rdbdrugi, rdbbrak) oraz pole tekstowe o nazwie txtpomoc. Poniżej widok tego formularza z formantem typu CrystalReportViewer w cześci głównej i pomocniczymi formantami w dolnej jego części. Dla formantów crvankieta, pola kombi cboedycja i jego etykiety oraz dla ramki GroupBox musimy jeszcze zmodyfikować sposób zakotwiczenia tych obiektów w formularzu. Zrobimy to z pomocą właściwości Anchor kolejno dla tych formantów.

313 313 W przypadku formantu crvankieta ustawiamy zakotwiczenie jako Left, Top, Right i Bottom, a dla pozostałych formantów jako Bottom i Left. Poniżej widok okna właściwości przy zmianie zakotwiczenia dla pola kombi. Zmiana zakotwiczenia jest niezbędna, jeżeli pozwolimy użytkownikowi na zmianę rozmiarów formularza (w tym na jego maksymalizację). Brak zakotwiczenia powoduje bowiem, że taki formant nie dostosowuje swojej lokalizacji do zmian rozmiaru formularza. Pole tekstowe txtpomoc ma w naszym zamyśle specjalne znaczenie, będzie bowiem wykorzystywane do identyfikacji raportu wyświetlanego w instancji tego formularza. Pole to musi być niewidoczne dla użytkownika, stąd zmiana jego właściwości Visible na False. Musimy jeszcze utworzyć kod obsługujący zdarzenia związane ze zmianą edycji studiów czy też ze zmianą semestru Kod formularza prezentującego raport Procedury utworzone w module formularza będą obsługiwać zdarzenia związane z wyborem edycji studiów w polu kombi cboedycja i/lub zmianą semestru w grupie przycisków radiowych. W każdym z tych przypadków musi nastąpić modyfikacja danych prezentowanych w raporcie. Pierwszym zdarzeniem, które musimy obsłużyć jest załadowanie formularza, po jego załadowaniu zmienna globalna flaga otrzymuje wartość True jako sygnał, że zdarzenia związane ze zmianą wartości w polu kombi czy zmianą zaznaczenia przycisków radiowych mogą już być obsługiwane. W przypadku, gdy zajdzie jedno z tych dwóch zdarzeń wykonywana jest prywatna procedura o nazwie DajRaport, jest ona odpowiedzialna za modyfikację danych wykorzystywanych w raporcie. Poniżej pełny kod klasy tego formularza wraz ze stosownymi komentarzami.

314 314 Public Class frmankietaraport ' zmienna globalna flaga otrzymuje wartość True Private Sub frmankietaraport_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load flaga = True ' wspólna procedura obsługująca zdarzenia związane ze zmianą ' zaznaczenia przycisków radiowych Private Sub rdbbrak_checkedchanged(byval sender As Object, ByVal e As System.EventArgs) Handles rdbbrak.checkedchanged, rdbdrugi.checkedchanged, rdbpierwszy.checkedchanged ' wywołanie prywatnej procedury DajRaport DajRaport() ' procedura obsługująca zmianę edycji studiów Private Sub cboedycja_selectedvaluechanged(byval sender As Object, ByVal e As System.EventArgs) Handles cboedycja.selectedvaluechanged DajRaport() ' prywatna procedura modyfikująca dane do raportu i sam raport Private Sub DajRaport() ' jeżeli flaga jest False to wyjdź z procedury If Not flaga Then Exit Sub ' deklaracja prywatnych zmiennych procedury Dim tytul As String = "", ide, semestr As Integer ' tytuł raportu komponowany jest zależnie od rodzaju raportu ' prezentowanego w instancji formularza, a informacja o tym ' zapisana jest w ukrytym polu tekstowym txtpomoc Select Case Me.txtPomoc.Text Case "KierunkiZjazdy" tytul = "Wyniki ankiet przedmiotwych wg kierunków " & _ "studiów i zjazdów" Case "PracownicyZjazdy" tytul = "Wyniki ankiet przedmiotwych wg pracownikow " & _ "i zjazdów" End Select ' ustalenie o który semestr chodzi semestr = UstalGrb(Me.grbSemestr) ' ustalenie, która edycja studiów została wybrana ide = Me.cboEdycja.SelectedValue ' dokończenie kompozycji tytułu raportu If ide > 0 Then tytul &= " dla edycji " & _ Me.cboEdycja.SelectedItem(1).ToString If semestr > 0 Then

315 If ide > 0 Then tytul &= " i semestru " & _ Choose(semestr, "pierwszego", "drugiego") Else tytul &= " dla semestru " & _ Choose(semestr, "pierwszego", "drugiego") ' w zalezności od tekstu w txtpomoc różnicujemy dane raportu Select Case Me.txtPomoc.Text Case "KierunkiZjazdy" ' deklarujemy obiekt w oparciu o odpowiedni iterfejs Dim w As IRaportKierunkiZjazdy ' tworzymy instancję klasy CRaporty w = New CRaporty ' uruchamiamy metodę udostępnioną przez interfejs w.danedokierunkizjazdy(strbaza, ide, semestr) ' badamy, czy wszystko przebiegło pozytywnie If w.komunikat.length > 0 Then ' niestety nie, komunikat na ekran MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' tak, mamy dane, tworzymy instancję raportu Dim objraport As New crprzykladowyszablon ' przypisujemy jego źródło danych objraport.setdatasource(w.dajtabele) ' przypisujemy wartości do pól specjalnych raportu objraport.summaryinfo.reporttitle = tytul objraport.summaryinfo.reportcomments = _ "Średnio dla kierunku" objraport.summaryinfo.reportauthor = "Zjazdy" ' wskazujemy źródło raportu dla viewera Me.crvAnkieta.ReportSource = objraport ' zmieniamy tytuł okna formularza Me.Text = tytul ' odświeżamy viewer Me.crvAnkieta.Refresh() Case "PracownicyZjazdy" ' komentarza analogiczne jak w poprzednim przypadku Dim w As IRaportPracownicyZjazdy w = New CRaporty w.danedopracownicyzjazdy(strbaza, ide, semestr) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else Dim objraport As New crprzykladowyszablon objraport.setdatasource(w.dajtabele) objraport.summaryinfo.reporttitle = tytul 315

316 316 objraport.summaryinfo.reportcomments = _ "Średnio dla pracownika" objraport.summaryinfo.reportauthor = "Zjazdy" Me.crvAnkieta.ReportSource = objraport Me.Text = tytul Me.crvAnkieta.Refresh() End Select End Class Odpowiednia wersja raportu wyników ankiet przedmiotowych uruchamiana jest poprzez menu aplikacji, w którym w pozycji Raporty/Ankiet znajdziemy cztery ich wersje. Wybór jednej z tych pozycji uruchamia odpowiednią procedurę, których kod pokazany jest niżej. Private Sub mnuraportkierunkizjazdy_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuraportkierunkizjazdy.click Dim frm As New frmankietaraport frm.txtpomoc.text = "KierunkiZjazdy" Dim w As IRaportAnkiet w = New CRaporty w.przygotujdaneotwarcia(strbaza, frm) PokazForm(frm, w.komunikat, _ "Raport ankiet wg kierunków i zjazdów") Private Sub mnuraportpracownicyzjazdy_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuraportpracownicyzjazdy.click Dim frm As New frmankietaraport frm.txtpomoc.text = "PracownicyZjazdy" Dim w As IRaportAnkiet w = New CRaporty w.przygotujdaneotwarcia(strbaza, frm) PokazForm(frm, w.komunikat, _ "Raport ankiet wg wykładowców i zjazdów")

317 317 Private Sub mnuraportprzedmiotyzjazdy_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuraportprzedmiotyzjazdy.click Dim frm As New frmankietaraport frm.txtpomoc.text = "PrzedmiotyZjazdy" Dim w As IRaportAnkiet w = New CRaporty w.przygotujdaneotwarcia(strbaza, frm) PokazForm(frm, w.komunikat, _ "Raport ankiet wg przedmiotów i zjazdów") Private Sub mnuraportporwadzacyprzedmiot_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuraportporwadzacyprzedmiot.click Dim frm As New frmankietaraport frm.txtpomoc.text = "PrzedmiotyPracownicy" Dim w As IRaportAnkiet w = New CRaporty w.przygotujdaneotwarcia(strbaza, frm) PokazForm(frm, w.komunikat, _ "Raport ankiet wg wykładowców i przedmiotów") Widok gotowych raportów ankiet przedmiotowych Poniżej kilka zrzutów ekranowych demonstrujących przygotowane raporty wyników ankiet przedmiotowych. Zmiana edycji czy semestru zajęć modyfikuje wygląd raportu.

318 318 Wszystkie raporty przedmiotowe zostały kolejno otwarte, każdy jest inny (w sensie prezentowanej informacji), a zostały zbudowane przy pomocy tego samego szablonu raportu.

319 7.7. Przygotowanie wzorców ankiet przedmiotowych Projekt formularza frmprzygotowanieankiet 319 Formularz frmprzygotowanieankiet pozwala na wybranie semestru i zjazdu szkoleniowego, dla którego chcemy przygotować wzorce ankiet przedmiotowych. Na powierzchni formularza umieszczono: grbsemestr grupę opcji z dwoma przyciskami radiowymi pozwalającymi na wybór semestru zajęć; grbzjazd grupę opcji z sześcioma przyciskami radiowymi pozwalającymi na wybór zjazdu szkoleniowego; btnprzygotuj przycisk polecenia. W module klasy tego formularza utworzono dwie procedury obsługujące zdarzenia związane z jego funkcjonowaniem. Public Class frmprzygotowanieankiet Private Sub frmprzygotowanieankiet_load(byval sender As Object, _ ByVal e As System.EventArgs) Handles Me.Load ZaznaczRdb(Me.rdbPierwszy1) ZaznaczRdb(Me.rdbZjazd1) Private Sub btnprzygotuj_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnprzygotuj.click Dim w As IWzorceAnkiet w = New CRaporty w.przygotujwzorceankiet(strbaza, UstalGrb(Me.grbSemestr), _ UstalGrb(Me.grbZjazd)) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else ' można pokazac raport Dim frm As New frmankietyzjazdu ' tworzy kopię naszego szablonu

320 320 Dim objraport As New crwzorzecankiety ' przypisanie źródła danych objraport.setdatasource(w.dajtabele) frm.crystalreportviewer1.reportsource = objraport frm.mdiparent = frmmdistudia frm.show() End Class Utworzenie obiektu DataTable Kolejny krok w pracy nad raportem prezentującym wzorce ankiet to dodanie do istniejącego obiektu dsprzykladowy nowej tabeli o nazwie np. dtankieta. Kolumny tego obiektu mają dokładnie takie same nazwy, jak te, które są zwracane przez procedurę przechowywaną pwykazktoco. Obiekt dtankieta będzie źródłem danych wykorzystanym do przygotowania szablonu raportu crwzorzecankiety Projekt szablonu crwzorzecankiety Postępując dokładnie tak samo jak w przypadku tworzenia szablonu raportu prezentującego wyniki ankiet dodajemy do naszego rozwiązania nowy obiekt typu CrystalReports, w naszym przypadku nadaliśmy mu nazwę crwzorzecankiety. Korzystając z kreatora wskazujemy typ raportu, jego źródło danych (czyli obiekt dtankieta) i dalej te wszystkie elementy, które są niezbędne dla raportu. Po zakończeniu pracy kreatora musimy ręcznie dokonać dość znacznych poprawek w przygotowanym projekcie. W znacznie powiększonej sekcji nagłówka strony (Page Header) umieszczamy niezbędne informacje ogólne oraz logotyp instytucji współfinansującej studia podyplomowe. Sekcja detali jest całkowicie przebudowana, w jej górnej części umieszczamy pola źródła danych z niezbędnymi etykietami, a w dolnej stały tekst treści ankiety. Po odpowiednim sformatowaniu, dodaniu linii itd. szablon raportu jest gotowy.

321 321 Poniżej fragment przygotowanego projektu raportu wzorca ankiet Projekt formularza frmankietyzjazdu Musimy do naszego rozwiązania dodać jeszcze jeden formularz, będziemy w nim prezentować gotowy raport.

322 322 Formularz ten zawiera jeden formant typu CrystalReportViever, którego nazwę zmieniono na crywzorzecankiet Prezentacja raportu wzorców ankiet Poniżej pokazany jest widok wzorca ankiet przedmiotowych wydrukowanynych na zjazd 5 semestru 1.

323 8. Rozliczenia finansowe 323 W ramach rozliczeń finansowych ograniczymy się w tej książce do pokazania sposobów przygotowywania wypłat wynagrodzeń dla wykładowców jak i pracowników zatrudnionych do prac administracyjnych w trakcie realizacji studiów podyplomowych Klasa CSkladki Klasa CSkladki zawiera dwie metody, pierwszą z nich będziemy wykorzystywać do wyznaczenia składników płac dla pracowników administracyjnych projektu, a drugą dla wykładowców. W klasie będą wykorzystywane publiczne zmienne zawierające procentowe wskaźniki wykorzystywane w tego typu obliczeniach (składki emerytalne, zdrowotne, rentowe itd.). Zmienne te otrzymały odpowiednie wartości w momencie uruchamiania aplikacji poprzez ich odczytanie z pliku konfiguracyjnego. Poza metodami w klasie zdefiniowano szereg właściwości zwracających wyliczone składniki płac. Klasa importuje przestrzeń System.Math z uwagi na wykorzystywanie funkcji zaokrągleń (Round). Imports System.Math Public Class CSkladki ' zmienne prywatne klasy opisujące składnik płac ponoszone przez ' firmę Private msef, msrf, mswf, mfp, mfgsp As Decimal ' pracowników Private msep, msrp, mschp, msd1, msd2, mpus As Decimal ' inne Private mdowyplaty, mzus1, mzus2, mzus3 As Decimal ' Public Sub ObliczSkladkiPersonelu(ByVal Start As Decimal, _ ByVal forma As String) ' deklaracja zmiennych prywatnych procedury Dim sef, srf, swf, fp, fgsp As Single Dim sep, srp, schp, razemf As Single Dim bruttop, kosztf, psz As Decimal Dim sd1, sd2 As Single Dim kup, pnp, pn As Decimal ' wysokości składek firmy zależą od formy zatrudnienia Select Case forma Case "P", "Z" sef = EnerytalnaFirmy srf = RentowaFirmy swf = WypoczynkowaFirmy fp = FunduszPracowniczy fgsp = FirmyGSP Case "D"

324 324 sef = 0 srf = 0 swf = WypoczynkowaFirmy fp = 0 fgsp = 0 End Select ' kwoty składek ponoszone przez firmę razemf = sef + srf + swf + fp + fgsp bruttop = Round(Start / (1 + razemf), 2) kosztf = Start - bruttop ' koszt firmy msef = Round((kosztF * sef) / razemf, 2) msrf = Round((kosztF * srf) / razemf, 2) mswf = Round((kosztF * swf) / razemf, 2) mfp = Round((kosztF * fp) / razemf, 2) mfgsp = kosztf - msef - msrf - mswf - mfp ' wysokość składek pracownika zależy też od formy zatrudnienia Select Case forma Case "P" sep = EmerytalnaPracownika srp = RentowaPracownika schp = ChorobowaPracownika sd1 = SkladkaZdrowia1 sd2 = SkladkaZdrowia2 Case "Z" sep = EmerytalnaPracownika srp = RentowaPracownika schp = 0 sd1 = SkladkaZdrowia1 sd2 = SkladkaZdrowia2 Case "D" sep = 0 srp = 0 schp = 0 sd1 = SkladkaZdrowia1 sd2 = SkladkaZdrowia2 End Select msep = Round(sep * bruttop, 2) msrp = Round(srp * bruttop, 2) mschp = Round(schp * bruttop, 2) psz = bruttop - msep - msrp - mschp 'podstawa skl. zdrowia msd1 = Round(psz * sd1, 2) msd2 = Round(psz * sd2, 2) kup = psz * 0.2 pnp = psz - kup pn = pnp * 0.18 mpus = Round(pn - msd1, 0) mdowyplaty = _ bruttop - msep - msrp - mschp - msd1 - msd2 - mpus ' zbiorcze skladki do zus

325 325 mzus1 = msef + msrf + mswf + msep + msrp + mschp mzus2 = msd1 + msd2 mzus3 = mfp + mfgsp Public Sub ObliczSkladkiWykladowcy(ByVal Start As Decimal, _ ByVal forma As String) Dim sef As Single, srf As Single, swf As Single, _ fp As Single, fgsp As Single Dim sep As Single, srp As Single, schp As Single Dim razemf As Single Dim bruttop As Decimal, kosztf As Decimal Dim psz As Decimal, sd1 As Single, sd2 As Single Dim kup As Decimal, pnp As Decimal, pn As Decimal If forma = "P" Then sef = EnerytalnaFirmy srf = RentowaFirmy swf = WypoczynkowaFirmy fp = FunduszPracowniczy fgsp = FirmyGSP ' razemf = sef + srf + swf + fp + fgsp bruttop = Round(Start / (1 + razemf), 2) kosztf = Start - bruttop ' koszt firmy msef = Round((kosztF * sef) / razemf, 2) msrf = Round((kosztF * srf) / razemf, 2) mswf = Round((kosztF * swf) / razemf, 2) mfp = Round((kosztF * fp) / razemf, 2) mfgsp = kosztf - msef - msrf - mswf - mfp Else bruttop = Start kosztf = 0 ' koszt firmy msef = 0 msrf = 0 mswf = 0 mfp = 0 mfgsp = 0 ' składki pracownika If forma = "P" Then sep = EmerytalnaPracownika srp = RentowaPracownika schp = ChorobowaPracownika sd1 = SkladkaZdrowia1 sd2 = SkladkaZdrowia2 Else sep = 0 srp = 0 schp = 0

326 326 sd1 = 0 sd2 = 0 msep = Round(sep * bruttop, 2) msrp = Round(srp * bruttop, 2) mschp = Round(schp * bruttop, 2) psz = bruttop - msep - msrp - mschp ' podstawa skladki zdrowia msd1 = Round(psz * sd1, 2) msd2 = Round(psz * sd2, 2) kup = psz * 0.5 pnp = psz - kup pn = pnp * 0.18 mpus = Round(pn - msd1, 0) mdowyplaty = _ bruttop - msep - msrp - mschp - msd1 - msd2 - mpus ' zbiorcze skladki do zus mzus1 = msef + msrf + mswf + msep + msrp + mschp mzus2 = msd1 + msd2 mzus3 = mfp + mfgsp ' seria właściwości zwracających składniki płac ReadOnly Property ZUS1() As Decimal Get Return mzus1 End Get End Property ReadOnly Property ZUS2() As Decimal Get Return mzus2 End Get End Property ReadOnly Property ZUS3() As Decimal Get Return mzus3 End Get End Property ReadOnly Property DoWyplaty() As Decimal Get Return mdowyplaty End Get End Property ReadOnly Property PodatekDoUS() As Decimal Get PodatekDoUS = mpus

327 327 End Get End Property ReadOnly Property SkladkaZdrowiaJeden() As Decimal Get SkladkaZdrowiaJeden = msd1 End Get End Property ReadOnly Property SkladkaZdrowiaDwa() As Decimal Get SkladkaZdrowiaDwa = msd2 End Get End Property ReadOnly Property SkladkaEmerytalnaPracownika() As Decimal Get SkladkaEmerytalnaPracownika = msep End Get End Property ReadOnly Property SkladkaRentowaPracownika() As Decimal Get SkladkaRentowaPracownika = msrp End Get End Property ReadOnly Property SkladkaChorobowaPracownika() As Decimal Get SkladkaChorobowaPracownika = mschp End Get End Property ReadOnly Property SkladaEmerytalnaFirmy() As Decimal Get SkladaEmerytalnaFirmy = msef End Get End Property ReadOnly Property SkladaRentowaFirmy() As Decimal Get SkladaRentowaFirmy = msrf End Get End Property ReadOnly Property SkladaWypadkowaFirmy() As Decimal Get SkladaWypadkowaFirmy = mswf End Get

328 328 End Property ReadOnly Property FunduszPracowniczyFirmy() As Decimal Get FunduszPracowniczyFirmy = mfp End Get End Property ReadOnly Property FunduszGSP() As Decimal Get FunduszGSP = mfgsp End Get End Property End Class Klasę CSkladki wykorzystamy w metodach klasy CRozlicznia odpowiedzialnych za rozliczenie wykładowców czy pracowników administracyjnych Tabele wykorzystane do rozliczeń Tabela Rachunki przechowuje numeru rachunków bankowych Uczelni, które będą wykorzystywane w rozliczeniach. Tabela RachunkiOperacje ma przechowywać wszystkie operacje wykonywane w ramach prowadzenia studiów podyplomowych. Tabela temprozliczenie ma charakter pomocniczy, będą w niej umieszczane te informacje, które wykorzystamy do przygotowania przelewów bankowych.

329 329 Analogiczny charakter ma tabela tempskladki, będziemy w niej umieszczać wyliczone składniki płac wyznaczone zgodnie z obowiązującymi w tej materii przepisami. Tabela StawkiWykladowcy przechowuje stawki wynagrodzeń wykładowców za realizację godziny zajęć dydaktycznych (oczywiście to jest skrót myślowy, bo w tej stawce jest także przygotowanie materiałów dydaktycznych, testów przedmiotowych i semestralnych, ich sprawdzanie itd.). Stawki te zawierają również tą część wydatków płacowych, która musi być poniesiona w imieniu Uczelni jako pracodawcy).

330 330 Tabela StawkiAdministracji zawiera informacje o miesięcznych wynagrodzeniach brutto (wraz z kosztami ponoszonymi przez Uczelnię). Tabele te będą oczywiście współpracować (poprzez procedury przechowywane i funkcje) z innymi tabelami bazy danych, takimi jak np. Pracownicy, Personel czy PlanZajec Procedury przechowywane i funkcje skalarne Metody klasy CRozliczenia będą wywoływać wykonanie szeregu procedur i funkcji przechowywanych. W kolejnych podrozdziałach przedstawiono ich kod i w skrócie podano ich przeznaczenie. Procedury te zostały pogrupowane wg interfejsów tej klasy Wykorzystywane w IRozliczenieWykladowcow Poniżej przedstawiono procedury przechowywane i funkcje wykorzystywane w trakcie finansowego rozliczania wykładowców za przeprowadzone zajęcia dydaktyczne. Procedura pjakisemestrzjazd zwraca specjalnie przygotowane pole opisujące ten semestr i zjazd, które nie zostały jeszcze rozliczone. create procedure int as select distinct semestr*10+zjazd as ktory, ' ' +cast(semestr as varchar(10))+' ' +cast(zjazd as varchar(10)) as SemestrZjazd from PlanZajec INNER JOIN Terminy ON PlanZajec.idt = Terminy.idt where datar is null and Terminy.ide=dbo.fAktywnaEdycja() Funkcja skalarna faktywnaedycja zwraca identyfikator aktywnej edycji studiów podyplomowych (aktualnie realizowanej).

331 331 create function faktywnaedycja () RETURNS int as begin int from dbo.edycjestudiow where StatusE=2 end Procedura pzestawienierozliczenia odpowiada za wykonanie szeregu działań, ich efektem końcowym jest wstawienie do tabeli pomocniczej temp rozliczenie rekordów opisujących dla wykładowców uwzględnionych w rozliczeniu takie informacje, jak liczba godzin dydaktycznych, formę zatrudnienia, stawkę godzinową, numer konta bankowego i nazwę banku, dane adresowe, kwotę wynagrodzenia brutto oraz numer rachunku bankowego Uczelni, z którego ma być zrealizowana płatność. create procedure int as delete from dbo.temprozliczenie delete from dbo.tempskladki insert into dbo.temprozliczenie (idp, Kto, rozliczyc, ilegodzin, formaz, stawka, Bank, NrRachunku, Adres, Kod, Kwota, NaszRachunek) select Pracownicy.id_w, Pracownicy.Wykladowca, 0 as rozliczyc, sum(godziny.ilegodzin) as Godzin, Pracownicy.FormaZ, dbo.fdajstawke(dbo.faktywnaedycja(), Pracownicy.id_w) as Stawka, Pracownicy.NazwaBanku, Pracownicy.Rachunek, Pracownicy.Adres, Pracownicy.Kod, dbo.fdajbrutto(pracownicy.id_w, sum(godziny.ilegodzin)) as Kwota, as NaszRachunek from PlanZajec INNER JOIN Terminy ON PlanZajec.idt = Terminy.idt INNER JOIN Godziny ON PlanZajec.idg = Godziny.idg INNER JOIN Pracownicy ON PlanZajec.idw = Pracownicy.id_w INNER JOIN StawkiWykladowcy ON Pracownicy.id_w = StawkiWykladowcy.id_w where Terminy.ide = dbo.faktywnaedycja() AND Terminy.semestr AND Terminy.zjazd AND PlanZajec.DataR IS NULL group by Pracownicy.id_w, Pracownicy.Wykladowca, Pracownicy.NazwaBanku, Pracownicy.Rachunek, Pracownicy.FormaZ, Pracownicy.Adres, Pracownicy.Kod Funkcja skalarna fdajbrutto zwraca wyloczoną kwotę wynagrodzenia brutto dla danego pracownika na podstawie przekazanej liczby wykonanych godzin dydaktycznych. create function fdajbrutto] int)

332 332 RETURNS money as begin int = stawka from StawkiWykladowcy WHERE id_e = dbo.faktywnaedycja() AND id_w set end Funkcja skalarna fnaszrachunek zwraca numer rachunku bankowego Uczelni na podstawie przekazanego identyfikatora rachunku. create function fnaszrachunek int) RETURNS nvarchar(32) as begin nvarchar(32) from dbo.rachunki where end Procedura poniższa zwraca z pomocniczej tabeli temprozlicznia identyfikatory i dane pracowników do przygotowania przelewów wynagrodzeń za wykonane zajęcia dydaktyczne. create procedure int as select idp, Kto as Wykladowca from dbo.temprozliczenie order by Kto Procedura pupdatetemprozliczenia zmienia wartość pola rozliczyć dla danego pracownika na przekazaną (0 lub 1). creater procedure bit as update dbo.temprozliczenie set where Procedura pdajkwotebrutto zwraca kwotę brutto wynagrodzenia danego pracownika. create procedure money out as

333 333 from dbo.temprozliczenie where Procedura poniższa zwraca sumę wynagrodzeń brutto dla tych pracowników w tabeli temprozliczenia, dla których pole rozliczyc jest ustawione na 1. create procedure money out as from dbo.temprozliczenie where rozliczyc=1 Procedura pdajstanrachunku zwraca aktualny stan salda wskazanego rachunku. create procedure money out as select from dbo.rachunkioperacje where idr order by id desc Procedura pileprzelewow zwraca rekordset identyfikatorów tych pracowników, dla których mają być przygotowane przelewy. create procedure int as select idp from dbo.temprozliczenie where rozliczyc = 1 Procedura pupdatenaszrachunek będzie wykorzystywana w tych sytuacjach, w których w trakcie przygotowywania przelewów zmienimy rachunek bankowy Uczelni. create procedure int as update dbo.temprozliczenie set NaszRachunek = Procedura poniższa zwraca informacje niezbędne do wyliczenia składników płac dla wskazanego pracownika. create procedure int as select Kto, ilegodzin, formaz, stawka from dbo.temprozliczenie where

334 334 Procedura pwstawskladki odpowiada za wstawienie do pomocniczej tabeli tempskladki kwot wyliczonych składników płac. create procedure money as insert into dbo.tempskladki (idw, Kto, EmerytalnaF, RentowaF, WypadkowaF, FunduszP, FunduszGSP, EmerytalnaP, RentowaP, ChorobowaP, Zdrowia1, Zdrowia2, PodatekUS, ZUS1, ZUS2, ZUS3, update dbo.temprozliczenie set where Procedura pdajwyplatew zwraca te informacje, które bezpośrednio posłużą do skomponowania treści przelewu bankowego. create procedure nvarchar(100) as select idp, Kto, Bank, NrRachunku, Kwota, Adres, as Tytulem, NaszRachunek from dbo.temprozliczenie order by Kto Procedura pupdatedatyrozliczenia odpowiada za aktualizację pola DataR w tabeli PlanZajec dla tych zajęć, za wykonanie których pracownik otrzymał wynagrodzenie. create procedure smalldatetime as update dbo.planzajec set where idt in ( select idt from Terminy where ide = dbo.faktywnaedycja() and and ) and DataR is null and idw in ( select idp from temprozliczenie where rozliczyc=1 )

335 Wykorzystywane w IRozliczeniaAdministracji Procedura psaldopersonelu zwraca saldo wskazanego rachunku po ewentualnym obciążeniu go kosztami wypłaty wynagrodzeń dla pracowników administracji. create procedure money out as money = SUM(Brutto) from EdycjeAdministracja where id_e = dbo.faktywnaedycja() begin select = saldo from dbo.rachunkioperacje where idr order by id desc set end else begin set end Procedura pileprzelewowpersonelu odpowiada za zwrócenie rekordsetu zawierającego informacje płacowe tej grupy pracowników. ma charakter jedynie techniczny wynikający z konstrukcji procedur klasy CForStorageSub. create procedure int as select Personel.idp, Personel.NazwiskoImie, Personel.NazwaBanku, Personel.Rachunek, Personel.FormaZ, EdycjeAdministracja.Brutto, Personel.Adres, Personel.Kod from Personel INNER JOIN EdycjeAdministracja ON Personel.idp = _ EdycjeAdministracja.id_p where EdycjeAdministracja.id_e = dbo.faktywnaedycja() Procedura pwstawskladkipersonelu odpowiada za wstawienie do tabeli pomocniczej tempskladki wyliczonych składników płac. create procedure money,

336 money as insert into Procedura pwstawtemprozliczaniea wstawia do tabeli temprozliczenie informacje niezbędne do wygenerowania przelewu banlowego. create procedure int as insert into dbo.temprozliczenie (idp, Kto, rozliczyc, ilegodzin, Bank, NrRachunku, Kwota, Adres, Kod, NaszRachunek) @kod,

337 Klasa CRozliczenia W klasie CRozliczenia zostały zebrane te metody i właściwości, które będziemy wykorzystywać w rozliczeniach finasowych z wykładowcami i pracownikami administracyjnymi edycji studiów. Pierwsze trzy instrukcje zapisane w module tej klasy importują potrzebne przestrzenie nazw. Imports System.Data Imports System.Data.SqlClient Imports System.IO W klasie utworzono kilka interfesów, każdy z nich zawiera wyspecjalizowane metody i właściwości, które będziemy wykorzystywać do obsługi określonych zadań Interfejsy klasy CRozliczenia Interfejs IRozliczenieWykladowcow W tym interfejsie zadekalarowano te właściwości i metody, które będą wykorzystane do rozliczeń wynagrodzeń za wykonane zajęcia dydaktyczne. Jako argumenty do metod zapowiedzianych w tym interfejsie będą przekazywane instancje dwóch formularzy, których projekty będą przedstawione później. Public Interface IRozliczenieWykladowcow Function Komunikat() As String Function DajTabele() As DataTable Sub OtwarcieRozliczenia(ByVal strconn As String, ByVal frm As _ frmrozliczeniewykladowcow) Sub PrzygotujRozliczenie(ByVal strconn As String, ByRef frm As _ frmrozliczeniewykladowcow) Sub ZmianaWykladowcy(ByVal strconn As String, ByRef frm As _ frmrozliczeniewykladowcow, ByVal idp As Integer, _ ByVal jak As Boolean) Sub ZmianaRachunku(ByVal strconn As String, ByRef frm As _ frmrozliczeniewykladowcow) Sub ZaplacWykladowcom(ByVal strconn As String, ByRef frm As _ frmrozliczeniewykladowcow) Sub RaportSkladek(ByVal strconn As String, ByVal frm As _ frmraportskladek) End Interface Interfejs IRozlicznieAdministracji Interfejs deklaruje właściwości i metody, które będą wykorzystane przy przygotowaniu miesięcznych wynagrodzeń dla pracowników administracyjnych zatrudnionych przy realizacji studiów podyplomowych.

338 338 Public Interface IRozliczeniaAdministracji Function Komunikat() As String Function DajSaldo() As Decimal Sub OtworzWyplateAdministracji(ByVal strconn As String, _ ByVal frm As frmwyplataadministracyjna) Sub ZaplacAdminstracji(ByVal strconn As String, ByVal frm As _ frmwyplataadministracyjna) Sub ZmianaRachunkuAdministracji(ByVal strconn As String, ByVal _ idr As Integer) End Interface Kod klasy CRozliczenia Kod kklasy CRozliczenia zaczyna się instrukcją dziedziczenia po klasie bazowej CForStorageSub, dalsze dwie instrukcją zapowiadają implementację obu interfejsów, a po nich są deklaracje zmiennych prywatnych klasy. Public Class CRozliczenia Inherits CForStorageSub Implements IRozliczenieWykladowcow Implements IRozliczeniaAdministracji Private mkomunikat As String = "" Private msaldo As Decimal Private mide As Integer = 0 Private mtable1 As DataTable Private mtable2 As DataTable Po tych wstępnych instrukcjach mamy implementację właściwości i metod zadeklarowanych w interfejsach klasy. Public Function Komunikat() As String Implements _ IRozliczenieWykladowcow.Komunikat, _ IRozliczeniaAdministracji.Komunikat Return mkomunikat End Function Public Function DajTabele() As DataTable Implements _ IRozliczenieWykladowcow.DajTabele Return mtable1 End Function Public Function DajSaldo() As Decimal Implements _ IRozliczeniaAdministracji.DajSaldo Return msaldo End Function Metoda OtwarcieRozliczenia jest odpowiedzialna za przygotowanie danych niezbędnych do przygotowania instancji formularza frmrozliczeniewykladowcow do pokazania użytkownikowi. Jej głównym zadaniem jest pobranie z bazy danych

339 339 informacji o tym, z jakich semestrów i zjazdów nie zostały jeszcze rozliczone wynagrodzenia wykładowców. Public Sub OtwarcieRozliczenia(ByVal strconn As String, _ ByVal frm As frmrozliczeniewykladowcow) Implements _ IRozliczenieWykladowcow.OtwarcieRozliczenia Dim conn As New SqlConnection(strconn) Try conn.open() mtable2 = MyBase.DajRekordset(conn, _ "dbo.pjakisemestrzjazd", _ 1, 1, 0) UstawListBox(frm.lstSemestrZjazd, mtable2, _ "SemestrZjazd", "ktory") ZaznaczRdb(frm.rdbPodstawowy3) ZaznaczRdb(frm.rdbHomeBanking) frm.txtsaldo.text = "0" Catch ex As Exception mkomunikat = "Błąd ustalenia semestru i zjazdu" Finally conn.close() conn = Nothing End Try Metoda PrzygotujRozliczenie odpowiada za ustalenie kwot wynagrodzenia i innych informacji niezbędnych do rozliczenia finansowego wykładowców. Innym zadaniem jest przygotowanie źródła danych do zaznaczanej listy zawierających nazwiska tych wykładowców, dla których powinny być przygotowane przelewy. Public Sub PrzygotujRozliczenie(ByVal strconn As String, _ ByVal frm As frmrozliczeniewykladowcow) Implements _ IRozliczenieWykladowcow.PrzygotujRozliczenie Dim conn As New SqlConnection(strConn), t As String, _ semestr, zjazd, idr As Integer t = frm.lstsemestrzjazd.selectedvalue.tostring semestr = CInt(t.Substring(0, 1)) zjazd = CInt(t.Substring(1, 1)) idr = UstalGrb(frm.grbRachunek) Try conn.open() MyBase.Wykonaj(conn, "dbo.pzestawienierozliczenia", _ semestr, 1, 0, _ zjazd, 1, 0, _ idr, 1, 0) mtable2 = MyBase.DajRekordset(conn, _ "dbo.pdajpozycjedorozliczenia", _ 1, 1, 0) UstawChdListBox(frm.chlDoRozliczenia, mtable2, _

340 340 "Wykladowca", "idp") Catch ex As Exception mkomunikat = "Błąd przygotowania listy wykładowców" Finally conn.close() conn = Nothing End Try Metoda ZmianaWykladowcy odpowiada za aktualizację kwot, które powinniśmy wypłacić w sytuacji, gdy użytkownik zmienił decyzję co do wypłacenia lub nie danemu wykładowcy wynagrodzenia w tym rozliczeniu. Public Sub ZmianaWykladowcy(ByVal strconn As String, _ ByRef frm As frmrozliczeniewykladowcow, ByVal idp As _ Integer, ByVal jak As Boolean) Implements _ IRozliczenieWykladowcow.ZmianaWykladowcy Dim conn As New SqlConnection(strconn), kw, kp As Decimal, _ idr As Integer Try conn.open() MyBase.Wykonaj(conn, "dbo.pupdatetemprozliczenie", _ idp, 1, 0, _ jak, 1, 0) kw = CDec(MyBase.DajWartosc(conn, "dbo.pdajkwotebrutto", _ idp, 1, 0, _ 3, 0)) If jak Then frm.txtsaldo.text = DecimalLikeMoney( _ (CDec(frm.txtSaldo.Text) - kw).tostring) Else frm.txtsaldo.text = DecimalLikeMoney( _ (CDec(frm.txtSaldo.Text) + kw).tostring) idr = UstalGrb(frm.grbRachunek) If idr < 3 Then kp = CDec(frm.txtSaldo.Text) If kp < 100 Then ' nie ma wystarczających środków, komunikat mkomunikat = "Na rachunku " & _ DajSkrotLubPelnyRachunek(conn, idr, False) & _ " nie ma wystarczających środków" & vbcrlf & _ "Zmień rachunek" MyBase.Wykonaj(conn, _ "dbo.pupdatetemprozliczenie", _ idp, 1, 0, _ False, 1, 0) frm.txtsaldo.text = DecimalLikeMoney(_ (CDec(frm.txtSaldo.Text) + kw).tostring)

341 341 Catch ex As Exception mkomunikat = "Błąd pobrania kwot z bazy SQL" Finally conn.close() conn = Nothing End Try Prywatna funkcja klasy odpowiada za zwrócenie wskazanego rachunku bankowego Uczelni w pełnej werskji lub w postaci symbolicznego skrótu. Private Function DajSkrotLubPelnyRachunek(ByVal conn As _ SqlConnection, ByVal idr As Integer, _ ByVal codac As Boolean) As String If codac = False Then DajSkrotLubPelnyRachunek = _ Choose(idr, "080", "090", "010") Else DajSkrotLubPelnyRachunek = MyBase.DajWartosc(conn, _ "dbo.pdajrachunek", _ idr, 1, 0, _ 5, 32) End Function Metoda ZmianaRachunku odpowiada za aktualizację kwot, które powinniśmy wypłacić w sytuacji, gdy użytkownik zmienił decyzję co do rachunku, z którego mają być wypłacone honoraria wykładowców. Public Sub ZmianaRachunku(ByVal strconn As String, ByRef frm As _ frmrozliczeniewykladowcow) Implements _ IRozliczenieWykladowcow.ZmianaRachunku Dim conn As New SqlConnection(strconn), zob, ile As Decimal, _ idr As Integer Try conn.open() idr = UstalGrb(frm.grbRachunek) zob = CDec(MyBase.DajWartosc(conn, _ "dbo.pdajkwotebruttorazem", _ "kwota", 3, 0)) If idr < 3 Then ile = CDec(MyBase.DajWartosc(conn, _ "dbo.pdajstanrachunku", _ "idr", idr, 1, 0, _ "saldo", 3, 0)) Else ile = 0

342 342 frm.txtsaldo.text = DecimalLikeMoney ((ile - zob).tostring) Catch ex As Exception mkomunikat = "Błąd pobrania kwot z bazy SQL" Finally conn.close() conn = Nothing End Try Metoda ZaplacWykladowcom odpowiada za przygotowanie przelewów dla wykładowców. Public Sub ZaplacWykladowcom(ByVal strconn As String, _ ByVal frm As frmrozliczeniewykladowcow) Implements _ IRozliczenieWykladowcow.ZaplacWykladowcom Dim conn As New SqlConnection(strconn), tb As DataTable Dim z As New CSkladki Dim folder, plik, td, tp As String, idr, gdzie, ile, i, _ idprz As Integer folder = FolderParp idr = UstalGrb(frm.grbRachunek) Try If frm.rdbhomebanking.checked Then gdzie = 1 'HB plik = Choose(Now().Month, "Styczen", "Luty", "Marzec", _ "Kwiecien", "Maj", "Czerwiec", "Lipiec", _ "Sierpien", "Wrzesien", "Pazdziernik", _ "Listopad", "Grudzien") & _ Format(Now().Year, "0000") & _ "PoborySPWykladowcy.txt" td = "110," & Format(Now().Year, "0000") & _ Format(Now().Month, "00") & Format(Now().Day, "00") FileOpen(1, FolderParp & plik, OpenMode.Output) Else gdzie = 2 'drukarka conn.open() mtable1 = MyBase.DajRekordset(conn, "dbo.pileprzelewow", _ "ile", 1, 1, 0) ile = mtable1.rows.count If ile > 0 Then MyBase.Wykonaj(conn, "dbo.pupdatenaszrachunek", _ "idr", idr, 1, 0) For i = 0 To ile - 1 idprz = mtable1.rows(i).item(0) mtable2 = MyBase.DajRekordset(conn, _ "dbo.pdajdanedoskladek", idprz, 1, 0) z.obliczskladki(mtable2.rows(0).item(1) * _ mtable2.rows(0).item(3), mtable2.rows(0).item(2))

343 343 WstawSkladki(conn, "dbo.pwstawskladki", z, idprz, _ mtable2.rows(0).item(0)) Next i 'rozszyfrowanie semestru i zjazdu Dim t As String = frm.lstsemestrzjazd.selectedvalue.tostring Dim semestr As String = t.substring(0, 1) Dim zjazd As String = t.substring(1, 1) Dim za As String = "Za zajęcia na semestrze " & semestr & _ " zjazdu " & zjazd tb = MyBase.DajRekordset(conn, "dbo.pdajwyplatew", _ za, 5, 100) If gdzie = 1 Then For i = 0 To tb.rows.count - 1 tp = DajWierszDoHomeBanking(tb, td, i) PrintLine(1, tp) Next FileClose(1) MsgBox("Przelewy do HB przygotowane w pliku " & _ folder & plik, MsgBoxStyle.Information, _ "Rozliczenie wykładowców") Else ' przygotowanie raportu z przelewami Dim objrpt As New rpwyplataw objrpt.setdatasource(tb) Dim f As New frmwyplata f.crystalreportviewer1.reportsource = objrpt f.mdiparent = frmmdistudia f.show() ' aktualizujemy pole DataR w tabeli PlanyZajec MyBase.Wykonaj(conn, "dbo.pupdatedatyrozliczenia", _ semestr, 1, 0, _ zjazd, 1, 0, _ Now().ToShortDateString, 4, 0) ' ponowne dostarczenie danych do lstsemestrzjazd mtable2 = MyBase.DajRekordset(conn, _ "dbo.pjakisemestrzjazd", 1, 1, 0) UstawListBox(frm.lstSemestrZjazd, mtable2, "SemestrZjazd", _ "ktory") ZaznaczRdb(frm.rdbPodstawowy3) ZaznaczRdb(frm.rdbHomeBanking) frm.txtsaldo.text = "0" Catch ex As Exception mkomunikat = "Błąd przygotowania przelewów dla wykładowców" Finally conn.close() conn = Nothing End Try

344 344 Metoda OtworzWyplateAdministracji odpowiada za inicjalizację formularza frmwyplataadministracyjna. Public Sub OtworzWyplateAdministracji(ByVal strconn As String, _ ByVal frm As frmwyplataadministracyjna) Implements _ IRozliczeniaAdministracji.OtworzWyplateAdministracji Dim conn As New SqlConnection(strconn) Try conn.open() msaldo = MyBase.DajWartosc(conn, _ "dbo.psaldoperspnelu", _ 3, 1, 0, _ 3, 0) ZaznaczRdb(frm.rdbPodstawowy3) ZaznaczRdb(frm.rdbHomeBanking) Catch ex As Exception mkomunikat = _ "Błąd ustalenia salda rachunku dla administracji" Finally conn.close() conn = Nothing End Try Metoda ZaplacAdminstracji odpowiada za przygotowanie przelewów dla pracowników administracyjnych. Public Sub ZaplacAdminstracji (ByVal strconn As String, _ ByVal frm As frmwyplataadministracyjna) Implements _ IRozliczeniaAdministracji.PrzygotujWyplate Dim conn As New SqlConnection(strconn), tb As DataTable ' tworzymy instancję klasy CSkladki Dim w As New CSkladki Dim folder, plik, td, tp As String, idr, gdzie, _ ile, i, idprz As Integer folder = FolderParp idr = UstalGrb(frm.grbRachunek) Try If frm.rdbhomebanking.checked Then gdzie = 1 'HB plik = Choose(Now().Month, "Styczen", "Luty", "Marzec", _ "Kwiecien", "Maj", "Czerwiec", "Lipiec", _ "Sierpien", "Wrzesien", "Pazdziernik", "Listopad", _ "Grudzien") & Format(Now().Year, "0000") & _ "PoborySPAdministracja.txt" td = "110," & Format(Now().Year, "0000") & _ Format(Now().Month, "00") & Format(Now().Day, "00")

345 345 FileOpen(1, folder & plik, OpenMode.Output) Else gdzie = 2 'drukarka conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pileprzelewowpersonelu", 1, 1, 0) ' ile przelewów do przygotowania ile = mtable1.rows.count If ile > 0 Then MyBase.Wykonaj(conn, "dbo.pusuntempskladki", _ 1, 1, 0) MyBase.Wykonaj(conn, "dbo.pusunrozliczenia", _ 1, 1, 0) MyBase.Wykonaj(conn, "dbo.pupdatenaszrachunek", _ idr, 1, 0) For i = 0 To ile - 1 idprz = mtable1.rows(i).item(0) ' obliczenie składników płacy w.obliczskladkipersonelu(mtable1.rows(i).item(5), _ mtable1.rows(i).item(4)) WstawSkladki(conn, "dbo.pwstawskladkipersonelu", _ w, idprz, mtable1.rows(i).item(1)) MyBase.Wykonaj(conn, "dbo.pwstawtemprozliczaniea", _ idprz, 1, 0, _ mtable1.rows(i).item(1), 5, 100, _ mtable1.rows(i).item(2), 5, 100, _ mtable1.rows(i).item(3), 5, 32, _ w.dowyplaty, 3, 0, _ mtable1.rows(i).item(6), 5, 100, _ mtable1.rows(i).item(7), 5, 50, _ idr, 1, 0) Next i ' skomponowanie tytułu przelewu Dim za As String = "Wynagrodzenie za m-c " & Now().Month tb = MyBase.DajRekordset(conn, "dbo.pdajwyplatew", _ za, 5, 100) If gdzie = 1 Then For i = 0 To tb.rows.count - 1 ' czytamy wiersz z tb tp = DajWierszDoHomeBanking(tb, td, i) PrintLine(1, tp) Next FileClose(1) MsgBox("Przelewy do HB przygotowane w pliku " & _ folder & plik, MsgBoxStyle.Information, _ "Rozliczenie wykładowców") Else ' przygotowanie raportu z przelewami

346 346 Dim objrpt As New rpwyplataw objrpt.setdatasource(tb) Dim f As New frmwyplata f.crystalreportviewer1.reportsource = objrpt f.mdiparent = frmmdistudia f.show() Catch ex As Exception mkomunikat = _ "Błąd przygotowania przelewów dla administracji" Finally conn.close() conn = Nothing End Try Prywatna procedura WstawSkladki odpowiada za wstawienie składników płac do tabeli tempskladki. Private Sub WstawSkladki(ByRef cn As SqlConnection, ByVal sp As _ String, ByRef z As CSkladki, ByVal idw As Integer, _ ByVal kto As String) MyBase.Wykonaj(cn, sp, _ idw, 1, 0, _ kto, 5, 100, _ z.skladaemerytalnafirmy, 3, 0, _ z.skladarentowafirmy, 3, 0, _ z.skladawypadkowafirmy, 3, 0, _ z.funduszpracowniczyfirmy, 3, 0, _ z.funduszgsp, 3, 0, _ z.skladkaemerytalnapracownika, 3, 0, _ z.skladkarentowapracownika, 3, 0, _ z.skladkachorobowapracownika, 3, 0, _ z.skladkazdrowiajeden, 3, 0, _ z.skladkazdrowiadwa, 3, 0, _ z.podatekdous, 3, 0, _ z.zus1, 3, 0, _ z.zus2, 3, 0, _ z.zus3, 3, 0, _ z.dowyplaty, 3, 0) Metoda RaportSkladek będzie wykorzystywana do zbudowania raportu składek płacowych (zarówno wyliczonych dla wykładowców jak i dla administracji) przy wykorzystaniu formularza z gridem (formantem typu DataGridView). Public Sub RaportSkladek(ByVal strconn As String, ByVal frm As frmraportskladek) Implements _

347 347 IRozliczenieWykladowcow.RaportSkladek Dim conn As New SqlConnection(strconn), i, j As Integer, _ xp As Decimal Try conn.open() mtable1 = MyBase.DajRekordset(conn, _ "dbo.pdajskaldkidoraportu", 1, 1, 0) If mtable1.rows.count > 0 Then DodajWierszPodsumowaniaDoDataTable(mTable1, _ "Razem składki") ' mamy juz podsumowanie, tworzymu źródło danych dla gdv With frm.dgvskladki.datasource = mtable1.columns(0).width = 150.Columns(0).HeaderText = "Nazwisko i imię".columns(0).readonly = True For i = 1 To mtable1.columns.count - 1.Columns(i).DefaultCellStyle.Format = "c".columns(i).defaultcellstyle.alignment = _ DataGridViewContentAlignment.MiddleRight.Columns(i).Width = 70.Columns(i).ReadOnly = True Next.AllowUserToAddRows = False.AllowUserToDeleteRows = False End With Else mkomunikat = "Brak składek do zbudowania raportu" Catch ex As Exception mkomunikat = "Błąd pobrania składek z bazy SQL" Finally conn.close() conn = Nothing End Try Metoda ZmianaRachunkuAdministracji odpowiada za zwrócenie potencjalnego stanu wybranego rachunku po obciążeniu go kosztami wypłaty wynagrodzenia pracownikom administracyjnym. Public Sub ZmianaRachunkuAdministracji(ByVal strconn As String, _ ByVal idr As Integer) Implements _ IRozliczeniaAdministracji.ZmianaRachunkuAdministracji Dim conn As New SqlConnection(strconn) Try conn.open() msaldo = MyBase.DajWartosc(conn, _ "dbo.psaldoperspnelu", _

348 348 idr, 1, 0, _ 3, 0) Catch ex As Exception mkomunikat = _ "Błąd ustalenia salda rachunku dla administracji" Finally conn.close() conn = Nothing End Try End Class 8.5. Szablon raportu przelewu bankowego Prace nad szablonem raportu przelewu zaczynamy od utworzenia obiektu typu DataTable o strukturze odpowiadającej rekordsetowi zwracanemu przez procedurę przechowywaną pdajwyplatew. W naszym przypadku taka tabela pod nazwą dtwyplataw została utworzona w istniejącym obiekcie dsprzykladowy. W oparciu o tabelę dtwyplataw zaprojektowano szablon raportu o nazwie rpwyplataw.rpt, przy czym szkielet raportu może być wykonany przy pomocy kreatora raportów. Mając szkielet raportu dokonujemy stosownych zmian, generalnie musimy powiększyć sekcję detali tak, aby przelew dla jednej osoby był drukowany na stronie A4. Aktualny wzór tego typu dokumentu nakazuje przygotowanie dwóch, prawie analogicznych odcinków przelewu (A i B). W każdym z tych odcinków muszą znaleźć się informacje o odbiorcy przelewu i jego nadawcy, numery kont bankowych, kwota przelewu i informacja o tytule przelewu.

349 349 Poniżej pokazany jest górny fragment przygotowanego w ten sposób szablonu raportu Formularz prezentujący raport przelewu Formularz frmwyplata zawiera jeden formant typu CrystalReportViewer, który będzie widziany dla naszego kodu pod nazwą crvwyplata.

350 350 W module klasy tego formularza nie musimy napisać nawet jednej linijki kodu, zdefiniowanie właściwości tego formantu będzie się odbywało w klasie CRozliczenia (zobacz metody PrzygotujWyplate czy ZaplacWykladowcom) Rozliczenie wykładowców Formularz frmrozliczeniewykladowcow Projekt tego formularza pokazany jest niżej. Umieszczono w nim następujące formanty: lstsemestrzjazd lista wyświetlające numer semestru i zjazdu, dla których nie rozliczono wykładowców; grbrachunek grupa opcji z trzema przyciskami radiowymi pozwalającymi na wybór jednego z rachunków bankowych Uczelni; grpwyprowadzic grupa opcji z dwoma przyciskami radiowymi określającymi miejsce wyprowadzenia przelewów; chldorozliczenia lista zaznaczana, w niej będziemy wybierać tych pracowników, dla których mają być (w danym momencie) przygotowane przelewy bankowe; txtsaldo pole tekstowe pokazujące stan salda wybranego rachunku; btnwykonaj przycisk polecenia uruchamiający przygotowanie przelewów oraz etykiety opisujące niektóre formanty.

351 351 Instancja tego formularza uruchamiana jest poprzez menu aplikacji, gdzie znajdziemy stosowne polecenie. Jego klik uruchamia pokazaną niżej procedurę zdarzeniową (z formularza frmmdistudia). Private Sub WmnuRozliczeniaWykladowcow_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnurozliczeniawykladowcow.click Dim frm As New frmrozliczeniewykladowcow Dim w As IRozliczenieWykladowcow w = New CRozliczenia w.otwarcierozliczenia(strbaza, frm) PokazForm(frm, w.komunikat) Kod formularza frmrozliczeniewykladowcow W module klasy formularza musimy napisać kilka procedur reagujących na zdarzenia związane z tym formularzem. Public Class frmrozliczeniewykladowcow ' procedura reagująca na wybór pozycji w liście lstsemestzjazd Private Sub lstsemestrzjazd_selectedvaluechanged(byval sender _ As Object, ByVal e As System.EventArgs) Handles _ lstsemestrzjazd.selectedvaluechanged If Not flaga Then Exit Sub Dim w As IRozliczenieWykladowcow w = New CRozliczenia w.przygotujrozliczenie(strbaza, Me) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) ' procedura obsługująca zmianę rachunku bankowego Private Sub rdbparp1_checkedchanged(byval sender As Object, + ByVal e As System.EventArgs) Handles _ rdbparp1.checkedchanged, rdbparp2.checkedchanged, _ rdbpodstawowy3.checkedchanged If Not flaga Then Exit Sub Dim w As IRozliczenieWykladowcow w = New CRozliczenia w.zmianarachunku(strbaza, Me) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr)

352 352 ' procedura obsługująca zmianę zaznaczenia pracownika w liście ' zaznaczanej, w zależności od tego, czy go wybierzemy czy nie ' modyfikowana jest lista wykładowców do przygotowania wypłaty Private Sub chldorozliczenia_itemcheck(byval sender As Object, _ ByVal e As System.Windows.Forms.ItemCheckEventArgs) _ Handles chldorozliczenia.itemcheck Dim chklst As System.Data.DataRowView, idw As Integer, _ jak As Boolean chklst = Me.chlDoRozliczenia.SelectedItem idw = chklst.item(0) If e.newvalue = CheckState.Checked Then 'dodanie jak = True Else ' usuniecie jak = False Dim w As IRozliczenieWykladowcow w = New CRozliczenia w.zmianawykladowcy(strbaza, Me, idw, jak) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) e.newvalue = CheckState.Unchecked ' procedura obsługująca zdarzenie Click przycisku polecenia ' zaczyna swoją pracę od sprawdzenia, czy są wybrani wykładowcy ' do przygotowania przelewów, jeżeli tak, to uruchamia proces ' ich przygotowania. Private Sub btnwykonaj_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles btnwykonaj.click ' czy są pozycje do rozliczenia? If Me.chlDoRozliczenia.CheckedItems.Count = 0 Then MsgBox("Proszę zaznaczyć przynajmniej jednego pracownika!", MsgBoxStyle.Critical, "Rozliczenie wykładowców") Exit Sub Dim w As IRozliczenieWykladowcow w = New CRozliczenia w.zaplacwykladowcom(strbaza, Me) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else Me.chlDoRozliczenia.DataSource = Nothing End Class

353 353 Poniżej widok instancji formularza frmrozliczeniewykladowcow w trakcie przygotowywania wystawienia przelewów za zajęcia wykonane na jednym ze zjazdów. Po wybraniu semestru i zjazdu w liście chldorozliczenia zostały wymienione nazwiska tych pracowników, dla których powinny być wystawione przelewy. W pokazanym przykładzie zaznaczono wszystkie nazwiska, w polu Dostępne środki mamy pokazaną kwotę brutto, która obciąży konta podstawowe Uczelni (stąd minusowa). Przelewy zostaną przygotowane w wersji elektronicznej. Po akceptacji przycisku Wykonaj przelewy są przygowywane i zapisywane w postaci pliku tekstowego, pokazany niżej komunikat potwierdza ten fakt podając ścieżkę do tego pliku. Na zakończenie ilustracji tego zadania jeszcze widok zawartości utworzonego pliku.

354 Rozliczenie pracowników administracyjnych Projekt formularza frmwyplataadministracyjna Formularz obsługujący przygotowanie wypłaty dla pracowników obsługi ad ministracyjnej jest stosunkowo prosty. Na jego powierzchni umieszczono: grbrachunek grupa opcji z trzema przyciskami radiowymi pozwalającymi na wybór jednego z rachunków bankowych Uczelni; grpwyprowadzic grupa opcji z dwoma przyciskami radiowymi określającymi miejsce wyprowadzenia przelewów; chldorozliczenia lista zaznaczana, w niej będziemy wybierać tych pracowników, dla których mają być (w danym momencie) przygotowane przelewy bankowe; txtsaldo pole tekstowe pokazujące stan salda wybranego rachunku; btnwykonaj przycisk polecenia uruchamiający przygotowanie przelewów oraz etykiety opisujące niektóre formanty.

355 355 Instancja formularza uruchamiana jest poprzez odpowiednie polecenie w menu aplikacji, którego klik powoduje wykonanie pokazanej niżej procedury zdarzeniowej. Private Sub mnurozliczenieadministracji_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnurozliczenieadministracji.click Dim frm As New frmwyplataadministracyjna Dim w As IRozliczeniaAdministracji w = New CRozliczenia w.otworzwyplateadministracji(strbaza, frm) PokazForm(frm, w.komunikat) Kod formularza frmwyplataadministracyjna W module klasy formularza musimy utworzyć kilka procedur, które będą obsługiwać zdarzenia związane z tym formularzem. Public Class frmwyplataadministracyjna ' deklaracja zmiennych klasy (zmienną idr2 wykorzystamy do ' ustalenia, czy nastąpiła zmiana rachunku Dim idr, idr2 As Integer ' procedura obsługująca zmianę rachunku bankowego Private Sub rdbparp1_checkedchanged(byval sender As Object, _ ByVal e As System.EventArgs) Handles _ rdbparp1.checkedchanged, rdbparp2.checkedchanged, _ rdbpodstawowy3.checkedchanged idr = UstalGrb(Me.grbRachunek) If idr <> idr2 Then idr2 = idr Dim w As IRozliczeniaAdministracji w = New CRozliczenia w.zmianarachunkuadministracji(strbaza, idr) If w.komunikat.length > 0 Then MsgBox(w.Komunikat, MsgBoxStyle.Critical, conmsgerr) Else Me.txtSaldo.Text = DecimalLikeMoney(w.DajSaldo.ToString) ' procedura obsługująca przygotowanie przelewów Private Sub btnwykonaj_click(byval sender As Object, ByVal e As _ System.EventArgs) Handles btnwykonaj.click Dim w As IRozliczeniaAdministracji w = New CRozliczenia

356 356 w.przygotujwyplateobslugi(strbaza, Me) End Class Poniżej widok instancji formularza frmwyplataadministracyjna, tym razem jako miejsce wyprowadzenia przelewów wybrano drukarkę. Klik przycisku Wykonaj otwiera gotowy raport przelewów, poniżej fragment tego raportu.

357 8.9. Raport składek Formularza frmraportskladek 357 Projekt formularza frmraportskladek pokazany jest poniżej. Umieszczono w nim formant typu DataGridView o nazwie dgvskladki oraz dodano formant typu ContexMenuStrip w celu zbudowania menu kontekstowego dla formantu dgvskladki. W menu kontekstowym zdefiniowano trzy polecenia, dzięki nim będzie można zawartość gridu wydrukować, wyeksportować do pliku Excela lub skopiować do schowka Windows. Instancja tego formularza uruchamiana jest z menu aplikacji poleceniem pokazanym obok, klik tego polecenia skutkuje wykonaniem pokazanej niżej procedury zdarzeniowej z formularza frmmdistudia. Private Sub mnuraportskladek _Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnuraportskladek.click Dim frm As New frmraportskladek Dim w As IRozliczenieWykladowcow w = New CRozliczenia w.raportskladek(strbaza, frm) PokazForm(frm, w.komunikat)

358 Kod formularza frmraportskladek W module klasy tego formularza musimy napisać procedury obsługujące polecenia menu kontekstowego. Public Class frmraportskladek Private Sub mnudrukgridu_click(byval sender As System.Object, _ ByVal e As System.EventArgs) Handles mnudrukgridu.click Dim w As TypBooleanPrintPage = _ UstawDrukGridu(Me.dgvSkladki, "Raport naliczonych składek ") If w.f Then Dim myprintpreviewdialog As PrintPreviewDialog = _ New PrintPreviewDialog myprintpreviewdialog.document = w.p myprintpreviewdialog.showdialog() Private Sub mnugriddoexcela_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnugriddoexcela.click ZapiszGridDoExcela(Me.dgvSkladki, "A1", _ Me.dgvSkladki.Columns.Count) Private Sub mnugriddoschowka_click(byval sender As _ System.Object, ByVal e As System.EventArgs) Handles _ mnugriddoschowka.click Clipboard.Clear() Clipboard.SetText(GridDoSchowka(Me.dgvSkladki, _ Me.dgvSkladki.Columns.Count)) End Class

359 Widok raportu składek Powiedzmy, że ostatnia czynność przygotowania przelewów płacowych dotyczyła pracowników administracyjnych, w takim razie w tabeli tempskladki są jeszcze ich dane. Wywołanie polecenia Rozliczenia finansowe/raport składek skutkuje wyświetleniem takiego formularza, jak pokazany niżej. Korzystając z menu kontekstowego możemy zawartość gridu np. wydrukować, otrzymamy wtedy pisemny raport postaci jak niżej. Inna możliwości to wyeksortownie raportu składek do Excela, gdzie ewentualnie mogą być dalej przetworzone. Na kolejnej stronie mamy pokazane okna dialogowe Zapisywanie jako otwarte w efekcie wyboru z menu kontekstowego polecenia Skopiuj grid do MS Excel.

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

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

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

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

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

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

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

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

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

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości część 2 Zaprojektowaliśmy stronę dodaj_dzial.aspx proszę jednak spróbować dodać nowy dział nie podając jego nazwy

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

Podręcznik Użytkownika LSI WRPO

Podręcznik Użytkownika LSI WRPO Podręcznik użytkownika Lokalnego Systemu Informatycznego do obsługi Wielkopolskiego Regionalnego Programu Operacyjnego na lata 2007 2013 w zakresie wypełniania wniosków o dofinansowanie Wersja 1 Podręcznik

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

UNIWERSYTET RZESZOWSKI KATEDRA INFORMATYKI

UNIWERSYTET RZESZOWSKI KATEDRA INFORMATYKI UNIWERSYTET RZESZOWSKI KATEDRA INFORMATYKI LABORATORIUM TECHNOLOGIA SYSTEMÓW INFORMATYCZNYCH W BIOTECHNOLOGII Aplikacja bazodanowa: Cz. II Rzeszów, 2010 Strona 1 z 11 APLIKACJA BAZODANOWA MICROSOFT ACCESS

Bardziej szczegółowo

Ćwiczenie laboratoryjne. Oprogramowanie i badanie stosu lub kolejki w środowisku Visual Basic 2005

Ćwiczenie laboratoryjne. Oprogramowanie i badanie stosu lub kolejki w środowisku Visual Basic 2005 Ćwiczenie laboratoryjne Oprogramowanie i badanie stosu lub kolejki w środowisku Visual Basic 2005 Tematy ćwiczenia realizacja stosu lub kolejki dla tablicowej lub listowej reprezentacji. operacje na stosie

Bardziej szczegółowo

ASP.NET MVC. Podstawy. Zaawansowane programowanie internetowe Instrukcja nr 3

ASP.NET MVC. Podstawy. Zaawansowane programowanie internetowe Instrukcja nr 3 3 ASP.NET MVC Podstawy 1 1. Cel zajęć Celem zajęć jest zapoznanie się z podstawami ASP.NET MVC 2.0 Framework. 2. Zadanie Proszę zbudować prostą aplikację WWW przy zastosowaniu framework a ASP.NET MVC 2.0

Bardziej szczegółowo

Formularze w programie Word

Formularze w programie Word Formularze w programie Word Formularz to dokument o określonej strukturze, zawierający puste pola do wypełnienia, czyli pola formularza, w których wprowadza się informacje. Uzyskane informacje można następnie

Bardziej szczegółowo

Makra Access 2003 wg WSiP Wyszukiwanie, selekcjonowanie i gromadzenie informacji Ewa Mirecka

Makra Access 2003 wg WSiP Wyszukiwanie, selekcjonowanie i gromadzenie informacji Ewa Mirecka Makra Access 2003 wg WSiP Wyszukiwanie, selekcjonowanie i gromadzenie informacji Ewa Mirecka Makra pozwalają na zautomatyzowanie często powtarzających się czynności. Opierają się na akcjach np.: otwarcie

Bardziej szczegółowo

WOJEWÓDZTWO PODKARPACKIE

WOJEWÓDZTWO PODKARPACKIE WOJEWÓDZTWO PODKARPACKIE UNIA EUROPEJSKA EUROPEJSKI FUNDUSZ ROZWOJU REGIONALNEGO Instrukcja instalacji generatora wniosku o dofinansowanie projektu ze środków EFRR w ramach I osi priorytetowej Regionalnego

Bardziej szczegółowo

wstawianie przycisków umożliwiających wybieranie wartości poprzez klikanie strzałek

wstawianie przycisków umożliwiających wybieranie wartości poprzez klikanie strzałek VBA Excel Formularz Formanty Label wstawianie etykiet TextBox wstawianie pól tekstowych ComboBox wstawianie pól kombi ComboBox wstawianie pól kombi ComboBox wstawianie pól kombi OptionButton wstawianie

Bardziej szczegółowo

Janusz Górczyński. Projekt WynajemSal realizowany w trakcie drugiego semestru studiów podyplomowych

Janusz Górczyński. Projekt WynajemSal realizowany w trakcie drugiego semestru studiów podyplomowych Janusz Górczyński Projekt WynajemSal realizowany w trakcie drugiego semestru studiów podyplomowych WSZiM w Sochaczewie, 2011 Spis treści 1 WSTĘP...3 2 BAZA DANYCH...4 2.1 TABELE...4 2.2 PROCEDURY PRZECHOWYWANE...11

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

Kadry Optivum, Płace Optivum

Kadry Optivum, Płace Optivum Kadry Optivum, Płace Optivum Jak seryjnie przygotować wykazy absencji pracowników? W celu przygotowania pism zawierających wykazy nieobecności pracowników skorzystamy z mechanizmu Nowe wydruki seryjne.

Bardziej szczegółowo

WebMobile7 and Sello Integrator wersja 1.1.2

WebMobile7 and Sello Integrator wersja 1.1.2 Instrukcja obsługi aplikacji WebMobile7 and Sello Integrator wersja 1.1.2 Piotr Taraszkiewicz Strona 1 Spis treści 1 WSTĘP O APLIKACJI 3 2 KONFIGURACJA APLIKACJI 4 2.1 KONFIGURACJA POŁĄCZENIA 4 2.2 POZOSTAŁE

Bardziej szczegółowo

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem.

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem. WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM NetBeans Wykonał: Jacek Ventzke informatyka sem. VI 1. Uruchamiamy program NetBeans (tu wersja 6.8 ) 2. Tworzymy

Bardziej szczegółowo

Zaawansowane aplikacje internetowe - laboratorium

Zaawansowane aplikacje internetowe - laboratorium Zaawansowane aplikacje internetowe - laboratorium Web Services (część 3). Do wykonania ćwiczeń potrzebne jest zintegrowane środowisko programistyczne Microsoft Visual Studio 2005. Ponadto wymagany jest

Bardziej szczegółowo

Instrukcja użytkownika

Instrukcja użytkownika SoftwareStudio Studio 60-349 Poznań, ul. Ostroroga 5 Tel. 061 66 90 641 061 66 90 642 061 66 90 643 061 66 90 644 fax 061 86 71 151 mail: poznan@softwarestudio.com.pl Herkules WMS.net Instrukcja użytkownika

Bardziej szczegółowo

Microsoft.NET: ASP.NET MVC + Entity Framework (Code First)

Microsoft.NET: ASP.NET MVC + Entity Framework (Code First) Microsoft.NET: ASP.NET MVC + Entity Framework (Code First) Do realizacji projektu potrzebne jest zintegrowane środowisko programistyczne Microsoft Visual Studio 2012. W ramach projektu budowana jest prosta

Bardziej szczegółowo

Visual Basic w programie Excel dla Windows

Visual Basic w programie Excel dla Windows Visual Basic w programie Excel dla Windows Ćwiczenie nr 1 Makrodefinicje. Zakres ćwiczenia: Nagrywanie, odtwarzanie, modyfikowanie i upraszczanie makrodefinicji. Makrodefinicje lokalne i globalne. Przyporządkowanie

Bardziej szczegółowo

LK1: Wprowadzenie do MS Access Zakładanie bazy danych i tworzenie interfejsu użytkownika

LK1: Wprowadzenie do MS Access Zakładanie bazy danych i tworzenie interfejsu użytkownika LK1: Wprowadzenie do MS Access Zakładanie bazy danych i tworzenie interfejsu użytkownika Prowadzący: Dr inż. Jacek Habel Instytut Technologii Maszyn i Automatyzacji Produkcji Zakład Projektowania Procesów

Bardziej szczegółowo

Wykład III. dr Artur Bartoszewski www.bartoszewski.pr.radom.pl. Wydział Nauczycielski, Kierunek Pedagogika Wprowadzenie do baz danych

Wykład III. dr Artur Bartoszewski www.bartoszewski.pr.radom.pl. Wydział Nauczycielski, Kierunek Pedagogika Wprowadzenie do baz danych Wydział Nauczycielski, Kierunek Pedagogika Wprowadzenie do baz danych dr Artur Bartoszewski www.bartoszewski.pr.radom.pl Wykład III W prezentacji wykorzystano fragmenty i przykłady z książki: Joe Habraken;

Bardziej szczegółowo

LABORATORIUM 8,9: BAZA DANYCH MS-ACCESS

LABORATORIUM 8,9: BAZA DANYCH MS-ACCESS UNIWERSYTET ZIELONOGÓRSKI INSTYTUT INFORMATYKI I ELEKTROTECHNIKI ZAKŁAD INŻYNIERII KOMPUTEROWEJ Przygotowali: mgr inż. Arkadiusz Bukowiec mgr inż. Remigiusz Wiśniewski LABORATORIUM 8,9: BAZA DANYCH MS-ACCESS

Bardziej szczegółowo

Scenariusz lekcji. Scenariusz lekcji 1 TEMAT LEKCJI: 2 CELE LEKCJI: 2.1 Wiadomości: 2.2 Umiejętności: 3 METODY NAUCZANIA: 4 ŚRODKI DYDAKTYCZNE:

Scenariusz lekcji. Scenariusz lekcji 1 TEMAT LEKCJI: 2 CELE LEKCJI: 2.1 Wiadomości: 2.2 Umiejętności: 3 METODY NAUCZANIA: 4 ŚRODKI DYDAKTYCZNE: Praca z projektemi w MS VB.NET Scenariusz lekcji Scenariusz lekcji 1 TEMAT LEKCJI: Praca z projektami w MS VB.NET. 2 CELE LEKCJI: 2.1 Wiadomości: Uczeń potrafi: podać definicje podstawowych pojęć związanych

Bardziej szczegółowo

Cash Flow System Instrukcja

Cash Flow System Instrukcja Cash Flow System Instrukcja Wersja 1.17 Instalacja Instalacja programu Cash Flow System polega na wywołaniu programu instalatora. Następnie postępujemy zgodnie z sugestiami proponowanymi przez program

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

Utworzenie aplikacji mobilnej Po uruchomieniu Visual Studio pokazuje się ekran powitalny. Po lewej stronie odnośniki do otworzenia lub stworzenia

Utworzenie aplikacji mobilnej Po uruchomieniu Visual Studio pokazuje się ekran powitalny. Po lewej stronie odnośniki do otworzenia lub stworzenia Utworzenie aplikacji mobilnej Po uruchomieniu Visual Studio pokazuje się ekran powitalny. Po lewej stronie odnośniki do otworzenia lub stworzenia nowego projektu (poniżej są utworzone projekty) Po kliknięciu

Bardziej szczegółowo

Spis treści. Podziękowania... xi Wstęp... xiii

Spis treści. Podziękowania... xi Wstęp... xiii Podziękowania... xi Wstęp.... xiii Część I Wprowadzenie do Microsoft Visual Basic 2010 1 Poznawanie środowiska Visual Studio Integrated Development Environment.... 3 Środowisko programowania Visual Studio...

Bardziej szczegółowo

Kurs walut. Specyfikacja projektu. Marek Zając 2013-12-16

Kurs walut. Specyfikacja projektu. Marek Zając 2013-12-16 Kurs walut Specyfikacja projektu Marek Zając 2013-12-16 Spis treści 1. Podsumowanie... 2 1.1 Wstęp... 2 1.2 Projekt interfejsu... 2 1.2.1 Rozmiar głównego okna... 2 2. Słownik pojęć... 2 2.1 Definicja

Bardziej szczegółowo

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości

Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości Budowa aplikacji ASP.NET współpracującej z bazą dany do obsługi przesyłania wiadomości Rozpoczniemy od zaprojektowania bazy danych w programie SYBASE/PowerDesigner umieszczamy dwie Encje (tabele) prawym

Bardziej szczegółowo

Produkcja by CTI. Proces instalacji, ważne informacje oraz konfiguracja

Produkcja by CTI. Proces instalacji, ważne informacje oraz konfiguracja Produkcja by CTI Proces instalacji, ważne informacje oraz konfiguracja Spis treści 1. Ważne informacje przed instalacją...3 2. Instalacja programu...4 3. Nawiązanie połączenia z serwerem SQL oraz z programem

Bardziej szczegółowo

Co nowego w systemie Kancelaris 3.31 STD/3.41 PLUS

Co nowego w systemie Kancelaris 3.31 STD/3.41 PLUS Ten dokument zawiera informacje o zmianach w wersjach: 3.31 STD w stosunku do wersji 3.30 STD 3.41 PLUS w stosunku do wersji 3.40 PLUS 1. Kancelaria 1.1. Opcje kancelarii Co nowego w systemie Kancelaris

Bardziej szczegółowo

Instrukcja użytkownika Systemu Elektronicznej Faktury

Instrukcja użytkownika Systemu Elektronicznej Faktury Instrukcja użytkownika Systemu Elektronicznej Faktury Aby zalogować się do Systemu Elektronicznej Faktury, wejdź na stronę internetową www.upc.pl/ebok W pola formularza wpisz swój Numer Identyfikacyjny

Bardziej szczegółowo

Inżynieria Programowania Laboratorium 3 Projektowanie i implementacja bazy danych. Paweł Paduch paduch@tu.kielce.pl

Inżynieria Programowania Laboratorium 3 Projektowanie i implementacja bazy danych. Paweł Paduch paduch@tu.kielce.pl Inżynieria Programowania Laboratorium 3 Projektowanie i implementacja bazy danych Paweł Paduch paduch@tu.kielce.pl 06-04-2013 Rozdział 1 Wstęp Na dzisiejszych zajęciach zajmiemy się projektem bazy danych.

Bardziej szczegółowo

Tworzenie bazy danych na przykładzie Access

Tworzenie bazy danych na przykładzie Access Tworzenie bazy danych na przykładzie Access Tworzenie tabeli Kwerendy (zapytania) Selekcja Projekcja Złączenie Relacja 1 Relacja 2 Tworzenie kwedend w widoku projektu Wybór tabeli (tabel) źródłowych Wybieramy

Bardziej szczegółowo

Janusz Górczyński. Opis projektu WynajemSal

Janusz Górczyński. Opis projektu WynajemSal Janusz Górczyński Opis projektu WynajemSal WSZiM w Sochaczewie, 2011 Spis treści 1 WSTĘP...3 2 BAZA DANYCH...4 2.1 TABELE...4 2.2 PROCEDURY PRZECHOWYWANE...11 3 APLIKACJA WINDOWSOWA...15 3.1 UTWORZENIE

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

Systemy baz danych Prowadzący: Adam Czyszczoń. Systemy baz danych. 1. Import bazy z MS Access do MS SQL Server 2012:

Systemy baz danych Prowadzący: Adam Czyszczoń. Systemy baz danych. 1. Import bazy z MS Access do MS SQL Server 2012: Systemy baz danych 16.04.2013 1. Plan: 10. Implementacja Bazy Danych - diagram fizyczny 11. Implementacja Bazy Danych - implementacja 2. Zadania: 1. Przygotować model fizyczny dla wybranego projektu bazy

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

Instrukcja Użytkownika (Studenta) Akademickiego Systemu Archiwizacji Prac

Instrukcja Użytkownika (Studenta) Akademickiego Systemu Archiwizacji Prac Instrukcja Użytkownika (Studenta) Akademickiego Systemu Archiwizacji Prac Akademicki System Archiwizacji Prac (ASAP) to nowoczesne, elektroniczne archiwum prac dyplomowych zintegrowane z systemem antyplagiatowym

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

Włączanie/wyłączanie paska menu

Włączanie/wyłączanie paska menu Włączanie/wyłączanie paska menu Po zainstalowaniu przeglądarki Internet Eksplorer oraz Firefox domyślnie górny pasek menu jest wyłączony. Czasem warto go włączyć aby mieć szybszy dostęp do narzędzi. Po

Bardziej szczegółowo

Właściwości i metody obiektu Comment Właściwości

Właściwości i metody obiektu Comment Właściwości Właściwości i metody obiektu Comment Właściwości Właściwość Czy można zmieniać Opis Application nie Zwraca nazwę aplikacji, która utworzyła komentarz Author nie Zwraca nazwę osoby, która utworzyła komentarz

Bardziej szczegółowo

Użycie Visual Basic for Applications ("VBA")

Użycie Visual Basic for Applications (VBA) Użycie Visual Basic for Applications ("VBA") Przegląd SEE z modułem VBA Developer SEE używa języka programowania Visual Basic for Applications (VBA) pozwalającego tworzyć krótkie programy zwane "makrami".

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

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

16) Wprowadzenie do raportowania Rave

16) Wprowadzenie do raportowania Rave 16) Wprowadzenie do raportowania Rave Tematyka rozdziału: Przegląd wszystkich komponentów Rave Tworzenie nowego raportu przy użyciu formatki w środowisku Delphi Aktywacja środowiska Report Authoring Visual

Bardziej szczegółowo

Budowa aplikacji ASP.NET współpracującej z bazą dany do przeprowadzania ankiet internetowych

Budowa aplikacji ASP.NET współpracującej z bazą dany do przeprowadzania ankiet internetowych Budowa aplikacji ASP.NET współpracującej z bazą dany do przeprowadzania ankiet internetowych widok ankiety w przeglądarce Rozpoczniemy od zaprojektowania bazy danych w programie SYBASE/PowerDesigner umieszczamy

Bardziej szczegółowo

Aplikacja MDI. Rysunek 1. Tworzenie nowego projektu

Aplikacja MDI. Rysunek 1. Tworzenie nowego projektu Aplikacja MDI Co to takiego jest ta aplikacja MDI? OtóŜ w zasadzie w kaŝdej aplikacji występuje przynajmniej kilka okien umoŝliwiających wprowadzanie / wyświetlanie róŝnych danych. Okna te mogą być wyświetlane

Bardziej szczegółowo

Materiał szkoleniowy:

Materiał szkoleniowy: UNIWERSYTET MARII CURIE-SKŁODOWSKIEJ W LUBLINIE Projekt Nowoczesny model zarządzania w UMCS umowa nr UDA-POKL.04.01.01-00-036/11-00 Pl. Marii Curie-Skłodowskiej 5, 20-031 Lublin, www.nowoczesny.umcs.lublin.pl

Bardziej szczegółowo

MS Visual Studio Express 2012 for Web instalacja i konfiguracja

MS Visual Studio Express 2012 for Web instalacja i konfiguracja MS Visual Studio Express 2012 for Web instalacja i konfiguracja Strona 1 z 10 Spis treści 1. Instalacja Visual Studio for Web....3 2. Przygotowanie projektu....5 3. Otwarcie projektu przy pomocy VSW....6

Bardziej szczegółowo

Currenda EPO Instrukcja Konfiguracji. Wersja dokumentu: 1.3

Currenda EPO Instrukcja Konfiguracji. Wersja dokumentu: 1.3 Currenda EPO Instrukcja Konfiguracji Wersja dokumentu: 1.3 Currenda EPO Instrukcja Konfiguracji - wersja dokumentu 1.3-19.08.2014 Spis treści 1 Wstęp... 4 1.1 Cel dokumentu... 4 1.2 Powiązane dokumenty...

Bardziej szczegółowo

Instrukcja użytkownika programu QImport (wydanie II 25.07.2012 r.)

Instrukcja użytkownika programu QImport (wydanie II 25.07.2012 r.) Instrukcja użytkownika programu QImport (wydanie II 25.07.2012 r.) Wymagania techniczne komputer z procesorem 1,5 GHz lub lepszym 512 MB pamięci RAM lub więcej system operacyjny Microsoft Windows XP z

Bardziej szczegółowo

Dodanie nowej formy do projektu polega na:

Dodanie nowej formy do projektu polega na: 7 Tworzenie formy Forma jest podstawowym elementem dla tworzenia interfejsu użytkownika aplikacji systemu Windows. Umożliwia uruchomienie aplikacji, oraz komunikację z użytkownikiem aplikacji. W trakcie

Bardziej szczegółowo

1. Zarządzanie informacją w programie Access

1. Zarządzanie informacją w programie Access 1. Zarządzanie informacją w programie Access a. 1. Cele lekcji i. a) Wiadomości Uczeń: zna definicję bazy danych i jej zadania, zna pojęcia: rekord, pole, klucz podstawowy, zna obiekty bazy danych: tabele,

Bardziej szczegółowo

Instrukcja użytkownika STUDENTA AKADEMICKIEGO SYSTEMU ARCHIWIZACJI PRAC

Instrukcja użytkownika STUDENTA AKADEMICKIEGO SYSTEMU ARCHIWIZACJI PRAC Instrukcja użytkownika STUDENTA AKADEMICKIEGO SYSTEMU ARCHIWIZACJI PRAC Strona 1 z 14 Akademicki System Archiwizacji Prac (ASAP) to nowoczesne, elektroniczne archiwum prac dyplomowych zintegrowane z systemem

Bardziej szczegółowo

Plik->Opcje->Zakladka Główne->Dostosuj Wstążkę Zaznaczamy kwadracik Developer na liscie po prawej stronie. Klikamy OK.

Plik->Opcje->Zakladka Główne->Dostosuj Wstążkę Zaznaczamy kwadracik Developer na liscie po prawej stronie. Klikamy OK. Aktywacja zakładki Developer. Plik->Opcje->Zakladka Główne->Dostosuj Wstążkę Zaznaczamy kwadracik Developer na liscie po prawej stronie. Klikamy OK. Rejestracja makr. Klikamy Zakladke Developer. Klikamy

Bardziej szczegółowo

Praca z bazą danych. Rysunek 1. Projekt tabeli UZYTKOWNIK bazy KURSY

Praca z bazą danych. Rysunek 1. Projekt tabeli UZYTKOWNIK bazy KURSY Praca z bazą danych Aby móc korzystać z niniejszego kursu musimy utworzyć bazę danych o nazwie KURSY, tabelę o nazwie UZYTKOWNIK, a w tabeli tej utworzyć następujące kolumny: user_id typu integer/autonumer

Bardziej szczegółowo

Excel z elementami VBA w firmie.

Excel z elementami VBA w firmie. Excel z elementami VBA w firmie. Autor: Sergiusz Flanczewski Wykorzystaj potencjał Excela, by Twoja firma odniosła sukces! Jak zaprząc dodatki Excela do tworzenia dokumentacji firmowej? Jak importować

Bardziej szczegółowo

Instrukcja użytkownika. Aplikacja dla WF-Mag

Instrukcja użytkownika. Aplikacja dla WF-Mag Instrukcja użytkownika Aplikacja dla WF-Mag Instrukcja użytkownika Aplikacja dla WF-Mag Wersja 1.0 Warszawa, Kwiecień 2015 Strona 2 z 13 Instrukcja użytkownika Aplikacja dla WF-Mag Spis treści 1. Wstęp...4

Bardziej szczegółowo

Instrukcja użytkownika. Aplikacja dla Comarch ERP XL

Instrukcja użytkownika. Aplikacja dla Comarch ERP XL Instrukcja użytkownika Aplikacja dla Comarch ERP XL Instrukcja użytkownika Aplikacja dla Comarch ERP XL Wersja 1.0 Warszawa, Listopad 2015 Strona 2 z 12 Instrukcja użytkownika Aplikacja dla Comarch ERP

Bardziej szczegółowo

Formularz pierwszej oceny w służbie cywilnej

Formularz pierwszej oceny w służbie cywilnej Narzędzie informatyczne wspomagające dokonywanie pierwszej oceny w służbie cywilnej przygotowane w ramach projektu pn. Strategia zarządzania zasobami ludzkimi w służbie cywilnej współfinansowanego przez

Bardziej szczegółowo

Instrukcja obsługi Zaplecza epk w zakresie zarządzania tłumaczeniami opisów procedur, publikacji oraz poradników przedsiębiorcy

Instrukcja obsługi Zaplecza epk w zakresie zarządzania tłumaczeniami opisów procedur, publikacji oraz poradników przedsiębiorcy Instrukcja obsługi Zaplecza epk w zakresie zarządzania tłumaczeniami opisów procedur, publikacji oraz poradników przedsiębiorcy Spis treści: 1 WSTĘP... 3 2 DOSTĘP DO SYSTEMU... 3 3 OPIS OGÓLNY SEKCJI TŁUMACZENIA...

Bardziej szczegółowo

Formularz oceny okresowej arkusz B w służbie cywilnej Instrukcja użytkownika

Formularz oceny okresowej arkusz B w służbie cywilnej Instrukcja użytkownika Narzędzie informatyczne wspomagające dokonywanie ocen okresowych w służbie cywilnej przygotowane w ramach projektu pn. Strategia zarządzania zasobami ludzkimi w służbie cywilnej współfinansowanego przez

Bardziej szczegółowo

Zastanawiałeś się może, dlaczego Twój współpracownik,

Zastanawiałeś się może, dlaczego Twój współpracownik, Kurs Makra dla początkujących Wiadomości wstępne VBI/01 Piotr Dynia, specjalista ds. MS Office Czas, który poświęcisz na naukę tego zagadnienia, to 15 20 minut. Zastanawiałeś się może, dlaczego Twój współpracownik,

Bardziej szczegółowo

Delphi podstawy programowania. Środowisko Delphi

Delphi podstawy programowania. Środowisko Delphi Delphi podstawy programowania Środowisko Delphi Olsztyn 2004 Delphi Programowanie obiektowe - (object-oriented programming) jest to metodologia tworzeniu programów komputerowych definiująca je jako zbiór

Bardziej szczegółowo

KASK by CTI. Instrukcja

KASK by CTI. Instrukcja KASK by CTI Instrukcja Spis treści 1. Opis programu... 3 2. Pierwsze uruchomienie... 4 3. Okno główne programu... 5 4. Konfiguracja atrybutów... 6 5. Nadawanie wartości atrybutom... 7 6. Wybór firmy z

Bardziej szczegółowo

Tworzenie okna dialogowego w edytorze raportu SigmaNEST część 2

Tworzenie okna dialogowego w edytorze raportu SigmaNEST część 2 Tworzenie okna dialogowego w edytorze raportu SigmaNEST część 2 W ostatniej części newslettera wyjaśniliśmy czym jest okno dialogowe oraz w jaki sposób można je utworzyć. Przy pomocy edytora raportów SigmaNEST

Bardziej szczegółowo

Laboratorium 050. Crystal Reports. Ćwiczenie 1. Otwarte pozycje

Laboratorium 050. Crystal Reports. Ćwiczenie 1. Otwarte pozycje Laboratorium 050 Crystal Reports Ćwiczenie 1 Otwarte pozycje 1. Uruchomić Microsoft.NET 2. Wybrać New Project, preferowany język (np. VB), Reporting, Crystal Reports Application i w polu Name (nazwa projektu)

Bardziej szczegółowo

Przewodnik Szybki start

Przewodnik Szybki start Przewodnik Szybki start Program Microsoft Access 2013 wygląda inaczej niż wcześniejsze wersje, dlatego przygotowaliśmy ten przewodnik, aby skrócić czas nauki jego obsługi. Zmienianie rozmiaru ekranu lub

Bardziej szczegółowo

Viatoll Calc v1.3. Viatoll Calc. Instrukcja użytkownika. Strona 1

Viatoll Calc v1.3. Viatoll Calc. Instrukcja użytkownika. Strona 1 Viatoll Calc Instrukcja użytkownika Strona 1 Spis treści 1 Wstęp...3 2 Opis panelu głównego...3 2.1 Menu aplikacji...4 2.2 Tabela z trasami...5 2.3 Strona kalkulatora viatoll...6 2.4 Pasek statusu...7

Bardziej szczegółowo

Programowanie MorphX Ax

Programowanie MorphX Ax Administrowanie Czym jest system ERP? do systemu Dynamics Ax Obsługa systemu Dynamics Ax Wyszukiwanie informacji, filtrowanie, sortowanie rekordów IntelliMorph : ukrywanie i pokazywanie ukrytych kolumn

Bardziej szczegółowo

dokumentacja Edytor Bazy Zmiennych Edytor Bazy Zmiennych Podręcznik użytkownika

dokumentacja Edytor Bazy Zmiennych Edytor Bazy Zmiennych Podręcznik użytkownika asix 4 Edytor Bazy Zmiennych Podręcznik użytkownika asix 4 dokumentacja Edytor Bazy Zmiennych ASKOM i asix to zastrzeżone znaki firmy ASKOM Sp. z o. o., Gliwice. Inne występujące w tekście znaki firmowe

Bardziej szczegółowo

MS Excell 2007 Kurs podstawowy Filtrowanie raportu tabeli przestawnej

MS Excell 2007 Kurs podstawowy Filtrowanie raportu tabeli przestawnej MS Excell 2007 Kurs podstawowy Filtrowanie raportu tabeli przestawnej prowadzi: dr inż. Tomasz Bartuś Kraków: 2008 04 04 Przygotowywanie danych źródłowych Poniżej przedstawiono zalecenia umożliwiające

Bardziej szczegółowo

Wymagane jest podłączenie serwera do Internetu (konieczne do zdalnego dostępu).

Wymagane jest podłączenie serwera do Internetu (konieczne do zdalnego dostępu). Spis treści Informacje ogólne...2 Tryby pracy...3 Wygląd interfejsu...4 Tryb użytkownika...5 Tryb administratora...6 Import kontrahentów z pliku XML...8 2 Informacje ogólne Aplikacja internetowa umożliwia

Bardziej szczegółowo

Sposób tworzenia tabeli przestawnej pokażę na przykładzie listy krajów z podstawowymi informacjami o nich.

Sposób tworzenia tabeli przestawnej pokażę na przykładzie listy krajów z podstawowymi informacjami o nich. Tabele przestawne Tabela przestawna to narzędzie służące do tworzenia dynamicznych podsumowań list utworzonych w Excelu lub pobranych z zewnętrznych baz danych. Raporty tabeli przestawnej pozwalają na

Bardziej szczegółowo

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych Obiekty reprezentują pewne pojęcia, przedmioty, elementy rzeczywistości. Obiekty udostępniają swoje usługi: metody operacje,

Bardziej szczegółowo

Informatyka Arkusz kalkulacyjny Excel 2010 dla WINDOWS cz. 1

Informatyka Arkusz kalkulacyjny Excel 2010 dla WINDOWS cz. 1 Wyższa Szkoła Ekologii i Zarządzania Informatyka Arkusz kalkulacyjny Excel 2010 dla WINDOWS cz. 1 Slajd 1 Excel Slajd 2 Ogólne informacje Arkusz kalkulacyjny podstawowe narzędzie pracy menadżera Arkusz

Bardziej szczegółowo

Jak utworzyć plik SIO dla aktualnego spisu?

Jak utworzyć plik SIO dla aktualnego spisu? System Informacji Oświatowej Jak utworzyć plik SIO dla aktualnego spisu? Programy Arkusz Optivum, Kadry Optivum, Płace Optivum, Sekretariat Optivum oraz Księgowość Optivum dostarczają znaczną część danych

Bardziej szczegółowo

5.4. Tworzymy formularze

5.4. Tworzymy formularze 5.4. Tworzymy formularze Zastosowanie formularzy Formularz to obiekt bazy danych, który daje możliwość tworzenia i modyfikacji danych w tabeli lub kwerendzie. Jego wielką zaletą jest umiejętność zautomatyzowania

Bardziej szczegółowo

Tak przygotowane pliki należy umieścić w głównym folderze naszego programu. Klub IKS www.informatyka.edu.pl

Tak przygotowane pliki należy umieścić w głównym folderze naszego programu. Klub IKS www.informatyka.edu.pl To jeden z ostatnich odcinków naszego kursu. Mam nadzieję, że pisanie własnego programu było ciekawym doświadczeniem. Zaproponowana w tym odcinku funkcja uatrakcyjni twój program. Stworzymy tak zwane okno

Bardziej szczegółowo

BAZY DANYCH Formularze i raporty

BAZY DANYCH Formularze i raporty BAZY DANYCH Formularze i raporty Za pomocą tabel można wprowadzać nowe dane, przeglądać i modyfikować dane już istniejące. Jednak dla typowego użytkownika systemu baz danych, przygotowuje się specjalne

Bardziej szczegółowo

Instrukcja obsługi dla studenta

Instrukcja obsługi dla studenta Instrukcja obsługi dla studenta Akademicki System Archiwizacji Prac (ASAP) to nowoczesne, elektroniczne archiwum prac dyplomowych zintegrowane z systemem antyplagiatowym Plagiat.pl. Student korzystający

Bardziej szczegółowo

Elektroniczny Urząd Podawczy

Elektroniczny Urząd Podawczy Elektroniczny Urząd Podawczy Dzięki Elektronicznemu Urzędowi Podawczemu Beneficjent może wypełnić i wysłać formularz wniosku o dofinansowanie projektów w ramach Regionalnego Programu Operacyjnego Województwa

Bardziej szczegółowo

Ćwiczenie 8. Kontrolki serwerowe

Ćwiczenie 8. Kontrolki serwerowe Ćwiczenie 8 Temat: Kontrolki serwerowe ASP.NET cz.2 Cel ćwiczenia: W ramach tego ćwiczenie student zapozna się z kolejnymi kontrolkami serwerowymi oraz z metodami ich walidacji, a także z kontrolkami umożliwiającymi

Bardziej szczegółowo

Program RMUA. Instrukcja konfiguracji i pracy w programie. (Wersja 2)

Program RMUA. Instrukcja konfiguracji i pracy w programie. (Wersja 2) Program RMUA Instrukcja konfiguracji i pracy w programie (Wersja 2) 1 Wstęp Program RMUA powstał w związku z obowiązkiem przekazywania ubezpieczonym informacji rocznej zwanej wcześniej RMUA. Aplikacja

Bardziej szczegółowo

Microsoft.NET: LINQ to SQL, ASP.NET AJAX

Microsoft.NET: LINQ to SQL, ASP.NET AJAX Microsoft.NET: LINQ to SQL, ASP.NET AJAX Do realizacji projektu potrzebne jest zintegrowane środowisko programistyczne Microsoft Visual Studio 2008 oraz serwer bazy danych SQL Server Express 2005 (lub

Bardziej szczegółowo

autor poradnika - KS Jak zamieszczać i edytować artykuły na szkolnej stronie internetowej

autor poradnika - KS Jak zamieszczać i edytować artykuły na szkolnej stronie internetowej Jak zamieszczać i edytować artykuły na szkolnej stronie internetowej adres naszej strony: www.zs3.wroc.pl logo liceum 1. Aby dodać artykuł należy się zalogować: System pokaże nazwę zalogowanego użytkownika

Bardziej szczegółowo

Informatyka Arkusz kalkulacyjny Excel 2010 dla WINDOWS cz. 1

Informatyka Arkusz kalkulacyjny Excel 2010 dla WINDOWS cz. 1 Wyższa Szkoła Ekologii i Zarządzania Informatyka Arkusz kalkulacyjny 2010 dla WINDOWS cz. 1 Slajd 1 Slajd 2 Ogólne informacje Arkusz kalkulacyjny podstawowe narzędzie pracy menadżera Arkusz kalkulacyjny

Bardziej szczegółowo

Ekran główny lista formularzy

Ekran główny lista formularzy Administracja modułem formularzy dynamicznych Konfigurator formularzy dynamicznych Funkcjonalność konfiguratora formularzy dynamicznych pozwala administratorowi systemu na stworzenie formularza, w którym

Bardziej szczegółowo