150 likes | 219 Vues
Programozás III. Ismétlés (Grafikai lehetőségek WPF-ben) Visual utódok. Grafikai lehetőségek WPF-ben. Shape-ek ( System.Windows.Shapes.Shape leszármazottak) Egyszerű, előre elkészített grafikai alakzatok Toolboxban is szerepelnek FrameworkElement utódok: input, fókusz, események…
E N D
Programozás III. Ismétlés (Grafikai lehetőségek WPF-ben) Visual utódok
Grafikai lehetőségek WPF-ben • Shape-ek (System.Windows.Shapes.Shape leszármazottak) • Egyszerű, előre elkészített grafikai alakzatok • Toolboxban is szerepelnek • FrameworkElement utódok: input, fókusz, események… • Csak kevés számú (max100) objektum esetén • Drawing objektumok (System.Windows.Media.Drawing leszármazottak) • Nincs belső támogatásuk input eseményekhez • Nem képesek maguktól a megjelenésre, hosztoló objektumban kell őket elhelyezni • Legtöbbször XAML-ból kezeljük • Gyorsabb a Shape-eknél (max néhány 100 objektumig) • Visual objektumok (System.Windows.Media.Visual) • Legbonyolultabb, leggyorsabb (max kb. 10000 objektumig) • XAML lehetőségek korlátozottak, mindig kódból kezeljük
Visual • Ahhoz biztosít szolgáltatásokat, hogy a leszármazott típus renderelhető legyen • Több speciális célú utódosztály: pl. DrawingVisual (2D), Viewport3DVisual (3D) • Az ezzel való rajzolásnak elsősorban kétféle variációja létezik: • Egy adott grafikusfelület-elem „vizuális gyermekei” (kirajzolandó objektumok) közé beteszünk újabb Visual objektumokat • Egyedi leszármazott típust definiálunk valamelyik grafikusfelület-elemből (tipikusan: FrameworkElement), kihasználva, hogy a GUI-elemek maguk is Visual utódok
DrawingVisual • 2D rajzolásra • RenderOpen() függvényét kell hívni, DrawingContext objektumot ad vissza • A DrawingContext segítségével „tölthetjük fel” a Visualt (vagy egy DrawingGroupot) tartalommal • Pl. a következő függvények értelmezettek rajta: • DrawEllipse() • DrawRectangle() • DrawGeometry() • DrawImage() … • A grafikai parancsok igazából nem rajzolnak, hanem csak tárolják/ megadják a kirajzolandó dolgokat (visszatartott módú grafikai rendszer) • A Visualon belül Drawingok formájában vannak tárolva a rajzok (DrawingGroupban). • A rajzolás időpontját a rendszer dönti el
Visual használat – 1. variáció • Minden Visual utódnak (így a grafikusfelület-elemeknek is) vannak „vizuális gyermekei” (kirajzolandók) • Új Visual objektumokat (pl. DrawingVisualokat) kell létrehozni és azokat elhelyezni a „vizuális gyermekek” között • Kötelező felülírni az új Visualok „tulajdonosában” a VisualChildrenCount, GetVisualChild tulajdonságokat • VisualChildrenCount: adjuk vissza, hogy hány „vizuális gyermek” van. • GetVisualChild: adjuk vissza az n. „vizuális gyermeket”. • Lehetséges az új Visual objektumokat az objektumfákban is elhelyezni (AddVisualChild(), AddLogicalChild()) • Események és találattesztelés támogatása miatt
Visual használat 1. variáció példa • publicpartialclassMainWindow : Window • { //sokszor nem a MainWindow-ban • DrawingVisualvisualChild; //csináljuk, hanem egy FrameworkElement • publicMainWindow() //utódot származtatunk és azt rakjuk • { //a MainWindow-ra majd • InitializeComponent(); • visualChild = newDrawingVisual(); • using (DrawingContext context = visualChild.RenderOpen()) • { • context.DrawEllipse(Brushes.Red, null, newPoint(50, 50),10,10); • } • AddVisualChild(visualChild); • AddLogicalChild(visualChild); • } • protectedoverrideint VisualChildrenCount • { • get { returnbase.VisualChildrenCount + 1; } • } • protectedoverrideVisualGetVisualChild(int index) • { • if (index < base.VisualChildrenCount) • returnbase.GetVisualChild(index); • else • return visualChild; • }
Visual használat 2. variáció • Kihasználjuk, hogy az ablak (vagy bármilyen más GUI elem) is Visual • Amikor rajzolódik, az OnRender() metódusa hívódik • Ez felülírható, DrawingContext objektumot kap paraméterül, a DrawingContext-en keresztül tudunk rajzolni a Visualra • Új rajzolás mindig kikényszeríthető az InvalidateVisual() függvénnyel • classMainWindow: Window //tipikusan ezt sem a MainWindow-ban, • { //hanem pl. FrameworkElement utód... • //... //- ablaknál Background=Transparent kell. • protectedoverridevoid OnRender(DrawingContext drawingContext) • { • drawingContext.DrawGeometry(Brushes.Blue, • newPen(Brushes.Red, 2), geometry); • } • }
Asteroids szabályok: • Játékos csak foroghat és lőhet. • Az aszteroida véletlenszerű irányba egyenletesen mozog, ha a képernyő szélére ér, visszatér a másik oldalon • Ha a játékos lövése eltalál egy aszteroidát, az eltűnik. (Nehezebb verzió: két kisebb és gyorsabban mozgó részre válik szét, egy bizonyos mérethatárig.) • Ha a játékos lövése a képernyő szélére ér, visszatér a másik oldalon. Viszont a lövés csak bizonyos ideig „él”, egy idő után eltűnik.
Transzformációk • Transform utódokkal reprezentálódnak (transzformációs mátrix) • Forgatás (RotateTransform) • Skálázás (ScaleTransform) • Nyújtás (SkewTransform) • Mozgatás (MoveTransform) • Általános transzformáció (MatrixTransform) • Több transzformáció egymás után (TransformGroup)
Transzformáció alkalmazásai • GUI-elemeken (FrameworkElement utódok): • LayoutTransform (kihelyezés előtt transzformál) • RenderTransform (kihelyezés után transzformál) • Geometriákon: • Transform • Figyelem: nem módosít koordinátákat! • A Transform-ot levéve (xxx.Transform = Transform.Identity) az eredeti koordinátákon marad az objektum • Metszésnél esetleg gondot okoz
Geometriák metszése (érintésvizsgálat) • Geometriák metsződésének vizsgálatához az elmetszéssel létrejött új geometriát létre kell hozni (Geometry.Combine()), majd a területét vizsgálni (GetArea()) • Figyelem: LineGeometry-nak nincs kiterjedése, így a metszet területe 0 • Megoldása a vonal „kiterjesztésével” • geometry.GetWidenedPathGeometry(newPen(Brushes.Blue, 2)) • Geometryintersection = Geometry.Combine(geometry, • otherGeometry, GeometryCombineMode.Intersect, null); • returnintersection.GetArea() != 0;
Megoldási alternatíva • Minden játékelem Geometry típusú adattagja úgy kerül beállításra, hogy a középpont koordinátája (0;0) legyen • Kirajzolás/ütközésvizsgálat előtt transzformáljuk a megfelelő pozícióba • TransformGrouptg = newTransformGroup(); • tg.Children.Add(newTranslateTransform(cx, cy)); • tg.Children.Add(newRotateTransform(degree, cx, cy)); • Geometrycopy = area.Clone(); • copy.Transform= tg; • returncopy.GetFlattenedPathGeometry();