Visual 5
Aplikacje okienkowe
Interfejs Windows Forms (nazywany także WinForms) znajduje się w przestrzeni
nazw System.Windows.Forms. Zawiera klasy przydatne przy tworzeniu aplikacji
działających w systemie Windows, w pełni wykorzystujących bogate funkcje interfejsu
użytkownika. Interfejs ten powstał na bazie biblioteki Windows Foundation
Classes, przygotowanej początkowo dla języka J++. Wszystkie języki programowania
platformy .NET Framework — niezależnie od tego, z jakiej biblioteki korzystały
dotychczas (MFC lub wywołania Win32API w przypadku C++ albo VB Forms Engine
w przypadku Visual Basic) - wykorzystują ten sam sposób komunikacji z graficznym
interfejsem użytkownika systemu Windows. Programista nie musi już korzystać
bezposrednio z funkcji interfejsu Windows API.
Przestrzeń System.Windows.Forms zawiera klasy definiujące kontrolki, klasy pozwalające tworzyć kontrolki użytkownika, klasy odpowiedzialne za tworzenie okien
aplikacji i okien aplikacji wielodokumentowych (MDI), okna dialogowe i inne. Zapewniona
jest także obsługa standardowych okien dialogowych (otwieranie plików, ustawienia wydruku, podgląd wydruku i inne), a także tworzenie menu i etykiet podpowiedzi (tooltip).
Rys. 1. Tworzenie nowego projektu dla aplikacji okienkowej
Prosty kalkulator
Rys. 2. Widok gotowej aplikacji
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim liczba1 As Integer
Dim liczba2 As Integer
Dim s As String
liczba1 = TextBox1.Text
liczba2 = TextBox2.Text
s = String.Format("{0}", liczba1 + liczba2)
Label1.Text = s
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Dim liczba1 As Integer
Dim liczba2 As Integer
Dim s As String
liczba1 = TextBox1.Text
liczba2 = TextBox2.Text
s = String.Format("{0}", liczba1 - liczba2)
Label1.Text = s
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button3.Click
Dim liczba1 As Integer
Dim liczba2 As Integer
Dim s As String
liczba1 = TextBox1.Text
liczba2 = TextBox2.Text
s = String.Format("{0}", liczba1 * liczba2)
Label1.Text = s
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button4.Click
Dim liczba1 As Integer
Dim liczba2 As Integer
Dim s As String
liczba1 = TextBox1.Text
liczba2 = TextBox2.Text
s = String.Format("{0}", liczba1 / liczba2)
Label1.Text = s
End Sub
End Class
Inna wersja
Private Sub button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click, Button4.Click,
Button3.Click, Button2.Click
Dim liczba1 As Integer
Dim liczba2 As Integer
Dim s As String = ""
Dim b As Button = DirectCast(sender, Button)
liczba1 = TextBox1.Text
liczba2 = TextBox2.Text
If b.Equals(Button1) Then
s = String.Format("{0}", liczba1 + liczba2)
End If
If b.Equals(Button2) Then
s = String.Format("{0}", liczba1 - liczba2)
End If
If b.Equals(Button3) Then
s = String.Format("{0}", liczba1 * liczba2)
End If
If b.Equals(Button4) Then
s = String.Format("{0}", liczba1 / liczba2)
End If
Label1.Text = s
End Sub
Po zmianie kodu metody button1_click musimy w edytorze właściwości przypisać
tę metodę do pozostałych przycisków do obsługi zdarzenia click. Po wybraniu przycisku
w edytorze właściwości klikamy na ikonkę Events (żółta błyskawica), odszukujemy
zdarzenie click i ustawiamy procedurę obsługi wybierając z listy button1_click.
Powyższy kod jest niestety podatny na błędnie wprowadzone dane. Jeżeli pola edycyjne
nie zawierają poprawnej liczby, konwersja napisu na liczbę spowoduje powstanie wyjatku i nasz program zostanie przerwany. Dodajmy więcdo naszego kodu obsługę wyjątku.
Obsługa wyjątku
Obsługa wyjątku polega na wypełnieniu treścią bloków Try...Catch...End Try.
Private Sub button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click, Button2.Click, Button4.Click, Button3.Click
Dim liczba1 As Integer
Dim liczba2 As Integer
Dim s As String = ""
Dim b As Button = DirectCast(sender, Button)
Dim ok As Boolean = True
Try
liczba1 = TextBox1.Text
liczba2 = TextBox2.Text
Catch
ok = False
End Try
If ok Then
If b.Equals(Button1) Then
s = String.Format("{0}", liczba1 + liczba2)
End If
If b.Equals(Button2) Then
s = String.Format("{0}", liczba1 - liczba2)
End If
If b.Equals(Button3) Then
s = String.Format("{0}", liczba1 * liczba2)
End If
If b.Equals(Button4) Then
s = String.Format("{0}", liczba1 / liczba2)
End If
Else
s = "Popraw!"
End If
Label1.Text = s
End Sub
Rys. 3. Wynik wprowadzenia niepoprawnych danych
Rys. 4. Wynik dzielenia przez zero
Zegar elektroniczny
Program będzie wyswietlał bieżącą datę i godzinę lub tylko godzinę. Jako kontrolkę do wyświetlenia godziny użyjemy kontrolki Label, a dodatkowo, jako przełącznik do wyboru trybu pracy zegarka (data i godzina lub godzina), kontrolki CheckBox.
Problemem jest tylko to, gdzie mamy umieścić procedurę wyświetlającą godzinę. Jak
wspomnieliśmy wcześniej, nasze aplikacje są sterowane zdarzeniami, możemy więc skorzystać z kontrolki Timer, która reprezentuje zegar. Możemy ustawić dla niej częstotliwość ”tykania” zegara. W efekcie końcowym nasza aplikacja w określonych przedziałach czasu będzie otrzymywała komunikat o ”tyknięciu” zegara. Umieśćmy na formie kontrolki Label, CheckBox oraz Timer.
Kolejnym krokiem jest ustawienie odpowiednich właściwości kontrolki Timer. Po
pierwsze, musimy włączyć generowanie zdarzeń dla tej kontrolki, ustawiając jej właściwość Enabled na true, oraz ustawić właściwość Interval, określającą jak często ma być generowany komunikat ”tyknięcie zegara” (Tick). Wartość ta podawana jest w milisekundach. Nasz zegar będzie wyswietlał godziny, minuty oraz sekundy. Jeśli ustawimy właściwość Interval na 1000, to komunikat będzie generowany raz na sekundę.
Jeżeli chcemy, aby użytkownik nie mógł zmieniać rozmiaru okna podczas pracy programu, to
możemy zmodyfikować właściwość formy FormBorderStyle przypisująć jej
wartość FixedDialog, oraz zmodyfikować właściwość MaximizeBox przestawiając jej
wartość na False, aby dezaktywoać przycisk służący do maksymalizacji okna. Okno programu będzie można tylko zminimalizować (zwinąć na belkę) oraz przywrócić do pierwotnego rozmiaru.
Rys. 5. Widok poczatkowy formularza aplikacji Zegar elektroniczny
Dopisujemy kod obsługi zdarzenia pochodzącego od kontrolki Timer i CheckBox, klikamy dwukrotnie na kontrolce lub w edytorze właściwości wybieramy zdarzenia (events) i klikamy dwukrotnie przy zdarzeniu Tick.
Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
Dim s As String
Dim d As DateTime = DateTime.Now
If CheckBox1.Checked Then
s = String.Format("{0:dddd}, {1:M} {2:yyyy}", d, d, d)
Label4.Text = s
Else
s = String.Format("{0:T} ", d)
Label1.Text = s
Label4.Text = ""
End If
End Sub
Rys. 6a. Wynik uruchomienia kontrolki Timer bez zaznaczenia pola wyboru
Rys. 6b. Wynik uruchomienia kontrolki Timer po zaznaczeniu pola wyboru
Obsługa menu
Menu jest jednym z podstawowych elementów aplikacji okienkowej, umożliwia użytkownikowi na wybieranie różnych opcji oferowanych przez program w wygodny i
usystematyzowany sposób. Dodanie kontrolki menu do aplikacji pisanych w językach
wchodzących w skład platformy .NET sprowadza się do umieszczenia na formie odpowiedniej kontrolki, dodaniu pozycji do menu oraz podmenu oraz dopisaniu kodu
obsługi zdarzeń związanych z wybraniem przez użytkownika danej pozycji z menu.
Aby dodać menu do formy umieszczamy na niej komponent, w zależności od wersji
środowiska Visual Studio, dla wersji 2005 o nazwie MenuStrip,a dla wersji 2003
MainMenu. Po umieszczeniu kontrolki na formie możemy w miejscu gdzie pojawia się
napis Type Here wpisać odpowiednie nazwy opcji w menu. Jeżeli chcemy rozdzielić
opcje poziomą linią w miejscu gdzie ma pojawić się separator, wpisujemy znak minus.
Dodajmy do programu wyświetlającego zegarek elektroniczny menu i nazwijmy pozycje
tak jak na rysunku 7.
Rys. 7. Widok projektu Menu
Aby dopisać metodę obsługi zdarzenia związanego z wybraniem danej pozycji menu
klikamy na niej dwukrotnie i zostanie wstawiona odpowiednia metoda. Wszystko co
musimy teraz zrobić, to dopisać odpowiedni kod.
Najpierw napiszmy obsługę zdarzenia wyboru z menu pozycji Zakończ, klikamy dwukrotnie na pozycji Zakończ w zależności od posiadanej wersji Vusial Studio do kodu
zostanie dodana metoda menuItem2_Click w przypadku Visual Stidio 2003 lub koniecToolStripMenuItem_Click w przypadku Visual Studio 2005. Żeby
zakończyć pracę naszego programu wystarczy dopisać kod, który zamknie naszą formę, czyli Me.Close().
Private Sub ZakończToolStripMenuItem_Click_1 _
(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles ZakończToolStripMenuItem.Click
Me.Close()
End Sub
Wybranie pozycji Data z menu ma w efekcie dać taki sam wynik jak kliknięcie na kontrolce CheckBox. Napiszemy metodę obsługi zdarzenia wybrania pozycji z menu w taki sposób, że zmieni ona stan kontrolki CheckBox na przeciwny.
Private Sub DataToolStripMenuItem_Click _
(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles DataToolStripMenuItem.Click
CheckBox1.Checked = Not CheckBox1.Checked
End Sub
Dodatkowo, aby wyświetlić w menu przy pozycji Data znaczek oznaczający, że dana opcja jest wybrana lub nie, zmodyfikujemy metodę checkBox1_CheckedChanged.
Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged
DataToolStripMenuItem.Checked = CheckBox1.Checked
End Sub
Kontrolka ProgressBar
Dodajmy do formy kontrolkę ProgressBar, która zasadniczo służy do wyświetlania
post ępu podczas wykonywania długotrwałej operacji, w naszym przypadku kontrolka
bedzie wyświetlała informację, ile jeszcze pozostało do zakończenia bieżącej minuty.
Po umieszczeniu kontrolki ProgressBar na formie ustawiamy jej właściwość Maximum
korzystając z edytora właściwości na wartość 59. Wpisanie tej wartości oznacza, że 59 dla kontrolki stanowi 100%.
Musimy jeszcze zmodyfikować kod metody Tick kontrolki Timer.
Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
Dim s As String
Dim d As DateTime = DateTime.Now
If CheckBox1.Checked Then
s = String.Format("{0:dddd}, {1:M} {2:yyyy}", d, d, d)
Label4.Text = s
Else
s = String.Format("{0:T} ", d)
Label1.Text = s
Label4.Text = ""
End If
ProgressBar1.Value = d.Second
End Sub
Rys. 8. Pasek postępu
Technika przeciągnij i upuść (drag & drop)
Jednym z charakterystycznych mechanizmów dostepnych dla aplikacji w środowisku
MS Windows, jest technika przeciągnij i upuść (drag & drop), umożliwiająca użytkownikowi przeciaganie elementów znajdujących się na formie i upuszczaniu ich na innych kontrolkach. Wzbogacimy nasz zegar o możliwość przeciągnięcia koloru z palety kolorów i upuszczeniu go na etykiecie wyświetlającej zegar, po upuszczeniu zmieni się kolor tła etykiety. Najpierw umieśćmy trzy elementy typu Label na formie, ustawimy w laściwość AutoSize na False, właściwość Cursor na Hand, Size zgodnie z własnym gustem, oraz usuńmy tekst
wyswietlany na etykiecie na pusty łańcuch znaków.
Rys. 9. Etykiety służące do zmiany koloru tła zegara
Ponieważ kontrolką, która będzie reagowała na upuszczanie elementów jest kontrolka
Label1, ustawimy jej właściwość AllowDrop na True.
Proces przeciągania i upuszczania składa się co najmniej z trzech etapów. Najpierw
naciskamy i trzymamy lewy przycisk myszy na elemencie, który będzie przeciągany,
musimy więc w obsłudze zdarzenia naciśnięto guzik myszy MouseDown zainicjować
proces przeciągania. Pierwszy krok będzie polegał na napisaniu metody obsługi zdarzenia MouseDown dla kontrolek Label reprezentujących paletę kolorów. Klikamy na pierwszej z nich, przechodzimy do edytora właściwości, wybieramy zakładkę zdarzenia i odszukujemy
zdarzenie MouseDown. Klikamy dwukrotnie w celu wstawienia metody do kodu i modyfikujemu dopisując wywołanie metody inicjalizującej przeciąganie.
Private Sub Label5_MouseDown(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles Label5.MouseDown, Label6.MouseDown, Label7.MouseDown
DirectCast(sender, Label).DoDragDrop(sender, DragDropEffects.All)
End Sub
Rys. 10. Wynik operacji Drag and Drop
Drugim etapem jest dopisanie kodu informującego użytkownika w trakcie procesu
przeciągania, że kontrolka nad którą się właśnie znajdujemy jest gotowa na przyjęcie
elementu. Dopiszemy metodę obsługi zdarzenia DragOver dla komponentu Label1.
Zdarzenie DragOver jest generowane kiedy nad kontrolką przeciągany jest obiekt.
Uwaga: niezbędne jest ustawienie właściwości AllowDrop wspomnianej wcześniej.
Ponieważ będziemy akceptowali upuszczanie tylko kontrolek typu Label, musimy
sprawdzić jaki jest typ obiektu, który jest przeciagany nad naszą kontrolką. Kiedy
stwierdzimy, że jest to obiekt typu Label, zasygnalizujemy to użytkownikowi tak, aby
wiedział, że możemy upuścić dany obiekt.
Private Sub Label1_DragOver(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Label1.DragOver
If (e.Data.GetDataPresent(GetType(Label))) Then
e.Effect = DragDropEffects.All
Else
e.Effect = DragDropEffects.None
End If
End Sub
Ostatnim etapem jest dopisanie metody odpowiedzialnej za obsłużenie zdarzenia
upuszczono obiekt DragDrop, ponieważ metoda DragOver dokonała sprawdzenia jaki
rodzaj obiektu przeciągamy, wiemy już, że jest to obiekt typu Label i możemy w
momencie kiedy użytkownik zwolni klawisz myszy przyjąć upuszczony obiekt.
Private Sub Label1_DragDrop(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.DragEventArgs) _
Handles Label1.DragDrop
Dim l As Label = DirectCast(e.Data.GetData(GetType(Label)), Label)
Label1.BackColor = l.BackColor
End Sub
Visual 5.doc 6/11