Programowanie obiektowe i zdarzeniowe wykład 1 Wprowadzenie do programowania zdarzeniowego 1/34 Wymagania wstępne: Znajomość podstaw programowania. Efekty kształcenia: Umiejętność tworzenia prostych aplikacji okienkowych w środowisku Microsoft Visual Studio, wykorzystujących techniki programowania obiektowego w języku C#. Treści kształcenia: 1. Wprowadzenie do WPF. Tworzenie interfejsu użytkownika. 2. Pojecie klasy i obiektu. Składniki klas pola i metody. Konstruktory. 3. Okna dialogowe i kontrolki zawartości. Wiązanie danych. 4. Kompozycja. Kolekcje. Kontrolki list. 5. Dziedziczenie. 6. Polimorfizm. 7. Wyjątki. Style. 8. Grafika i animacja w WPF. Oprogramowanie: Microsoft Visual Studio 2008 lub nowsze (może być w wersji Express) wraz z dostępnym w nim systemem pomocy (MSDN). Dodatkowa literatura: 1. Adam Boduch, Wstęp do programowania w języku C#, Helion 2. Krzysztof Rychlicki-Kicior, Tworzenie aplikacji graficznych w.net 3.0, Helion 3. Matthew MacDonald, Pro WPF in C# 2008: Windows Presentation Foundation with.net 3.5
2/34 Co to jest programowanie obiektowe? Co to jest programowanie zdarzeniowe? Typowa aplikacja konsolowa (w C): #include "stdio.h" int main() { int a, b, c; printf("podaj pierwszą liczbę: "); scanf("%d", &a); printf("podaj drugą liczbę: "); scanf("%d", &b); c = a + b; printf("suma = %d", c); return 0; }
3/34 Co to jest programowanie obiektowe? Co to jest programowanie zdarzeniowe? Typowa aplikacja konsolowa (w C++): #include "iostream" using namespace std; int main() { int a, b, c; cout << "Podaj pierwszą liczbę: "; cin >> a; cout << "Podaj drugą liczbę: "; cin >> b; c = a + b; cout << "Suma = " << c; return 0; }
4/34 Co to jest programowanie obiektowe? Co to jest programowanie zdarzeniowe? Typowa aplikacja konsolowa (w C#): using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { int a, b, c; Console.Write("Podaj pierwszą liczbę: "); a = int.parse(console.readline()); Console.Write("Podaj drugą liczbę: "); b = int.parse(console.readline()); c = a + b; Console.Write("Suma = {0}", c); Console.ReadKey(); } } }
5/34 Jak powinna wyglądać aplikacja okienkowa? Krok pierwszy tworzenie interfejsu użytkownika (wizualne lub w kodzie).
Jak powinna wyglądać aplikacja okienkowa? Krok drugi obsługa zdarzeń. (chcemy, aby akcja użytkownika spowodowała wykonanie naszego kodu) void Oblicz(...) {......... } 6/34
Jak powinna wyglądać aplikacja okienkowa? Krok trzeci interakcja z kontrolkami. (chcemy odczytać wprowadzone przez użytkownika dane, wykonać obliczenia i wyświetlić wynik) void Oblicz(...) {......... } 7/34
8/34 Dlaczego programowanie obiektowe? Jest bliższe postrzeganiu świata przez człowieka, który najpierw dostrzega pewne rzeczy, pojęcia (obiekty), a nie wykonywane przez nie czynności (funkcje). W programowaniu obiektowym, program to zbiór obiektów posiadających określone cechy (właściwości). Mogą one wchodzić między sobą w interakcje lub łączyć się w bardziej złożone struktury. Obiekt to serwer usług może wykonać pewną operację, jeśli zostanie poproszony. Taka usługa nazywa się metodą obiektu. W aplikacji okienkowej obiektami są np. elementy, z których składamy interfejs użytkownika okno, pola tekstowe, przyciski, etc. Język C# (C Sharp): Prosty, nowoczesny, uniwersalny, język zorientowany obiektowo. Zaprojektowany przez Microsoft, powiązany z platformą.net. Programy w nim napisane wymagają środowiska uruchomieniowego (takiego jak.net lub Mono).
9/34 WPF Windows Presentation Foundation Interfejs programowania aplikacji okienkowych w systemie Windows. Wykorzystuje DirectX do rysowania okien i zawartości. Niezależność od rozdzielczości (oparcie się na jednostkach logicznych =1/96 cala) umożliwia łatwe skalowanie i dopasowanie do rozdzielczości ekranu. Ułożenie kontrolek: dynamiczne, oparte na zawartości (dopasowują się do swojej zawartości oraz dostępnego miejsca). Obiektowy model rysowania oparty na grafice wektorowej. Wsparcie dla mediów i grafiki 3D. Deklaratywne tworzenie animacji. Style i szablony pozwalają dopasowywać formatowanie i sposób renderowania elementów interfejsu. Deklaratywne *) tworzenie interfejsu użytkownika (XAML) pozwala oddzielić wygląd interfejsu od kodu. *) Deklaratywne czyli nie opisujemy kroków prowadzących do rozwiązania (algorytmu), a jedynie samo rozwiązanie. Nie mówmy jak ma być coś zrobione, ale co ma być zrobione.
10/34 XAML Extensible Application Markup Language oparty na XMLu *) (deklaratywny) język do tworzenia interfejsu definiuje ułożenie (oraz inne cechy) kontrolek w oknie pozwala na podział pracy pomiędzy programistów i grafików (twórców interfejsu) XAML nie jest obowiązkowy to samo można zrobić w kodzie, ale wymaga to większego nakładu pracy można korzystać z narzędzi wizualnych do generowania plików XAML (np. Microsoft Expression Blend) warto znać XAMLa aby móc w pełni wykorzystywać możliwości WPFa *) XML uniwersalny język znaczników do strukturalnego reprezentowania danych
11/34
12/34 XML wprowadzenie prawidłowy plik XML <!-- komentarz --> <lista> znacznik otwierający <osoba> Kowalski </osoba> <osoba imię="piotr" nazwisko="nowak"> <telefon numer="0123456789"/> </osoba> </lista> znacznik zamykający atrybuty znacznik pusty
13/34 XML wprowadzenie nieprawidłowy plik XML <lista> <osoba>nowak</osoba> <osoba> <adres> </osoba> </adres> </lista> <osoba> Kowalski </osoba>
14/34 XAML każdy znacznik odpowiada określonemu elementowi interfejsu możliwe jest zagnieżdżanie używane do określenia zawierania np. jednych elementów w innych ustawianie właściwości przez atrybuty <Window... Title="Okienko" Height="200" Width="300" FontSize="14"> <Grid> <Button Margin="30"> Nie dotykać </Button> </Grid>
15/34 Element <Window> okno aplikacji <Window... Title="Okienko" Height="200" Width="300" FontSize="14"> <Grid> <Button Margin="30"> Nie dotykać </Button> </Grid> Przykładowe atrybuty okna: Title tekst na pasku tytułowym Height wysokość Width szerokość FontSize rozmiar czcionki używanej przez wszystkie kontrolki w oknie
16/34 Układy zawartości <Window... Title="Okienko" Height="200" Width="300" FontSize="14"> <Grid> <Button Margin="30"> Nie dotykać </Button> </Grid> Okno może zawierać tylko jeden element. Aby umieścić ich więcej musimy wykorzystać specjalny element, który posłuży za kontener dla innych kontrolek. jest on odpowiedzialny za ułożenie kontrolek w oknie dba o dopasowanie kontrolek do zawartości oraz do dostępnego miejsca elementy nie powinny mieć ustalonego rozmiaru nie powinny mieć ustalonego położenia (współrzędnych) o te aspekty będzie dbał kontener różne rodzaje (typy) kontenerów będą kierować się różną logiką rozmieszczania elementów
17/34 <StackPanel> <Window...> <StackPanel> <Button>jeden</Button> <Button>dwa</Button> <Button>trzy</Button> <Button>cztery</Button> </StackPanel>
18/34 <StackPanel> <Window...> <StackPanel Orientation="Horizontal"> <Button>jeden</Button> <Button>dwa</Button> <Button>trzy</Button> <Button>cztery</Button> </StackPanel>
19/34 Przy pomocy atrybutów możemy sterować ułożeniem kontrolek: <Window...> <StackPanel Orientation="Horizontal"> <Button VerticalAlignment="Top">jeden</Button> <Button VerticalAlignment="Center">dwa</Button> <Button VerticalAlignment="Bottom">trzy</Button> <Button VerticalAlignment="Stretch">cztery</Button> </StackPanel> VerticalAlignment HorizontalAlignment
20/34 Margin dodaje odstęp od krawędzi kontenera i sąsiednich elementów: <Window...> <StackPanel> <Button HorizontalAlignment="Left" Margin="5"> jeden</button> <Button HorizontalAlignment="Right" Margin="5"> dwa</button> <Button Margin="5">trzy</Button> <Button Margin="15, 5">cztery</Button> <Button Margin="30, 5, 15, 0">pięć</Button> </StackPanel> marginesy sąsiadujących kontrolek sumują się!
21/34 Podobnie sterujemy ułożeniem zawartości wewnątrz kontrolki: <Window...> <StackPanel> <Button HorizontalContentAlignment="Left"> jeden</button> <Button HorizontalContentAlignment="Right"> dwa</button> <Button HorizontalContentAlignment="Center"> trzy</button> <Button>cztery</Button> </StackPanel> VerticalContentAlignment HorizontalContentAlignment
22/34 Podobnie sterujemy ułożeniem zawartości wewnątrz kontrolki: <Window...> <StackPanel> <Button HorizontalAlignment="Center"> jeden</button> <Button HorizontalAlignment="Center" Padding="5"> dwa</button> <Button HorizontalAlignment="Center" Padding="15, 5"> trzy</button> <Button HorizontalAlignment="Center" Padding="30, 0, 15, 5">cztery</Button> </StackPanel> Padding steruje odstępem od zawartości kontrolki
23/34 <WrapPanel> <Window...> <WrapPanel> <Button Margin="5">jeden</Button> <Button Margin="5">dwa</Button> <Button Margin="5">trzy</Button> <Button Margin="5">cztery</Button> <Button Margin="5">pięć</Button> <Button Margin="5">sześć</Button> </WrapPanel>
24/34 <DockPanel> dołączone <Window...> właściwości <DockPanel> <Button DockPanel.Dock="Top">jeden</Button> <Button DockPanel.Dock="Left">dwa</Button> <Button DockPanel.Dock="Right">trzy</Button> <Button DockPanel.Dock="Bottom">cztery</Button> <Button DockPanel.Dock="Top">pięć</Button> <Button DockPanel.Dock="Right">sześć</Button> <Button>siedem</Button> </DockPanel> kolejność elementów ma znaczenie!
<Grid> <Window...> <Grid ShowGridLines="True"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions>......... </Grid> elementy umieszczamy w polach siatki krok pierwszy zdefiniowanie siatki tylko do testu 25/34
26/34 <Grid> <Window...> <Grid> <Grid.RowDefinitions>...</Grid.RowDefinitions> <Grid.ColumnDefinitions>...</Grid.ColumnDefinitions> <Button>jeden</Button> <Button Grid.Row="1">dwa</Button> <Button Grid.Column="2">trzy</Button> <Button Grid.Row="1" Grid.Column="1">cztery</Button> </Grid> krok drugi rozmieszczenie elementów
27/34 <Grid> <Window...> <Grid> <Grid.RowDefinitions>...</Grid.RowDefinitions> <Grid.ColumnDefinitions>...</Grid.ColumnDefinitions> <Button Grid.ColumnSpan="2">jeden</Button> <Button Grid.Row="1">dwa</Button> <Button Grid.Column="2" Grid.RowSpan="2">trzy</Button> <Button Grid.Row="1" Grid.Column="1">cztery</Button> </Grid> element może rozciągać się na więcej niż jedno pole siatki
28/34 <Grid> <Window...> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="70"/> </Grid.ColumnDefinitions>...... </Grid> Width dla kolumn Height dla wierszy
29/34 Kontenery można dowolnie zagnieżdżać: <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <StackPanel>... </StackPanel> <StackPanel Grid.Column="1" Orientation="Horizontal">... </StackPanel> <WrapPanel Grid.Column="2">... </WrapPanel> </Grid>
30/34 A jak zaprojektujemy nasze okienko? <Window... Title="Obliczenia" Height="200" Width="300" FontSize="14">...
31/34 <Window...> <Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> </Grid> cztery wiersze, dwie kolumny wysokość wierszy dopasowuje się do zawartości szerokość pierwszej kolumny dopasowuje się do zawartości szerokość kolumny z polem tekstowym rozciągnięta
32/34 <Window...> <Grid> <Grid.RowDefinitions>...</Grid.RowDefinitions> <Grid.ColumnDefinitions>...</Grid.ColumnDefinitions> <Label Margin="5">Pierwsza liczba:</label> <Label Margin="5" Grid.Row="1">Druga liczba:</label> <Label Margin="5" Grid.Row="2">Wynik:</Label> <TextBox Margin="5" Grid.Column="1"/> <TextBox Margin="5" Grid.Row="1" Grid.Column="1"/> <TextBox Margin="5" Grid.Row="2" Grid.Column="1" IsReadOnly="True"/> <Button Grid.Row="3" Grid.ColumnSpan="2" Margin="5" Padding="10,3" HorizontalAlignment="Right"> Oblicz</Button> </Grid> Label etykieta TextBox pole tekstowe IsReadOnly tylko do odczytu przycisk zajmuje cały wiersz
Jak dodać obsługę zdarzeń? również przy pomocy atrybutów: <Button Click="Oblicz"...>Oblicz</Button> // zawartość pliku Window1.xaml.cs: namespace WpfApplication1 { public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void Oblicz(object sender, RoutedEventArgs e) { } } } Ta funkcja zostanie wywołana, gdy użytkownik naciśnie przycisk Oblicz 33/34
34/34 Jak odczytać dane z okna w kodzie programu? najpierw musimy nazwać elementy, do których chcemy mieć dostęp: <TextBox Name="pierwsze".../> <TextBox Name="drugie".../> <TextBox Name="wynik"... IsReadOnly="True"/> następnie w pliku *.cs: private void Oblicz(object sender, RoutedEventArgs e) { int a = int.parse(pierwsze.text); int b = int.parse(drugie.text); int c = a + b; wynik.text = c.tostring(); } pierwsze.text zawartość pola tekstowego int.parse(...) konwersja tekstu na liczbę c.tostring() konwersja zmiennej na tekst