Budowa aplikacji w technologii.net wykład 10 Kształty, pędzle, transformacje, ścieżki

Podobne dokumenty
Programowanie obiektowe i zdarzeniowe wykład 8 grafika i animacja

Jarosław Kuchta Podstawy Programowania Obiektowego. Podstawy grafiki obiektowej

Wizualne systemy programowania. Wykład 11 Grafika. dr Artur Bartoszewski -Wizualne systemy programowania, sem. III- WYKŁAD

narzędzie Linia. 2. W polu koloru kliknij kolor, którego chcesz użyć. 3. Aby coś narysować, przeciągnij wskaźnikiem w obszarze rysowania.

Budowa aplikacji w technologii.net wykład 11 Animacje

Podstawy Processingu. Diana Domańska. Uniwersytet Śląski

4. Rysowanie krzywych

Laboratorium Programowanie urządzeń mobilnych

CorelDRAW. wprowadzenie

Programowanie obiektowe i zdarzeniowe wykład 1 Wprowadzenie do programowania zdarzeniowego

Adobe InDesign lab.1 Jacek Wiślicki, Paweł Kośla. Spis treści: 1 Podstawy pracy z aplikacją Układ strony... 2.

Wprowadzenie do rysowania w 3D. Praca w środowisku 3D

AUTOCAD teoria i zadania z podstaw rysowania Rysowanie linii, prostej, półprostej, punktu, trasy, polilinii. Zadania geodezyjne.

Kurs Adobe Photoshop Elements 11

Windows Presentation Foundation

Grażyna Koba. Grafika komputerowa. materiały dodatkowe do podręcznika. Informatyka dla gimnazjum

Przetwarzanie grafiki rastrowej na wektorową

Ćw. I Projektowanie opakowań transportowych cz. 1 Ćwiczenia z Corel DRAW

Adobe InDesign rysowanie obiektów wektorowych- przygotowanie pracy

KGGiBM GRAFIKA INŻYNIERSKA Rok III, sem. VI, sem IV SN WILiŚ Rok akademicki 2011/2012

WIZUALIZACJA INFORMACJI TEKSTOWEJ WSTĘP DO HTML 5 CANVAS

Multimedia i interfejsy. Ćwiczenie 5 HTML5

Programowanie telefonów z Windows Phone 7, cz. 5

Obsługa programu Paint. mgr Katarzyna Paliwoda

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

Narzędzia programu Paint

Księgarnia PWN: Andrzej Jaskulski - AutoCAD 2010/LT Podstawy projektowania parametrycznego i nieparametrycznego

Projektowanie graficzne. Wykład 2. Open Office Draw

Obsługa programu Paint materiały szkoleniowe

Skalowanie i ustawianie arkuszy/układów wydruku w AutoCAD autor: M. Motylewicz, 2012

Dodatek A. Palety. QuarkXPress 4.1. Projekty praktyczne. Podstawowe palety

RYSUNEK TECHNICZNY I GEOMETRIA WYKREŚLNA INSTRUKCJA DOM Z DRABINĄ I KOMINEM W 2D

Maskowanie i selekcja

4.3 WITRAś. 1. UŜywając polecenia Linia (_Line) narysować odcinek, podając jako punkt początkowy współrzędną 90,-300 i punkt końcowy 90,55.

GIMP Grafika rastrowa (Ćwiczenia cz. 2)

Następnie zdefiniujemy utworzony szkic jako blok, wybieramy zatem jak poniżej

Rysowanie precyzyjne. Polecenie:

1. Wprowadzenie do WPF i XAML. Tworzenie interfejsu użytkownika.

Szybkie tworzenie grafiki w GcIde

Techniki wstawiania tabel

CorelDRAW. 1. Rysunek rastrowy a wektorowy. 2. Opis okna programu

Edytor tekstu OpenOffice Writer Podstawy

Systemy multimedialne 2015

Modele zawartości. WPF wykorzystuje 4 modele zawartości kontrolek: ContentControl pojedyncza zawartość

Wymagania edukacyjne - Informatyka w klasie I

Silverlight. Od podstaw

1. Umieść kursor w miejscu, w którym ma być wprowadzony ozdobny napis. 2. Na karcie Wstawianie w grupie Tekst kliknij przycisk WordArt.

Adobe InDesign lab. 3 Jacek Wiślicki,

Ćwiczenia - CorelDraw

Inżynieria Materiałowa i Konstrukcja Urządzeń - Projekt

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

PyX jest pakietem Pythona do grafiki wektorowej. Pozawala zatem tworzyd pliki EPS oraz PDF.

Paweł Kaźmierczak. styczeń 2009

TWORZENIE OBIEKTÓW GRAFICZNYCH

Baltie 3. Podręcznik do nauki programowania dla klas I III gimnazjum. Tadeusz Sołtys, Bohumír Soukup

Wstawianie nowej strony

Adobe InDesign lab. 3 Jacek Wiślicki, Paweł Kośla

Tematy lekcji zajęć komputerowych klasa 5b grupa 1 i grupa 2

WSTĘP; NARZĘDZIA DO RYSOWANIA

1. OPEN OFFICE RYSUNKI

Wstęp Pierwsze kroki Pierwszy rysunek Podstawowe obiekty Współrzędne punktów Oglądanie rysunku...

Animacje cz. 2. Rysujemy koło zębate

Microsoft Small Basic

Ćwiczenie 2 Warstwy i kształty podstawowe

W tej instrukcji zostanie opisany sposób w jaki tworzy się, edytuje i usuwa obiekty na mapie. Następnie wybierz Rysuj

Krok 2 Następnie kliknij raz na obszar roboczy za pomocą narzędzia Elipsa (L). Ustaw szerokość i wysokość tak, jak szerokość zaokrąglonego prostokąta.

1. Opis okna podstawowego programu TPrezenter.

Inkscape. Narzędzia informatyki

Podstawy Informatyki Wykład V

Spis treści CZĘŚĆ I. NIEPARAMETRYCZNE PROJEKTOWANIE 2D...31

PLAN WYNIKOWY KLASA 1

O czym należy pamiętać?

Jak dodać własny szablon ramki w programie dibudka i dilustro

Dodawanie grafiki i obiektów

WARSTWY cd. Narzędzia służące do transformacji warstw są przedstawione na poniższym rysunku: Służą one odpowiednio do:

Kolory elementów. Kolory elementów

GRAFIKA WEKTOROWA. WYKŁAD 1 Wprowadzenie do grafiki wektorowej. Jacek Wiślicki Katedra Informatyki Stosowanej

Podstawy technologii WWW

Użycie przestrzeni papieru i odnośników - ćwiczenie

Ćwiczenie nr 2 - Rysowanie precyzyjne

Ćwiczenie 14 Dmuchawce

Wymagania edukacyjne na poszczególne stopnie zgodnie z obowiązującą podstawą programową

INFORMATYCZNE SYSTEMY STEROWANIA INSTRUKCJA ĆWICZENIA LABORATORYJNEGO

Przewodnik po obszarze roboczym

Ćwiczenie 1 Automatyczna animacja ruchu

Praca z Inkscape. 1. Klonowanie obiektów.

Zajęcia nr 15 JavaScript wprowadzenie do JavaScript

Ćwiczenie 6 Animacja trójwymiarowa

- biegunowy(kołowy) - kursor wykonuje skok w kierunku tymczasowych linii konstrukcyjnych;

CorelDraw - obiekty tekstowe

Tik Z wiadomości wstępne

CorelDraw - Edytor grafiki wektorowej

b) Dorysuj na warstwie pierwszej (1) ramkę oraz tabelkę (bez wymiarów) na warstwie piątej (5) według podanego poniżej wzoru:

Java: otwórz okienko. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Podstawy pozycjonowania CSS

Jak uzyskać efekt 3D na zdjęciach z wykorzystaniem programu InkScape

Widżety KIWIPortal. tworzenie umieszczanie na stronach internetowych opcje zaawansowane. Autor: Damian Rebuś Data: Wersja: 1.

Informatyka Edytor tekstów Word 2010 dla WINDOWS cz.3

Wymiarowanie i teksty. Polecenie:

Transkrypt:

Budowa aplikacji w technologii.net wykład 10 Kształty, pędzle, transformacje, ścieżki 1/58 Kształty Najprostszy sposób rysowania własnej zawartości w WPF, to wykorzystanie kształtów. Shapes klasy reprezentujące linie, elipsy, prostokąty, wielokąty (prymitywy, kształty podstawowe). Wszystkie one dziedziczą z FrameworkElement, a zatem: Odpowiadają za narysowanie samych siebie (również automatycznie reagują na zmianę właściwości). Są zorganizowane w ten sam sposób co inne elementy (umieszczane w kontenerze układu, przeważnie Canvas). Obsługują te same zdarzenia, co inne elementy (a także wspierają tooltipy, menu kontekstowe, operacje drag-and-drop).

2/58 Klasy kształtów Każdy kształt dziedziczy z abstrakcyjnej klasy System.Windows.Shapes.Shape: Rectangle prostokąt Ellipse elipsa Line odcinek Polyline połączony ciąg odcinków Polygon zamknięty kształt z ciągu połączonych odcinków Path pozwala na łączenie w jednym elemencie wszystkich innych kształtów

3/58 Własności klasy Shape: Fill pędzel do namalowania zawartości (wnętrza) kształtu Stroke pędzel do namalowania krawędzi kształtu StrokeThickness grubość krawędzi. Jest rozdzielana po równo na obie strony. StrokeStartLineCap, StrokeEndLineCap określają kształt końca i początku odcinków StrokeDashArray, StrokeDashOffset, StrokeDashCap pozwalają na zdefiniowanie linii przerywanych. StrokeLineJoin, StrokeMiterLimit określają kształt narożników (wierzchołków) Stretch określa, jak kształt ma dopasować się do dostępnego miejsca (można też używać HorizontalAlignment i VerticalAlignment). DefiningGeometry dostarcza definicję geometrii kształtu (np. współrzędnych punktów). GeometryTransform pozwala zastosować transformację (np. przesunięcie, pochylenie, obrót, skalowanie). RenderedGeometry dostarcza geometrię ostatecznego,renderowanego kształtu.

4/58 Rectangle and Ellipse Wystarczy zdefiniować rozmiar kształtu (a także Fill lub/i Stroke, aby kształt stał się widoczny): <StackPanel> <Ellipse Fill="Yellow" Stroke="Blue" Height="50" Width="100" Margin="5" HorizontalAlignment="Left"/> <Rectangle Fill="Yellow" Stroke="Blue" Height="50" Width="100" Margin="5" HorizontalAlignment="Left"/> </StackPanel>

Rectangle dodaje dwie własności: RadiusX i RadiusY (pozwalają na rysowanie zaokrąglonych narożników). 5/58

6/58 Rozmieszczanie kształtów Przeważnie rozmiar i położenie kształtów określa się ręcznie. Możemy też pozwolić, by kształt dopasował się do dostępnego miejsca: <Grid> <Ellipse Fill="Yellow" Stroke="Blue"></Ellipse> </Grid>

Określając wartość własności Stretch: Fill dopasowanie wysokości i szerokości do dostępnego miejsca. None bez dopasowania. Uniform dopasowanie proporcjonalne (tak, by kształt mieścił się w kontenerze). Jeśli określimy wysokość i szerokość, będą traktowane jako górne ograniczenie. UniformToFill podobnie, ale każdy z wymiarów ma wypełnić dostępną przestrzeń (część kształtu może zostać ucięta). 7/58

8/58 Położenie kształtów jest określane na tych samych zasadach, co innych elementów: rządzi nim kontener. Największą kontrolę nad położeniem daje Canvas: <Canvas> <Ellipse Fill="Yellow" Stroke="Blue" Canvas.Left="100" Canvas.Top="50" Width="100" Height="50"/> <Rectangle Fill="Yellow" Stroke="Blue" Canvas.Left="30" Canvas.Top="40" Width="100" Height="50"/> </Canvas> (uwaga: kolejność definicji ma znaczenie, gdy kształty nakładają się na siebie) (uwaga: Cansa nie musi być elementem najwyższego poziomu możemy umieścić go np. w komórce Grida).

9/58 Viewbox Jest sposobem na połączenie precyzyjnego rozmieszczania kształtów i skalowania do dostępnego rozmiaru. Viewbox to Decorator, przyjmujący pojedyncze dziecko (może nim być kontener z dalszymi elementami), które skaluje, dopasowując do dostępnej przestrzeni. Najbardziej opłacalne w wypadku grupy kształtów: <Grid Margin="5"> <Viewbox Stretch="UniformToFill"> <Canvas Width="50" Height="50"> <Ellipse Fill="Yellow" Stroke="Blue" Canvas.Left="5" Canvas.Top="5" Width="40" Height="40"/> </Canvas> </Viewbox> </Grid>

10/58 (Viebox skaluje całą zawartość: nie tylko rozmiar samego kształtu, ale i np. grubość krawędzi, a także kontrolki, które w nim umieścimy). Własność Viewbox.Stretch domyślnie ustawiona jest na Uniform, ale można też użyć Fill i UniformToFill, aby zmienić sposób skalowania zawartości, a także StretchDirection (poza Both mamy UpOnly, aby tylko powiększać i DownOnly aby tylko zmniejszać). Uwaga: element umieszczony w ViewBoxie musi mieć określony rozmiar, aby Viewbox wiedział jak go przeskalować (tzn. jaki jest jego rozmiar bazowy).

11/58 Line Własności X1, Y1 oraz X2, Y2 określają współrzędne początkowego i końcowego punktu linii. <Grid Margin="5"> <Line Stroke="Blue" X1="0" Y1="0" X2="100" Y2="10"/> </Grid> Dla linii określamy tylko właność Stroke (Fill nie jest brany pod uwagę). Współrzędne są określane w odniesieniu do lewego, górnego narożnika kontenera (plus Margin), w którym umieszczono kształt. W przeciwieństwie do Rectangle i Ellipse, możemy rysować linie poza kontenerem (np. podając ujemne współrzędne). Nie możemy za to ustawić dla nich marginesu i alignmentu. Nadal możemy określić położenie punktu początkowego linii w Canvasie przy pomocy Canvas.Top, Canvas.Left a rozmiar przy pomocy Width i Height.

Polyline Pozwala narysować linię łamaną. Definiujemy ją przy pomocy listy współrzędnych X i Y. Można podać ją jako kolekcję punktów: <Polyline Stroke="MediumBlue" StrokeThickness="5"> <Polyline.Points> <PointCollection> <Point X="10" Y="110"/> <Point X="30" Y="120"/> <Point X="50" Y="100"/> <Point X="70" Y="140"/> <Point X="90" Y="80"/> <Point X="110" Y="170"/> <Point X="130" Y="50"/> <Point X="150" Y="170"/> <Point X="170" Y="80"/> <Point X="190" Y="140"/> </PointCollection> </Polyline.Points> </Polyline> 12/58

Albo w skróconej formie, jako wartości oddzielane spacjami (przecinek między X a Y jest opcjonalny). <Polyline Stroke="MediumBlue" StrokeThickness="5" Points="10,90 30,100 50,80 70,120 90,60 110,150 130,30 150,150 170,60 190,120"/> 13/58

Polygon Działa niemal tak samo jak Polyline. Jedyna różnica: Polygon jest krzywą zamkniętą (sam dodaje ostatni segment, łączący punkt końcowy z początkowym). Może używać pędzla wypełnienia (Fill). <Polygon Stroke="MediumBlue" Fill="LightBlue" StrokeThickness="5" Points="20,85 30,100 50,80 70,120 90,60 110,150 130,30 150,150 170,60 180,130"/> 14/58

Są dwa sposoby wypełniania Polygonu. Domyślny: <Polygon Stroke="MediumBlue" Fill="LightBlue" FillRule="EvenOdd" StrokeThickness="5" Points="95,20 160,150 20,70 180,60 50,160"/> 15/58

<Polygon Stroke="MediumBlue" Fill="LightBlue" FillRule="Nonzero" StrokeThickness="5" Points="95,20 160,150 20,70 180,60 50,160"/> 16/58

17/58 Line Caps, Line Joins W wypadku rysowania linii możemy określić kształt zakończeń StrokeStartLineCap i StrokeEndLineCap: Flat (domyślne), Round, Square i Triangle (wszystkie zwiększają długość linii o ½ szerokości). <Canvas> <Polyline StrokeEndLineCap="Flat" Stroke="MediumBlue" StrokeThickness="20" Points="20,40 40,60 80,20 100,40 200,40"/> <Polyline StrokeEndLineCap="Round".../> <Polyline StrokeEndLineCap="Square".../> <Polyline StrokeEndLineCap="Triangle".../> </Canvas>

18/58 StrokeLineJoin pozwala określić kształt łączeń (wierzchołków łamanej) Miter (domyślny), Bevel (ścięte narożniki), Round (zaokrąglone). Miter pozwala podać StrokeMiterLimit, który ogranicza wydłużanie narożników (wartość 1 to maksymalnie ½ szerokości linii). <Canvas> <Polyline Stroke="MediumBlue" StrokeThickness="20" StrokeLineJoin="Miter" Points="20,20 140,40 40,60 60,80"/> <Polyline StrokeLineJoin="Bevel".../> <Polyline StrokeLineJoin="Round".../> <Polyline StrokeLineJoin="Miter" StrokeMiterLimit="3".../> </Canvas>

19/58 Dashes <Canvas> <Polyline StrokeDashArray="1".../> <Polyline StrokeDashArray="1 2".../> <Polyline StrokeDashArray="2 1".../> <Polyline StrokeDashArray="3 2 1 2".../> <Polyline StrokeDashArray="5 2 1".../> <Polyline StrokeDashArray="2 2" StrokeDashCap="Round".../> </Canvas> StrokeDashArray pozwala zdefiniować dowolny wzór linii przerywanej podajemy wartości, określające długość segmentu i przerwy między segmentami. Liczba tych wartości nie musi być parzysta. StrokeDashCap pozwala określić kształt zakończeń segmentów (uwaga na długość zwiększoną o ½ szerokości). StrokeDashOffset pozwala zacząć przerywaną od wybranej wartości wzorca.

20/58 Pixel Snapping Uwaga: wymiary podajemy zawsze w jednostkach logicznych (1/96 cala). Mogą być to liczby całkowite. W zależności od urządzenia nie muszą się one tłumaczyć na faktyczne położenie pixeli. Domyślnie jest to niwelowane przez antyaliasing. Gdy nie jest to pożądane, można włączyć opcję SnapsToDevicePixels (można to ustawić osobno dla każdego kształtu) powoduje ona zaokrąglenie wartości do faktycznych pikseli urządzenia. Brushes Pędzle używane są zarówno do rysowania tła (background), pierwszego planu (foreground), krawędzi (border) elementów, jak też wypełnienia (fill) oraz obwiedni (stroke) kształtów. Pędzle obsługują powiadamianie o zmianie (gdy zmodyfikujemy pędzel, wszystkie elementy, które go używają, powinny się odrysować). Obsługują półprzeźroczystość (własność Opacity). Klasa SystemBrushes udostępnia pędzle używające kolorów systemowych (zdefiniowanych w ustawieniach użytkownika).

21/58 Dostępne rodzaje pędzli: SolidColorBrush najprostszym rodzaj pędzla: wypełnia zawartość jednolitym kolorem. Jest on stosowany domyślnie, gdy podajemy sam kolor jako wartość własności w XAMLu. LinearGradientBrush, RadialGradientBrush wypełnienie gradientowe. ImageBrush wypełnienie przy pomocy obrazka. DrawingBrush wypełnienie przy użyciu własnej grafiki (np. kształtów). VisualBrush wypełnianie przy użyciu dowolnego obiektu typu Visual (a więc np. również elementów interfejsu przydatne do różnych efektów specjalnych). LinearGradientBrush Wymaga podania listy elementów GradientStop (każdy element to kolejny kolor). <Rectangle> <Rectangle.Fill> <LinearGradientBrush> <GradientStop Color="LightBlue" Offset="0" /> <GradientStop Color="MediumBlue" Offset="1" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle>

22/58 Offset określa położenie każdego koloru, można w ten sposób sterować szerokością przejścia: <Rectangle Margin="3"> <Rectangle.Fill> <LinearGradientBrush> <GradientStop Color="LightBlue" Offset="0.3" /> <GradientStop Color="MediumBlue" Offset="0.7" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> StartPoint i EndPoint pozwalają sterować kierunkiem gradientu. <Rectangle Margin="3"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> <GradientStop Color="LightBlue" Offset="0" /> <GradientStop Color="MediumBlue" Offset="1" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle>

23/58 <Rectangle Margin="3"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="LightBlue" Offset="0" /> <GradientStop Color="MediumBlue" Offset="1" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle Margin="3"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="0,0.2" SpreadMethod="Reflect"> <GradientStop Color="LightBlue" Offset="0" /> <GradientStop Color="MediumBlue" Offset="1" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle>

<Rectangle Margin="3"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="0,0.2" SpreadMethod="Repeat"> <GradientStop Color="LightBlue" Offset="0" /> <GradientStop Color="MediumBlue" Offset="1" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> Można określić więcej kolorów składowych: <Rectangle Margin="3"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> <GradientStop Color="Red" Offset="0" /> <GradientStop Color="White" Offset="0.5" /> <GradientStop Color="Black" Offset="1" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> (Uwaga: oczywiście, takiego pędzla możemy używać nie tylko do rysowania kształtów, ale i np. tekstu, krawędzi, etc.) 24/58

25/58 RadialGradientBrush Kolory definiuje się, jak w LinearGradientBrush. Różnica polega na określeniu pozycji. <Ellipse Margin="3"> <Ellipse.Fill> <RadialGradientBrush> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="1" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse> <Ellipse Margin="3"> <Ellipse.Fill> <RadialGradientBrush Center="0.2,0.8"> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="1" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse>

26/58 <Ellipse Margin="3"> <Ellipse.Fill> <RadialGradientBrush GradientOrigin="0.2,0.8"> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="1" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse> <Ellipse Margin="3"> <Ellipse.Fill> <RadialGradientBrush RadiusX="0.25" RadiusY="1"> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="1" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse>

27/58 ImageBrush <Rectangle Margin="3"> <Rectangle.Fill> <ImageBrush ImageSource="happy_face.png"> </ImageBrush> </Rectangle.Fill> </Rectangle> Viewbox pozwala wskazać fragment obrazka do użycia w roli pędzla (koordynaty względne). <Rectangle Margin="3"> <Rectangle.Fill> <ImageBrush ImageSource="happy_face.png" Viewbox="0.5 0.1 0.4 0.4"> </ImageBrush> </Rectangle.Fill> </Rectangle>

28/58 Tiled ImageBrush Viewport określa względny rozmiar pojedynczego obrazka (a tym samym ile powtórzeń znajdzie się w wypełnianym obszarze niezależnie od jego rozmiaru). <Ellipse Margin="3" Stroke="Black"> <Ellipse.Fill> <ImageBrush ImageSource="happy_face.png" TileMode="Tile" Viewport="0,0 0.4,0.5"> </ImageBrush> </Ellipse.Fill> </Ellipse> <Ellipse Margin="3" Stroke="Black"> <Ellipse.Fill> <ImageBrush ImageSource="happy_face.png" TileMode="FlipXY" Viewport="0,0 0.4,0.5"> </ImageBrush> </Ellipse.Fill> </Ellipse>

29/58 Ustawienie ViewportUnits jako Absolute spowoduje, że obrazek nie będzie skalowany, a powtarzany ilość razy zależną od rozmiaru figury. <Ellipse Margin="3" Stroke="Black"> <Ellipse.Fill> <ImageBrush ImageSource="happy_face.png" ViewportUnits="Absolute" TileMode="Tile" Viewport="0,0 48,48"> </ImageBrush> </Ellipse.Fill> </Ellipse>

VisualBrush Pozwala pobrać obraz dowolnego elementu i używać go jako pędzla. Uwaga: kopiuje to tylko wygląd elementu, skopiowane kontrolki nie dadzą się używać. Pędzel reaguje na zmianę wyglądu kontrolki (np. naciśnięcie przycisku, wpisanie wartości do pola tekstowego). <StackPanel> <Button Margin="3" Name="ok">OK</Button> <Rectangle Margin="3" Height="{Binding ElementName=ok, Path=ActualHeight}"> <Rectangle.Fill> <VisualBrush Visual="{Binding ElementName=ok}"/> </Rectangle.Fill> </Rectangle> <Rectangle Margin="3" Height="50"> <Rectangle.Fill> <VisualBrush Visual="{Binding ElementName=ok}"/> </Rectangle.Fill> </Rectangle> </StackPanel> Jest to używane np. aby pokazać podgląd zawartości okna, wygenerować miniaturę, albo do efektów specjalnych (odbicia, cienie, animacje). 30/58

31/58 Transforms Transformacje afiniczne. Wszystkie klasy dziedziczą z System.Windows.Media.Transform. TranslateTransform translacja (własności X i Y) RotateTransform obrót (Angle, CenterX, CenterY) ScaleTransform skalowanie (ScaleX, ScaleY, CenterX, CenterY) SkewTransform pochylenie (AngleX, AngleY, CenterX, CenterX) MatrixTransform dowolne przekształcenie z wykorzystaniem własnej macierzy przekształcenia (Matrix) TransformGroup łączy kilka transformacji (ich kolejność jest ważna) Aby transformować kształt należy ustawić własność RenderTransform. W obrocie określamy kąt: <Canvas Margin="3"> <Rectangle Stroke="DarkBlue" Width="150" Height="20"> <Rectangle.RenderTransform> <RotateTransform Angle="10"/> </Rectangle.RenderTransform> </Rectangle>... </Canvas>

32/58 Można też wybrać środek obrotu: <Canvas Margin="3"> <Rectangle Stroke="DarkBlue" Width="150" Height="20"> <Rectangle.RenderTransform> <RotateTransform Angle="10" CenterX="75" CenterY="10"/> </Rectangle.RenderTransform> </Rectangle>... </Canvas> Środek można też wskazać jako wartość względną: <Canvas Margin="3"> <Rectangle Stroke="DarkBlue" Width="150" Height="20" RenderTransformOrigin="0.2,0.5"> <Rectangle.RenderTransform> <RotateTransform Angle="10" /> </Rectangle.RenderTransform> </Rectangle>... </Canvas>

33/58 Transforming Elements Te same transformacje mogą być stosowane również w stosunku do elementów: <Button Margin="3" Name="ok" RenderTransformOrigin="0.5,0.5"> <Button.RenderTransform> <TransformGroup> <SkewTransform AngleX="-45" /> <RotateTransform Angle="30"/> <TranslateTransform Y="50"/> </TransformGroup> </Button.RenderTransform> OK</Button> Dostępne jest jeszcze LayoutTransform, które jest aplikowane przed ułożeniem zawartości. <StackPanel> <Button Margin="3" Name="ok" RenderTransformOrigin="0.5,0.5"> <Button.LayoutTransform> <TransformGroup> <RotateTransform Angle="45"/> </TransformGroup> </Button.LayoutTransform> OK</Button> </StackPanel>

Transparency Sposoby na efekt przeźroczystości: Własność Opacity elementu (od 1 nieprzejrzysty do 0 całkowicie przeźroczysty). Opacity pędzla wówczas dotyczy tylko tego, co jest rysowane tym pędzlem. Użycie koloru o wartości alfa mniejszej niż 255 (często daje lepsze efekty niż ustawienie Opacity). <StackPanel Background="LawnGreen"> <Button Margin="3"> Nieprzejrzysty </Button> <Button Margin="3" Opacity="0.5" Background="Yellow"> Półprzeźroczysty </Button> <Button Margin="3" Background="#80FFFF00"> Półprzeźroczysty kolor </Button> </StackPanel> 34/58

35/58 Opacity Masks W odróżnieniu od Opacity, która ustawia jeden poziom przeźroczystości dla całego elementu, Opacity Mask pozwala na bardziej urozmaicone efekty. Akceptuje dowolny pędzel i używa jego kanału alfa (kolor nie jest ważny) by określić przezroczystość. <StackPanel Background="LawnGreen"> <Button Margin="3" Padding="3"> <Button.OpacityMask> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="#00000000" Offset="0"/> <GradientStop Color="#ff000000" Offset="1"/> </LinearGradientBrush> </Button.OpacityMask> Opacity Mask </Button> </StackPanel>

36/58 Wykorzystanie do efektu lustra: <StackPanel> <Button Margin="3" Name="ok">Naciśnij mnie</button> <Rectangle Margin="3" Height="{Binding ElementName=ok, Path=ActualHeight}" RenderTransformOrigin="0,0.5"> <Rectangle.Fill> <VisualBrush Visual="{Binding ElementName=ok}"/> </Rectangle.Fill> <Rectangle.RenderTransform> <ScaleTransform ScaleY="-1"/> </Rectangle.RenderTransform> <Rectangle.OpacityMask> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="Transparent" Offset="0.3"/> <GradientStop Color="#80000000" Offset="1"/> </LinearGradientBrush> </Rectangle.OpacityMask> </Rectangle> </StackPanel>

37/58 Ścieżki i geometrie Path to najbardziej złożony z dostępnych kształtów (shapes). Może zastąpić dowolne z innych kształtów, a także umożliwia posługiwanie się krzywymi. Klasa Path ma własność Data, pobierającą obiekt Geometry (klasa abstrakcyjna). Definiuje on kształt lub kształty wchodzące w skład ścieżki. Używamy następujących klas dziedziczących z Geometry: LineGeometry linia prosta. RectangleGeometry odpowiednik kształtu Rectangle. EllipseGeometry elipsa. GeometryGroup dodaje dowolną liczbę geometrii do jednej ścieżki. CombinedGeometry łączy dwie geometrie w jedne kształt. Pozwala wybrać sposób połączenia. PathGeometry reprezentuje złożoną figurę (otwartą lub zamkniętą), składającą się z sekwencji łuków, odcinków i krzywych. StreamGeometry oszczędza pamięć nie przechowując całej geometrii, ale po stworzeniu jest tylko do odczytu. Geometry pozwala na opisanie geometrii dwuwymiarowych obiektów. Jest bardziej uniwersalna od Shape, ale nie jest elementem okna (a zatem musi się znaleźć np. w Path).

38/58 Kształty można zapisać również za pomocą ścieżek: <Rectangle Fill="Yellow" <Path Fill="Yellow" Stroke="Blue"> Stroke="Blue" Width="100" <Path.Data> Height="50" /> <RectangleGeometry Rect="0,0 100,50"/> </Path.Data> </Path> <Line Stroke="Blue" X1="0" Y1="0" X2="10" Y2="100"/> <Ellipse Fill="Yellow" Stroke="Blue" Width="100" Height="50" HorizontalAlignment="Left"/> <Path Fill="Yellow" Stroke="Blue"> <Path.Data> <LineGeometry StartPoint="0,0" EndPoint="10,100"/> </Path.Data> </Path> <Path Fill="Yellow" Stroke="Blue"> <Path.Data> <EllipseGeometry RadiusX="50" RadiusY="25" Center="50,25"/> </Path.Data> </Path> W tej chwili jedyna widoczna korzyść to to, że nie musimy umieszczać ich w Canvas. Prawdziwe możliwości pojawiają się gdy zechcemy połączyć kilka geometrii.

39/58 Łączenie kształtów przy pomocy GeometryGroup To najprostszy sposób połączenie geometrii: <Path Fill="Yellow" Stroke="Blue" Margin="5" Canvas.Top="10" Canvas.Left="10" > <Path.Data> <GeometryGroup> <RectangleGeometry Rect="0,0 100,100"/> <EllipseGeometry Center="150,50" RadiusX="35" RadiusY="25"/> </GeometryGroup> </Path.Data> </Path> Plusy: jeden obiekt zamiast dwóch większa wydajność (jeden element złożony działa szybciej niż wiele elementów prostych) grupy kształtów można definiować w zasobach i wykorzystywać w innych elementach ścieżkach

40/58 W zasobach: <Window.Resources> <GeometryGroup x:key="geometria"> <RectangleGeometry Rect="0,0 100,100"/> <EllipseGeometry Center="150, 50" RadiusX="35" RadiusY="25"/> </GeometryGroup> </Window.Resources> <Canvas> <Path Fill="Yellow" Stroke="Blue" Margin="5" Canvas.Top="10" Canvas.Left="10" Data="{StaticResource geometria}"> </Path> <Path Fill="Green" Stroke="Blue" Margin="5" Canvas.Top="50" Canvas.Left="50" Data="{StaticResource geometria}"> </Path> </Canvas>

41/58 Minusy geometrii: obsługa zdarzeń (np. myszy) możliwa tylko dla grupy elementów (dla Path) a nie dla każdego z nich. Istnieje jednak możliwość manipulacji pojedynczymi obiektami np. transformacja, pochylanie czy obrót Ciekawsze rzeczy dzieją się, jeśli kształty się przecinają: <GeometryGroup x:key="geometria"> <RectangleGeometry Rect="0,0 100,100"/> <EllipseGeometry Center="80, 10" RadiusX="35" RadiusY="25"/> </GeometryGroup>

42/58 Bardziej urozmaicone sposoby łączenia kształtów oferuje CombinedGeometry Może ona łączyć tylko dwie geometrie (własności Geometry1 i Geometry2). GeometryCombineMode określa wykonywaną na nich operację: Union suma Intersect część wspólna Xor alternatywa wykluczająca Exclude różnica <Window.Resources> <RectangleGeometry x:key="kwadrat" Rect="0,0 100,100"/> <EllipseGeometry x:key="koło" Center="80, 10" RadiusX="35" RadiusY="35"/> <CombinedGeometry x:key="geometria" Geometry1="{StaticResource kwadrat}" Geometry2="{StaticResource koło}" GeometryCombineMode="Union" /> </Window.Resources>

43/58 <CombinedGeometry x:key="geometria" Geometry1="{StaticResource kwadrat}" Geometry2="{StaticResource koło}" GeometryCombineMode="Intersect" /> <CombinedGeometry x:key="geometria" Geometry1="{StaticResource kwadrat}" Geometry2="{StaticResource koło}" GeometryCombineMode="Xor" /> <CombinedGeometry x:key="geometria" Geometry1="{StaticResource kwadrat}" Geometry2="{StaticResource koło}" GeometryCombineMode="Exclude" />

Bardziej złożone kształty należy składać z kilku CombinedGeometry. <CombinedGeometry x:key="geometria" GeometryCombineMode="Union"> <CombinedGeometry.Geometry1> <CombinedGeometry GeometryCombineMode="Exclude"> <CombinedGeometry.Geometry1> <EllipseGeometry Center="50,50" RadiusX="50" RadiusY="50"/> </CombinedGeometry.Geometry1> <CombinedGeometry.Geometry2> <EllipseGeometry Center="50,50" RadiusX="40" RadiusY="40"/> </CombinedGeometry.Geometry2> </CombinedGeometry> </CombinedGeometry.Geometry1> <CombinedGeometry.Geometry2> <RectangleGeometry Rect="0,45,100,10"> <RectangleGeometry.Transform> <RotateTransform Angle="-45" CenterX="50" CenterY="50"/> </RectangleGeometry.Transform> </RectangleGeometry> </CombinedGeometry.Geometry2> </CombinedGeometry> 44/58

Efekt: 45/58

46/58 Krzywe i linie przy użyciu PathGeometry PathGeometry to najbardziej zaawansowana z geometrii, może narysować wszystko to, co poprzednie (i wiele więcej). Minusem jest trochę dłuższa i czasami bardziej skomplikowana składnia. Każdy obiekt PathGeometry zbudowany jest z jednego lub wielu obiektów PathFigure (przechowywanych w kolekcji PathGeometry.Figures). Każdy PathFigure jest zbiorem połączonych linii i krzywych mogących tworzyć zamknięte lub otwarte obszary. Własności PathFigure: StartPoint punkt początkowy figury Segments kolekcja obiektów PathSegment IsClosed jeśli true, WPF dodaje linię łączącą punkt początkowy i końcowy )o ile nie są takie same) IsFilled jeśli true, wnętrze jest wypełniane przy użyciu pędzla Path.Fill PathFigure to kształt który narysowany jest linią składającą się z wielu segmentów (PathSegment). Kolejny segment zaczyna się w punkcie, w którym skończył się poprzedni. (Uwaga: jedna PathGeometry może zawierać wiele osobnych PathFigure, czyli może składać się z wielu osobnych figur.)

47/58 Istnieje kilka typów segmentów, dzięki czemu możemy narysować najróżniejsze kształty: LineSegment linia prosta łącząca dwa punkty ArcSegment łuk BezierSegment krzywa Beziera QuadraticBezierSegment prostsza forma krzywej Beziera, z jednym punktem kontrolnym (szybsza) PolyLineSegment ciąg odcinków PolyBezierSegment, PolyQuadraticBezierSegment ciąg krzywych Beziera LineSegment <Path Stroke="Blue" StrokeThickness="5"> <Path.Data> <PathGeometry> <PathFigure IsClosed="True" StartPoint="20,20"> <LineSegment Point="90,50" /> <LineSegment Point="50,90"/> </PathFigure> </PathGeometry> </Path.Data> </Path>

ArcSegment Łuk to część elipsy o rozmiarze Size. Dodatkowo możemy wybrać dłuższą lub krótszą część łuku, a także położenie krzywej. <Path Stroke="Blue" StrokeThickness="3"> <Path.Data><PathGeometry> <PathFigure IsClosed="False" StartPoint="20,20" > <ArcSegment Point="150,150" Size="100,100" IsLargeArc="False" SweepDirection="Clockwise" /> </PathFigure> </PathGeometry></Path.Data> </Path> <Path Stroke="Green" StrokeThickness="3">...<ArcSegment Point="150,150" Size="190,110" IsLargeArc="False" SweepDirection="Clockwise" />... </Path> <Path Stroke="Red" StrokeThickness="3">...<ArcSegment Point="150,150" Size="200,200" IsLargeArc="False" SweepDirection="Counterclockwise" />... </Path> 48/58

49/58 Krzywe Beziera <Path Stroke="Blue" StrokeThickness="5"> <Path.Data><PathGeometry> <PathFigure StartPoint="10,10"> <BezierSegment Point1="130,30" Point2="40,140" Point3="150,150" /> </PathFigure> </PathGeometry></Path.Data> </Path> Pierwsze dwa punkty, to punkty kontrolne, trzeci koniec segmentu. (punkty kontrolne i linie przerywane zostały dodane w celu poglądowym i oczywiście nie pojawiają się samoistnie na obrazie)

50/58 Geometry Mini-Language Pozwala zdefiniować geometrię w skróconej formie: napisu zawierającego ciąg poleceń. Każde polecenie to litera i wartości liczbowe oddzielane spacjami. Np. zamiast takiej definicji: <Path Stroke="Blue" StrokeThickness="5"> <Path.Data> <PathGeometry> <PathFigure IsClosed="True" StartPoint="20,20"> <LineSegment Point="90,50" /> <LineSegment Point="50,90"/> </PathFigure> </PathGeometry> </Path.Data> </Path> Mamy to: <Path Stroke="Blue" StrokeThickness="5" Data="M 20,20 L 90,50 L 50,90 Z"/> Przecinki są opcjonalne, ale poprawiają czytelność. Tworzony jest (niemodyfikowalny) obiekt StreamGeometry, a nie PathGeometry.

51/58 Dostępne polecenia: F value ustawia własność Geometry.FillRule (0 oznacza EvenOdd, 1 Nonzero). Może pojawić się tylko na początku stringu. M x,y tworzy nową ścieżkę i ustawia punkt startowy. Musi pojawić się przed jakąkolwiek inną (poza F), ale może pojawić się też później, by przemieścić punkt startowy (M znaczy Move). L x,y 0 tworzy LineSegment H x tworzy poziomy LineSegment V y tworzy pionowy LineSegment A radiusx, radiusy degrees islargearc, isclockwise x,y tworzy ArcSegment do wskazanego punktu C x1,y1 x2,y2 x,y tworzy krzywą Beziera z punktami kontrolnymi x1,y1 i x2,y2 Q x1, y1 x,y QuadraticBezierSegment z jednym punktem kontrolnym S x2,y2 x,y tworzy kolejny segment Beziera, wykorzystując ostatni punkt kontrolny z poprzedniej krzywej (smooth BezierSegment) Z kończy PathFigure i ustawia IsClosed na true (nieobowiązkowe) Polecenie zapisane małymi znakami oznacza, że parametry są podane względem poprzedniego punktu (a nie wartości absolutne).

52/58 Geometrie są używane nie tylko do definiowania ścieżek. Można ich użyć np. jako własności Clip (określa obszar obcinania). Przeważnie stosuje się to do obcinania obrazów i grafiki, ale może być też użyte do elementów: <StackPanel Margin="5"> <StackPanel.Clip> <EllipseGeometry Center="100,100" RadiusX="80" RadiusY="120" /> </StackPanel.Clip> <Button>Jeden</Button> <Button>Dwa</Button> <Button>Trzy</Button> <Button>Cztery</Button> </StackPanel> Minus - clipping nie bierze pod uwagę rozmiaru elementu więc przy zmianie wielkości okna element się nie zmieni.

53/58 Drawings Uzupełnieniem Geometry jest klasa Drawing. Dodaje do geometrii informacje o tym, jak ją wyświetlić (np. kolor pędzla, grubość linii). Drawing, podobnie jak geometria, nie jest elementem nie można umieścić jej w oknie. GeometryDrawing uzupełnia geometrię (Geometry) o dane pędzla wypełnienia (Brush) i pióra (Pen określa ono wszystko, co dotyczy krawędzi: jej pędzel, grubość, a także kształty końców, narożników, etc.) DrawingGroup kolekcja obiektów Drawing, pozwala stosować efekty na całej grupie obiektów ImageDrawing obraz (ImageSource) wraz z prostokątem określającym rozmiar (Rect) VideoDrawing własności Player i Rect GlyphRunDrawing elementy tekstowe niskiego poziomu wraz z pędzlem Wyświetlanie obiektów Drawing muszą być umieszczone w jednym z dostępnych elementów: DrawingImage pozwala umieścić Drawing wewnątrz elementu Image DrawingBrush pozwala wykorzystać Drawing jako Brush DrawingVisual pozwala umieścić Drawing w niskopoziomowym obiekcie Visual (więcej na przyszłych wykładach)

54/58 Tak może wyglądać proste rozwiązanie umieszczające grafikę na przycisku: <Button... > <Canvas... > <Polyline... > <Polyline... > <Rectangle... > <Ellipse... > <Polygon... >... </Canvas> </Button> Można też zrobić to przy pomocy ścieżek (każda z własną geometrią) bardziej wydajne: <Button... > <Canvas... > <Path... > <Path... >... </Canvas> </Button>

55/58 Wykorzystując Drawing geometria umieszczona jest w GeometryDrawing: <GeometryDrawing Brush="..."> <GeometryDrawing.Geometry> <EllipseGeometry.../> <PathGeometry.../> <RectangleGeometry.../> </GeometryDrawing.Geometry> </GeometryDrawing> Drawing można umieścić w DrawingImage, który może służyć jako źródło obrazka Image: <Image...> <Image.Source> <DrawingImage> <DrawingImage.Drawing> <GeometryDrawing...>... </GeometryDrawing> </DrawingImage.Drawing> </DrawingImage> </Image.Source> </Image>

56/58 Taki obrazek można umieścić w przycisku. Wiele GeometryDrawing można łączyć przy pomocy DrawingGroup. <Button... > <Image... > <Image.Source> <DrawingImage> <DrawingImage.Drawing> <DrawingGroup> <GeometryDrawing... > <GeometryDrawing... > <GeometryDrawing... >... </DrawingGroup> </DrawingImage.Drawing> </DrawingImage> <Image.Source> </Image> </Button> Jeśli zamiast DrawingImage użyjemy DrawingBrush, możemy użyć go jako pędzla.

DrawingVisual najlżejszy sposób rysowania, bez zdarzeń i układów, pozwala renderować własny tekst i rysunki; nadaje się do wymagających zastosowań (np. aplikacje graficzne) hit test dostępny jako statyczna metoda HitTest() z klasy VisualTreeHelper public partial class MainWindow : Window { // lista na DrawingVisual private List<Visual> visuals = new List<Visual>(); public MainWindow() { InitializeComponent(); // tworzymy obiekt DrawingVisual dv = new DrawingVisual(); // rozpoczynamy rysowanie using (DrawingContext dc = dv.renderopen()) { // i rysujemy dc.drawrectangle(brushes.red, new Pen(Brushes.Green, 2.0), new Rect(100, 100, 200, 100)); //... 57/58

58/58 } //... dc.drawellipse(brushes.green, new Pen(Brushes.Yellow, 2.0), new Point(200,100), 50, 100); } // dodajemy obiekt do drzewa logicznego i wizualnego visuals.add(dv); AddVisualChild(dv); AddLogicalChild(dv); } // wymagane nadpisanie kontener udostępnia swoje dzieci protected override int VisualChildrenCount { get { return visuals.count; } } protected override Visual GetVisualChild(int index) { return visuals[index]; }