7
Tags:
.net
Skrevet af
Bruger #3491
@ 06.05.2005
IntroduktionGDI bruges til at tegne med under Microsoft Windows. GDI+ er en forbedret udgave af GDI (Graphical Device Interface) og er en del af .NET’s klasse bibliotek.
GDI+ klasserne kan findes i følgende namespaces:
- System.Drawing
- System.Drawing2D
- System.Text
- System.Printing
- System.Internal
- System.Imaging
- System.Design
I denne artikel vil jeg forklare noget om de klasser som du skal kende for at kunne bruge GDI+ til at tegne med. Du vil derfor senere kunne bruge artiklen som reference hvis du ikke kan huske hvordan du bruger en af klasserne.
Det er primært klasserne som ligger i System.Drawing der er vigtige at kende. Her findes bl.a klasserne:
Image, Brush, Pen, Font og Graphics.
Men først vil jeg fortælle om de vigtigste strukturer som du skal kende.
Strukturer (structs)Der er nogle vigtige strukturer det er vigtigt at kende funktionen af. De fleste af de vigtige findes i System.Drawing og er:
Color, Point, Size og Rectangle.
Color strukturenRepræsentere en RGB farve med en alpha kanal.
Strukturen har en mængde statiske properties der repræsentere hver sin farve.
F.eks. er Color.Green en Color struktur der repræsentere en grøn farve.
Point strukturenAngiver et punkt I et 2 dimenionelt koordinatsystem. X og Y værdierne er her integers, men der findes også en PointF struktur hvor de istedet er angivet med floats.
Size strukturenAngiver en størrelse med en bredde og en højde. Har derfor de to properties Width og Height.
Der findes ligesom med Point strukturen en udgave hvor der benyttes floats. Denne hedder SizeF.
Rectangle strukturenAngiver et rektangel med en position. Man kan nærmest sige at det er sammensmeltning af Size og Point strukturerne. Den har ligeledes en anden udgave hvor der benyttes floats, RectangleF.
KlasserneI det følgende vil jeg forklare om de vigtigste klasser I GDI+.
Graphics klassen
Graphics klassen er vigtig da den repræsentere en GDI+ overflade som vi vha. forskellige metoder kan tegne på. Et Graphics objekt kan f.eks. repræsentere et billede, en control eller en form.
Hvis vil tegne på en f.eks. en form bliver vi nød til at få en reference til formens Graphics objekt. Det kan gøres på forskellige måder. Enten abonnerer vi på formens Paint event.
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
}
Ellers overrider vi formens OnPaint metode:
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
}
I begge tilfælde finder vi Graphics objektet i PaintEventArgs objektet.
Graphics klassen indeholder en masse forskellige metoder til at tegne med, her er nogen af dem jeg bruger oftest med forklaring.
For en fuld liste så kig på Graphics objektet på msdn, hvor du også kan se parametrene til de forskellige metoder.
Som det kan ses af listen skal der bruges forskellige andre objekter for at tegne kunne noget. Det drejer sig om Brush, Pen og Font objekterne.
Der er en ting der gælder alle disse 3 typer objekter og som er vigtigt at have i tankerne når du skriver kode der gør brug af dem. C# har en garbage collector som burde frigøre objekter fra hukommelsen når du er færdig de ikke bruges mere. Men disse objekter kan på en måde bruge ressourcer hurtigere end garbage collectoren kan frigøre dem. Derfor bør du selv frigører ressourcerne ved at bruge objekternes Dispose() metode når du er færdige med dem.
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen rødpen = new Pen(Color.Red); //Vi opretter et Pen objekt
//Vi bruger Pen objektet til at tegne med
rødpen.Dispose(); //vi husker at frigøre de ressourcer Pen objektet optog.
}
Brush klassenBruges til definere hvordan former skal udfyldes med farver eller mønstre.
Du kan ikke lave objekter ud fra selve Brush klassen da det er en abstrakt klasse som andre skal nedarve fra. Der findes forskellige af disse i frameworket
I System.Drawing findes følgende Brush implementeringer:
- SolidBrush, udfylder med en enkelt farve.
- TextureBrush, udfylder med et billede.
I System.Drawing.Drawing2D findes følgende Brush implementeringer:
- HatchBrush, udfylder med en valgt HatchStyle, forgrundsfarve og baggrundsfarve. De forskellige HatchStyle’s der kan vælges i mellem findes i enum’en HatchStyle.
- LinearGradientBrush, udfylder med en farveovergang mellem 2 farver eller flere.
- PathGradientBrush, udfylder en GraphicsPath struktur med en farveovergang mellem 2 farver eller flere.
Pen klassenEt Pen objekt bruges til at tegne linjer med en valgt tykkelse og udfyldningsmetode. Udfyldningsmetoden kan enten være en Brush eller en Color og angives i contructoren.
Der findes således 4 forskellige contructors:
//definerer en Pen med en Brush som udfyldningstype og bredden 1.
public Pen(Brush brush);
//definerer en Pen med en Color som udfyldningstype og bredden 1.
public Pen(Color color);
//definerer en Pen med en Brush som udfyldningstype og en bredde.
public Pen(Brush brush, float width);
//definerer en Pen med en Color som udfyldningstype og en bredde.
public Pen(Color color, float width);
Pen klassen har en DashStyle property som angiver hvilken DashStyle der skal bruges når der tegnes stiplede linjer. De forskellige DashStyle’s findes i enum’en DashStyle:
Som nævnt i ovenstående tabel kan du definere din egen DashStyle i DashPattern propertyen.
Når du sætter DashPattern propertyen bliver DashStyle propertyen automatiskt sat til DashStyle.Custom.
For at definere dit eget DashPattern laver du et array af floats. Hver anden værdi angiver længden af en streg og hver anden angiver længen af et mellemrum.
For at illustrere det har jeg lavet en lille applikation hvor jeg abonnere på en forms Paint event:
private void Form1_Paint(object sender, PaintEventArgs e)
{
//definere start og slut punkterne
Point start = new Point(10, 10);
Point slut = new Point(100, 10);
//henter Graphics objektet
Graphics g = e.Graphics;
//opretter en blå pen med bredden 3
Pen pen = new Pen(Color.Blue, 3.0F);
//tegner en alm streg
g.DrawLine(pen, start, slut);
//flytter punkterne 10 pixels ned
start.Y += 10;
slut.Y += 10;
//skifter DashStyle
pen.DashStyle = DashStyle.DashDot;
//tegner en streg med den nye DashStyle
g.DrawLine(pen, start, slut);
//flytter punkterne 10 pixels ned
start.Y += 10;
slut.Y += 10;
//skifter til en Custom DashStyle
pen.DashStyle = DashStyle.Custom;
pen.DashPattern = new float[] {3,1,3,1,1,1};
//tegner en streg med den nye DashStyle
g.DrawLine(pen, start, slut);
//rydder op
pen.Dispose();
}
Den kommer så til at se således ud:
Font klassenFont klassen definere hvilket format noget tekst skal skrives med. F.eks. skrifttype, størrelse, om teksten skal være normal, fed, kursiv, understreget eller gennemstreget.
Font klassen har over 10 forskellige contructors alt efter hvor meget information du har behov for at give. Når du instantiere et Font objekt finder GDI ud fra parametrene ud af hvilken font du har valgt. Hvis du f.eks. vil have skrifttypen ”Verdana” i størrelse 10, så finder GDI ud af hvilken font der skal bruges. Hvis vi kigger i mappen C:\\Windows\\Fonts kan vi se at der er 4 forskellige ud gaver af Verdana skrifttypen:
verdana.ttf – Normal Verdana
verdanab.ttf – Fed Verdana
verdanai.ttf – Kursiv Verdana
verdanaz.ttf – Fed & Kursiv Verdana
Vores Font objekt peger således på verdana.ttf, hvis vi så vil gøre skrifttypen kursiv kan det ikke gøres ved blot at ændre på Font objektet da det peger på en enkelt fil og ikke gruppen af Verdana filer. Vi bliver i stedet nød til at oprette et nyt Font objekt som så peger på den nye fil.
En af contructorsne tager et Font objekt som parameter og kan ud fra det Font objekt og de resterende parametre finde den ændrede version af skrifttypen.
Her er et eksempel hvor jeg først opretter et Font objekt og derefter modificere det ved at instantiere det igen med en anden constructor.
private void Form1_Paint(object sender, PaintEventArgs e)
{
//vi definerer placeringen, brush og tekst
PointF point = new PointF(10, 10);
string tekst = "Hello World";
SolidBrush brush = new SolidBrush(Color.Black);
//vi laver vores font objekt
Font font = new Font("Verdana", 10.0F);
//sætter fonten kursiv
font = new Font(font, FontStyle.Italic);
//henter Graphics objektet
Graphics g = e.Graphics;
//tegner teksten med den valgte font & brush
e.Graphics.DrawString(tekst, font, brush, point);
//rydder op
brush.Dispose();
font.Dispose();
}
Resultat bliver så følgende:
Se evt. mere om Font klassen på msdn, hvor du også kan læse om alle de forskellige constructors.
AfslutningJeg håber du kunne bruge artiklen til noget og måske har fået lyst til at læse mere om GDI+, for der er meget mere at lære om emnet.
Jeg var lidt i tvivl om hvornår jeg burde bruge det engelsk og hvornår jeg burde bruge det danske ord til f.eks. strukturer/structs og konstruktører/constructors, så jeg vil meget gerne have kritik af mine valg i den sammenhæng
.
Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.
Del også gerne artiklen med dine Facebook venner:
Kommentarer (3)
Dejligt at se en artikel om GDI+. Lige et par ting:
Du skriver at for at få fat i Graphics skal man enten tage fat i det i form_paint eventhandleren eller override OnPaint(). Hvad med at gøre dette: Graphics g = form1.CreateGraphics(); Dette kan gøres alle steder i din kode, så er du fri for at være afhængig af dine events.
I dit eksempel laver du dette trick: Graphics g = e.Graphics; Hvorfor? du har jo allerede e.Graphics, hvorfor lave et nyt objekt nøjagtigt magen til (det er faktisk det samme)? i stedet for bare at bruge e.Graphics.DrawString(.....);
P.S. Garbage Collectoren kører altid med lav priority, det betyder at den ikke vil køre, hvis dit program hele tiden tegner (men hvis du hele tiden laver det trick med at lave et nyt Graphics objekt i din paint metode, så har den på et tidspunkt brugt for meget hukommelse og bliver nødt til at sætte prioriteten op på garbage collectorens tråd) :-)
Sry: du allokerer jo ikke hukommelse når du laver dit "Graphics g" trick, som jeg var så hurtig til at skrive....
Rart med en artikel om 2D!
Du skal være
logget ind for at skrive en kommentar.