Kompendium programisty VB

advertisement
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Kompendium programisty VB.NET - nr 5
Bazy danych, odtwarzacze plików dźwiękowych, algorytmy
wyszukiwania wzorca w tekście … chyba starczy na jeden numer.
Bazy danych to nie tylko ACCESS, to także systemy oparte na serwerach SQL.
Prosta aplikacja wykorzystująca darmową wersję serwera firmy Microsoft –
MSDE, to ciekawa propozycja rozpoczęcia pracy z profesjonalnymi systemami
bazodanowymi. Dla amatorów multimediów (o)krągły odtwarzacz plików WAV. W
każdym numerze kompendium nie może zbraknąć algorytmiki- dziś Knuth, Morris,
Pratt, Boyer, Mooore oraz Naiwny- znacie ich ?
Obsługa baz danych w VS.NET
MSDE
MSDE 2000 to darmowa edycja bazy danych mająca zgodność z komercyjnym produktem firmy
Microsoft SQL Server 2000. Wykorzystuje tę samą odmianę dialektu języka SQL - T-SQL.
Zastosowanie MSDE to nie tylko wersje testowe dużych aplikacji bazodanowych opartych na serwerze
SQL, lecz także główny sposób przechowywania danych w mniejszych aplikacjach opartych na bazie
SQL. Zaletą tego systemu jest możliwość łatwej i bezproblemowej migracji danych do systemu
serwerowego (Microsoft SQL Server 2000) w przypadku, gdy baza się rozrośnie i wymaga większej
skalowalności.
Zaletą MSDE jest jego dostępność z wieloma produktami firmy Microsoft, co znacznie ułatwia
rozpowszechnianie aplikacji opartych na tym silniku baz danych. Posiadacze pakietu Office XP
Professional mogą wykorzystywać aparat MSDE jako alternatywne narzędzie do przechowywania baz
danych w stosunku do Microsoft Jet (silnik baz danych, na którym jest oparty system ACCESS).
Komercyjnie MDSE mogą wykorzystywać w swoim oprogramowaniu posiadacze następujących
produktów:
- MSDN Universal. Enterprise i Professional
- Microsoft Office XP Developer
- SQL Server Developer, Standard, Enterprise
- Microsoft Visual Studio.NET Architect, Developer, Professional
SQL Server 2000 Desktop Engine (MSDE) - jest w 100% kompatybilny z pełną komercyjną
wersją serwera. Pisząc programy do MSDE pisze się je w ten sam sposób jak dla wersji SQL Server.
Jako wersja darmowa MSDE posiada pewne ograniczenia. Podstawowym jest górna granica wielkości
bazy danych. Maksymalny łączny rozmiar pików mdf i ldf nie może przekroczyć 2 GB. Liczba baz nie
jest ograniczona w stosunku do SQL serwera i możne wynosić maksymalnie 32 767. Drugim
ograniczeniem jest limit jednocześnie przetwarzanych zapytań. Dokumentacja firmy Microsoft podaje, iż
po przekroczeniu 5 jednoczesnych zapytań wydajność motoru bazy spada, w wyniku dokładania przez
MSDE dodatkowych „pustych” operacji. Wynika stąd wniosek o mniejszej użyteczność tego narzędzia
Algorytmika i programowanie
1
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
w wypadku obsługi większej liczby użytkowników. Dodatkowo należy pamiętać, iż MSDE jest
przeznaczony głównie do przechowywania danych, stąd też jest pozbawiony narzędzi do zarządzania
danymi. Standardowo można dokonywać operacji na danych oraz uprawnieniach za pomocą
dostarczanego z MSDE narzędzia osql, pracującego w trybie konsolowym. MSDE pracujący na stacji
roboczej jest aplikacją w małym stopniu absorbującą pamięć komputera, ponieważ została
zaprogramowana jako program działający w tle. Pełna wersja SQL Server wymaga znacznie większych
zasobów systemowych.
Klasy VS.NET do obsługi i komunikacji z różnymi bazami danych
VS.NET udostępnia wiele wbudowanych klas pozwalających na komunikację i obsługę baz
danych. Niektóre tych z klas są specyficzne dla dostawcy (klasy dostawców), tzn. stanowią interfejs dla
określonego typu systemu bazodanowego. Zadaniem ich jest połączenie z bazą danych, wykonywanie
poleceń i odczytywanie danych. VS.NET wspomaga cztery odmiany dostawców baz danych: Microsoft
SQL Server, OLE DB, ODBC oraz Oracle. W naszym kompendium omówimy współpracę z MS SQL
Server. Należy pamiętać, że praca z innymi dostawcami będzie bardzo podobna, np. dla programistów
wykorzystujących silnik Microsoft JET (czyli dane są zapisane w pliku ACCESS-a) przeznaczone będą
klasy wspierające OLE DB zorganizowane w ten sam sposób co klasy SQL. Należy pamiętać, że
wszystkie klasy wspomagające pracę z bazami danych znajdują się w przestrzeni nazw System.Data.
Najważniejsze klasy dostawców w .NET to: Connection, Command, DataReader oraz
DataAdapter. Ze względu na dostawców umieszczone są one w odpowiednich przestrzeniach nazw,
np. SQLClient i OLEDB oraz zostały odpowiednio nazwane, np. SQLCommand.
Klasa dostawcy
Connection
Command
DataReader
DataAdapter
Przestrzeń nazw SQLClient
SQLConection
SQLCommand
SQLDataReader
SQLDataAdapter
Przestrzeń nazw OleDb
OleDbConnection
OleDbCommand
OleDbDataReader
OleDbDataAdapter
Klasa Connection powala nawiązać lub zakończyć połączenie z bazą danych. Do wykonania
tej operacji jest potrzebny tzw. łańcuch połączeniowy (ConnectionString), czyli tekst zawierający
najważniejsze informacje, pozwalające na połączenie z wybraną bazą danych udostępnioną przez
wskazanego dostawcę. Łańcuch połączeniowy zawiera informacje w postaci par – klucz-wartość,
specyficznych dla serwera baz danych, systemu zabezpieczeń. Przykładowe łańcuchy połączeń:
- dla bazy obsługiwanej przez system SQL, gdzie system zabezpieczeń jest monitorowany
przez serwer SQL (uwierzytelnianie SQL): Password=ala;Persist Security Info=True;User
ID=sa;Initial Catalog=ksiazaki;Data Source=STACJA18
- dla bazy opartej na systemie Access (dostawca OleDb):
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Documents and
Settings\Janusz\Moje dokumenty\AS.mdb;Persist Security Info=False
Łańcuch połączeniowy można uzyskać w następujący sposób:
1. Otwieramy w dowolnym miejscu (np. na pulpicie) nowy plik o dowolnej nazwie i rozszerzeniu UDL, np.
Nowy.UDL.
2. Otwieramy utworzony plik poprzez dwukrotne kliknięcie na nim. Pojawi się okno Właściwości łącza
danych widoczne poniżej. Z listy Dostawcy OLE DB wybieramy dostawcę danych, od którego pochodzi
nasza baza danych, np. Microsoft Ole DB Provider for SQL Serwer (jest to wybór SQL Servera lub
silnika bazy MSDE).
Algorytmika i programowanie
2
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
3. Przechodzimy na kartę Połączenie. Wybieramy nazwę serwera, sposób uwierzytelniania oraz bazę na
serwerze. Sprawdzamy, czy jest połączenie z bazą, wciskając przycisk Testuj połączenie. W przypadku
pozytywnej odpowiedzi można zamknąć okno, klikając przycisk OK.
Algorytmika i programowanie
3
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
4. Otwieramy za pomocą Notatnika plik UDL. Tekst od słowa Provider zawiera łańcuch połączeniowy
potrzebny do nawiązania połączenia z bazą ksiazki.
W przypadku, gdy wykorzystujemy MS SQL Server lub MSDE w łańcuchu połączeniowym pomijamy
klucz Provider.
Połączenie z bazą polega na utworzeniu nowego obiektu klasy System.Data.SqlClient.SqlConnection
zainicjowanego łańcuchem połączeniowym, a następnie wywołaniu metody Open dla tego obiektu, np.:
Dim strPolacz As String
strPolacz = "Password=ala;Persist Security Info=True;User ID=sa;Initial
Catalog=ksiazaki;Data Source=STACJA18"
objPolaczenie = New System.Data.SqlClient.SqlConnection(strPolacz)
objPolaczenie.Open()
Zamkniecie połączenia z bazą polega na wywołaniu metody Close, np.:
objPolaczenie.Close()
W trakcie działania aplikacji można sprawdzić, czy jest połączenie, wywołując właściwość State, np.:
If objPolaczenie.State = ConnectionState.Open Then
objPolaczenie.Close()
End If
Fragment kodu powyżej sprawdza, czy połączenie z bazą jest otwarte; w przypadku pozytywnej
odpowiedzi zamyka zbędne już połączenie (należy pamiętać, że próba zamknięcia połączenia, gdy
zostało ono już wcześniej zakończone, spowoduje wystąpienie wyjątku).
Klasa Command pozwala wykonywać instrukcje SQL wraz z parametrami. Wykorzystujemy ją
w celu, np. utworzenia bazy, tabeli, wpisu lub aktualizacji danych, wyszukania informacji
z wykorzystaniem języka SQL. Do wykonania zapytań wykorzystujemy 3 metody ExecuteReader,
ExecuteScalar oraz ExecuteNonQuery. Działanie tych metod jest następujące:
- ExecuteReader –zwraca obiekt typu DataReader zawierający, np. zestaw rekordów będący
wynikiem zapytania.
- ExecuteScalar – zwraca zawartość pierwszej kolumny z pierwszego wiersza zestawu
wyników, otrzymanego w wyniku zapytania.
- ExecuteNonQuery wykonuje instrukcję SQL i zwraca ilość zmodyfikowanych wierszy.
Przykładowe wykorzystanie klasy Command do usunięcia rekordu o wskazanym identyfikatorze może
wyglądać następująco:
strSQL = "delete from ksiazki" & " where id_k=3"
Utworzenie zapytania SQL.
Algorytmika i programowanie
4
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Dim objZapytanie As New System.Data.SqlClient.SqlCommand(strSQL,
objPolaczenie)
Utworzenie nowego obiektu typu System.Data.SqlClient.SqlCommand (klasa Command dla
dostawcy SQL) i zainicjowanie go zapytaniem SQL oraz obiektem klasy Connection (zawierającym
informacje o połączeniu z bazą danych).
objZapytanie.ExecuteNonQuery()
Wykonanie zapytania SQL.
Klasa DataReader pozwala na tworzenie obiektów odczytujących strumień danych
otrzymanych w wyniku zapytania. Obiekt typu DataReader posiada metody pozwalające na odczytanie
kolejnych rekordów z bazy (tylko w przód) i nie ma możliwości modyfikacji danych w bazie. Przykładowe
wykorzystanie klasy DataReader może wyglądać następująco:
strSQL = "delete from ksiazki where id_k=3"
Dim objZapytanie As New System.Data.SqlClient.SqlCommand(strSQL,
objPolaczenie)
Utworzenie zapytania SQL oraz nowego obiektu klasy SQLCommand.
Dim objOdczyt As System.Data.SqlClient.SqlDataReader
Utworzenie nowego obiektu DataReader.
objOdczyt= objZapytanie.ExecuteReader()
Wywołanie metody ExecuteReader (wykonanie zapytania SQL) i podstawienie wyniku
wyszukiwań do obiektu typu DataReader.
Do While objOdczyt.Read
objOdczyt.GetInt32(0)
objOdczyt.GetString(1)
Loop
Pobranie w pętli kolejnych rekordów i odczytywanie pierwszych dwóch pól bazy (o podanych
typach).
Klasa DataAdapter pozwala utworzyć obiekt pełniący kilka zadań:
- pobiera i przechowuje podzbiór danych uzyskany w wyniku zapytania i zapisuje go w obiekcie
typu DataSet.
- umożliwia wykonywanie operacji na danych
- umożliwia przesłanie zaktualizowanych danych do bazy
Należy pamiętać, że obiekt DataAdapter pozwala na bezpołączeniowe operowanie na danych.
Oznacza to, że dane pobrane z bazy są umieszczane w pamięci komputera i tam można wykonywać na
nich różne operacje. Obiekt ten pozwala zwrócić informacje do bazy, dokonując jednocześnie ich
aktualizacji. Do pobierania danych i umieszczania ich w obiekcie typu DataSet służy metoda Fill.
Aktualizacja danych zapisanych w pamięci do bazy odbywa się za pomocą metody Update.
Klasa DataSet pozwala tworzyć obiekty przechowujące dane w pamięci. Mogą one zawierać
obiekty typu DataTable będące odpowiednikami danych z tabelami oraz pozwalają na definiowanie
relacji za pomocą metody DataRelations.
Klasa DataTable jest odpowiednikiem tabeli bazy danych, z tą różnicą, że dane
przechowywane są w pamięci komputera. W klasie tej możemy wyróżnić kilka kolekcji pozwalających
na uzyskanie informacji o danych, z których najważniejsze są DataRow i DataColumn. Pierwsza z nich
Algorytmika i programowanie
5
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
pozwala na uzyskanie pojedynczego wiesza z obiektu DataTable, druga natomiast reprezentuje
kolumnę w DataTable.
Klasa DataView pozwala na sortowanie i filtrowanie danych umieszczonych w obiekcie typu
dataTable.
Przykład wykorzystania klasy DataAdapter może wyglądać następująco:
Dim objTabela As DataTable
Dim objWiersz As DataRow
Deklaracja nowych obiektów typu DataTable i DataRow.
Dim strSQL As String
strSQL = "select * from ksiazki"
Utworzenie ciągu znaków, stanowiącego zapytanie SQL.
Dim objZapytanie As New System.Data.SqlClient.SqlDataAdapter(strSQL,
objPolaczenie)
Utworzenie nowego obiektu klasy DataAdapter i zainicjowanie go zapytaniem SQL oraz
obiektem typu Connection)
objDane = New DataSet("ksiazki")
Utworzenie nowego obiektu DataSet o nazwie ksiazki.
objZapytanie.Fill(objDane, "ksiazki")
Wypełnienie obiektu typu DataSet danymi, uzyskanymi w wyniku wykonania zapytania.
objTabela = objDane.Tables("ksiazki")
Podstawienie pod obiekt typu DataTable tabeli ksiazki, znajdującej się w obiekcie typu
DataSet.
objWiersz = objTabela.Rows(wiersz)
Pobranie jednego wiersza tabeli danych z obiektu typu DataTable i podstawienie go do obiektu
typu DataRow (parametr wiersza określa numer rekordu z zestawu danych, zapisanych w pamięci).
txtEID_k.Text = objWiersz.Item(0)
txtEAutor.Text = objWiersz.Item(1)
txtETytul.Text = objWiersz.Item(2)
Odczyt kolejnych pól rekordu i umieszczenie pobranych danych w kontrolach typu TextBox.
Kontrolka DataGrid pozwala wyświetlać dane w postaci tabeli umieszczonej na formularzu. Jest
to najprostszy sposób wyświetlenia wyników zapytania w postaci tabelarycznej.
Algorytmika i programowanie
6
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Do wypełnienia kontrolki DatGrid danymi wykorzystuje się wcześniej poznane klasy. Fragment kodu
realizujący to zadanie może wyglądać następująco:
Dim strSql As String
strSql = "select * from ksiazki"
Dim objZapytanie As New System.Data.SqlClient.SqlDataAdapter(strSql,
objPolaczenie)
Dim objDane As New DataSet("ksiazki")
Dim objDaneWidok As DataView
Dim objTabela As DataTable
Utworzenie obiektów potrzebnych do pobrania i przeglądania danych.
objZapytanie.Fill(objDane, "ksiazki")
objTabela = objDane.Tables("ksiazki")
Wypełnienie obiektu typu DataSet danymi, uzyskanymi w wyniku wykonania zapytania.
objDaneWidok = objTabela.DefaultView
Utworzenie nowego obiektu typu DataView określającego sposób wyświetlania danych.
DataGrid1.DataSource = objDane
DataGrid1.DataMember = "ksiazki"
Przypisanie do kontrolki DataGrid zawartość obiektu typu DataSet (metoda DataSource).
Ponieważ obiekt klasy DataSet może zawierać wiele tabel wskazanie poprzez właściwość
DataMember, która z tabel będzie wyświetlana w kontrolce.
Prosta aplikacja bazodanowa Książki oparta na aparacie MSDE
W tym rozdziale zostanie omówiona prosta aplikacja bazodanowa pozwalająca na przeglądanie, edycje
i wprowadzanie danych do bazy. Baza danych zostanie oparta na darmowej, okrojonej wersji SQL
Server – MSDE. Interfejs aplikacji będą stanowiły cztery karty kontrolki TabControl.
Algorytmika i programowanie
7
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Pierwszym krokiem w tworzeniu aplikacji będzie utworzenie bazy danych na serwerze MSDE. VS.NET
udostępnia narzędzie – Server Explorer pozwalające na obsługę usług serwerowych oraz serwerów
baz danych. W przypadku użycia MSDE jako silnika bazy danych dla aplikacji, zastosowanie Server
Explorer ułatwia zarządzanie bazami na serwerze ze względu na brak narzędzi do zarządzania w
okrojonej wersji SQL Servera. W celu utworzenia nowej bazy należy otworzyć okno Server Explorer
i z listy serwerów wybrać serwer MSDE zainstalowany lokalnie na komputerze.
Kliknięcie prawym przyciskiem myszy w nazwę serwera uaktywnia menu kontekstowe, z którego należy
wybrać polecenie New Database.
Algorytmika i programowanie
8
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
W oknie Create Database podajemy w polu New Database Name nazwę nowej bazy danych –
ksiazki. Należy wybrać jeszcze sposób uwierzytelniania przy połączeniu z bazą. Do wyboru jest
możliwość uwierzytelniania na poziomie wbudowanych zabezpieczeń systemu Windows lub system
uwierzytelniania serwera SQL.
W przypadku wyboru pierwszego sposobu weryfikacji uprawnień użytkownik, który będzie pracował z
bazą, musi mieć uprawnienia do jej obsługi na poziomie systemu Windows. Wybieramy uwierzytelnianie
na poziomie serwera SQL czyli opcję Use SQL Serwer Authentication jako sposób weryfikacji
uprawnień. Jako Login Name wpiszemy nazwę użytkownika sa, oraz hasło ustawione podczas
instalacji MSDE.
Rozwijamy bazę danych ksiazki i wybieramy gałąź Tables, by utworzyć nową tabelę.
Klikamy prawym przyciskiem myszy w gałąź Tables i z menu kontekstowego wybieramy polecenie New
Table. Pojawi się okno, w którym należy zdefiniować pola bazy danych.
Algorytmika i programowanie
9
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Definiujemy pola bazy (nazwa pola, typ, długość pola) wg rysunku poniżej. Baza zwiera 6 pól
przechowujących informacje o książkach.
Zapisanie nowo utworzonej tabeli nastąpi po wybraniu z menu kontekstowego polecenia Save Table.
Algorytmika i programowanie
10
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Pojawi się okno dialogowe, do którego należy wpisać nazwę tabeli.
Nowo utworzona tabela pojawia się jako obiekt w gałęzi Tables. Po rozwinięciu tabeli ksiazki pojawi się
widok jej struktury.
Algorytmika i programowanie
11
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Należy pamiętać, że Server Explorer pozwala nie tylko na tworzenie baz i tabel. Narzędzie to
umożliwia modyfikację struktury tabel oraz wprowadzanie edycji i usuwanie danych.
Kodowanie programu rozpoczniemy od utworzenia zmiennych globalnych oraz procedur
umożliwiających połączenie z bazą i sprawdzenie ilości rekordów w bazie. W celu wykorzystania klas
służących do obsługi baz danych, należy zaimportować przestrzeń nazw System.Data.
Imports System.Data
Deklaracja zmiennych globalnych wygląda następująco:
Dim objPolaczenie As System.Data.SqlClient.SqlConnection
Deklaracja obiektu typu SQLConnection, służącego do połączenia z bazą danych.
Dim objDane As New DataSet("ksiazki")
Deklaracja obiektu typu DataSet, służącego do przechowywania danych będących wynikiem
zapytań SQL.
Dim nr_rekordu As Integer = 0
Deklaracja zmiennej, w której będzie zapamiętany numer aktualnie przeglądanego rekordu.
Dim objTabela As DataTable
Deklaracja obiektu typu DataTable, służącego zapamiętania tabeli przechowywanej w obiekcie
typu DataSet.
Dim objWiersz As DataRow
Deklaracja obiektu typu DataRow, pobierającego wiersz danych z tabeli przechowywanej
w obiekcie typu DataTable.
Algorytmika i programowanie
12
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Połączenie z bazą danych zostanie realizowane poprzez procedurę, która będzie wielokrotnie
wywoływania w aplikacji.
Private Sub polacz_z_baza()
Dim strPolacz As String
Deklaracja zmiennej typu String, w której zostanie zapamiętany łańcuch połączeniowy.
strPolacz = "Password=janusz;Persist Security Info=True;User ID=sa;Initial
Catalog=ksiazki;Data Source=(local)"
Ustalenie wartości łańcucha połączeniowego (zostało to już opisane wcześniej).
Try
Rozpoczęcie bloku kodu chronionego.
objPolaczenie = New System.Data.SqlClient.SqlConnection(strPolacz)
Utworzenie nowego obiektu klasy SQLConnection.
objPolaczenie.Open()
Otwarcie połączenia z bazą.
Catch ex As Exception
MessageBox.Show("Bład w połączeniu z bazą danych", "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Obsługa ewentualnych wyjątków, mogących wystąpić przy połączeniu z bazą.
Aplikacja będzie informowała użytkownika o ilości rekordów w bazie. Informacja ta będzie także
wykorzystywana podczas obsługi karty Edytuj dane. Funkcja ile_rekordow wykorzystuje poznane
klasy do obliczenia ilości rekordów w tabeli ksiazki.
Private Function ile_rekordow() As Integer
Dim strSQL As String
objDane.Clear()
Deklaracja zmiennej typy String przechowującej zapytanie SQL oraz wyczyszczenie obiektu
typu DataSet.
strSQL = "select * from ksiazki"
Zapamiętanie zapytania SQL, które będzie wykonane w funkcji.
Dim objZapytanie As New System.Data.SqlClient.SqlDataAdapter(strSQL,
objPolaczenie)
Utworzenie nowego obiektu typu DataAdapter.
If objPolaczenie.State = ConnectionState.Open Then
Try
Sprawdzenie, czy jest połączenie z bazą i rozpoczęcie bloku kodu chronionego.
objZapytanie.Fill(objDane, "ksiazki")
ksiazki.
Wypełnienie obiektu typu DataSet (objDane) wynikiem zapytania SQL, wykonanego na tabeli
Return objDane.Tables("ksiazki").Rows.Count
Zwrócenie ilości rekordów w bazie (dokładnie ilości wierszy zapamiętanych w obiekcie typu
DataSet w tabeli ksiazki.
Algorytmika i programowanie
13
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Catch ex As DataException
MessageBox.Show("Odczyt z bazy nie jest możliwy", "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End If
End Function
Obsługa ewentualnych wyjątków, mogących wystąpić przy połączeniu z bazą i zakończenie
kodu funkcji.
Zakładka Dopisz dane umożliwia wprowadzanie nowych danych do tabeli ksiazki.
W programie dane są wprowadzane do pól tekstowych, następnie sprawdzana jest ich poprawność.
Wpis danych jest realizowany poprzez wykonanie zapytania SQL, służącego do wprowadzania danych.
Procedura realizująca to zadanie może wyglądać następująco:
Private Sub btnWpis_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnWpis.Click
Dim strWpis As String
If txtID_k.Text.Length = 0 OrElse Not IsNumeric(txtID_k.Text) Then
MessageBox.Show("Proszę uzupełnić brakujace dane", "Brak danych",
MessageBoxButtons.OK, MessageBoxIcon.Error)
txtID_k.Focus()
Exit Sub
End If
Sprawdzenie poprawności wprowadzonych danych do pola tekstowego. W przypadku błędnych
danych (pole puste lub niewłaściwy typ danych, np. tekst) działanie procedury jest przerywane a kursor
jest ustawiany w polu z błędem.
If txtAutor.Text.Length = 0 Then
MessageBox.Show("Proszę uzupełnić brakujace dane", "Brak danych",
MessageBoxButtons.OK, MessageBoxIcon.Error)
txtAutor.Focus()
Exit Sub
End If
If txtTytul.Text.Length = 0 Then
MessageBox.Show("Proszę uzupełnić brakujace dane", "Brak danych",
MessageBoxButtons.OK, MessageBoxIcon.Error)
txtTytul.Focus()
Exit Sub
End If
Algorytmika i programowanie
14
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
If txtRok_wydania.Text.Length = 0 OrElse Not IsNumeric(txtRok_wydania.Text)
Then
MessageBox.Show("Proszę uzupełnić brakujace dane", "Brak danych",
MessageBoxButtons.OK, MessageBoxIcon.Error)
txtRok_wydania.Focus()
Exit Sub
End If
If txtCena.Text.Length = 0 OrElse Not IsNumeric(txtCena.Text) Then
MessageBox.Show("Proszę uzupełnić brakujace dane", "Brak danych",
MessageBoxButtons.OK, MessageBoxIcon.Error)
txtCena.Focus()
Exit Sub
End If
If txtWydawnictwo.Text.Length = 0 Then
MessageBox.Show("Proszę uzupełnić brakujace dane", "Brak danych",
MessageBoxButtons.OK, MessageBoxIcon.Error)
txtWydawnictwo.Focus()
Exit Sub
End If
Sprawdzenie pozostałych pól formularza.
strWpis = "insert into ksiazki(id_k,autor,tytul,rok_wydania," & _
"cena,wydawnictwo) values (" & txtID_k.Text & "," & "'" & txtAutor.Text &
"'" & "," & "'" & txtTytul.Text & "'" & "," & txtRok_wydania.Text & "," &
txtCena.Text & "," & "'" & txtWydawnictwo.Text & "'" & ")"
Utworzenie zapytania SQL służącego do wprowadzania danych.
polacz_z_baza()
Połączenie z bazą.
Dim objZapytanie As New System.Data.SqlClient.SqlCommand(strWpis,
objPolaczenie)
Utworzenie nowego obiektu typu SQLCommand.
If objPolaczenie.State = ConnectionState.Open Then
Try
objZapytanie.ExecuteNonQuery()
Sprawdzenie, czy jest połączenie z bazą i wykonanie w bloku kodu chronionego zapytania
poprzez wywołanie metody ExecuteNonQuery.
lblIleKsiazek.Text = "W bazie znajduje się " & ile_rekordow() & "książek"
Aktualizacja informacji o ilości rekordów w bazie.
Catch ex As Exception
MessageBox.Show("Bład podczas wpisywania danych", "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
objPolaczenie.Close()
End Try
Obsługa ewentualnych wyjątków mogących wystąpić przy połączeniu z bazą i zakończenie
połączenia z bazą w bloku Finally (w przypadku wystąpienia wyjątku połączenie na pewno zostanie
zamknięte).
czysc_wpis()
MessageBox.Show("Dane zostały wpisane do bazy", "Wpis udany",
MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
End If
Algorytmika i programowanie
15
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
End Sub
Wyczyszczenie pól tekstowym po wprowadzeniu danych oraz poinformowanie użytkownika
o przeprowadzonej operacji.
Karta przegląd danych wyświetla zwartość bazy w kontrolce typu DataGrid. Zawartość
kontrolki jest zawsze aktualizowana przy zmianie karty w kontrolce TabControl. Wywołanie aktualizacji
następuje podczas przejścia na odpowiednią kartę.
Private Sub tclBaza_SelectedIndexChanged(ByVal sender As Object, ByVal
e As System.EventArgs) Handles tclBaza.SelectedIndexChanged
Procedura obsługi zdarzenia zmiany aktywnej karty w kontrolce typu TabControl..
If tclBaza.SelectedIndex = 1 Then
czysc_wpis()
End If
W przypadku, gdy jest aktywna karta Dopisz dane (indeks 1), zostaje wywoływana procedura
czyszczenia pół tekstowych na tej karcie.
If tclBaza.SelectedIndex = 2 Then
polacz_z_baza()
przeglad_bazy()
End If
W przypadku, gdy jest aktywna karta Przegląd danych (indeks 2), zostaje nawiązywane
połączenie z bazą i wywoływana procedura wypełniająca kontrolkę typu DataGrid danymi.
If tclBaza.SelectedIndex = 3 Then
nr_rekordu = 0
polacz_z_baza()
odczyt_do_edycji(0)
End If
End Sub
Algorytmika i programowanie
16
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
W przypadku, gdy jest aktywna karta Edytuj dane (indeks 3) zostaje nawiązywane połączenie
z bazą i wywoływana procedura wyświetlająca pierwszy rekord bazy.
Wyświetlanie danych w kontrolce typu DataGrid jest realizowane w następującej procedurze.
Private Sub przeglad_bazy()
Dim strSql As String
strSql = "select * from ksiazki"
Utworzenie zapytania SQL.
Dim objZapytanie As New System.Data.SqlClient.SqlDataAdapter(strSql,
objPolaczenie)
Utworzenie nowego obiektu typu SQLDataAdapter.
Dim objDane As New DataSet("ksiazki")
Utworzenie nowego obiektu typu DataSet.
Dim objDaneWidok As DataView
Utworzenie nowego obiektu typu DataView.
Dim objTabela As DataTable
Utworzenie nowego obiektu typu DataTable.
If objPolaczenie.State = ConnectionState.Open Then
Try
Sprawdzenie, czy jest połączenie z bazą danych i rozpoczęcie bloku kodu chronionego.
objZapytanie.Fill(objDane, "ksiazki")
Wypełnienie obiektu typu DataSet danymi będącymi wynikiem zapytania.
objTabela = objDane.Tables("ksiazki")
objDaneWidok = objTabela.DefaultView
Zapamiętanie tabeli ksiazki w obiekcie typu DataTable i ustawienie sposobu sortowania
danych.
DataGrid1.DataSource = objDane
DataGrid1.DataMember = "ksiazki"
Wypełnienie kontrolki typu DataGrid danymi.
Catch ex As DataException
MessageBox.Show("Odczyt z bazy nie jest możliwy", "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
objPolaczenie.Close()
End Try
End If
End Sub
Obsługa ewentualnych wyjątków mogących wystąpić przy połączeniu z bazą i zakończenie
połączenia z bazą w bloku Finally (w przypadku wystąpienia wyjątku połączenie na pewno zostanie
zamknięte).
Algorytmika i programowanie
17
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Karta Edytuj dane pozwala na przeglądanie pojedynczych rekordów. Użytkownik może
zmodyfikować zwartość rekordu i zapisać zmiany oraz usunąć rekord. Funkcje te są realizowane
poprzez odpowiednie zapytania SQL. Odczyt danych jest realizowany przez następującą procedurę:
Private Sub odczyt_do_edycji(ByVal nr_rekordu As Integer)
Dim strSQL As String
strSQL = "select * from ksiazki"
Dim objZapytanie As New System.Data.SqlClient.SqlDataAdapter(strSQL,
objPolaczenie)
objDane = New DataSet("ksiazki")
If objPolaczenie.State = ConnectionState.Open Then
Try
objDane.Clear()
objZapytanie.Fill(objDane, "ksiazki")
Catch ex As System.Exception
MessageBox.Show("Odczyt z bazy nie jest możliwy", "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
objPolaczenie.Close()
End Try
End If
Zapamiętanie wszystkich rekordów bazy w obiekcie typu DataTable.
If objDane.Tables("ksiazki").Rows.Count = 0 Then
MessageBox.Show("Baza pusta- brak rekordów", "Baza ",
MessageBoxButtons.OK, MessageBoxIcon.Warning)
btnPoprzedni.Enabled = False
btnNastepny.Enabled = False
btnUsunRekord.Enabled = False
btnEZapiszDane.Enabled = False
wyswietl_rekord(-1)
Exit Sub
Sprawdzenie ilości rekordów w bazie. W przypadku, gdy baza jest pusta, poinformowanie
użytkownika o tym fakcie i wyłączenie przycisków służących do operacji na danych. Wywołanie
procedury wyswietl_rekord z wartością ujemną powoduje wyczyszczenie pól tekstowych.
Algorytmika i programowanie
18
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Else
btnNastepny.Enabled = True
btnPoprzedni.Enabled = True
btnUsunRekord.Enabled = True
btnEZapiszDane.Enabled = True
wyswietl_rekord(nr_rekordu)
End If
End Sub
W przypadku gdy w bazie są dane włącznie przycisków służących do operacji na danych
i wywołanie procedury wyswietl_rekord z numerem rekordu, który ma być aktualnie wyświetlony.
Procedura wyswietl_rekord wyświetla jeden wiersz danych z obiektu typu DataTable.
Private Sub wyswietl_rekord(ByVal wiersz As Integer)
If wiersz >= 0 Then
objTabela = objDane.Tables("ksiazki")
objWiersz = objTabela.Rows(wiersz)
txtEID_k.Text = objWiersz.Item(0)
txtEAutor.Text = objWiersz.Item(1)
txtETytul.Text = objWiersz.Item(2)
txtERok_wydania.Text = objWiersz.Item(3)
txtECena.Text = objWiersz.Item(4)
txtEWydawnictwo.Text = objWiersz.Item(5)
W przypadku, gdy w bazie są dane, do wyświetlenia zawartości pól wybranego rekordu
wykorzystany jest obiekt typu DataRows.
Else
czysc_edycja()
End If
End Sub
W przypadku, gdy baza jest pusta, wywoływana zostaje procedura czyszcząca pola tekstowe.
Przyciski Następny i Poprzedni pozwalają na poruszanie się pomiędzy rekordami. Procedury
zdarzenia z nimi związane zwiększają (lub zmniejszają) numer rekordu, jaki ma być wyświetlony
i wywołują procedurę wyswietl_rekord. Dodatkowo informują użytkownika o osiągnięciu pierwszego
lub ostatniego rekordu.
Private Sub btnNastepny_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnNastepny.Click
If nr_rekordu < objDane.Tables("ksiazki").Rows.Count - 1 Then
nr_rekordu += 1
wyswietl_rekord(nr_rekordu)
Else
MessageBox.Show("Ostatni rekord - przejście dalej nie jest możliwe",
"Uwaga", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End If
End Sub
Private Sub btnPoprzedni_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnPoprzedni.Click
If nr_rekordu > 0 Then
nr_rekordu -= 1
wyswietl_rekord(nr_rekordu)
Else
MessageBox.Show("Pierwszy rekord - przejście dalej nie jest możliwe",
„Uwaga", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End If
Algorytmika i programowanie
19
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
End Sub
Zapis zmian w danych następuje po kliknięciu przycisku Zapisz zmiany w rekordzie. Do modyfikacji
rekordu jest wykorzystywane polecenie SQL w połączeniu z klasami VS.NET służącymi do obsługi baz
danych. Procedura wypełniająca to zadanie może wyglądać następująco:
Private Sub btnEZapiszDane_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnEZapiszDane.Click
Dim strWpis As String
Dim strSQL As String
If txtEID_k.Text.Length = 0 OrElse Not IsNumeric(txtEID_k.Text) Then
MessageBox.Show("Błędny wpis", "Błąd", MessageBoxButtons.OK,
MessageBoxIcon.Error)
txtEID_k.Focus()
Exit Sub
End If
Sprawdzenie poprawności wprowadzonych danych do pola tekstowego. W przypadku błędnych
danych (pole puste lub niewłaściwy typ danych, np. tekst) działanie procedury jest przerywane a kursor
zostaje ustawiony w polu z błędem.
If txtEAutor.Text.Length = 0 Then
MessageBox.Show("Błędny wpis", "Błąd", MessageBoxButtons.OK,
MessageBoxIcon.Error)
txtEAutor.Focus()
Exit Sub
End If
If txtETytul.Text.Length = 0 Then
MessageBox.Show("Błędny wpis", "Błąd", MessageBoxButtons.OK,
MessageBoxIcon.Error)
txtETytul.Focus()
Exit Sub
End If
If txtERok_wydania.Text.Length = 0 OrElse Not
IsNumeric(txtERok_wydania.Text) Then
MessageBox.Show("Błędny wpis", "Błąd", MessageBoxButtons.OK,
MessageBoxIcon.Error)
txtERok_wydania.Focus()
Exit Sub
End If
If txtECena.Text.Length = 0 OrElse Not IsNumeric(txtECena.Text) Then
MessageBox.Show("Błędny wpis", "Błąd", MessageBoxButtons.OK,
MessageBoxIcon.Error)
txtECena.Focus()
Exit Sub
End If
If txtEWydawnictwo.Text.Length = 0 Then
MessageBox.Show("Błędny wpis", "Błąd", MessageBoxButtons.OK,
MessageBoxIcon.Error)
txtEWydawnictwo.Focus()
Exit Sub
End If
Sprawdzenie pozostałych pól formularza
polacz_z_baza()
Połączenie z bazą danych
strWpis = "id_k=" & txtEID_k.Text & ", autor='" & txtEAutor.Text &
"',Tytul='" & _
Algorytmika i programowanie
20
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
txtETytul.Text & "', rok_wydania=" & txtERok_wydania.Text & ", cena=" &
txtECena.Text & ", Wydawnictwo='" & _
txtEWydawnictwo.Text & "'"
strSQL = "update ksiazki set " & strWpis & " where id_k=" & txtEID_k.Text
Utworzenie zapytania SQL aktualizującego dane.
If objPolaczenie.State = ConnectionState.Open Then
Try
Sprawdzenie, czy jest połączenie z bazą i otwarcie bloku kodu chronionego.
Dim objZapytanie As New System.Data.SqlClient.SqlCommand(strSQL,
objPolaczenie)
objZapytanie.ExecuteNonQuery()
Utworzenie nowego obiektu typu SQLCommand i wykonanie aktualizacji danych za pomocą
zapytania SQL.
odczyt_do_edycji(nr_rekordu)
Aktualizacja danych na formularzu.
MessageBox.Show("Rekord został zaktualizowany", "Informacja",
MessageBoxButtons.OK, MessageBoxIcon.Information)
Poinformowanie użytkownika o wykonaniu aktualizacji danych.
Catch ex As DataException
MessageBox.Show("Bład podczas aktualizacji danych", "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
objPolaczenie.Close()
End Try
End If
End Sub
Obsługa ewentualnych wyjątków mogących wystąpić przy połączeniu z bazą i zakończenie
połączenia z bazą w bloku Finally (w przypadku wystąpienia wyjątku połączenie na pewno zostanie
zamknięte).
Ostatnim przyciskiem, który należy oprogramować jest Usuń rekord. Ponownie zostanie wykorzystane
polecenie SQL służące do usuwania danych oraz klasy VS.NET.
Private Sub btnUsunRekord_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnUsunRekord.Click
polacz_z_baza()
Połączenie z bazą danych.
If objPolaczenie.State = ConnectionState.Open Then
If ile_rekordow() > 0 Then
Sprawdzenie, czy jest połączenie z bazą, i czy są rekordy w bazie.
Dim Pytanie As DialogResult
Pytanie = MessageBox.Show("Czy chcesz slasować bieżacy rekord?",
"Usuwanie danych", MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2)
If Pytanie = DialogResult.Yes Then
Potwierdzenie usunięcia danych przez użytkownika.
Dim strSQL As String
strSQL = "delete from ksiazki" & " where id_k=" & txtEID_k.Text
Algorytmika i programowanie
21
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Utworzenie zapytania SQL..
Try
Dim objZapytanie As New System.Data.SqlClient.SqlCommand(strSQL,
objPolaczenie)
objZapytanie.ExecuteNonQuery()
Utworzenie nowego obiektu typu SQLCommand i usunięcie rekordu za pomocą zapytania
SQL.
MessageBox.Show("Rekord został usunięty", "Informacja",
MessageBoxButtons.OK, MessageBoxIcon.Information)
lblIleKsiazek.Text = "W bazie znajdują się " & ile_rekordow() &
"książek"
odczyt_do_edycji(0)
Potwierdzenie usunięcia rekordu oraz aktualizacji informacji o ilości rekordów w bazie.
W formularzu zostanie wyświetlony pierwszy rekord.
Catch ex As DataException
MessageBox.Show("Bład podczas aktualizacji danych", "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
objPolaczenie.Close()
End Try
End If
End If
Else
MessageBox.Show("Brak połaczenia z bazą", "Bład", MessageBoxButtons.OK,
MessageBoxIcon.Error)
End If
End Sub
Obsługa ewentualnych wyjątków mogących wystąpić przy połączeniu z bazą i zakończenie
połączenia z bazą w bloku Finally (w przypadku wystąpienia wyjątku połączenie na pewno zostanie
zamknięte).
Przedstawiony powyżej przykład pokazuje podstawowe mechanizmy obsługi baz danych
wykorzystywane w VS.NET. Wiele rzeczy można zrobić także inaczej, np. aktualizację danych
wykonywać za pomocą obiektów klasy DataAdapter. Powyższy przykład miał pokazać, jak można
połączyć efektywnie język SQL z klasami .NET Framework.
Modyfikacja kształtu formularzy oraz biblioteka WinAPI
Modyfikacja kształtu formularzy
Formularz jest standardowym interfejsem aplikacji Windows. Domyślny kształt formularza to
prostokąt lub kwadrat zawierający elementy charakterystyczne dla aplikacji - pasek aplikacji. Przyciski
Zamknij, Minimalizuj czy Maksymalizuj. Istnieje jednak możliwość zmiany kształtu formularzy.
Wykonanie tego zadania można opisać następująco: tworzymy nowy obiekt Region i przypisujemy go
do właściwości Form.Region. Obiekt Region powinien zawierać definicję żądanego kształtu formularza.
Do tego można wykorzystać klasę System.Drawing.Drawing2D.GraphicsPath, która pozwala
zdefiniować obszar za pomocą różnych krzywych, elips kół czy prostokątów.
Realizacja tego zadania może wyglądać następująco:
Dim kolo As New System.Drawing.Drawing2D.GraphicsPath()
Utworzenie nowego obiektu typu System.Drawing.Drawing2D.GraphicsPath.
Algorytmika i programowanie
22
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
kolo.AddEllipse(100, 100, 300, 300)
Zdefiniowanie obszaru – w tym przypadku koło o podanych współrzędnych. Należy pamiętać,
że współrzędne koła to nie x, y środka, lecz górnego prawego narożnika obszaru, w którym znajduje się
koło).
Me.Region = New Region(kolo)
Utworzenie nowego obiektu typu Region i przypisanie go do właściwości Region formularza.
Należy pamiętać, że np. taka zmiana kształtu spowoduje, że nie będzie widać paska aplikacji oraz
przycisków do obsługi okna. Skutkuje to brakiem możliwości przesunięcia czy zamknięcia formularza,
stąd też należy to samodzielnie oprogramować. Przykładowy kod pozwalający na przesuwanie
formularza zostanie przedstawiony w opisie aplikacji Odtwarzacza.
Wykorzystanie biblioteki WinAPI do odtwarzania plików WAV.
Biblioteki WinAPI pozwalają programistom na dostęp do wielu funkcji, których nie ma w
narzędziach programistycznych. Dodatkowo nie zależą od języka programowania, co pozwala je
wykorzystywać na różnych platformach stosowanych przez programistów. Środowisko .NET Framework
nie posiada wbudowanych klas do obsługi plików audio. Do tego zdania można wykorzystać funkcje
sndPlaySoundA zaszytą w bibliotece wimm.dll. Funkcja ta może odtwarzać dźwięk w następujących
trybach:
- synchronicznym (następuje przerwa w działaniu programu)
- asynchronicznym (odtwarzanie jest wykonywane w tle).
Wywołanie tej funkcji ma dwa parametry - nazwę odtwarzanego pliku i tryb odtwarzania pliku
(synchroniczny lub asynchroniczny). Wykorzystanie funkcji WinAPI w VB.NET wymaga jej
zadeklarowania ze wskazaniem biblioteki, z której pochodzi.
Private Declare Function graj Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal
plik As String, ByVal flaga As Long) As Long
Powyższy kod deklaruje nową funkcje w VB.NET o nazwie: graj. Tak naprawdę jest to funkcja
sndPlaySoundA z biblioteki wimm.dll.
Po takiej deklaracji wywołanie odtwarzania pliku WAV jest już bardzo proste.
graj(PlikWAV, 1)
Funkcja posiada dwa parametry – nazwę pliku oraz tryb odtwarzania dźwięku.
Prosty odtwarzacz plików WAV
Przedstawione powyżej wiadomości można wykorzystać w prostej aplikacji, służącej do odtwarzania
plików audio. Interfejs aplikacji może wyglądać następująco.
Algorytmika i programowanie
23
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Pierwszym krokiem jest zdefiniowanie procedury rysującej koło – obwódkę formularza. Działanie to
będzie wykonywane w procedurze zdarzenia Paint formularza.
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
Dim pioro As New Pen(Color.Navy, 8)
Zdefiniowanie koloru oraz grubości linii.
Dim rysunek As System.Drawing.Graphics
rysunek = Me.CreateGraphics
Utworzenie nowego obiektu typu Graphics.
rysunek.DrawEllipse(pioro, 100, 100, 300, 300)
End Sub
Narysowanie koła o podanych współrzędnych.
Narysowany okrąg będzie obwódkę nowego formularza. Procedura zmiany kształtu zostanie wykonana
podczas ładowania formularza (zdarzenie Load dla formularza).
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim kolo As New System.Drawing.Drawing2D.GraphicsPath()
kolo.AddEllipse(100, 100, 300, 300)
Me.Region = New Region(kolo)
btnOdtwarzaj.Enabled = False
btnStop.Enabled = False
End Sub
W kodzie procedury oprócz określenia nowego kształtu jest także deaktywacja przycisków.
Nowy formularz nie ma paska aplikacji oraz przycisku Zamknij. Funkcje te należy samemu
zaprogramować. Zamknięcie aplikacji jest bardzo proste.
Private Sub btnKoniec_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnKoniec.Click
Dim Pytanie As DialogResult
Pytanie = MessageBox.Show("Czy zakończyc pracę odtwarzacza?", "Koniec
pracy", MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2)
If Pytanie = DialogResult.Yes Then
Close()
End If
End Sub
Do przesuwania formularza służą trzy procedury. Jednak konieczne jest zadeklarowanie zmiennych
globalnych w aplikacji.
Dim Przesun As Boolean
Dim Punkt As Point
Dim PlikWAV As String
Pierwsze dwie zmienne służą do obsługi przemieszczania formularza, trzecia przechowuje nazwę
otwartego pliku WAV.
Wciśnięcie przycisku myszy na przycisku Przesuń wywołuje procedurę dla zdarzenia MouseDown tej
kontrolki.
Algorytmika i programowanie
24
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Private Sub btnPrzesun_MouseDown(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles btnPrzesun.MouseDown
If e.Button = MouseButtons.Left Then
Sprawdzenie czy zostal wciśnięty lewy przycisk myszki.
Przesun = True
Punkt = New Point(e.X, e.Y)
Zmiana wartości zmiennej przesun (informacja, że formularz będzie przesuwany) oraz
odczytanie współrzędnych myszki w momencie, gdy lewy przycisk jest wciśnięty.
Else
Przesun = False
End If
End Sub
Zmiana wartości zmiennej przesun – informacja, że formularz nie będzie przemieszczany.
Przesuwanie formularza jest realizowane dla zdarzenia MouseMove przycisku Przesuń. Procedura ta
oblicza nowe współrzędne formularza i zmienia jego położenie poprzez właściwość Location.
Private Sub btnPrzesun_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles btnPrzesun.MouseMove
If Przesun Then
Dim PunktNowy As Point
PunktNowy = Me.PointToScreen(New Point(e.X, e.Y))
PunktNowy.Offset(-Punkt.X, Punkt.Y)
Me.Location = PunktNowy
End If
End Sub
Procedura dla zdarzenia MouseUp (przycisk myszy nie jest wciśnięty) ustala wartość zmiennej
przesun na False (przenoszenie nie będzie wykonywane).
Private Sub btnPrzesun_MouseUp(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles btnPrzesun.MouseUp
Przesun = False
End Sub
Odtwarzanie pliku jest związane z jego wyborem. Zadanie to będzie realizowane poprzez kontrolkę
OpenFileDialog dodaną w kodzie procedury. Procedura zdarzenia dla kliknięcia przycisku Otwórz WAV
wygląda następująco:
Private Sub btnOtworzPlik_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnOtworzPlik.Click
Dim dlgOtworz As New OpenFileDialog()
Utworzenie nowego obiektu (kontrolki) typu OpenFileDialog.
Dim sciezka() As String
Deklaracja pustej tablicy służącej do zapamiętania ścieżki dostępu i nazwy pliku.
dlgOtworz.Filter = "pliki WAV|*.wav"
Utworzenie filtru dla okna dialogowego.
If dlgOtworz.ShowDialog() = DialogResult.OK Then
PlikWAV = dlgOtworz.FileName
Wyświetlenie okna i odczyt nazwy wybranego pliku.
Algorytmika i programowanie
25
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
sciezka = PlikWAV.Split("\")
lblPlik.Text = sciezka(sciezka.Length - 1)
Wyświetlenie w kontrolce typu Label nazwy wybranego pliku.
btnOdtwarzaj.Enabled = True
Włączenie przycisku Odtwarzaj.
End If
End Sub
By aplikacja osiągnęła swoją funkcjonalność, brakuje jeszcze procedur zdarzenia dla przycisków
Odtwarzaj i Stop. Wymaga to jednak zadeklarowania funkcji sndPlaySoundA.
Private Declare Function graj Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal
plik As String, ByVal flaga As Long) As Long
Procedura zdarzenia dla przycisku Odtwarzaj wygląda następująco:
Private Sub btnOdtwarzaj_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnOdtwarzaj.Click
Try
btnOtworzPlik.Enabled = False
btnStop.Enabled = True
Deaktywacja przycisku Otwórz WAV oraz włączenie przycisku Stop.
graj(PlikWAV, 1)
Wywołanie funkcji graj – plik WAV jest odtwarzany w trybie asynchronicznym (parametr 1 – tryb
asynchroniczny, parametr 2- tryb synchroniczny).
Catch ex As Exception
MessageBox.Show("Bład przy odtworzeniu pliku", "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Obsłużenie ewentualnych błędów mogących wystąpić podczas odczytu z pliku.
Ostatnia procedura pozwala zatrzymać odtwarzanie pliku. Parametrem funkcji graj jest wartość 4
oznaczająca zatrzymanie odtwarzania pliku audio.
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnStop.Click
graj("", 4)
btnOtworzPlik.Enabled = True
End Sub
Przedstawiona powyżej aplikacja jeszcze nie dorasta do programów komercyjnych, jednak pokazuje,
jak można modyfikować kształty formularzy oraz wykorzystywać WinAPI, zawierającą wiele
użytecznych funkcji, niedostępnych na platformach programistycznych.
Algorytmika i programowanie
26
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Algorytmy wyszukiwania wzorca w ciągu znaków
Czym się zajmują komputery? Nie tylko obliczeniami, lecz także wyszukiwaniem danych. W
dzisiejszym numerze kompendium w bloku poświęconym algorytmowi, troszkę o sposobach
wyszukiwaniu wzorca w tekście. Oczywiście, jako tekst rozumiemy ciąg znaków w sensie
informatycznym, który niekoniecznie musi mieć sens w kontekście treści. Biorąc pod uwagę ostatnie
zdanie, tekstem może być także ciąg bitów, które przecież stanowią podstawę przy przetwarzaniu
danych przez komputer.
Istnieje wiele algorytmów wyszukiwania, stąd w bieżącym numerze musieliśmy dokonać
pewnego wyboru. Zaczniemy od przedstawienia idei wyszukiwania w postaci algorytmu naiwnego. Jakie
to będą algorytmy, o tym w dalszej części kompendium.
Algorytm naiwny
Wyszukiwanie wzorca w tekście. Problem ten dotyczy wielu aplikacji, np. najzwyklejszego
edytora tekstu w momencie, gdy chcemy sprawdzić, czy dana fraza występuje we wprowadzonym
łańcuchu znaków. Na początek wprowadźmy sobie dwa określenia:
- tekst: ciąg znaków pewnego ustalonego alfabetu, który będziemy przeszukiwali o długości M
- wzorzec: ciąg znaków, którego wystąpień będziemy wyszukiwali w tekście o długości N.
Najprostszym rozwiązaniem problemu wyszukiwania wzorca w tekście jest tzw.algorytm
naiwny. Polega on na porównywaniu kolejnych znaków tekstu ze wzorcem. Zaczynamy od pierwszego
znaku tekstu.
A
C
B
C
B
A
C
F
F
C
C
A
F
A
A
B
A
B
A
TEKST
WZORZEC
W przypadku, gdy znaki są różne, przesuwamy wzorzec o jeden i ponownie sprawdzamy tekst.
A
B
C
B
C
C
A
F
F
C
C
A
F
A
A
B
A
B
A
TEKST
WZORZEC
A
B
B
C
C
C
F
A
C
F
C
A
F
A
A
B
A
B
A
TEKST
WZORZEC
Przesuwając wzorzec, odnajdujemy miejsce, gdy pierwszy znak wzorca zgadza się ze znakiem
tekstu. Wtedy sprawdzamy zgodność kolejnych elementów wzorca z elementami tekstu.
A
B
B
C
C
F
C
C
A
C
F
A
F
A
A
B
A
B
A
TEKST
WZORZEC
Na rysunku przedstawionym powyżej, występuje niezgodność drugiego znaku wzorca
z elementem tekstu. Wyszukiwanie zaczynamy od początku, przesuwając wzorzec po raz kolejny
o jedną pozycję.
Algorytmika i programowanie
27
Kompendium wiedzy programisty VB.NET – nr 5
A
B
B
C
A
B
B
C
autor: Janusz Białowąs
F C C A F A A B A B A
TEKST
C C A F
WZORZEC
Działanie to wykonujemy do momentu, gdy odszukamy wystąpienie wzorca:
F
C
C
C
C
A
A
F
F
A
A
B
A
B
A
TEKST
WZORZEC
lub gdy ostatni znak wzorca pokryje się z ostatnim znakiem tekstu (jednocześnie pierwszy znak
wzorca będzie różny od odpowiadającego mu znaku w teście). Wydaje się to oczywiste, warto jednak
pamiętać o tym, że kończymy wyszukiwanie dla indeksu znaku w tekście M-N, (chyba że znaki na tej
pozycji są równe; wtedy należy sprawdzać ich zgodność dalej).
A
B
B
C
F
C
C
A
F
A
A
B
C
A
C
B
A
A
F
TEKST
WZORZEC
Praktyczna implementacja tego algorytmu jest bardzo prosta. Interfejs aplikacji może wyglądać
następująco:
Tekst jest odczytywany z pliku podczas ładowania aplikacji.
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim NrPliku As String
NrPliku = FreeFile()
Try
FileOpen(NrPliku, "..\tekst.txt", OpenMode.Input)
tekst = LineInput(NrPliku)
lblTekst.Text = tekst
Catch ex As Exception
MessageBox.Show("Bład podczas odczytu z pliku", "Błąd",
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
FileClose(NrPliku)
End Try
Algorytmika i programowanie
28
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
End Sub
Praktyczna implementacja opisanego powyżej algorytmu wygląda następująco:
Private Sub btnSprawdz_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnSprawdz.Click
Dim i, j As Integer
i = 0
j = 0
Deklaracja zmiennych pomocniczych. Zmienna i służy do przechowywania indeksu znaku
w tekście, od którego zaczynamy porównywanie, zmienna j służy do zliczania ilości zgodnych znaków
we wzorcu i tekście.
wzorzec = txtWzorzec.Text
Pobranie wzorca z kontrolki typu TextBox i podstawienie pod zmienną
Do While i <= tekst.Length - wzorzec.Length
Rozpoczęcie pętli przesuwającej wzorzec co jeden znak w stosunku do tekstu Ostania
pozycja indeksu w tekście ma wartość M-N.
Do While j < wzorzec.Length AndAlso tekst.Chars(i + j) = wzorzec.Chars(j)
j += 1
Loop
W przypadku gdy znak wzorca i testu są równe, ma miejsce sprawdzanie kolejnych znaków
i zliczanie ilości zgodnych wystąpień. Pętla kończy działanie, gdy porównywane znaki wzorca i tekstu są
różne lub zliczona ilość zgodnych wystąpień osiągnie długość wzorca (oznacza to, że wzorzec został
odnaleziony).
If j = wzorzec.Length Then
MessageBox.Show("Wzorzec występuje na pozycji " & i)
End If
Poinformowanie użytkownika o znalezieniu wzorca na pozycji i.
j = 0
Wyzerowanie zmiennej zliczającej zgodne wystąpienia znaków we wzorcu i tekście.
i += 1
Loop
Przesunięcie indeksu, od którego rozpoczynamy porównywanie znaków o jeden i zakończenie
bloku pętli.
End Sub
Opisany powyżej algorytm jest bardzo prosty w implementacji, lecz jednocześnie bardzo
nieefektywny. Jego wadą jest to, że podczas wyszukiwania nie wykorzystuje się informacji zawartych
we wzorcu, tzn. możliwości zwiększania przesunięcia wzorca o więcej niż o jeden znak.
Algorytm K-M-P (Knuta, Morrisa, Ptatta)
Algorym K-M-P wykorzystuje informacje zawarte we wzorcu, by zwiększyć przesunięcie
podczas stwierdzenia niezgodności wzorca z tekstem na n - pozycji. Wracając do algorytmu naiwnego
rozważmy sytuację następującą:
Algorytmika i programowanie
29
Kompendium wiedzy programisty VB.NET – nr 5
A
B
B
C
F
A
A
B
B
A
A
autor: Janusz Białowąs
D
B
A
A
B
A
B
A
TEKST
WZORZEC
Stwierdzamy niezgodność wzorca z tekstem na 3. pozycji, po czym przesuwamy wzorzec o jeden,
rozpoczynając ponownie porównywanie.
A
B
B
C
F
A
B
A
A
B
D
A
A
B
A
B
A
B
A
TEKST
WZORZEC
Znaki oznaczone zielonym tłem pokazują, do którego miejsca już sprawdziliśmy tekst, a teraz
cofamy się o kilka pozycji i ponownie rozpoczynamy sprawdzanie. Algorytm K-M-P wykorzystuje
informacje zawarte we wzorcu i pozwala zwiększyć przesuniecie, tak byśmy w niektórych przypadkach
nie cofali się o tyle pozycji. Zwiększone przesunięcie jest widoczne na rysunku poniżej.
A
B
B
C
F
A
B
A
A
D
B
A
A
A
B
B
A
B
A
TEKST
WZORZEC
Zanim wyjaśnimy, jak działa algorytm K-M-P, trzeba wyjaśnić kilka pojęć.
Prefiks łańcucha tekstowego o długości M znaków to K początkowych znaków tego łańcucha.
Dla wartości k=0 prefiks nie zawiera żadnego znaku i jest to prefiks pusty. Jeśli K<M to jest to prefiks
właściwy (czyli prefiks nie jest jednocześnie całym łańcuchem znakowym). W przypadku gdy K=M
otrzymujemy prefiks niewłaściwy.
Przykłady prefiksów dla łańcucha znaków ALE:
„”
prefiks pusty o długości K-0
„A”
prefiks właściwy o długości K=1
„AL.”
prefiks właściwy o długości K=2
„ALE”
prefiks niewłaściwy o długości K=3
Sufiks łańcucha tekstowego o długości M znaków to K końcowych znaków tego łańcucha.
Dla wartości k=0 prefiks nie zawiera żadnego znaku i jest to sufiks pusty. Jeśli K<M to jest to sufiks
właściwy (czyli prefiks nie jest jednocześnie całym łańcuchem znakowym). W przypadku gdy K=M
otrzymujemy sufiks niewłaściwy.
Przykłady sufiksów dla łańcucha znaków ALE:
„”
sufiks pusty o długości K-0
„E”
sufiks właściwy o długości K=1
„LE.”
sufiks właściwy o długości K=2
„ELA”
sufiks niewłaściwy o długości K=3
Brzegiem łańcucha znaków nazywamy jego prefiks i sufiks właściwy, w przypadku gdy prefiks i sufiks
są sobie równe, np. dla tekstu ABAKAB jego brzeg jest zaznaczony pogrubioną czcionką ABAKAB.
Dla tego łańcucha możemy określić maksymalną szerokość brzegu, czyli taką długość sufiksu i
prefiksu, dla której te dwa podciągi są sobie równe. W tekście ABAKAB maksymalna szerokość brzegu
wynosi 2. Algorytm K-M-P do obliczenia przesunięcia, o które można przesunąć wzorzec podczas
wyszukiwania, wykorzystuje tablicę przechowującą informację o maksymalnych brzegach kolejnych
Algorytmika i programowanie
30
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
prefiksów wzorca. Powstawanie takiej tablicy możemy zaobserwować na przykładzie poniżej. Wzorzec,
który będziemy badali ma wartość: ABDCABDDAB.
A
0
B
D
C
A
B
D
D
A
B
Dla pierwszej komórki tablicy, gdzie prefiks ma
długość 1 i wartość „A” szerokość brzegu wynosi
0.
A
0
B
0
D
C
A
B
D
D
A
B
Dla drugiej komórki tablicy, gdzie prefiks ma
długość 2 i wartość „AB” szerokość brzegu wynosi
0 (prefiks nie równa się sufiksowi).
A
0
B
0
D
0
C
A
B
D
D
A
B
Dla trzeciej komórki tablicy, gdzie prefiks ma
długość 3 i wartość „ABD” szerokość brzegu
wynosi 0.
A
0
B
0
D
0
C
0
A
B
D
D
A
B
Dla czwartej komórki tablicy, gdzie prefiks ma
długość 4 i wartość „ABDC” szerokość brzegu
wynosi 0.
A
0
B
0
D
0
C
0
A
0
B
D
D
A
B
Dla piątej komórki tablicy, gdzie prefiks ma
długość 5 i wartość „ABDCA” szerokość brzegu
wynosi 1(prefiks A jest równy sufiksowi A- długość
prefiksu i sufiksu jest równa 1, czyli maksymalnej
szerokości brzegu).
A
0
B
0
D
0
C
0
A
1
B
D
D
A
B
Dla szóstej komórki tablicy, gdzie prefiks ma
długość 6 i wartość „ABDCAB” szerokość brzegu
wynosi 2 (prefiks AB jest równy sufiksowi AB długość prefiksu i sufiksu jest równa 2, czyli
maksymalnej szerokości brzegu).
A
0
B
0
D
0
C
0
A
1
B
2
D
3
D
A
B
Dla siódmej komórki tablicy, gdzie prefiks ma
długość 7 i wartość „ABDCABD” szerokość
brzegu wynosi 3(prefiks ABD jest równy sufiksowi
ABD - długość prefiksu i sufiksu jest równa 3, czyli
maksymalnej szerokości brzegu).
A
0
B
0
D
0
C
0
A
1
B
2
D
3
D
0
A
B
Dla ósmej komórki tablicy, gdzie prefiks ma
długość 8 i wartość „ABDCABDD” szerokość
brzegu wynosi 0.
A
0
B
0
D
0
C
0
A
1
B
2
D
3
D
0
A
1
B
Dla dziewiątej komórki tablicy, gdzie prefiks ma
długość 9 i wartość „ABDCABDA” szerokość
brzegu wynosi 3 (prefiks A jest równy sufiksowi A
- długość prefiksu i sufiksu jest równa 1, czyli
maksymalnej szerokości brzegu).
Algorytmika i programowanie
31
Kompendium wiedzy programisty VB.NET – nr 5
A
0
B
0
D
0
C
0
A
1
B
2
D
3
D
0
A
1
B
2
autor: Janusz Białowąs
Dla dziesiątej komórki tablicy, gdzie prefiks ma
długość 10 i wartość „ABDCABDAB” szerokość
brzegu wynosi 2.
Zbudowanie tablicy przesunięć, widocznej powyżej, pozwala na zmianę wartości przesunięcia wzorca
podczas przeszukiwania tekstu.
Procedura wypełniająca tablice szerokością brzegu dla kolejnych fragmentów wzorca wygląda
następująco:
Private Sub przesuniecia(ByVal wzorzec As String)
Dim i As Integer
Dim szb As Integer = 0
Ustalenie początkowej wartości szerokości brzegu.
ReDim tablicaP(wzorzec.Length)
Ustalenie rozmiaru tablicy na podstawie długości wzorca (tablica została zadeklarowana jako
tablica globalna o rozmiarze zerowym).
tablicaP(0) = 0
Ustalenie szerokości brzegu (zerowej) dla pierwszego elementu tablicy.
For i = 1 To wzorzec.Length – 1
Rozpoczęcie pętli sprawdzającej kolejne prefiksy wzorca.
Do While szb > 0 And wzorzec.Chars(szb) <> wzorzec.Chars(i)
szb = tablicaP(i)
Loop
If wzorzec.Chars(szb) = wzorzec.Chars(i) Then
szb += 1
End If
Obliczenie szerokości brzegu dla kolejnego prefiksu wzorca.
tablicaP(i) = szb
Zapisanie szerokości brzegu w tablicy przesunięć.
Next
End Sub
Procedura przedstawiona powyżej jest wykorzystywana w wyszukiwaniu wzorca do ustalenia
skoku, o jaki można przesunąć wzorzec, gdy część znaków tekstu jest zgodna z wzorcem.
Wyszukiwanie wzorca jest wtedy modyfikacją algorytmu naiwnego.
Private Sub btnSprawdz_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnSprawdz.Click
Dim i, j As Integer
i = 1
j = 0
wzorzec = txtWzorzec.Text
przesuniecia(wzorzec)
Wypełnienie tablicy przesunięć
Do While i <= tekst.Length - wzorzec.Length
j = tablicaP(j)
Do While j < wzorzec.Length AndAlso wzorzec.Chars(j) = tekst.Chars(i + j)
j = j + 1
Algorytmika i programowanie
32
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Loop
If j = wzorzec.Length Then
MessageBox.Show("Wzorzec wystepuje na pozycji " & i, "Wynik wyszukiwań",
MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
i = i + tablicaP(j) + 1
Ustalenie wartości przesunięcia wzorca na bazie tablicy przesunięć (w przypadku gdy część
znaków się pokrywa, jest możliwe większe przesuniecie wzorca).
Loop
End Sub
Przedstawiony powyżej algorytm jest znacznie bardziej efektywny w porównaniu z algorytmem
naiwnym, ze względu na możliwość zmiany wartości przesunięcia wzorca.
Algorytm Boyera-Moore’a
Kolejny algorytm wyszukiwania wzorca w tekście ponownie wykorzysta tablice przesunięć.
Jednak sam proces wyszukiwania zacznie się inaczej. Algorytm ten sprawdza, czy ostatni znak wzorca
jest zgodny z badanym znakiem w tekście. W przypadku gdy znak w tekście nie należy do wzorca,
następuje skok o całą długość wzorca.
Pokazuje to następujący przykład:
A B B C D A A D A A D G A F
G A F A
A A S F
A A D A A A D
Ponieważ znak C nie występuje we wzorcu, możemy dokonać przesunięcia
o długość wzorca (4).
A
B B C D A A D A A D G A F
G A F A
A A S F
A A D A A A D
Ponieważ znak D nie występuje we wzorcu, możemy dokonać przesunięcia o długość wzorca
A
B B C D A A D A A D G A F
G A F A
A A S F
A A D A A A D
W kolejnym skoku okazało się, że znak G w tekście występuje we wzorcu. W tym momencie
następuje powolne przesuwanie wzorca i sprawdzanie, jak pokryją się znaki.
A
B B C D A A D A A D G A F
G A F
A A S F
A
A A D A A A D
Powyższy algorytm możemy zapisać następująco:
- jeżeli porównywany znak nie wchodzi w skład wzorca, możemy przesunąć wzorzec
o całą jego długość.
Algorytmika i programowanie
33
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
Jeżeli porównywany znak jest we wzorcu, algorytm przesuwa wzorzec, tak by znaki się pokryły
i porównywanie jest kontynuowane. Tablica przesunięć będzie miała tyle pozycji, ile jest znaków
w alfabecie. Dodatkowo wykorzystana będzie funkcja zwracająca numer znaku w alfabecie
(z rozróżnieniem małych i dużych znaków; spacja będzie zwracała wartość 0).
Funkcja zwracająca numer znaku wygląda następująco:
Function indeks(ByVal znak As Char) As Integer
If znak = " " Then
Return 0
Else
If znak.IsLower(znak) Then
Return Asc(znak) - Asc("a") + 1
Else
Return Asc(znak) - Asc("A") + 27
End If
End If
End Function
Jak widać, funkcja sprawdza, czy znak wzorca to spacja, jeżeli tak, zwraca 0. Następnie sprawdza, czy
znak to mała litera, oblicza jej numer, w przeciwnym przypadku oblicza numer dla dużej litery (dla
uproszczenia polskie znaki są pominięte)
Tablica przesunięć o rozmiarze alfabetu wykorzystuje funkcję indeks. Kod procedury tworzącej tablice
przesunięć wygląda następująco:
Sub przesuniecie(ByVal wzorzec As String)
Dim i As Integer
For i = 0 To 52
tablicaP(i) = wzorzec.Length - 1
Next
Wypełnienie tablicy wartością długości wzorca
For i = 0 To wzorzec.Length - 1
tablicaP(indeks(wzorzec.Chars(i))) = wzorzec.Length - i - 1
Next
Ustalenie wartości przesunięcia dla znaków znajdujących się we wzorcu (jeżeli znak nie
występuje we wzorcu, przesunięcie jest równe długości wzorca)
End Sub
Algorytm wyszukiwania jest realizowany przez następującą procedurę:
Private Sub btnSprawdz_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnSprawdz.Click
Dim i, j, x As Integer
wzorzec = txtWzorzec.Text
i = wzorzec.Length
j = wzorzec.Length
Do While j > 0
j -= 1
i -= 1
Do While tekst.Chars(i) <> wzorzec.Chars(j)
Algorytmika i programowanie
34
Kompendium wiedzy programisty VB.NET – nr 5
autor: Janusz Białowąs
x = tablicaP(indeks(tekst.Chars(i)))
If wzorzec.Length - j > x Then
i = i + wzorzec.Length - j
Else
i = i + x
End If
If i >= tekst.Length Then
MessageBox.Show("Brak wzorca w tekście ", "Wynik",
MessageBoxButtons.OK, MessageBoxIcon.Information)
Exit Sub
End If
j = wzorzec.Length - 1
Loop
Loop
MessageBox.Show("Wzorzec występuje na pozycji " & i, "Wynik",
MessageBoxButtons.OK, MessageBoxIcon.Information)
Jak widać, przedstawiony algorytm jest bardziej efektywny ze względu na to, iż rzadko jest
realizowane przesunięcie o jeden.
Algorytmika i programowanie
35
Download