Es gibt hier einfach zu viele Threads zu diesem Thema. Aber nirgendwo gebündelt, wie man etwas optimiert. Oder ich hab einfach die falschen Stichworte benutzt. Man möge es mir hiermit nachsehen.
Da ich auch gerade dieses Problem habe, kam ich auf die Idee, erst mal alle Methoden von
Graphics
und
Control
durchzusuchen.
Wenn man die APIs hinzunimmt sind natürlich auch BitBlt und Co mit von der Partie.
Natürlich sind auch die Implementierungen der Algorithmen nicht zu verachten.
Bei z.B. 1000 Shapes kann es sinnvoll (ist es sicher auch) sein, zu überprüfen, was und ob überhaupt neu gezeichnet werden muss.
Auf die Algorithmen möchte ich später eingehen.
Was ich jetzt möchte ist hier diskutieren, wie man Zeichenvorgänge optimieren kann.
Dabei gilt folgende Bedingung:
Es wird nicht mit OpenGL oder DirectX gezeichnet, sondern nur mit GDI.
Folgende Möglichkeiten habe ich bisher gefunden:
Methoden von Graphics:
IsVisible: hiermit kann geprüft werden, ob der Punkt/Rechteck usw. des Objekts überhaupt sichtbar ist.
IsVisibleClipEmpty: Überprüfen, ob im sichtbaren Clipbereich überhaupt was zu sehen ist
IsClipEmpty: Wie Clip-Empty auch für unsichtbaren Bereich
Clip: Region in der überhaupt gezeichnet wird
ClipBounds: Region umschliessendes Rechteck (Begrenzungen)
CompositingMode: enum SourceCopy/SourceOver
CompositingQuality: Qualitätsniveau während des Zusammensetzens
BeginContainer: Speichert GrafikContainer mit aktuellem Zustand
EndContainer: GrafikContainer der wieder hergestellt werden soll
Flush: Erzwingt zeichnen aller anstehenden Grafikoperationen, es wird nicht gewartet bis alles gezeichnet wurde.
InterpolationMode: Gibt an, wie z.B. Grafik beim verkleinern neu berechnet wird.
PageScale: Skalierung zwischen globalen Einheiten und Seiteneinheiten
PageUnit: Maßeinheiten (Page)
PixelOffsetMode: Der Pixeloffsetmodus bestimmt den Offset von Pixeln bei der Darstellung
TextRenderingHint: Angeben ob Text z.B. mit Antialiasing wiedergegeben wird.
Wie ihr sicher gemerkt habt, hab ich dabei versucht diese Befehle so weit wie möglich mit meinen eigenen Worten zu beschreiben.
Ansonsten hab ich einfach die Beschreibung von Microsoft übernommen.
Ich will einfach dahin kommen z.B. 1000 eigens definierte Objekte relativ schnell zu zeichnen.
Wenn sich der Algorithmus und die Implementation darum kümmern was neu gezeichnet werden muss und ggf. einige Optimierungsschalter gesetzt werden, sollte
es doch nicht so schwierig sein das ganze im Millisekunden Bereich zu zeichnen, oder was meint ihr?
Ich versuche also 1000 Grafik-Objekte zu zeichnen.
Diese sind von einer ganz einfachen Klasse CShape abgeleitet.
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Test
{
class CShape
{
private Point m_ptLocation = Point.Empty;
private bool m_bNeedsUpdate = false;
public bool NeedsUpdate
{
get { return this.m_bNeedsUpdate; }
set { this.m_bNeedsUpdate = value; }
}
public virtual Point Location
{
get { return this.m_ptLocation; }
set { this.m_ptLocation = value; }
}
public virtual void Draw(Graphics g)
{
}
}
}
Ob die Methode NeedsUpdate benötigt wird, ist noch fraglich. Lassen wir die einfach mal drin.
Und so sieht die Methode CRectangle aus:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace Test
{
class CRectangle:CShape
{
Random m_Random = new Random(DateTime.Now.Millisecond);
private Rectangle m_Rectangle = Rectangle.Empty;
public Size Size = new Size(150, 40);
private Color m_Color = Color.Blue;
private Brush m_Shadow = new SolidBrush(Color.FromArgb(128,0,0,0));
private Brush m_ColorBrush = null;
private Pen m_BorderPen = new Pen(new SolidBrush(Color.Black),2);
private Brush m_BlackBrush = new SolidBrush(Color.Black);
private SizeF m_szTextSize = SizeF.Empty;
private Font m_Font = new Font("Arial", 15);
private string m_sText = "Das ist ein test";
public CRectangle()
{
this.m_Random = new Random(this.GetHashCode());
this.m_Rectangle = new Rectangle(this.Location, this.Size);
int red = m_Random.Next(0, 255);
int green = m_Random.Next(0, 255);
int blue = m_Random.Next(0, 255);
this.m_Color = Color.FromArgb(red, green, blue);
this.m_ColorBrush = new SolidBrush(this.m_Color);
}
public override Point Location
{
get{ return this.m_Rectangle.Location; }
set{ this.m_Rectangle.Location = value; }
}
public override void Draw(Graphics g)
{
Rectangle rectShadow = new Rectangle(new Point(this.Location.X + 15, this.Location.Y + 15),this.Size);
g.FillRectangle(m_Shadow, rectShadow);
g.FillRectangle(m_ColorBrush, this.m_Rectangle);
g.DrawRectangle(m_BorderPen, this.m_Rectangle);
if (m_szTextSize.IsEmpty)
{
m_szTextSize = g.MeasureString(this.m_sText, this.m_Font);
}
g.DrawString(this.m_sText, this.m_Font, this.m_BlackBrush, new PointF(this.Location.X + this.Size.Width / 2 - m_szTextSize.Width / 2, this.Location.Y + this.Size.Height / 2 - m_szTextSize.Height / 2));
}
public Rectangle Rectangle
{
get { return this.m_Rectangle; }
}
public bool Hit(Point pt)
{
return this.m_Rectangle.Contains(pt);
}
public Color Color
{
get { return this.m_Color; }
set { this.m_Color = value; }
}
}
}
PS: Weitere Hinweise gibt es in "Gezieltes OwnerDrawing" - schnelles Zeichnen bewegter Objekte und Schnelle GDI(+) Grafik - wie? [Parallax Scrolling].